background jobs: tell the agent not to discard command output

Traced "(no output yet)" on a live commander to the actual running process on
this machine rather than guessing: the tray's log-tail was working correctly
(it's a general /chat feature, nothing to fix there) — the task's .output
file was genuinely empty because the agent had written
`timeout 8 ping -c 1 -W 5 google.com >/dev/null 2>&1`, throwing away ping's
own output and only echoing on a failed ping. Correct for "let me know if it
goes down," but it means a healthy watcher shows nothing at all, indistin-
guishable at a glance from a stuck one.

buildBackgroundJobPrompt gains an unconditional rule — every job shape, not
only watchers — telling the agent not to redirect a command's own output to
/dev/null or similar: whatever it would print in a terminal is what the owner
wants to see live in the job's log. Landed at rule 8 for watchers (after the
existing fire rule), 5 for a bare command, 4 for a bare prompt — whichever
number falls after the rules already in that branch, so rule 7's existing
identity (referenced by number in tests, docs and COMMS) is untouched.

Also lightly reworded rule 7's "stay silent" line: it was already only about
the agent's own narration, not the underlying command's output, but the
distinction wasn't explicit and reads exactly like the instinct that produced
the >/dev/null in the first place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 10:34:03 +00:00
co-authored by Claude Opus 5
parent 963c965056
commit a335fad9a6
2 changed files with 32 additions and 2 deletions
+13
View File
@@ -494,6 +494,19 @@ so a commander open in the panel at the moment this fires keeps showing the old
navigation or reload. The grid's cards do not have this problem — `GET /commanders` is already polled every
15s. Flagged rather than fixed; worth a `refetch()` hook if it turns out to matter in practice.
**"(no output yet)" on that same google.com watcher, traced to the actual running process on this
machine rather than guessed at.** The tray's live-log-tail (`BackgroundTaskTray` → `useTaskDetail` →
`GET /chat/tasks/:id` → `loadBackgroundTask`/`tailFile`) is a general `/chat` feature Command HQ gets for
free — nothing to build there, and it was already working correctly. The task's `.output` file was
genuinely empty: the agent had written `timeout 8 ping -c 1 -W 5 google.com >/dev/null 2>&1`, silencing
`ping`'s own output entirely and only ever `echo`ing on a FAILED ping — correct per "let me know if it goes
down," but it means a healthy watcher shows nothing at all, indistinguishable at a glance from a stuck one.
Fixed at the source rather than in the tray: `background-job-prompt.ts` gained an unconditional rule (every
job, not only watchers — number 4, 5 or 8 depending on which rules already preceded it in that particular
prompt) telling the agent not to discard a command's own output. The tray already shows whatever reaches
the log file live; the gap was that jobs were routinely told, by habit rather than by this prompt, to send
that output to `/dev/null`.
**A real bug, caught by tracing rather than by the compiler, worth stating plainly.** When the cost-tracking
schema changed `recordCommandHqWatcherFired`'s signature from `(userId, sessionId)` to `(sessionRowId,
taskId)`, the ONE existing call site was not updated in the same pass — and `bunx tsgo` stayed clean, because