Allow async Stop to start a same-session continuation (KV cache)

Open 💬 1 comment Opened Aug 12, 2026 by manojbajaj95

What we are trying

knowcards captures durable repo facts at end of turn. The reflect step must run on the same session id and message history so the model reuses KV cache. A separate worker/LLM (truncated transcript) throws that cache away.

We want that continuation after the user-facing turn ends (background / idle wake), not as a fake user message in the middle of the answer.

What Codex does today

  • Sync Stop + decision: \"block\" + reason works: Codex creates a new user prompt from reason and continues the same session. That keeps KV cache, but it is a user-channel message and it runs immediately.
  • Docs: a background hook that finishes while no turn is active waits for the next user turn and does not start a new turn.
  • Related: async command hooks may still be skipped at load (#34694).

So we cannot both (1) stay on this session for KV cache and (2) defer reflect until the UI has stopped.

Request

Let an async Stop handler start a same-session continuation when it returns decision: \"block\" + reason (or hookSpecificOutput.additionalContext as developer context, not a user prompt).

Ideal shape:

  • Same session_id / transcript prefix (KV cache hits).
  • Not a user-visible chat bubble (developer / system reminder).
  • May start after the user-facing turn is idle (wake), instead of only attaching to the next human prompt.

Workaround in knowcards

knowcards install codex keeps Stop synchronous for now. Adapter: src/adapters/codex-reflect.ts

Claude Code has asyncRewake (exit 2 wakes the idle session). We use that there. Codex has no equivalent.

View original on GitHub ↗

1 Comment

jdcodes1 · 9 days ago

The runtime primitive you need already exists — it's just not reachable from hook results. Core sessions have a mailbox whose items can be flagged trigger_turn; when the thread goes idle, maybe_start_turn_for_pending_work starts a synthetic same-session turn to drain them — no user prompt involved, same thread, same transcript prefix, so KV cache is preserved (https://github.com/openai/codex/blob/1f41cc5d92/codex-rs/core/src/tasks/mod.rs#L442-L492). That is exactly "wake the idle session with developer-channel input": it's how inter-agent mail and the goal extension's idle continuation (ext/goal/src/runtime.rs, continue_if_idle) already work.

So the feature could be narrow: let an async Stop handler's decision: "block" (or a new continuation field) enqueue a mailbox item with trigger_turn = true and developer-channel provenance, instead of today's behavior of synthesizing a user prompt inline. All three of your requirements fall out of the existing machinery — same session id, non-user-visible channel, and deferred start on idle rather than attached to the next human prompt.