cd17f8d23a
# Conflicts: # .agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml # .agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md # .agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml # .agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md # .agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml # .agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md # .agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml # .agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md # .agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml # .agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md # .agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml # .agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md # .agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml # .agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md # .agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml # .agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md # .agents/notes/implemented/architecture/2026-06-13-capability-seams.i18n.yaml # .agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md # .agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml # .agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md # .agents/notes/implemented/architecture/2026-06-14-session-persistence.i18n.yaml # .agents/notes/implemented/architecture/2026-06-14-session-persistence.zh.md # .agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml # .agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md # .agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml # .agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md # .agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml # .agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md # .agents/notes/implemented/architecture/2026-06-18-session-surface.i18n.yaml # .agents/notes/implemented/architecture/2026-06-18-session-surface.zh.md # .agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml # .agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md # .agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml # .agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md # .agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml # .agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md # .agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml # .agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md # .agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md # .agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml # .agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md # .agents/notes/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml # .agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md # .agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml # .agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md # .agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml # .agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md # .agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml # .agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.zh.md # .agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml # .agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md # .agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml # .agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md # .agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml # .agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md # .agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml # .agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md # .agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml # .agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md # .agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml # .agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.zh.md # .agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml # .agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md # .agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml # .agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md # .agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml # .agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md # .agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml # .agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md # .agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml # .agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md # .agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml # .agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md # .agents/notes/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml # .agents/notes/implemented/feature/2026-06-14-acp-multi-session.zh.md # .agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml # .agents/notes/implemented/feature/2026-06-15-code-mode.zh.md # .agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml # .agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md # .agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml # .agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md # .agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml # .agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md # .agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml # .agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md # .agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md # .agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml # .agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.zh.md # .agents/notes/implemented/feature/2026-06-25-ask-user-question.i18n.yaml # .agents/notes/implemented/feature/2026-06-25-ask-user-question.zh.md # .agents/notes/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml # .agents/notes/implemented/feature/2026-06-29-todo-write-tool.zh.md # .agents/notes/implemented/feature/2026-06-30-hook-bridges.i18n.yaml # .agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md # .agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml # .agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.zh.md # .agents/notes/implemented/feature/2026-06-30-interception-seams.i18n.yaml # .agents/notes/implemented/feature/2026-06-30-interception-seams.zh.md # .agents/notes/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml # .agents/notes/implemented/feature/2026-06-30-session-store-fork-api.zh.md # .agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml # .agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md # .agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml # .agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md # .agents/notes/implemented/feature/2026-07-05-skill-system.i18n.yaml # .agents/notes/implemented/feature/2026-07-05-skill-system.zh.md # .agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml # .agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md # .agents/notes/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml # .agents/notes/implemented/feature/2026-07-06-explicit-tool-order.zh.md # .agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml # .agents/notes/implemented/feature/2026-07-06-sandbox.zh.md # .agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml # .agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.zh.md # .agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml # .agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md # .agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml # .agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.zh.md # .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml # .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md # .agents/notes/implemented/feature/2026-07-10-session-query-service.i18n.yaml # .agents/notes/implemented/feature/2026-07-10-session-query-service.zh.md # .agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml # .agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md # .agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml # .agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.zh.md # .agents/notes/implemented/process/2026-06-11-quality-gates.i18n.yaml # .agents/notes/implemented/process/2026-06-11-quality-gates.md # .agents/notes/implemented/process/2026-06-11-quality-gates.zh.md # .agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml # .agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.zh.md # .agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml # .agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md # .agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml # .agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.zh.md # .agents/notes/implemented/process/2026-06-17-ts-build-config.i18n.yaml # .agents/notes/implemented/process/2026-06-17-ts-build-config.zh.md # .agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml # .agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md # .agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml # .agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.zh.md # .agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml # .agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.zh.md # .agents/notes/implemented/process/2026-06-20-rfc-classification.i18n.yaml # .agents/notes/implemented/process/2026-06-20-rfc-classification.zh.md # .agents/notes/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml # .agents/notes/implemented/process/2026-07-02-tool-schema-catalog.zh.md # .agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml # .agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.zh.md # .agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml # .agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md # .agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml # .agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md # .agents/notes/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml # .agents/notes/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md # .agents/notes/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml # .agents/notes/implemented/process/2026-07-04-persistence-log-catalog.zh.md # .agents/notes/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml # .agents/notes/implemented/process/2026-07-05-uniform-rfc-format.zh.md # .agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml # .agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md # .agents/notes/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml # .agents/notes/implemented/process/2026-07-06-generated-config-catalog.zh.md # .agents/notes/implemented/process/2026-07-06-node-engine-floor.i18n.yaml # .agents/notes/implemented/process/2026-07-06-node-engine-floor.zh.md # .agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml # .agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md # .agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml # .agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md # .agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml # .agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md # .agents/notes/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml # .agents/notes/implemented/process/2026-07-12-package-model-experience-contract.zh.md # .agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml # .agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md # .agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml # .agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md # .agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml # .agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md # .agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml # .agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md # .agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml # .agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.md # .agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md # .agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml # .agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md # .agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml # .agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md # .agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml # .agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md # .agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml # .agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md # .agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.zh.md # .agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md # .agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md # .agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md # .agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md # .agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md # .agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md # .agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md # .agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md # .agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md # .agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml # .agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md # .agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml # .agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md # .agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml # .agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md # .agents/notes/implemented/testing/2026-06-11-property-based-testing.i18n.yaml # .agents/notes/implemented/testing/2026-06-11-property-based-testing.zh.md # .agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml # .agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md # .agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml # .agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md # .agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml # .agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md # .agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml # .agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md # .agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml # .agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md # .agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml # .agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md # .agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml # .agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md # .agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml # .agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md # .agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml # .agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md # .agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml # .agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md # .agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml # .agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.zh.md # .agents/notes/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml # .agents/notes/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md # .agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml # .agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md # .agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml # .agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md # .agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml # .agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.zh.md # .agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml # .agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md # .agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml # .agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md # .agents/notes/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml # .agents/notes/proposed/process/2026-06-11-api-extractor-reports.md # .agents/notes/proposed/process/2026-06-11-api-extractor-reports.zh.md # .agents/notes/proposed/process/2026-06-11-architectural-conformance.i18n.yaml # .agents/notes/proposed/process/2026-06-11-architectural-conformance.zh.md # .agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml # .agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md # .agents/notes/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml # .agents/notes/proposed/process/2026-06-20-discover-package-inventory.zh.md # .agents/notes/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml # .agents/notes/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md # .agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml # .agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md # .agents/notes/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml # .agents/notes/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md # .agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml # .agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md # .agents/notes/proposed/testing/2026-06-11-mutation-testing.i18n.yaml # .agents/notes/proposed/testing/2026-06-11-mutation-testing.zh.md # .agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml # .agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md # .agents/notes/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml # .agents/notes/rejected/architecture/2026-06-20-providerless-example-base.zh.md # .agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md # .agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md # .agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md # .agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md # .agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md # .agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md # .agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md # .agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md # .agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md # .agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md # .agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml # .agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md # .agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml # .agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md # .agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml # .agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md # .agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml # .agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md # docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md # docs/rfc/implemented/architecture/2026-06-18-session-surface.md # docs/rfc/implemented/architecture/2026-06-20-branded-ids.md # docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md # docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md # docs/rfc/implemented/feature/2026-07-07-session-prefix.md # docs/rfc/implemented/process/2026-06-20-rfc-classification.md # docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md # docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md # docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md # docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md # docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md # docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md # docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md # docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md # docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md # docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md # docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md # docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md # docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md # scripts/translation-pairing.manifest.json
83 lines
8.8 KiB
Markdown
83 lines
8.8 KiB
Markdown
# Agent Note: Tagged render-intent union for tool-call presentation
|
|
|
|
Status: implemented
|
|
|
|
English | [中文](2026-07-02-tool-render-intent-union.zh.md)
|
|
|
|
## Problem
|
|
|
|
A tool declares how its calls render in a UI (an editor's tool-call card) through two callbacks, `presentCall`/`presentResult` on `ToolDefinition`, returning `ToolCallPresentation` / `ToolResultPresentation` with an optional `ToolTerminal` sub-shape. These grew incrementally into a **bag of optional fields**: `title`, `kind`, `rawInput`, `content`, `locations`, `terminal` on the call; `title`, `content`, `terminal` on the result; `cwd`/`output`/`exitCode`/`signal` on `ToolTerminal`. The split of responsibility is muddy:
|
|
|
|
- The call-side and result-side `terminal` fields overlap, and the bridge reconciles a `content` block AND a `terminal` block AND `rawInput` per call, stitching them together with ad-hoc conditionals.
|
|
- Which combinations are *valid* is unwritten: a `terminal` call that also sets `content` means "description above the card"; a generic call that sets `terminal` is meaningless but representable. The type permits nonsense.
|
|
- There is no way to express the one file-tool affordance an editor most wants — a **diff card** (`{path, oldText, newText}`, which Zed renders as an inline diff / new-file preview). `ToolCallPresentation.content` is the *LLM* `ContentBlock[]` vocabulary (text/image), so a tool literally cannot ask for a diff.
|
|
|
|
The existing `FIXME(tool-presentation)` in `packages/core/tools/src/index.ts` named the fix: "redesign the type so a tool declares its render INTENT once (e.g. a tagged union over card kinds) rather than a bag of optional fields the bridge stitches together." The rejected Agent Note [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) deferred it explicitly: rich rendering "should return later as a tagged render-intent union after there are at least two real tools and two real consumers to validate the vocabulary." That bar is now met — two producer families (`dsh-tool-bash`, `dsh-tool-fs`) and two consumers (the ACP bridge live path + the snapshot replay path).
|
|
|
|
## Decision
|
|
|
|
Replace the optional-field bag with a **`card`-tagged discriminated union**. A tool declares one render intent per call/result; the bridge switches on the tag.
|
|
|
|
```ts ignore-check
|
|
type FileLocation = { path: string; line?: number }
|
|
type FileDiff = { path: string; oldText: string | null; newText: string } // oldText null ⇒ new file
|
|
|
|
// presentCall → ToolCallView
|
|
type ToolCallView = GenericCallView | TerminalCallView | DiffCallView
|
|
interface GenericCallView { card: 'generic'; title: string; kind?: ToolCallKind; rawInput?: unknown; content?: ContentBlock[]; locations?: FileLocation[] }
|
|
interface TerminalCallView { card: 'terminal'; title: string; description?: string; cwd?: string }
|
|
interface DiffCallView { card: 'diff'; title: string; diffs: FileDiff[]; locations?: FileLocation[] }
|
|
|
|
// presentResult → ToolResultView
|
|
type ToolResultView = GenericResultView | TerminalResultView
|
|
interface GenericResultView { card: 'generic'; title?: string; content?: ContentBlock[] }
|
|
interface TerminalResultView { card: 'terminal'; title?: string; output?: string; exitCode?: number; signal?: string }
|
|
```
|
|
|
|
`card` is **required** on every variant — a real discriminant, not an optional default. The bridge does `switch (view.card) { case 'generic': … case 'terminal': … case 'diff': … default: assertNever(view) }`. The union is **closed** (per the [switch-exhaustiveness convention](../../../../AGENTS.md)): a fourth render intent (a table, a chart) needs new bridge code to render it anyway, so a plugin-added variant that the bridge silently drops would be worse than a compile error. Adding a variant breaks compilation at the bridge switch — exactly the signal we want.
|
|
|
|
### Why a tagged union beats the field-bag
|
|
|
|
- **Invalid states become unrepresentable.** A generic card cannot carry terminal output; a terminal card cannot carry a diff. The old bag permitted all of these.
|
|
- **The bridge switches instead of stitching.** One arm per card kind, each producing exactly the wire shape that card needs, rather than reconciling five optional fields whose interactions are undocumented.
|
|
- **`diff` is a first-class intent.** `dsh-tool-fs` write/edit declare `card:'diff'`; the bridge emits an ACP `{type:'diff', path, oldText, newText}` `ToolCallContent` (already in the SDK's `ToolCallContent` union, previously unused by the bridge). This is the affordance the redesign unlocks.
|
|
|
|
### Producer mapping
|
|
|
|
- `dsh-tool-fs` read → `generic` (`kind:'read'`, a follow-along `location`); write → `diff` (`oldText:null`); edit → `diff` (`oldText:old_string || null`, `newText:new_string ?? ''`). This mirrors `claude-agent-acp`'s `toolInfoFromToolUse` Read/Write/Edit arms field-for-field.
|
|
- `dsh-tool-bash` foreground → `terminal` call + `terminal` result; `run_in_background` → `generic`. The generic `task_*` controls own their own generic cards.
|
|
- `dsh-tool-todo` → `generic`.
|
|
|
|
### Terminal fallback ownership
|
|
|
|
`TerminalResultView` carries only `output`/`exitCode`/`signal`. A UI without the terminal capability needs a fenced ` ```console ` text fallback; that derivation moves to the **bridge** (it wraps `output` in a fenced block on the no-capability path), rather than the tool double-encoding it. This keeps the bash tool's result a single structured shape and preserves the existing capability-gated behavior byte-for-byte.
|
|
|
|
### Purity preserved
|
|
|
|
`presentCall`/`presentResult` remain pure functions of `args` (+ the result for `presentResult`) — they run on live streaming AND session-log replay, so they must be replay-deterministic. Every view is derived from args alone: write's diff is new-file style (`oldText:null`) because the tool has no old content at call time; edit's diff is `old_string`→`new_string`.
|
|
|
|
## Relative-path display titles
|
|
|
|
`claude-agent-acp` relativizes a file card's title path against the session cwd (`toDisplayPath`) — `Read src/foo.ts`, not `/abs/proj/src/foo.ts` — while keeping `locations[]`/`diff.path` **raw** (the editor opens the real path). Our `presentCall` is pure/args-only and cannot see the session cwd, so this relativization happens at the **bridge**, which already threads the session cwd into tool-call rendering (the same cwd it uses to resolve a terminal card's header). The bridge relativizes the title only, by an exact structured replace of the known `locations[0].path`/`diffs[0].path` substring — generic over the file-card kinds, never special-casing tool names.
|
|
|
|
## Alternatives considered
|
|
|
|
- **Delete tool-owned presentation entirely** — [the rejected collapse proposal](../../rejected/simplification/2026-06-20-generic-tool-rendering.md); its own verdict deferred to exactly this union once two real tools and two real consumers existed, and that bar is now met.
|
|
- **A merge-extensible union** (the `ContentBlockMap` pattern) — rejected: a new render intent needs new bridge code to render it anyway, so a plugin-added variant the bridge silently drops would be worse than the compile error the closed union raises at the bridge's `assertNever` switch.
|
|
- **Keeping the optional-field bag** — the status quo the Problem dissects: invalid states representable, undocumented field interactions, and no way to ask for a diff card at all.
|
|
|
|
## Consequences
|
|
|
|
A new render intent is a compile-breaking change at the bridge switch — deliberately: rendering code must exist before a card kind does. Invalid card/field combinations are now unrepresentable, and the bash fallback derivation lives in the bridge, so a tool returns one structured shape. The bar for a fourth card (a table, a chart) is writing its bridge arm in the same change.
|
|
|
|
## Non-goals
|
|
|
|
- **Live incremental `terminal_output_delta` streaming** and **command classification** — the terminal-rendering Agent Note's own deferred follow-ups, untouched here.
|
|
|
|
## Related
|
|
|
|
- Supersedes the deferral in [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) (rejected — "wait for two real tools and two real consumers, then a tagged render-intent union"). That bar is now met; this is that union.
|
|
- Extended by [Result-time applied-hunk diffs](2026-07-02-result-time-applied-hunk-diffs.md), which adds a persisted `meta` channel so write/edit emit a result-time `DiffResultView` — the applied change (a contextual hunk with context lines / one per `replace_all` site, or a whole-file diff for a create) — on top of this union's call-time diff card.
|
|
- Folds `ToolTerminal` into the `terminal` views described by [ACP terminal and tool-call rendering](../feature/2026-06-18-acp-terminal-and-tool-rendering.md) (the `_meta` terminal-card convention and capability gate are unchanged; only the harness-side presentation type changes).
|
|
- The ACP SDK's `Diff` / `ToolCallContent` types back the new `diff` card.
|