Skip to content

feat: surface permission-blocked crews - #19

Merged
ruby-dlee merged 4 commits into
mainfrom
fm/perm-dialog-detect-p2
Jul 22, 2026
Merged

feat: surface permission-blocked crews#19
ruby-dlee merged 4 commits into
mainfrom
fm/perm-dialog-detect-p2

Conversation

@ruby-dlee

Copy link
Copy Markdown
Owner

Intent

Make Firstmate surface blocking permission situations instead of silently stalling. Detect post-spawn Codex and Claude harness permission or trust prompts in stale crew panes using the existing harness-adapter knowledge and route them through the existing watcher and stuck-crewmate-recovery owner as a captain-facing request to grant the permission, never auto-approving, dismissing, or duplicating a recovery skill. Investigate macOS TCC and system-modal detection honestly; because portable direct detection is unavailable without pre-granted Accessibility or Screen Recording access and process or window-owner probes create false positives, use a documented semantic no-progress timeout heuristic for suspected system-dialog stalls and clearly label it as heuristic. Keep the diff single-concern: exclude away-mode reap-wake behavior, general permission-grant documentation, and self-compaction. Preserve one-sentence-per-line prose, shellcheck-clean scripts, colocated isolated watcher tests, and no agent co-author.

What Changed

  • Detect stale post-spawn Claude and Codex permission or trust prompts and escalate them to the captain without approving or dismissing them.
  • Add a configurable semantic no-progress timeout that flags possible macOS permission or system-dialog stalls while clearly identifying the result as heuristic.
  • Update recovery guidance and documentation, with isolated watcher coverage for prompt classification, lifecycle gating, and timeout escalation.

Risk Assessment

✅ Low: The change is well-bounded, generation-scopes trust escalation correctly, preserves spawn-time trust handling, covers verified Codex and Claude prompt variants, and labels the macOS fallback honestly as a heuristic.

Testing

The supplied complete baseline was green; focused prompt regression coverage and real-tmux end-to-end checks also passed, producing durable transcripts for captain-facing escalation, no auto-approval, and explicitly heuristic system-dialog suspicion.

Evidence: Permission prompt end-to-end transcript
END-USER PANE
Would you like to run the following command?

Environment: local

$ touch .permission-probe-codex

› 1. Yes, proceed (y)
  2. Yes, and don't ask again for this command (p)
  3. No, and tell Codex what to do differently (esc)

Press enter to confirm or esc to cancel














FIRSTMATE WATCHER OUTPUT
stale: @0 (permission-prompt detected: waiting for a command/tool permission grant; inspect the requested action and escalate it to the captain - do not approve it automatically; escalation 1)

DURABLE WAKE AS DRAINED BY FIRSTMATE
1784734723	1	stale	@0	stale: @0 (permission-prompt detected: waiting for a command/tool permission grant; inspect the requested action and escalate it to the captain - do not approve it automatically; escalation 1)

SAFETY CHECK
PASS: permission was not auto-approved; probe file does not exist.
Evidence: System-dialog heuristic end-to-end transcript
END-USER PANE (accelerated 1-second test threshold; production default is 900 seconds)
• Running osascript -e request_access
progress: waiting for user decision
• Working (901s • esc to interrupt)






















FIRSTMATE WATCHER OUTPUT
stale: @0 (permission/system-dialog suspected: no meaningful progress for 1s while the harness remained busy; inspect the visible macOS dialog or Privacy & Security in System Settings and escalate any grant to the captain; timeout heuristic, not direct OS detection; escalation 1)

DURABLE WAKE AS DRAINED BY FIRSTMATE
1784734743	1	stale	@0	stale: @0 (permission/system-dialog suspected: no meaningful progress for 1s while the harness remained busy; inspect the visible macOS dialog or Privacy & Security in System Settings and escalate any grant to the captain; timeout heuristic, not direct OS detection; escalation 1)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 2 issues found → auto-fixed (2) ✅
  • 🚨 .agents/skills/harness-adapters/SKILL.md:56 - Intent requires “Detect post-spawn Codex and Claude harness permission or trust prompts” and forbids auto-approval. This branch protects only mid-run permissions and explicitly leaves startup trust handling separate; the existing Claude and Codex instructions still accept trust dialogs with Enter. Trust prompts therefore receive only generic stale handling and can still be auto-approved instead of becoming a captain-facing request. Add both verified trust shapes to the protected recovery branch, unless trust prompts were intentionally excluded despite the acceptance criterion.
  • 🚨 bin/fm-watch.sh:453 - The Codex matcher requires 3. No for every listed prompt, but the current permissions overlay has three affirmative choices and No as option 4. It also omits Codex’s network-access approval title. Consequently these permission prompts miss immediate classification and fall through to generic stale handling. Match each verified shape independently and add fixtures for the permissions and network variants. Codex approval overlay

🔧 Fix: Protect trust and Codex permission prompts
1 error still open:

  • 🚨 bin/fm-watch.sh:447 - The requested fix says to protect trust shapes “only when they appear mid-run,” but the matcher has no lifecycle gate: task metadata becomes visible to the watcher before the harness launches, so the normal spawn-time Claude/Codex workspace-trust dialog can match here and be escalated instead of accepted during the spawn peek. The tests likewise classify bare newly-created metadata as mid-run. Gate directory-trust classification on evidence that the brief has started processing while retaining ordinary spawn-time trust handling.

🔧 Fix: Gate trust escalation on current-generation processing
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; uv run --directory tools/agent-fleet --locked pytest || rc=1; uv run --directory tools/agent-fleet --locked python -m compileall -q src || rc=1; exit "$rc"
  • Pre-run baseline reported successful: command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; uv run --directory tools/agent-fleet --locked pytest || rc=1; uv run --directory tools/agent-fleet --locked python -m compileall -q src || rc=1; exit "$rc"
  • FM_TEST_FOCUSED=permission-prompts bash tests/fm-watch-triage.test.sh
  • Real isolated tmux pane → bin/fm-watch.shbin/fm-wake-drain.sh for a Codex command-permission prompt; verified .permission-probe-codex remained absent
  • Real isolated tmux pane → bin/fm-watch.shbin/fm-wake-drain.sh for a busy no-progress stall using FM_PERMISSION_STALL_ESCALATE_SECS=1 to accelerate the documented 900-second production timeout
  • git status --short --untracked-files=all; confirmed the worktree remained clean and the isolated tmux server was stopped
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@ruby-dlee
ruby-dlee force-pushed the fm/perm-dialog-detect-p2 branch from 7621a54 to 74a79dd Compare July 22, 2026 16:04
@ruby-dlee
ruby-dlee merged commit ca4e068 into main Jul 22, 2026
5 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