Repository navigation
Replies: 2 comments 1 reply
|
So I ran into this issue and I'm not gonna open a PR for it until there's been some discussion because it changes a major way in which tasks are detected and completed. What are your thoughts on this? |
|
I took the steer and looked at how pluk is wired for claude in ClankeR before Setup: a real contributor relay task on Result 1 — pluk calls a working claude idle, in every sampleFeeding 96 out of 96. Not a single agreement while the agent was working, and the agent The cause is one line. claude renders its input box while a turn is in pluk's if (this.patterns.idle?.test(line)) newState = 'idle';
else if (this.patterns.working?.test(line)) newState = 'working';so idle wins on any line matching both. The relay avoids this by keying on Related: pluk's claude working glyphs are Result 1b — the one time it said "working", the agent was blockedpluk emitted The agent is stopped dead waiting for a keypress. pluk read it as working So across the run the classification was wrong in both directions: 96 samples Result 2 — over pipe-pane, the patterns never match at allThat was the charitable test — clean text, one line at a time. The real input is Correction to something I said earlier in this thread: I first read this as The problem is what those lines are. A cursor-addressed repaint delivers And none of them can match
That second one is the sharp end. Across the 141 captured panes, Replaying the captured bytes gives 7 What I think this meansNot that the pluk direction is wrong — the So I am not opening a PR to swap the relay's classifier over. What I would
CaveatsOne backend, one session, one machine. The numbers are claude-specific and I |
Uh oh!
There was an error while loading. Please reload this page.
Eight fixes have gone into the same subsystem, and I think they share one root cause. I've just written the eighth, so this is as much a note on my own patch as anyone's.
The pattern
Every one is the same question asked badly: is the agent still working? And every one answers it by reading rendered terminal output and guessing.
Two from the last few days show how narrow the failure surface is:
HIVE_GITHUB_TOKEN…".isWorkingmatched the wordwriting. A finished agent looked busy.hasCompletionMarkerneededcompleted|done|finished, none of which appeared. A finished agent looked unfinished.Same root cause, opposite directions. Both were patched by adjusting the pattern. The ninth of these is already out there waiting — a model phrases a summary differently, or a vendor moves a box-drawing rule, and we write another regex.
Why this can't be fixed by better regexes
The patterns aren't matching a protocol. They're matching a presentation layer owned by someone else, which changes without notice and without a version bump:
writing/done/finishedappearing is a coin flip on phrasing.The direction of error is asymmetric and both directions hurt. Reporting a busy agent as finished abandons real work. Reporting a finished agent as busy burns the task budget and books a failure — on tasks that shipped a green PR, in at least #4064, #4182 and #4265.
There is already a better answer in-tree
Headless mode decides completion from the process exit code.
No prose. No chrome.
exit 0means the same thing in every model, every version, forever. One-shot specs already exist for six backends —claude -p,codex exec,copilot -p,goose run --no-session -t,agy -p,litellm -p.Notably, none of the eight bugs above are in the headless path. It's less exercised, so that's suggestive rather than proof — but the structural reason holds: a one-shot process announces completion by exiting, while a REPL never announces anything, so the interactive path is reduced to reconstructing information the headless path gets for free.
And there's a second precedent:
HIVE_VERDICT: no_work_needed. That isn't inference either — the prompt specifies the exact form and the relay anchors on it. It's a contract. It has held across backends because both ends agreed on it in advance.Worth noting the contract approach demonstrably works on live agents: #4177 added a DCO sign-off instruction to the prompt, and on its first real run an agent planned and applied
git commit -sunprompted. #4244 did the same for draft PRs.Signals, ranked
HIVE_VERDICT:)esc to interrupt)writing,done)The eight bugs are all tier 3 and 4. #4128 and #4182 moved agy from 4 to 3; #4265 does the same for codex. That's an improvement, and it's still standing on someone else's presentation layer.
What I'm not proposing
Not "switch everyone to headless." Interactive mode earns its place. Every diagnosis behind these eight fixes came from attaching to the pane and watching — including the two this week, where the captured pane was the reproduction. It's also how a contributor intervenes when an agent goes sideways, and
agyis host-only regardless.And not a redesign PR. This is an architecture decision spanning every backend, and the tradeoffs aren't mine to weigh.
The actual question
Should interactive mode stop deciding completion from rendered output?
Two directions, both already precedented in this repo:
A. Extend the sentinel contract. The prompt already asks for
HIVE_VERDICT: no_work_neededwhen there's nothing to ship. It could equally ask for a completion marker when there is. Completion becomes a declared fact rather than an inferred one, and one contract replaces five backend-specific pattern sets. The weakness is honest: it depends on the agent complying, so the chrome heuristics stay as a fallback — but they'd stop being the primary signal.B. Detect the CLI's return to idle structurally. The same instinct as
paneForegroundCommand(), which already asks tmux what a pane is running rather than grepping its text. Harder for a REPL that never exits, but it's asking the OS instead of the vendor.Happy to implement whichever direction, or neither — mostly I wanted the pattern written down somewhere, because eight fixes to one subsystem reads like a bug count and I think it's actually a design signal.
Context: found while running a contributor relay on
agyandcodexover the last two days. Every claim above is from the code or captured relay/pane output.All reactions