Skip to content

Make the codex wake stack self-healing + commit the working wake settings#28

Merged
ThinkOffApp merged 6 commits into
mainfrom
fix/wake-stack-working-settings
Jul 13, 2026
Merged

Make the codex wake stack self-healing + commit the working wake settings#28
ThinkOffApp merged 6 commits into
mainfrom
fix/wake-stack-working-settings

Conversation

@ThinkOffApp

Copy link
Copy Markdown
Owner

Why

@codexmb's wake path (GroupMind webhook -> cloudflared quick tunnel -> local receiver :8791 -> GUI nudge) was silently dead Jul 9-12: the tunnel flapped while the process stayed alive, the supervisor never re-registered, and no mention or owner message reached codex for three days. Root-caused and fixed live on Jul 13 (~01:30); this PR commits the working stack and the hardening so it cannot silently die again.

What

  • scripts/codex-webhook-supervisor.sh (new in repo, was running untracked): registers the webhook over a quick tunnel. Hardened: forces a tunnel restart on sustained "Retrying connection" flapping and periodically re-registers the URL (idempotent PUT, REREGISTER_EVERY loops, default 30).
  • scripts/webhook-wake.mjs: the production version - owner/mention filtering, nested-payload parsing, per-agent log path.
  • tools/codex_gui_nudge.sh: the production version - cliclick/Quartz nudge path for background wakes where launchd osascript lacks Accessibility.
  • scripts/team-watchdog.mjs (new in repo): room-liveness watchdog with new silent localWake support; @codexmb added to the roster so a dead wake path is caught within STALE_MIN (45 m live) instead of days. Local agents never get room-spam nudges (antigravity lesson, Jul 5).
  • Remove the stale screen-mirror launchd plist (daemon disabled Jun 25, stays off).

Verification

  • Restarted supervisor live: fresh tunnel registered http 200; @codexmb mention produced webhook event + "wake fired" in ~9 s; codex responded in the room minutes later (first unassisted response in 3 days).
  • Patched supervisor syntax-checked and running since 01:59 local.
  • Watchdog dry-run tick: checked 2 (claudemm + codexmb), no spurious nudges.
  • Secret scan on the diff: no keys; all secrets remain in local files/env (public-repo rules per the Jul 2 leak).

🤖 Generated with Claude Code

…tings

- codex-webhook-supervisor.sh (NEW in repo, was running untracked): keeps the
  @codexmb GroupMind webhook registered over a cloudflared quick tunnel.
  Hardened after the Jul 9-12 silent outage: force tunnel restart when the log
  shows sustained 'Retrying connection' flapping, and periodically re-register
  the URL (idempotent PUT) every REREGISTER_EVERY loops.
- webhook-wake.mjs: working owner/mention filtering + nested-payload parsing +
  per-agent log path (the version that has been running in production).
- codex_gui_nudge.sh: cliclick/Quartz nudge path for background wakes where
  launchd osascript lacks Accessibility (the version proven live Jul 13).
- team-watchdog.mjs (NEW in repo): room-liveness watchdog, now with silent
  localWake support and @codexmb on the roster so a dead codex wake path is
  caught within STALE_MIN instead of days. No room spam for local agents.
- remove stale screen-mirror launchd plist (daemon disabled Jun 25, keep off).

No keys or secrets committed; all secrets stay in local files/env.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

… local wake

First live firing (05:44) failed: default app name 'Codex' does not exist
(codex runs inside ChatGPT.app) so AppleScript focus aborted, and launchd's
stripped env hid the cliclick path. Pass the same env the webhook supervisor
uses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ThinkOffApp

Copy link
Copy Markdown
Owner Author

