Skip to content

[enhancement] A raw engine forgets every previous turn — one-shot spawn is the design, and no preset, panel or doc says so #449

Description

@serge-ivo

Every turn on a raw engine starts a fresh conversation — continuity is one preset string, and no preset has it

Filed from the #249 assessment, recommendation item 3 — "Continuity as configuration… Zero code.
Memo item 2, still open."
#249 cannot close leaving the proposed ADR as its only record.

The mechanism

Claude is the only persistent engine: the runner keeps one process alive and speaks structured
stream-json to it across turns. Every other engine is one-shot
(packages/browser-runner/src/coding/headless.ts:378-380, :463-482):

private get oneShot(): boolean { return this.mode === "raw"; }

private runOneShot(text: string): void {
    const proc = spawn(this.cmdBin, [...this.cmdArgs, text], { cwd: , env: mergeEnv() });

with the contract stated deliberately at :466-468:

"the preset command is a prefix and the turn text is appended as the final argument"

So the Pilot's step 7 instruction is codex exec --sandbox danger-full-access "<step 7>" — a brand
new process that has never seen steps 1–6. The working tree carries state; the conversation does
not. A step that says "now do the same for the other two files" has no antecedent.

docs/coding-engines.md:7-27 documents the prefix contract precisely and correctly, and says
nothing about what it costs across turns.

None of the shipped presets carries a resume flag

workers/api/src/lib/coding-engines.ts:253-267 — the defaults an instance that has saved nothing gets:

id command persistent?
claude claude --dangerously-skip-permissions yes — stream-json, --resume handled by buildClaudeArgs
codex codex exec --sandbox danger-full-access no
gemini gemini --approval-mode yolo --skip-trust --prompt no
grok grok --permission-mode bypassPermissions -p no
local ollama run llama3 no

Claude's continuity is not a preset — it is the runner re-spawning with --resume <session id>
against ~/.claude (headless.ts:394-397, and buildClaudeArgs strips a user-supplied --resume
because it carries the wire protocol). Nothing equivalent exists for a raw engine, and nothing needs
to: a CLI that offers a resume subcommand gains multi-turn memory by editing one text field.

What this ticket is, and is not

It is not a request to change the runner. The mechanism above is deliberate and docs/adr's
proposed ADR 0002 states it as a consequence rather than a defect: "Multi-turn memory for raw
engines is a preset string, not a backend property."
The gap is that the platform never says so, so
the trade is invisible at exactly the moment a user picks an engine.

Stated honestly: I have not run a multi-turn codex/gemini/grok session. The claim above is
reconstructed from the spawn path and the shipped preset strings, both of which are unambiguous. What
I cannot tell you from the code is how badly it degrades a real 10-step objective — that needs a run,
and a run spends the owner's tokens.

What to do, cheapest first

  • Say it where the choice is made. The ⚙ CLI engines panel (EnginesModal.tsx) is where a
    preset is edited; one line per engine — "one-shot: each turn is a fresh process, with no memory
    of the previous one"
    vs "keeps its session between turns" — costs nothing and is the whole
    user-facing gap. deriveClientType(command) already decides which of the two a command is, so
    the label is derivable rather than hardcoded.
  • Document it in docs/coding-engines.md, next to the prefix contract it is a consequence of.
    The doc currently explains that everything after the binary passes through verbatim, which is
    exactly the sentence a reader needs in order to act on this — it just does not connect the two.
  • Ship resume-capable presets where the vendor has one. This is the item that needs a
    decision and a check per CLI, because a wrong flag is worse than none: a preset that dies on an
    unknown flag takes the whole session with it, which is precisely what happened to grok --prompt (coding-engines.ts:262-263: "grok has --prompt-file and --prompt-json but no
    --prompt, so the old preset died on an unknown/ambiguous flag before reaching the model"
    ).
    Verify against the installed binary, not against a memory of its docs.
  • Consider a second preset rather than a changed one — e.g. codex and codex (continues)
    so the existing default is untouched for anyone relying on a clean-slate turn. Cheap, reversible,
    and it makes the trade a visible choice instead of a silent default change.

Alternatives considered and rejected

Acceptance criteria

  • The engines panel states, per preset, whether turns share a session — derived from
    deriveClientType, not restated per engine.
  • docs/coding-engines.md says the one-shot spawn means no cross-turn memory, and that a
    vendor resume subcommand is the fix, in the same section as the prefix contract.
  • If resume presets ship: a two-turn session on that engine where turn 2 references turn 1 gets a
    correct answer, and the run id is recorded on this ticket.

Regression risk

  • A resume flag changes what the engine costs and what it remembers. A session that resumes into
    the wrong prior conversation is a worse failure than starting clean — verify the vendor's resume
    selects the session the runner intends, not "the last one on this machine", before shipping it as a
    default.
  • ENGINE_WRITE_FLAGS (coding-engines.ts:274-285) asserts no shipped default forgets its
    write flag. A new preset must appear there too, or an engine ships that cannot edit files.
  • Presets are per-instance and user-editable; changing DEFAULT_ENGINES only affects instances that
    have saved nothing (readEngines falls back only when the stored list is empty/invalid). Do not
    assume a default change reaches existing users — it does not.

Files: packages/browser-runner/src/coding/headless.ts:378-397,463-500,
workers/api/src/lib/coding-engines.ts:253-285, docs/coding-engines.md:1-40,
agents/coder/web/src/EnginesModal.tsx.
Related: #249 (the assessment that asks for this, item 3, and its proposed ADR 0002),
#391 (process exit as the turn boundary for one-shot engines), #248 (the console does not
report what actually resolved), #433 (the docs that should describe the split).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions