Skip to content

fix(interactive): the trigger prompt was never actually submitted - #278

Merged
ANonABento merged 1 commit into
mainfrom
interactive-prompt-submit
Aug 22, 2026
Merged

fix(interactive): the trigger prompt was never actually submitted#278
ANonABento merged 1 commit into
mainfrom
interactive-prompt-submit

Conversation

@ANonABento

Copy link
Copy Markdown
Owner

Two defects in the injection step, both found by watching a real claude TUI in its tmux pane. Together they meant interactive trigger mode had never submitted its own prompt — the pane sat with the text visible and unsent until the 2-hour timeout, which reads as a hung agent rather than a delivery bug.

1. The prompt was injected as a multiline payload

tmux send-keys -l sends text literally, newlines included. That does not submit each line — it leaves the TUI in multi-line input, and the Enter that follows adds another line instead of sending. Observed directly:

❯ add() subtracts instead of adding
  See .task.md for full spec.
  Follow the instructions in .agent.md.

…sitting in the composer indefinitely.

The default trigger prompt is "<title>\n\nSee .task.md for full spec.", so this was never an edge case.

flatten_for_injection collapses the prompt to one line. Nothing is lost — the detail lives in .task.md and .agent.md; the prompt is only a pointer.

Worth noting: the doc comment on append_sentinel_to_prompt already said the payload must stay newline-free, but the rule was only ever applied to the sentinel suffix, never to the prompt it was appended to. Its explanation of what a newline does was also wrong — it doesn't submit early — so that's corrected to match what the pane actually shows.

2. Enter was sent too soon after the text

Even flattened, the prompt stayed unsent. These TUIs ingest pasted text asynchronously and an immediate Enter is dropped. Confirmed by hand: the same pane submitted instantly when Enter was sent a moment later.

A 600ms settle now separates the two — generous on purpose, since the cost of waiting is a fraction of a second on a run measured in minutes, and the cost of being early is a trigger that hangs for two hours.

Verified end to end on a real column

step result
prompt injected + submitted
agent read .agent.md and followed it
planted bug fixed return a - breturn a + b
proof file written BENTO-INTERACTIVE
done sentinel emitted <<<KAITENCODE_DONE:…>>>
sentinel detected + persisted agent_done_signaled_at set
task advanced no — by design

That last row is correct behaviour, not a defect: interactive completion is advisory because the session stays alive for the human. The code says so itself, and the run confirmed the advisory path works.

Also confirmed on this path: git status in the worktree showed only math.js and agent-proof.txt.task.md and .agent.md correctly excluded, so #276's fix holds here too.

Checks

cargo clippy -D warnings · cargo test --lib 566 (+2) · tsc · eslint · test:ipc · test:type-scale · vitest 444.

Two defects, both in the injection step, both found by watching a real
claude TUI in its tmux pane.

The prompt was injected as a multiline payload.

`tmux send-keys -l` sends the text literally, newlines included. That does
not submit each line — it leaves the TUI in multi-line input, and the
`Enter` that follows adds another line instead of sending. The default
trigger prompt is `"<title>\n\nSee .task.md for full spec."`, so this was
not an edge case: interactive triggers had never submitted their own
prompt. The pane sat with the text visible and unsent until the 2-hour
timeout, which reads as a hung agent rather than a delivery bug.

`flatten_for_injection` collapses the prompt to one line. Nothing is lost —
the detail lives in `.task.md` and `.agent.md`, and the prompt is only a
pointer to them.

The existing doc comment on `append_sentinel_to_prompt` already said the
payload must stay newline-free, but the rule was only ever applied to the
sentinel suffix, never to the prompt it was appended to. Its explanation of
what a newline does was also wrong (it does not submit early); corrected to
match what the pane actually shows.

Enter was sent too soon after the text.

Even flattened, the prompt stayed unsent: these TUIs ingest pasted text
asynchronously and an immediate `Enter` is dropped. Confirmed by hand — the
same pane submitted instantly when Enter was sent a moment later. A 600ms
settle now separates the two. Generous on purpose: the cost of waiting is a
fraction of a second on a run measured in minutes, and the cost of being
early is a trigger that hangs for two hours.

Verified end to end on a real column: prompt submitted, agent read
`.agent.md` and followed it, fixed the planted bug, wrote its proof file,
and emitted `<<<KAITENCODE_DONE:…>>>`, which the watcher detected and
persisted to `agent_done_signaled_at`. The task deliberately did not
advance — interactive completion is advisory, since the session stays alive
for the human. `.task.md` and `.agent.md` were correctly absent from
`git status`, confirming the exclude fix holds on this path too.
@ANonABento
ANonABento merged commit a2f8b91 into main Aug 22, 2026
3 checks passed
@ANonABento
ANonABento deleted the interactive-prompt-submit branch August 22, 2026 17:33
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