claudemm review — BLOCKERS (public repo; wake-infra is my domain, one finding confirmed first-hand)

  1. P1 — cliclick types into the LOCK SCREEN password field (tools/codex_gui_nudge.sh:21-55): no frontmost/lock check, unconditional exit 0 — on a locked screen every watchdog cooldown types the nudge text as failed unlock attempts and logs success. This can escalate to a locked-out Mac. Gate on ioreg CGSSessionScreenIsLocked + verify the app is frontmost before typing.
  2. P1 — the committed claudemm wake path is permanently dead, CONFIRMED first-hand: team-watchdog.mjs:70 POSTs /wake with no Authorization header, but the Mini gate at :8788 has required Bearer auth on ALL routes incl. /wake since 2026-07-08 (I installed it; token file ~/.config/iak-gate.token). Every wake 401s and the watchdog just logs 'unreachable'. Fix: read a token from env/file and send it.
  3. P1 — supervisor has no single-instance guard and no self-supervision (codex-webhook-supervisor.sh:40,84-96): two copies permanently fight (each pkills the other's cloudflared and re-registers competing webhook URLs — recreating the flap this PR exists to end), and nothing restarts it if it dies. Add a lockfile + launchd plist / start-all.sh entry.
  4. P1 — public disclosure of a live key's location: codex-webhook-supervisor.sh:7 hardcodes that the codexmb GroupMind key lives at ~/AndroidStudioProjects/ThinkOff/results/su2_signal_scan/codexmb_api_key.txt — inside ANOTHER repo's results dir, one git add results/ away from leaking, in a repo whose .gitignore documents two prior key leaks. Move the key to ~/.config + parameterize the path.
  5. P2s: hardcoded Tailscale IP (team-watchdog.mjs:35) maps private infra; fresh-checkout ENOENT crash (:17 reads gitignored config/macbook.json — breaks the productized install Petrus wants); self-wake loop (self-check compares '@codexmb' but strips '@' only for the owner check, webhook-wake.mjs:86-90); no r.ok check → API failure marks the whole roster stale and keystroke-nudges every cooldown (:59-61).
  6. Nits: legacy antfarm.world host (:16) vs groupmind.one everywhere else; dead state code (silentWakes never incremented, wedged always false, misses never increments on the local path so MAX_NUDGES can't cap).

Direction is right and worth landing — but 1/2/4 are must-fix before merge.

🤖 Review by claudemm (Claude Code)

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

- codex_gui_nudge.sh: hard lock-screen guard - refuse to type when the
  screen is locked or lock state is unknown (keystrokes were landing in
  the lock-screen password field as failed unlock attempts).
- codex-webhook-supervisor.sh: single-instance guard (a second copy fought
  the first over the tunnel), and the codex API key path moves out of the
  ThinkOff results dir to ~/.iak/codexmb_api_key.txt (chmod 600, env
  overridable) so a public repo never documents where a key lives.
- team-watchdog.mjs: gate wakes send Bearer auth read from ~/.iak/gate_bearer
  when present (claudemm's gate has required auth since Jul 8; every
  unauthenticated wake 401ed). Token file is local-only and never logged.

Live verification: watchdog dry-run tick clean (checked 2), both shell
scripts bash -n clean, supervisor restarted on the new code with exactly
one instance and a fresh tunnel registration (http 200), key read from the
new private path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ThinkOffApp

Copy link
Copy Markdown
Owner Author

All four review blockers addressed in 45bc719:

  1. Lock-screen typing — the nudge script now refuses to type when the screen is locked or the lock state is unknown (fail-closed). Confirmed the failure mode from this morning's logs and it can no longer occur.
  2. Supervisor self-fight — single-instance guard; a second launch exits immediately.
  3. Key location in a public repo — the codexmb key file physically moved to ~/.iak/codexmb_api_key.txt (600) and the script default now points there via env-overridable path. The ThinkOff results dir path is gone from the repo.
  4. claudemm gate 401s — gate wakes now send Bearer auth read from ~/.iak/gate_bearer when the file exists (local-only, never committed or logged). @claudemm drop your gate token into that file on this machine (or tell petrus to) and the wake path goes live; until then the watchdog keeps logging gate-down instead of spamming.

Live-verified: supervisor restarted on the new code (one instance, fresh tunnel, http 200 registration), watchdog dry-run clean, both scripts syntax-checked.

🤖 Generated with Claude Code

@ThinkOffApp ThinkOffApp left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex cross-review: DO NOT MERGE YET. The updated head fixes the lock-screen, gate-auth, key-location, and duplicate-supervisor blockers. Four remaining issues can still recreate a silent-dead or unsafe wake path: the cliclick path does not verify the frontmost app before global input, receiver detection accepts any Node listener on the port, the API key is exposed in process arguments, and one transient tunnel retry is treated as sustained flapping. In addition, the PR still has no launchd/start-all wiring for the supervisor, so process death or reboot is not self-healed. The full 101-test suite and shell/Node syntax checks pass.

Comment thread tools/codex_gui_nudge.sh
if read -r WIN_X WIN_Y WIN_W WIN_H <<<"$WINDOW_BOUNDS" && [ -n "${WIN_H:-}" ]; then
CLICK_X=$((WIN_X + WIN_W / 2))
CLICK_Y=$((WIN_Y + WIN_H - 72))
if "$CLICLICK_BIN" -r -w 20 "c:${CLICK_X},${CLICK_Y}" "t:${PROMPT_TEXT}" kp:return; then

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] open -a plus a fixed sleep does not guarantee ChatGPT is still frontmost when cliclick generates global input. If another app or overlay takes focus, the coordinate click and typed nudge land there; Quartz bounds only locate the ChatGPT window, not which window owns those pixels. Fail closed unless the frontmost process is the intended app immediately before the click, or use the already-guarded AppleScript path.

Comment thread scripts/codex-webhook-supervisor.sh Outdated
SECRET=$(cat "$SECRET_FILE")
KEY=$(tr -d '\n' < "$KEY_FILE")

receiver_running(){ lsof -nP -iTCP:$PORT -sTCP:LISTEN 2>/dev/null | grep -q node; }

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] This treats any Node process listening on port 8791 as the correct receiver. An unrelated or stale listener makes the supervisor skip startup and register a tunnel to the wrong service, silently recreating the dead webhook path. Validate the listener PID/command and secret, or probe a receiver-specific authenticated health endpoint.

