diff --git a/src/servers/api/command-hq/directory.ts b/src/servers/api/command-hq/directory.ts index 72c12da6..c82387da 100644 --- a/src/servers/api/command-hq/directory.ts +++ b/src/servers/api/command-hq/directory.ts @@ -351,8 +351,12 @@ export function commanderClaudeMd(params: CommanderClaudeMdParams): string { 'broken on its first day.', '', 'Then how often to look — and offer **as soon as it lands** alongside the intervals, because that is a', - 'real option here rather than a wish. Categories and dispatching come later still, one at a time, and', - 'most commanders never need either.', + 'real option here rather than a wish.', + '', + 'Once it is armed, the conversation is not over: ask what should happen next. Filing what it produces', + 'into categories, doing something with a result beyond keeping it, or nothing at all — leaving it as a', + 'watcher that quietly does one job is a complete answer and often the right one. Ask, one at a time,', + 'rather than deciding for them that there is nothing more to discuss.', '', '**Never arm a watcher before the owner has agreed what it does.** Arming ahead of that is arming a', 'guess, and a wrong condition either never fires or fires constantly — either way it is found out days', @@ -367,6 +371,14 @@ export function commanderClaudeMd(params: CommanderClaudeMdParams): string { 'knows how to handle items it has not seen — that is the whole of what a watcher is — so handing it the', 'backlog costs nothing and hands the owner a running commander in the time one item takes.', '', + '**Then keep talking. Do not wait for the backlog to finish.** You proved the pipeline on one item, so', + 'the rest working is expected rather than news — say it is armed and move straight to the next', + 'question. No sleeping, no polling a log, no "I will confirm once it is done". The owner does not need a', + 'progress report on work they already know succeeds.', + '', + 'If something DOES go wrong in the backlog, that is worth saying — in the conversation if it is still', + 'open, or as a notification if it is not. A failure is news. A success is not.', + '', 'Once the job is settled, write it into this file, replacing this section: what you watch for, what you', 'do about it, and which numbers were guesses. The next session should read the answer, not the', 'questions.', diff --git a/src/servers/api/command-hq/router.ts b/src/servers/api/command-hq/router.ts index 92e7d0f5..74301230 100644 --- a/src/servers/api/command-hq/router.ts +++ b/src/servers/api/command-hq/router.ts @@ -274,6 +274,9 @@ commandHqRouter.get('/commanders', async (ctx) => { // on `dirName`, not the transcript id: the pid file lives in this commander's OWN `state/`, not // beside the transcript. watcherArmed: row.watcherArmed || liveLoopPid(who.email, row.dirName) !== null, + // Whether the LOOP is alive right now, separate from `running` (an agent turn in progress) and from + // `watcherArmed` (which is also true for a row that says armed but whose loop has gone). + watcherRunning: liveLoopPid(who.email, row.dirName) !== null, watcherArmedAt: row.watcherArmedAt, watcherStoppedAt: row.watcherStoppedAt, watcherLastFiredAt: lastFiredByRow.get(row.id) ?? null, @@ -457,6 +460,7 @@ commandHqRouter.get('/commanders/:sessionId', async (ctx) => { tagIds: tagsByRow.get(row.id) ?? [], running, watcherArmed: row.watcherArmed || liveLoopPid(who.email, row.dirName) !== null, + watcherRunning: liveLoopPid(who.email, row.dirName) !== null, watcherArmedAt: row.watcherArmedAt, watcherStoppedAt: row.watcherStoppedAt, watcherLastFiredAt: lastFiredByRow.get(row.id) ?? null, diff --git a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx index 658f2372..90c2843c 100644 --- a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx +++ b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx @@ -608,8 +608,10 @@ function MetaBar({ sessionId, title, isConnected, isGenerating, onDisconnect }: {commander.watcherArmed ? ( - - watcher armed + + {commander.watcherRunning ? 'watching' : 'armed, loop not running'}