Deduplicate the parallel sweep from codex/exhaustive-simplification-rfcs (merged in the parent commit) against the twelve RFCs already here, on the merits per item: Ported (rewritten to this set's evidence standard): - fold-stdio-ui-helper — verified: dsh-stdio-agent is the only runtime importer; the fold resolves the documented product-app-depends-on- support-package tension. The false acp-agent analogy is replaced with the real distinction (protocol product surface vs one app's front-door scaffolding). - generate-rfc-index-tables — verified: the classification RFC records rejecting generation; the index tables are the repo's only systematically conflicting docs region. Process framing made timeless. Consolidated into existing owners: - web searchStatus()/fetchStatus()/WebCapabilityStatus (verified: zero production callers; the tool-web README and architecture.md claims are drift) → drop-web-providers-change-event, renamed drop-unconsumed-web-observation-surface. - hook/result.durationMs (unread, nondeterministic, normalizer-scrubbed) and the double-defaulted defaultTimeoutMs knob → tighten-hook-protocol-contract. - the exercised-but-unadvertised exec.arguments mutation path (a tool-bash integration shim rewrites through it) → a sanction-or-seal note in the pre-tool-input-rewrite proposal. - the dormant-guard critique of subagent depth machinery → recorded in prune-unimplemented-subagent-vocabulary as the considered-and-rejected alternative, with the keep sharpened (uncapped-today acknowledged; wiring the cap is the completion, not deletion). getProvider()/list() and lastAssistantMessage recorded as examined-and-kept (bash-revert precedent; observe-enrich recorded keep). Not ported (with reasons): - tools/change + system-prompt/change removal — recorded keeps in the adapter-change RFC, unengaged by the sweep; no new facts. - LlmService.models() — flagged by both surveys, but two lines with a plausible consumer: TODO-or-drive-by territory per the RFC bar, not a proposal. - SchemaProp.default RFC — already XXX(unused-default)-tagged; the RFC bar excludes TODO-tracked provisional cleanups. - PreToolDecision 'ask' removal — FIXME(permissions)-anchored deferral with the permission system as its named consumer. - Codex bridge Config.model, merged systemMessages — wire-faithful tested surface / README-documented deferral. Their in-code TODO notes (acp-test-harness, hook-snapshot-noise, catalog-type-links) and the stale hook-prompt-block name fixes ride the merge unchanged.
4.0 KiB
RFC: Pre-tool input rewrite — a consistent design (proposed)
Status: proposed (2026-06-30)
Context
The interception-seams RFC added tools/pre-execute returning a PreToolDecision (allow/deny/ask) — but deliberately NOT input rewrite (a hook changing a tool call's arguments before it runs). Claude Code's PreToolUse hook offers an updatedInput, so a faithful CC bridge wants the same. This RFC designs that, separately, because doing it consistently is a real problem — not a field to bolt onto the allow decision.
The problem: three readers of pre-execution arguments
In the loop, a tool call's arguments are committed to the log and read by live consumers BEFORE the tool executes:
assistant/messageis appended before tool dispatch — it is the model-history sourcederiveMessages()replays, so it carries the tool-call arguments the model itself emitted.tool/callis the durable AUDIT record, appended beforectx.tools.execute().- Live presentation reads
tool/call.arguments: the ACP bridge remembers them and passes them topresentResult;dsh-tool-bashderives the card title, the rawInput, the cwd, and the terminal-vs-background treatment from them.
So an "input rewrite" that changes ONLY what executes would make the UI show one command while another RAN, and render result state against the wrong arguments — a real inconsistency, not a documentable gap. (The existing low-level capability to mutate exec.arguments in a listener has exactly this latent inconsistency; it is unadvertised precisely because of this — yet not unused: a tool-bash integration test rewrites a scripted call's arguments through it (packages/bash/tool-bash/tests/integration.spec.ts), so this design must either sanction that path with the consistency unit below or seal it — readonly arguments at the seam, with the test shim moved onto a behavior-level helper.)
Proposed design (sketch — to validate against the code when built)
Treat input rewrite as a consistency unit: when a pre-execute hook supplies updatedInput, the rewrite must be reflected in ALL three readers, atomically, before execution:
- The
tool/callaudit event records the REWRITTEN arguments (with the original retained in a sidecar field for the audit trail — a hook changed the call, and both the original and the effective arguments are facts worth keeping). - The
assistant/messagein derived history must agree with what executed — options to evaluate: rewrite the assistant message's tool-call block in place (changes what the model "sees it said"), or record a separate correction the next request carries. The CC model is that the model sees the rewrite took effect. - Presentation (
presentCall/presentResult) reads the rewritten arguments, so the UI shows what actually ran.
The shape would extend PreToolDecision with an allow-variant arguments (or a dedicated {kind:'rewrite', arguments}), and the loop would thread the rewrite through the three readers above rather than only into ctx.tools.execute().
Why not now
The interception-seams RFC notes input rewrite "fought the code across two review rounds" — the signal AGENTS.md names for an over-reaching change. Shipping allow/deny/ask first keeps the seam honest (no advertised contract that silently desyncs the UI), and a CC/Codex bridge that receives an updatedInput logs it and surfaces a faithful-but-degraded warning (like ask→deny) until this lands. This RFC is the home for the consistent design; TODO(pre-tool-input-rewrite) in the loop's pre-execute call site anchors it.
Open questions
- Does rewriting the
assistant/messagetool-call block corrupt any provider's expectation on replay, or is a separate correction safer? - Should the original arguments be preserved on the
tool/callevent (audit) and, if so, under what field? - How does this interact with a future permission
askflow (a user approving a rewritten call)?