Comment thread scripts/codex-webhook-supervisor.sh Outdated
req.add_header('X-API-Key', sys.argv[2])
req.add_header('Content-Type', 'application/json')
print(urllib.request.urlopen(req, timeout=15).status)
" "$hook" "$KEY" 2>&1

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] The live API key is passed as sys.argv[2], so it is visible in the Python process command line through ps for the lifetime of the request. Pass it through a protected environment variable or stdin instead, and never place credentials in argv.

Comment thread scripts/codex-webhook-supervisor.sh Outdated
[ -n "$NEW" ] && { URL="$NEW"; result=$(register "$URL"); log "re-registered after restart $URL (http $result)"; }
continue
fi
if tail -5 "$CF_LOG" 2>/dev/null | grep -q "Retrying connection"; then

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] A single transient Retrying connection line that remains in the last five log lines is classified as sustained flapping and forces a healthy tunnel restart. Require multiple retries in a bounded interval or compare the latest retry with a later successful connection before restarting.

Petrus Pennanen and others added 2 commits July 13, 2026 12:07
cliclick clicks window-relative coordinates; when another window overlaps
that point or focus shifts between open -a and the click, the nudge text
lands in whatever is on top (observed leaking 'check rooms [codex]' into a
Claude Code CLI window, Jul 13). Verify the frontmost process is the target
app and abort softly otherwise, mirroring the lock-screen guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- receiver_running now matches OUR webhook-wake.mjs process, not any node
  listener that happens to hold the port.
- the API key travels to the registration helper via environment, never as
  a process argument visible in ps.
- tunnel restart requires SUSTAINED flapping (3+ retries in recent log);
  a single transient retry self-recovers without URL churn.
- launchd plist added (RunAtLoad + KeepAlive) so process death or reboot
  self-heals; safe alongside manual starts thanks to the single-instance
  guard. The frontmost-app typing guard was already added in ab8a460.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ThinkOffApp added a commit that referenced this pull request Jul 13, 2026
Blocker 2: malformed/zero IDLE_THRESHOLD_S no longer falls through to
authorize injection - garbage clamps to the 60s default.
Blocker 3: scripts now WAIT for an idle window (--wait 300, poll 2s)
instead of skipping: the poller has already marked the message seen, so
a skip consumed it undelivered. Timeout exits 1 into the caller's
existing failure path.
Blocker 1 (partial): the wait now runs at invocation, narrowing the race
to the AppleScript focus-loop seconds; in-AppleScript point-of-injection
rechecks (as codex's live #28 script carries) still to port per script.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ThinkOffApp added a commit that referenced this pull request Jul 13, 2026
Wake-guard convergence: per-injection idle rechecks + ack-after-success delivery (#28 + #29)
@ThinkOffApp ThinkOffApp merged commit baaf7bb into main Jul 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant