coily dispatch: interactive mode should refuse non-TTY / agent callers #11

Open
opened 2026-05-25 00:05:36 +00:00 by coilysiren · 0 comments
Owner

Problem

coily dispatch <ref> interactive writes a JSON queue entry under /tmp/coily-dispatch-queue/ and fires a warppreview://tab_config/<name> URL via open to spawn a new Warp tab. When the caller is an agent (Claude Code Bash tool) or any non-interactive context, two failure modes:

  • On kai-server (Linux, no Warp): open does not resolve the warp:// scheme. Already soft-fails via printInteractiveFallback (cli-guard/dispatch/interactive.go:360-363) but leaves an orphan queue file and prints fallback text the agent can't act on usefully.
  • On Kai's Mac with Warp running: would spawn a new tab in the background that no human sees — a stealth-spawned interactive session.

Neither is what an agent wants. Discovered in an SSH session from inside a Claude Code agent loop where the inner agent considered firing interactive dispatch and we walked through what would happen.

Fix

In cli-guard/dispatch/interactive.go's runInteractive (entry point at line 282), detect non-interactive callers up front and refuse:

  • CLAUDECODE / CLAUDE_CODE_SSE_PORT env vars set → agent caller.
  • os.Stdin is not a TTY (golang.org/x/term.IsTerminal(int(os.Stdin.Fd()))) → piped/headless caller.
  • Optionally: runtime.GOOS == "linux" → no Warp consumer for the queue.

Error out before writing the queue entry, with:

coily dispatch: interactive mode requires a human at a Warp tab. You appear to be running from an agent / non-interactive context. Use coily dispatch <ref> headless instead.

Why

Saves the stealth-spawn footgun on Mac, saves the orphan queue file + opaque fallback on Linux, and the tool says clearly what to do next instead of pretending to work.

Meta-context

Filing this on forgejo via curl + the /forgejo/api-token SSM secret because GH issues are disabled on coilysiren/cli-guard and no coily ops forgejo issue create verb exists yet. Adding that verb is its own meta-improvement worth filing separately.

Design context: coilysiren/coily#270 (headless/interactive split), coilysiren/coily#310 (move to cli-guard/dispatch package).

**Problem** `coily dispatch <ref> interactive` writes a JSON queue entry under `/tmp/coily-dispatch-queue/` and fires a `warppreview://tab_config/<name>` URL via `open` to spawn a new Warp tab. When the caller is an agent (Claude Code Bash tool) or any non-interactive context, two failure modes: - On kai-server (Linux, no Warp): `open` does not resolve the `warp://` scheme. Already soft-fails via `printInteractiveFallback` (`cli-guard/dispatch/interactive.go:360-363`) but leaves an orphan queue file and prints fallback text the agent can't act on usefully. - On Kai's Mac with Warp running: would spawn a new tab in the background that no human sees — a stealth-spawned interactive session. Neither is what an agent wants. Discovered in an SSH session from inside a Claude Code agent loop where the inner agent considered firing interactive dispatch and we walked through what would happen. **Fix** In `cli-guard/dispatch/interactive.go`'s `runInteractive` (entry point at line 282), detect non-interactive callers up front and refuse: - `CLAUDECODE` / `CLAUDE_CODE_SSE_PORT` env vars set → agent caller. - `os.Stdin` is not a TTY (`golang.org/x/term.IsTerminal(int(os.Stdin.Fd()))`) → piped/headless caller. - Optionally: `runtime.GOOS == "linux"` → no Warp consumer for the queue. Error out before writing the queue entry, with: > coily dispatch: interactive mode requires a human at a Warp tab. You appear to be running from an agent / non-interactive context. Use `coily dispatch <ref> headless` instead. **Why** Saves the stealth-spawn footgun on Mac, saves the orphan queue file + opaque fallback on Linux, and the tool says clearly what to do next instead of pretending to work. **Meta-context** Filing this on forgejo via curl + the `/forgejo/api-token` SSM secret because GH issues are disabled on `coilysiren/cli-guard` and no `coily ops forgejo issue create` verb exists yet. Adding that verb is its own meta-improvement worth filing separately. Design context: coilysiren/coily#270 (headless/interactive split), coilysiren/coily#310 (move to cli-guard/dispatch package).
coilysiren added
P3
and removed
P2
labels 2026-05-31 07:00:14 +00:00
Sign in to join this conversation.
No labels
P0
P1
P2
P3
P4
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/cli-guard#11
No description provided.