diff --git a/.agents/notes/INDEX.md b/.agents/notes/INDEX.md deleted file mode 100644 index fe92f57aef..0000000000 --- a/.agents/notes/INDEX.md +++ /dev/null @@ -1,248 +0,0 @@ -# Agent Note index - -Generated by `pnpm run gen-agent-note-index` from the Agent Note tree — never edit by hand; `verify-agent-note-classification` fails when this file is stale. The curated front door — layout, classification, when to write one, and the in-file format — is [README.md](README.md). - -## Proposed - -### Feature - -| Title | First proposed | -|---|---| -| [Pre-tool input rewrite — a consistent design](proposed/feature/2026-06-30-pre-tool-input-rewrite.md) | 2026-06-30 | -| [Recallable compaction — index checkpoints, a state checkpoint, and in-session history recall](proposed/feature/2026-07-06-recallable-compaction.md) | 2026-07-06 | -| [Claude Code and Codex subagent backends (out-of-process delegation to external coding agents)](proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md) | 2026-07-07 | -| [Interactive side sessions and merge-back](proposed/feature/2026-07-08-interactive-side-sessions.md) | 2026-07-08 | -| [SQLite FTS5 session search](proposed/feature/2026-07-10-sqlite-session-query-provider.md) | 2026-07-10 | -| [Stream workflow progress through tool calls](proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md) | 2026-07-13 | -| [Developer-owned SDK projects](proposed/feature/2026-07-14-sdk-developer-projects.md) | 2026-07-14 | -| [SDK follow-up capabilities](proposed/feature/2026-07-17-sdk-follow-up-capabilities.md) | 2026-07-17 | - -### Simplification - -| Title | First proposed | -|---|---| -| [Prune dead public and result surface](proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md) | 2026-07-04 | -| [Make JSON-RPC completion and transport directional](proposed/simplification/2026-07-19-make-jsonrpc-directional.md) | 2026-07-19 | - -### Architecture - -| Title | First proposed | -|---|---| -| [Runtime schemas for the event vocabulary (Zod vs the merge-extensible-map pattern)](proposed/architecture/2026-06-16-typed-event-schemas.md) | 2026-06-16 | -| [SDK project editing architecture](proposed/architecture/2026-07-15-sdk-project-editing-architecture.md) | 2026-07-15 | - -### Process - -| Title | First proposed | -|---|---| -| [API extractor reports](proposed/process/2026-06-11-api-extractor-reports.md) | 2026-06-11 | -| [Architectural conformance — dependency rules and the adapter kit](proposed/process/2026-06-11-architectural-conformance.md) | 2026-06-11 | -| [Supply chain checks and vendor drift verification](proposed/process/2026-06-11-supply-chain-and-vendor-drift.md) | 2026-06-11 | -| [Discover package inventories instead of maintaining static lists](proposed/process/2026-06-20-discover-package-inventory.md) | 2026-06-20 | -| [Periodic human-review maintenance for dsh-code-review](proposed/process/2026-07-13-human-review-skill-maintenance.md) | 2026-07-13 | - -### Testing - -| Title | First proposed | -|---|---| -| [Deterministic tests, the replay invariant fixture, and race stress](proposed/testing/2026-06-11-deterministic-and-stress-testing.md) | 2026-06-11 | -| [Mutation testing as the coverage counterweight](proposed/testing/2026-06-11-mutation-testing.md) | 2026-06-11 | - -## Implemented - -### Feature - -| Title | First proposed | -|---|---| -| [Agent Client Protocol (ACP) support — drive the coding agent from external editors](implemented/feature/2026-06-14-acp-agent-client-protocol.md) | 2026-06-14 | -| [Multiplex concurrent ACP sessions over one connection](implemented/feature/2026-06-14-acp-multi-session.md) | 2026-06-14 | -| [Code Mode — the model writes TypeScript against the tool registry](implemented/feature/2026-06-15-code-mode.md) | 2026-06-15 | -| [Filesystem tool schemas — model-facing read/write/edit shapes](implemented/feature/2026-06-17-filesystem-tool-schemas.md) | 2026-06-17 | -| [Rich ACP bash rendering — the terminal card via the `_meta` convention](implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) | 2026-06-18 | -| [Compaction as a capability seam (abstract contract + basic backend)](implemented/feature/2026-06-18-compaction-capability-seam.md) | 2026-06-18 | -| [Subagent capability seam](implemented/feature/2026-06-21-subagent-capability-seam.md) | 2026-06-21 | -| [ACP subagent backend (out-of-process delegation)](implemented/feature/2026-06-22-acp-subagent-backend.md) | 2026-06-22 | -| [Workspace context instruction files](implemented/feature/2026-06-24-workspace-context.md) | 2026-06-24 | -| [Ask-user question capability](implemented/feature/2026-06-25-ask-user-question.md) | 2026-06-25 | -| [The `todo_write` tool — model task list as event-sourced session state](implemented/feature/2026-06-29-todo-write-tool.md) | 2026-06-29 | -| [dsh-hooks-claude + dsh-hooks-codex — the Claude Code / Codex hook bridges](implemented/feature/2026-06-30-hook-bridges.md) | 2026-06-30 | -| [dsh-hook-protocol — the shared Claude Code / Codex hook wire-protocol core](implemented/feature/2026-06-30-hook-protocol-lib.md) | 2026-06-30 | -| [Interception seams — the typed-Decision surface a hook programs against](implemented/feature/2026-06-30-interception-seams.md) | 2026-06-30 | -| [SessionStore fork API](implemented/feature/2026-06-30-session-store-fork-api.md) | 2026-06-30 | -| [Subagent lifecycle enrichment — lastAssistantMessage (observe-only)](implemented/feature/2026-06-30-subagent-observe-enrich.md) | 2026-06-30 | -| [Dynamic workflows — a script-driven multi-agent orchestration seam](implemented/feature/2026-07-05-dynamic-workflows.md) | 2026-07-05 | -| [Skill system — progressive disclosure instructions for agents](implemented/feature/2026-07-05-skill-system.md) | 2026-07-05 | -| [The approval seam — one-shot permission decisions over a waterfall of answerers](implemented/feature/2026-07-06-approval-seam.md) | 2026-07-06 | -| [Explicit model-facing tool order](implemented/feature/2026-07-06-explicit-tool-order.md) | 2026-07-06 | -| [The subprocess sandbox — confinement seam, native runners, escalation, and per-session modes](implemented/feature/2026-07-06-sandbox.md) | 2026-07-06 | -| [MCP client plugin — connect to external MCP servers and bridge their tools](implemented/feature/2026-07-07-mcp-client-plugin.md) | 2026-07-07 | -| [The session prefix — request-only messages in front of the derived history](implemented/feature/2026-07-07-session-prefix.md) | 2026-07-07 | -| [Background subagent tasks](implemented/feature/2026-07-08-background-subagent-tasks.md) | 2026-07-08 | -| [Repeat-tool-call guard plugin](implemented/feature/2026-07-08-repeat-tool-guard.md) | 2026-07-08 | -| [The self-referential cordis toolset](implemented/feature/2026-07-08-self-referential-cordis-toolset.md) | 2026-07-08 | -| [Bash-backed grep and glob discovery tools](implemented/feature/2026-07-09-bash-backed-grep-glob-discovery.md) | 2026-07-09 | -| [Expose agent session identity and JSONL location to tools and hooks](implemented/feature/2026-07-10-agent-session-identity-and-log-location.md) | 2026-07-10 | -| [Parallel tool-call execution by per-call safety](implemented/feature/2026-07-10-parallel-tool-call-execution.md) | 2026-07-10 | -| [Exact session query service](implemented/feature/2026-07-10-session-query-service.md) | 2026-07-10 | -| [Configure subagent persona, tool visibility, and depth](implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) | 2026-07-12 | -| [Session query relationship tracing](implemented/feature/2026-07-13-session-query-tracing.md) | 2026-07-13 | -| [Optional time-context plugin](implemented/feature/2026-07-14-time-context-plugin.md) | 2026-07-14 | -| [Durable per-step time context](implemented/feature/2026-07-16-durable-per-step-time-context.md) | 2026-07-16 | -| [Dedicated full-screen TUI front door](implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md) | 2026-07-17 | - -### Simplification - -| Title | First proposed | -|---|---| -| [Drop the mutable session summary](implemented/simplification/2026-06-19-drop-mutable-session-summary.md) | 2026-06-19 | -| [Fold trace-only session facts into load-bearing events](implemented/simplification/2026-06-20-collapse-trace-only-session-events.md) | 2026-06-20 | -| [Drop the unconsumed `llm/adapter-change` event](implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md) | 2026-06-20 | -| [Drop unconsumed assembled LLM convenience surfaces](implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md) | 2026-06-20 | -| [Prune dead methods from the persistence seam](implemented/simplification/2026-06-20-prune-dead-seam-methods.md) | 2026-06-20 | -| [Keep one public stop primitive](implemented/simplification/2026-06-20-public-agent-stop-surface.md) | 2026-06-20 | -| [Stop mirroring durable boundaries as agent events](implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md) | 2026-06-20 | -| [Unify the agent id and the session id](implemented/simplification/2026-06-20-unify-agent-and-session-id.md) | 2026-06-20 | -| [Split the filesystem seam — provider text mutations plus the `dsh-fs-policy` plugin](implemented/simplification/2026-06-26-fsspec-style-fs-seam.md) | 2026-06-26 | -| [Stop mirroring the token stream as an agent event](implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md) | 2026-07-02 | -| [Drop the `image` content block until a path can honor it](implemented/simplification/2026-07-04-drop-image-content-block.md) | 2026-07-04 | -| [Drop `GenerateOptions.prefill` and `ToolSchema.strict` — request knobs with no working end-to-end path](implemented/simplification/2026-07-04-drop-inert-request-knobs.md) | 2026-07-04 | -| [Drop the unconsumed web observation surface — the `providers-change` event and the status methods](implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md) | 2026-07-04 | -| [Fold the stdio UI helper into the stdio app](implemented/simplification/2026-07-04-fold-stdio-ui-helper.md) | 2026-07-04 | -| [Prune producer-less vocabulary variants (block cache hints, the `agent` message source, the `continuation` turn trigger)](implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md) | 2026-07-04 | -| [Prune write-only fields and a dead routing knob from the fs seam](implemented/simplification/2026-07-04-prune-write-only-fs-surface.md) | 2026-07-04 | -| [Remove the `agent/steering` mirror emit](implemented/simplification/2026-07-04-remove-agent-steering-mirror.md) | 2026-07-04 | -| [Share the app bins' boot glue instead of maintaining twin copies](implemented/simplification/2026-07-04-share-app-bin-boot-glue.md) | 2026-07-04 | -| [Tighten the hook-protocol contract — dialect, discarded fields, double defaults, and lib-owned `hook/result` semantics](implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md) | 2026-07-04 | -| [Trim unreachable ACP bridge surface — the branding knobs and the kind-sniffing fallback](implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md) | 2026-07-04 | -| [Drop unconsumed skill provider events](implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md) | 2026-07-12 | -| [Prune unused web seam fields](implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md) | 2026-07-12 | -| [Simplify session-log representation](implemented/simplification/2026-07-12-simplify-session-log-representation.md) | 2026-07-12 | -| [Retire the standalone subagent mock package](implemented/simplification/2026-07-19-retire-subagent-mock-package.md) | 2026-07-19 | -| [Use one surface manager per session](implemented/simplification/2026-07-19-use-one-session-surface-manager.md) | 2026-07-19 | - -### Architecture - -| Title | First proposed | -|---|---| -| [Provider-neutral content-block vocabulary owned by dsh-llm](implemented/architecture/2026-06-11-content-block-vocabulary.md) | 2026-06-11 | -| [Custom typed tool-schema DSL instead of schemastery](implemented/architecture/2026-06-11-custom-schema-dsl.md) | 2026-06-11 | -| [Source-owned session immutability and dev-mode invariants](implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md) | 2026-06-11 | -| [Event-sourced sessions with derived message history](implemented/architecture/2026-06-11-event-sourced-sessions.md) | 2026-06-11 | -| [Microkernel — extension via Cordis event taxonomy, one concrete loop](implemented/architecture/2026-06-11-microkernel-event-taxonomy.md) | 2026-06-11 | -| [Runtime arg validation at the model boundary](implemented/architecture/2026-06-11-runtime-arg-validation.md) | 2026-06-11 | -| [Structured error taxonomy](implemented/architecture/2026-06-11-structured-error-taxonomy.md) | 2026-06-11 | -| [Tool schemas are part of the system-prompt assembly](implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md) | 2026-06-11 | -| [Capability seams — interface / implementation / consumer split](implemented/architecture/2026-06-13-capability-seams.md) | 2026-06-13 | -| [Two LLM adapters as a design-verification twin](implemented/architecture/2026-06-13-twin-llm-adapters.md) | 2026-06-13 | -| [Session persistence as an abstract service over the existing `SessionEvent`](implemented/architecture/2026-06-14-session-persistence.md) | 2026-06-14 | -| [Every session event is enclosed in a turn](implemented/architecture/2026-06-15-turn-enclosure-invariant.md) | 2026-06-15 | -| [Filesystem capability seam — ctx.fs, local backend, and model-facing filesystem tools](implemented/architecture/2026-06-17-filesystem-capability-seam.md) | 2026-06-17 | -| [Agent lifecycle and ownership seams](implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md) | 2026-06-18 | -| [Session surface — an ordered projection over the event log](implemented/architecture/2026-06-18-session-surface.md) | 2026-06-18 | -| [Shared persistence write coordinator](implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md) | 2026-06-18 | -| [Branded IDs everywhere they belong](implemented/architecture/2026-06-20-branded-ids.md) | 2026-06-20 | -| [Extract example apps into packages](implemented/architecture/2026-06-20-extract-example-app-packages.md) | 2026-06-20 | -| [The background task runtime (`ctx.tasks`) and generic task control tools](implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md) | 2026-06-20 | -| [Reorganize packages into a modular hierarchy](implemented/architecture/2026-06-20-package-hierarchy.md) | 2026-06-20 | -| [Mandatory `User-Agent` attribution for provider requests](implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md) | 2026-06-21 | -| [Web capability seam - stable tools over multiple providers](implemented/architecture/2026-06-24-web-capability-seam.md) | 2026-06-24 | -| [Make `dsh-fs-policy` an event-gate plugin, not a method interface](implemented/architecture/2026-06-26-file-context-as-event-gate.md) | 2026-06-26 | -| [stdin + extra env on the bash seam](implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md) | 2026-06-30 | -| [Event-domain semantics — session is the fact log, agent is the live surface](implemented/architecture/2026-06-30-event-domain-semantics.md) | 2026-06-30 | -| [Resolve filesystem paths against the caller's session cwd](implemented/architecture/2026-07-02-fs-per-session-cwd.md) | 2026-07-02 | -| [Result-time applied-hunk diffs for file mutations](implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md) | 2026-07-02 | -| [Tagged render-intent union for tool-call presentation](implemented/architecture/2026-07-02-tool-render-intent-union.md) | 2026-07-02 | -| [Add direct directory listing to the filesystem seam](implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md) | 2026-07-03 | -| [Prompt variables and tool-guidance ownership](implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md) | 2026-07-05 | -| [Every LLM request is reconstructable from the session log](implemented/architecture/2026-07-05-reconstructable-requests.md) | 2026-07-05 | -| [Subagent provider-lifecycle events — `subagent/provider-added` / `subagent/provider-removed`](implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md) | 2026-07-05 | -| [A shared timeout/deadline primitive, with hard-kill left to each capability](implemented/architecture/2026-07-06-timeout-deadline-library.md) | 2026-07-06 | -| [Tool result retention library](implemented/architecture/2026-07-06-tool-result-retention-library.md) | 2026-07-06 | -| [Tool-call timeout policy as a plugin](implemented/architecture/2026-07-07-tool-call-timeout-policy.md) | 2026-07-07 | -| [The agent is a registration scope](implemented/architecture/2026-07-08-agent-scope-contexts.md) | 2026-07-08 | -| [Tool output spill policy](implemented/architecture/2026-07-08-tool-output-spill-files.md) | 2026-07-08 | -| [After-call compaction pressure and context-overflow recovery](implemented/architecture/2026-07-10-after-call-compaction-pressure-and-overflow-recovery.md) | 2026-07-10 | -| [Single-file executable SDK runtime distribution (single-exe)](implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md) | 2026-07-10 | -| [Agent-scope runtime design and correctness](implemented/architecture/2026-07-12-agent-scope-runtime-design.md) | 2026-07-12 | -| [Provider-routed LLM adapters and a generic pi-ai backend](implemented/architecture/2026-07-14-provider-routed-llm-adapters.md) | 2026-07-14 | -| [Initiating Agent scope over AsyncLocalStorage](implemented/architecture/2026-07-15-agent-initiator-scope.md) | 2026-07-15 | -| [Advisory LLM catalogs and per-session ACP model selection](implemented/architecture/2026-07-15-llm-model-catalog-and-acp-selection.md) | 2026-07-15 | -| [Replay token meter service](implemented/architecture/2026-07-15-replay-token-meter-service.md) | 2026-07-15 | - -### Process - -| Title | First proposed | -|---|---| -| [Doc-sync enforcement](implemented/process/2026-06-11-doc-sync-enforcement.md) | 2026-06-11 | -| [Mechanical quality gates over prose guidelines](implemented/process/2026-06-11-quality-gates.md) | 2026-06-11 | -| [tsdown for JS bundling instead of dumble](implemented/process/2026-06-11-tsdown-over-dumble.md) | 2026-06-11 | -| [Vendor Cordis as source, not npm dependencies](implemented/process/2026-06-11-vendor-cordis-as-source.md) | 2026-06-11 | -| [pnpm as the package manager instead of Yarn 4](implemented/process/2026-06-16-pnpm-over-yarn.md) | 2026-06-16 | -| [TSC-first build and one tsconfig](implemented/process/2026-06-17-ts-build-config.md) | 2026-06-17 | -| [Markdown cross-link validity linting](implemented/process/2026-06-18-markdown-cross-link-lint.md) | 2026-06-18 | -| [Classify Agent Notes by kind via path-encoded subdirectories](implemented/process/2026-06-20-agent-note-classification.md) | 2026-06-20 | -| [Core-data-structures catalog and the `ts type-equiv` drift gate](implemented/process/2026-06-20-core-data-structures-catalog.md) | 2026-06-20 | -| [Generated cordis events + services catalog](implemented/process/2026-06-20-generated-cordis-catalog.md) | 2026-06-20 | -| [Bilingual documentation via paired sibling files and a pairing gate](implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md) | 2026-07-02 | -| [Generated tool-schema catalog (boot-and-harvest)](implemented/process/2026-07-02-tool-schema-catalog.md) | 2026-07-02 | -| [Documentation graph index for maintainers and SDK users](implemented/process/2026-07-03-documentation-graph-atlas.md) | 2026-07-03 | -| [JSDoc completeness gate for the cordis surface](implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md) | 2026-07-04 | -| [Documentation tiers, budgets, and the ceiling gate](implemented/process/2026-07-04-doc-tiers-and-budgets.md) | 2026-07-04 | -| [Generate the Agent Note index tables](implemented/process/2026-07-04-generate-agent-note-index-tables.md) | 2026-07-04 | -| [Generated persistence log event catalog](implemented/process/2026-07-04-persistence-log-catalog.md) | 2026-07-04 | -| [One gated in-file format for Agent Notes](implemented/process/2026-07-05-uniform-agent-note-format.md) | 2026-07-05 | -| [Export-surface JSDoc gate](implemented/process/2026-07-06-export-surface-jsdoc-gate.md) | 2026-07-06 | -| [Generated plugin config catalog](implemented/process/2026-07-06-generated-config-catalog.md) | 2026-07-06 | -| [Raise the Node LTS engine floor to 22.19](implemented/process/2026-07-06-node-engine-floor.md) | 2026-07-06 | -| [Parallel GitHub CI gates](implemented/process/2026-07-06-parallel-github-ci-gates.md) | 2026-07-06 | -| [Parallel pre-push gates](implemented/process/2026-07-06-parallel-pre-push-gates.md) | 2026-07-06 | -| [A gated Known-Limitations section in every package README](implemented/process/2026-07-10-readme-known-limitations-gate.md) | 2026-07-10 | -| [Package Model Experience contract](implemented/process/2026-07-12-package-model-experience-contract.md) | 2026-07-12 | -| [TypeScript Program-backed semantic gates](implemented/process/2026-07-14-typescript-program-backed-semantic-gates.md) | 2026-07-14 | -| [Run CI examples from built lib](implemented/process/2026-07-17-run-ci-examples-from-built-lib.md) | 2026-07-17 | - -### Testing - -| Title | First proposed | -|---|---| -| [Property-based testing for protocol-shaped code](implemented/testing/2026-06-11-property-based-testing.md) | 2026-06-11 | -| [ACP snapshot tests — record-once / replay-deterministic](implemented/testing/2026-06-19-acp-snapshot-tests.md) | 2026-06-19 | -| [Real-API e2e in CI against the external DeepSeek API](implemented/testing/2026-06-19-real-api-e2e-ci.md) | 2026-06-19 | -| [Use `session.jsonl` as the only snapshot session-log artifact](implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.md) | 2026-06-20 | -| [Persist the seed boundary so fork-child replay routes correctly](implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md) | 2026-06-22 | -| [Record fork and mixed spawn+fork snapshot scenarios](implemented/testing/2026-06-22-fork-snapshot-scenarios.md) | 2026-06-22 | -| [Per-session snapshot replay for nested agents](implemented/testing/2026-06-22-subagent-snapshot-replay.md) | 2026-06-22 | -| [Hook snapshot matrix — end-to-end expected outputs for both bridges](implemented/testing/2026-07-04-hook-snapshot-matrix.md) | 2026-07-04 | -| [Single-source the acp-agent replay config](implemented/testing/2026-07-04-single-source-acp-replay-config.md) | 2026-07-04 | -| [Pin request-header content in one snapshot scenario](implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md) | 2026-07-06 | -| [Extract the ACP snapshot suite into a support package](implemented/testing/2026-07-08-shared-acp-snapshot-package.md) | 2026-07-08 | -| [Snapshot semantic terminal state for the TUI](implemented/testing/2026-07-18-tui-terminal-state-snapshots.md) | 2026-07-18 | - -## Rejected - -### Simplification - -| Title | First proposed | -|---|---| -| [Persist assembled assistant messages, not stream chunks](rejected/simplification/2026-06-20-assembled-assistant-messages-only.md) | 2026-06-20 | -| [Drop ACP session/load until resume has a product shape](rejected/simplification/2026-06-20-drop-acp-session-load.md) | 2026-06-20 | -| [Drop ACP terminal `_meta` rendering](rejected/simplification/2026-06-20-drop-acp-terminal-meta.md) | 2026-06-20 | -| [Drop bash full-output spill files](rejected/simplification/2026-06-20-drop-bash-output-spill-files.md) | 2026-06-20 | -| [Drop durable step boundary events](rejected/simplification/2026-06-20-drop-durable-step-boundaries.md) | 2026-06-20 | -| [Drop unused session lineage metadata](rejected/simplification/2026-06-20-drop-unused-session-lineage.md) | 2026-06-20 | -| [Fold the persistence interface into dsh-session](rejected/simplification/2026-06-20-fold-session-persistence-interface.md) | 2026-06-20 | -| [Collapse tool-owned UI presentation](rejected/simplification/2026-06-20-generic-tool-rendering.md) | 2026-06-20 | -| [Retire mid-turn steering](rejected/simplification/2026-06-20-retire-mid-turn-steering.md) | 2026-06-20 | -| [Return the ACP bridge to one live session per connection](rejected/simplification/2026-06-20-single-session-acp-bridge.md) | 2026-06-20 | -| [Truncate interrupted final turns on load](rejected/simplification/2026-06-20-truncate-interrupted-turns.md) | 2026-06-20 | -| [Prune the unimplemented subagent seam vocabulary](rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md) | 2026-07-04 | -| [Collapse workflows to the exercised foreground core](rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md) | 2026-07-12 | -| [Prune unused skill registry surface](rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md) | 2026-07-12 | -| [Fold the single compaction backend into its service package](rejected/simplification/2026-07-19-fold-compaction-package-split.md) | 2026-07-19 | - -### Architecture - -| Title | First proposed | -|---|---| -| [Deep-readonly public surfaces](rejected/architecture/2026-06-11-immutable-public-surfaces.md) | 2026-06-11 | -| [Make the shared example base providerless](rejected/architecture/2026-06-20-providerless-example-base.md) | 2026-06-20 | diff --git a/.agents/notes/README.md b/.agents/notes/README.md index 16cbf07037..79aa2fb8d4 100644 --- a/.agents/notes/README.md +++ b/.agents/notes/README.md @@ -1,6 +1,6 @@ # Agent Notes -One kind of design doc lives here. An **Agent Note** records a decision or proposal that shapes this codebase — the *why* and *what we gave up*, the parts code and docs can't carry. The full list is the generated [INDEX.md](INDEX.md); this file is the contract — where Agent Notes live, when to write one, and [the in-file format](#the-file-format). +One kind of design doc lives here. An **Agent Note** records a decision or proposal that shapes this codebase — the *why* and *what we gave up*, the parts code and docs can't carry. This file is the front door and contract: where Agent Notes live, when to write one, and [the in-file format](#the-file-format). ## Layout and naming @@ -14,9 +14,11 @@ Every Agent Note has two axes, both encoded in its **path** — `{lifecycle}/{cl The date in the filename is when the topic was **first proposed** (per git history). Cross-references between Agent Notes use relative markdown links (`[topic](../../implemented/architecture/2026-…-….md)`) — never bare prose or numbers — so they are mechanically checkable and survive moves between folders. +The tree is the inventory: browse its lifecycle/class folders or search the repository. Do not add a centralized `INDEX.md`; the [no-index Agent Note](implemented/process/2026-07-19-remove-generated-agent-note-index.md) owns the rationale. + ## Classification -Each Agent Note belongs to one path-encoded class from the closed set in `scripts/agent-note-index.ts`; the classification gate rejects other folders. [INDEX.md](INDEX.md) is generated from paths, titles, and filename dates, and its freshness is gated. Adding a class requires updating the canonical set and this section. See the [classification](implemented/process/2026-06-20-agent-note-classification.md) and [index-generation](implemented/process/2026-07-04-generate-agent-note-index-tables.md) Agent Notes. +Each Agent Note belongs to one path-encoded class from the closed set in `scripts/agent-note-tree.ts`; the classification gate rejects other folders. Adding a class requires updating the canonical set and this section. See the [classification Agent Note](implemented/process/2026-06-20-agent-note-classification.md). | Class | What it covers | |---|---| diff --git a/.agents/notes/implemented/process/2026-06-20-agent-note-classification.md b/.agents/notes/implemented/process/2026-06-20-agent-note-classification.md index 4984ac36c2..42c4523e0c 100644 --- a/.agents/notes/implemented/process/2026-06-20-agent-note-classification.md +++ b/.agents/notes/implemented/process/2026-06-20-agent-note-classification.md @@ -4,7 +4,7 @@ Status: implemented ## Problem -`.agents/notes/` grouped Agent Notes by **lifecycle** only — `proposed/` / `implemented/` / `rejected/`. Nothing recorded what *kind* of decision each Agent Note was. The index was one flat list per lifecycle, with no way to scan "show me every simplification" or "every testing-strategy decision." A wave of simplification Agent Notes landing on the same day made the gap concrete: a reader skimming `proposed/` could not tell a new capability from a removal from a tooling-policy change without opening each file. +A lifecycle-only Agent Note tree — `proposed/` / `implemented/` / `rejected/` — does not record what *kind* of decision each file contains. A reader browsing one lifecycle cannot distinguish a new capability from a removal or a tooling-policy change without opening each file. The repo's standing bias is [mechanical quality gates over prose guidelines](2026-06-11-quality-gates.md): a convention that isn't machine-checked rots. So a classification scheme here had to be enforceable, not an honor-system header. @@ -29,18 +29,18 @@ The `architecture` / `process` line: **architecture** is about the source we shi Both are `doc-sync` members, in the `verify-md-wrap` style (tsx ESM, verify-don't-generate, exit non-zero on the first violation): -- **`scripts/verify-agent-note-classification.ts`** — the closed set and index freshness. It asserts every file under a lifecycle folder lives in a class folder from the canonical set (a loose `.md` at a lifecycle root, or an unknown class folder, fails), and that the generated [INDEX.md](../../INDEX.md) byte-matches a fresh render from the tree (see [generate the Agent Note index tables](2026-07-04-generate-agent-note-index-tables.md)). The canonical class set lives as a `const` in `scripts/agent-note-index.ts` — the machine source of truth shared with the generator — and [the README](../../README.md) documents it in prose; the class *descriptions* stay hand-written, the index is generated. -- **`scripts/verify-doc-refs.ts`** — source comments that cite docs. Agent Note paths are referenced not only from Markdown but from TypeScript doc comments (root-relative prose like `.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md`). `verify-md-links` never saw those, so the reorg could have silently orphaned them. This gate scans repo-authored `.ts` under `packages/**` and `examples/**` (excluding built `lib/` and `vendor/`) for `docs/….md` tokens, resolves each root-relative, and asserts it exists. It requires the `.md` extension so extensionless prose (`docs/postmortem/0001`, `docs/architecture.md § Extending The Harness`) is left alone. +- **`scripts/verify-agent-note-classification.ts`** — the closed lifecycle and class sets. It asserts every file under a lifecycle folder lives in a class folder from the canonical set (a loose `.md` at a lifecycle root, or an unknown class folder, fails) and rejects a centralized `INDEX.md`. The canonical sets live in `scripts/agent-note-tree.ts`, and [the README](../../README.md) documents each class in prose. +- **`scripts/verify-doc-refs.ts`** — source comments that cite docs. Agent Note paths are referenced not only from Markdown but from TypeScript doc comments (root-relative prose like `.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md`). `verify-md-links` does not see those, so a reorganization could silently orphan them. This gate scans repo-authored `.ts` under `packages/**` and `examples/**` (excluding built `lib/` and `vendor/`) for `docs/….md` and `.agents/notes/….md` tokens, resolves each root-relative path, and asserts it exists. It requires the `.md` extension so extensionless prose is left alone. ## Alternatives considered - **A `Classification:` prose line** in each file (next to `Status:`), parsed by the gate. Workable, but it duplicates into the file a fact the path can already carry, and a line can disagree with its folder. Path-encoding makes the label and its storage the same thing — there is nothing to keep in sync. - **A `refactor` class.** It overlaps `simplification` almost entirely; the only discriminator anyone reached for was "does observable behavior change?", which `simplification` already encodes (it does not). One class, not two. -- **Auto-generating the index** from the filesystem. Rejected here to keep the index hand-written; superseded by [generate the Agent Note index tables](2026-07-04-generate-agent-note-index-tables.md) once stacked proposal waves made the hand-written tables the repo's most conflict-prone docs region — the list is now the fully generated [INDEX.md](../../INDEX.md) while the README prose stays curated. +- **A generated or hand-maintained corpus index.** Rejected because the lifecycle/class tree is authoritative, while a centralized inventory creates a merge hotspot without providing discovery that tree navigation or repository search cannot provide. The separate [index proposal](../../rejected/process/2026-07-04-generate-agent-note-index-tables.md) records the discarded generated shape. ## Consequences -- Every Agent Note now sits under a class folder, and the index groups by class within each lifecycle. A reader scans one heading to see all simplifications, or all testing decisions. +- Every Agent Note sits under a class folder. A reader can browse one folder to see all simplifications or all testing decisions within a lifecycle. - Two more fast tsx scripts in the `doc-sync` chain; no new dependency (the mdast/GFM stack was already present for `verify-md-wrap`/`verify-md-links`). -- Adding a class is a deliberate act: amend the `const` in `scripts/agent-note-index.ts` and the [Classification section](../../README.md#classification), not just `mkdir` a folder. The gate rejects an unknown folder, so an ad-hoc class can't slip in. +- Adding a class is a deliberate act: amend the `const` in `scripts/agent-note-tree.ts` and the [Classification section](../../README.md#classification), not just `mkdir` a folder. The gate rejects an unknown folder, so an ad-hoc class can't slip in. - Source-comment doc references are now gated too — a moved or renamed doc that a `.ts` comment cites fails the pre-push hook, closing a drift class `verify-md-links` structurally could not see. diff --git a/.agents/notes/implemented/process/2026-07-04-generate-agent-note-index-tables.md b/.agents/notes/implemented/process/2026-07-04-generate-agent-note-index-tables.md deleted file mode 100644 index b0f292d4a0..0000000000 --- a/.agents/notes/implemented/process/2026-07-04-generate-agent-note-index-tables.md +++ /dev/null @@ -1,32 +0,0 @@ -# Agent Note: Generate the Agent Note index tables - -Status: implemented - -## Problem - -The Agent Note index's per-lifecycle/per-class tables list facts that are fully derivable: an Agent Note's path encodes lifecycle and class, its filename encodes the first-proposed date, and its H1 carries the title. A hand-maintained copy of those facts is also the repo's highest-contention docs hotspot: every proposal wave appends rows to the same few lines, so concurrent Agent Note branches conflict precisely there while agreeing everywhere else, and each conflict is resolved by hand-merging rows whose content the filesystem already knows. [The classification Agent Note](2026-06-20-agent-note-classification.md) originally kept the index hand-written for curation's sake — but the curated part of the README is the prose, and the prose never conflicts; only the mechanical tables do. - -## Decision - -Keep the curated prose; generate the list. The tables live in [`.agents/notes/INDEX.md`](../../INDEX.md), a **fully generated file** — the curated prose stays in README.md, which carries no index rows at all. [`scripts/agent-note-index.ts`](../../../../scripts/agent-note-index.ts) is the shared source of truth — the tree walker (owning the closed lifecycle/class sets and the structure rules, including a parseable-H1 requirement) and the renderer (rows from H1 title with any `Agent Note: ` prefix stripped, plus the filename date, sorted by date then filename, grouped as `### {Class}` sections in canonical class order). Two thin consumers share it: - -- [`scripts/gen-agent-note-index.ts`](../../../../scripts/gen-agent-note-index.ts) (`pnpm run gen-agent-note-index`) rewrites INDEX.md in full from the tree. -- [`scripts/verify-agent-note-classification.ts`](../../../../scripts/verify-agent-note-classification.ts) (a `doc-sync` member) checks structure, asserts the committed INDEX.md byte-matches a fresh render — the `gen-cordis-catalog`/`verify-cordis-catalog` pattern — and rejects an index-shaped row in the curated README. Freshness subsumes the index-completeness check: a generated-from-disk table is definitionally complete and correctly headed. - -Adding, moving, or deleting an Agent Note means editing only the Agent Note file and running the generator; the classification Agent Note's rejected-alternatives record carries the supersession cross-link. - -## Alternatives considered - -### Why not marker-delimited regions inside README.md? - -The first landed shape: the generator spliced the tables into README.md between `gen-agent-note-index` marker comments, under each `## {Lifecycle}` heading. Superseded by the whole-file INDEX.md once the README also absorbed the in-file format contract ([the uniform-format Agent Note](2026-07-05-uniform-agent-note-format.md)): a front-door README hosting hundreds of generated rows dwarfed its curated prose, and splice mechanics (marker pairs, heading checks, outside-region row detection) exist only to protect curated text that a dedicated generated file simply doesn't contain. - -### Why not the verifier-only model? - -It catches mistakes but still makes every proposal edit a shared hotspot in a hand-maintained table, and a failed verifier is strictly more annoying than a generator for a purely mechanical row: the author has already named and placed the file; the index copy adds no information. This is the same hand-list-versus-derivation judgment the [package-inventory proposal](../../proposed/process/2026-06-20-discover-package-inventory.md) applies to tsconfig references and knip stanzas — applied to the one list that demonstrably conflicts. - -## Consequences - -- The generated file is explicit: its banner names the generator, there is no curated region to protect inside it, and the generator refuses to run on a structurally invalid tree. -- A malformed or missing H1 is a hard error in both the generator and the gate — the H1 is now load-bearing as the index title source. -- Concurrent Agent Note branches resolve index conflicts by rerunning the generator, never by hand-merging rows. diff --git a/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.md b/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.md index 40c2dd6ec2..1a6aa40477 100644 --- a/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.md +++ b/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.md @@ -18,10 +18,10 @@ The whole corpus was normalized in the same change that defined the format — t - **Header-only normalization** (H1 and Status, bodies untouched) — rejected: the debt markers flagged the *body* genre split, and leaving `Context`/`Decision` beside `Problem`/`Proposal` indefinitely resolves nothing. - **No Status line** (the folder already is the status; the three newest pre-format Agent Notes (and the zh counterpart of one) omitted the line) — rejected in favor of keeping a self-describing file: the drift risk that motivated dropping it is neutralized by gating the line against the folder instead. - **Dated status** (`Status: implemented (accepted YYYY-MM-DD)`) — rejected: the acceptance date is narrated history the writing rules keep out of docs; the filename carries first-proposed, git carries the rest, and the gate could check a date's format but never its truth. -- **A bare `# ` H1** — rejected: the `Agent Note: ` prefix is the corpus-majority form and self-describes the genre when a file is read outside its tree; the index generator strips it, so index rows are identical either way. +- **A bare `# <title>` H1** — rejected: the `Agent Note: ` prefix self-describes the genre when a file is read outside its tree, and the format gate prevents it from drifting. - **`## What we give up` as the implemented closer** (the README's own phrase for what an Agent Note records) — rejected: it names only costs, and an honest consequences section records what the trade-off bought as well. - **Convention without a gate** (write the contract down, enforce by review) — rejected: the slop checklist already outlawed spec-speak in `implemented/` by convention, and nineteen files show what convention alone achieves here. -- **A standalone `FORMAT.md` contract file** — the first landed home; folded into README.md once the generated index moved out to [INDEX.md](../../INDEX.md): with the tables gone the README regained the room, and one front door carrying layout, classification, and format beats splitting the contract across two files. +- **A standalone `FORMAT.md` contract file** — rejected because one front door carrying layout, classification, and format is easier to discover and maintain than two contract files. ## Consequences diff --git a/.agents/notes/implemented/process/2026-07-19-remove-generated-agent-note-index.i18n.yaml b/.agents/notes/implemented/process/2026-07-19-remove-generated-agent-note-index.i18n.yaml new file mode 100644 index 0000000000..2b1dc53f6b --- /dev/null +++ b/.agents/notes/implemented/process/2026-07-19-remove-generated-agent-note-index.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write +2026-07-19-remove-generated-agent-note-index.md: 27c1591b29a1ca64370de6ffadfb9c524a804ced +2026-07-19-remove-generated-agent-note-index.zh.md: 868955bc10900f784bd88066042abe24454e27b5 diff --git a/.agents/notes/implemented/process/2026-07-19-remove-generated-agent-note-index.md b/.agents/notes/implemented/process/2026-07-19-remove-generated-agent-note-index.md new file mode 100644 index 0000000000..27c1591b29 --- /dev/null +++ b/.agents/notes/implemented/process/2026-07-19-remove-generated-agent-note-index.md @@ -0,0 +1,33 @@ +# Agent Note: Keep Agent Notes discoverable without a generated index + +Status: implemented + +English | [中文](2026-07-19-remove-generated-agent-note-index.zh.md) + +## Problem + +A committed Agent Note index duplicates facts already encoded by each file's lifecycle/class path, filename date, and H1. Every branch that adds, moves, or renames an otherwise unrelated Agent Note rewrites the same generated file, making that artifact a predictable merge hotspot. + +The centralized chronological list adds little discovery value beyond browsing the lifecycle/class tree or searching the repository, while its generator, renderer, command, and freshness check remain maintenance surface. + +## Decision + +The lifecycle/class filesystem tree is the Agent Note inventory. [README.md](../../README.md) remains the curated front door and contract, while ordinary tree navigation and repository search provide discovery. + +`scripts/agent-note-tree.ts` owns the closed lifecycle/class sets and structural walker. `verify-agent-note-classification` validates that tree and rejects the legacy homes and a root `INDEX.md`; it does not render or freshness-check a centralized list. + +This decision supersedes the rejected [generated-index proposal](../../rejected/process/2026-07-04-generate-agent-note-index-tables.md). + +## Alternatives considered + +**Keep the committed generated index and resolve conflicts by regenerating it.** Regeneration makes conflict resolution mechanical but does not prevent unrelated branches from modifying the same artifact or reduce the review noise it creates. + +**Offer an uncommitted on-demand index command.** It avoids committed conflicts but preserves a renderer and command for a discovery path already served by tree navigation and repository search. + +**Restore a hand-maintained index.** It has the same shared-file contention and adds completeness/order mistakes that generation avoided. + +## Consequences + +- Adding, moving, or renaming an Agent Note no longer changes a corpus-wide generated file. +- The classification gate performs less work and the documentation gate topology gains no process or stage. +- Readers give up a single chronological page and use the lifecycle/class tree or repository search instead. diff --git a/.agents/notes/implemented/process/2026-07-19-remove-generated-agent-note-index.zh.md b/.agents/notes/implemented/process/2026-07-19-remove-generated-agent-note-index.zh.md new file mode 100644 index 0000000000..868955bc10 --- /dev/null +++ b/.agents/notes/implemented/process/2026-07-19-remove-generated-agent-note-index.zh.md @@ -0,0 +1,33 @@ +# Agent Note: 无需生成索引即可发现 Agent Note + +Status: implemented + +[English](2026-07-19-remove-generated-agent-note-index.md) | 中文 + +## 问题 + +提交到仓库的 Agent Note 索引,会重复记录每个文件的生命周期/类别路径、文件名日期和 H1 已经编码的事实。任何分支只要添加、移动或重命名彼此无关的 Agent Note,都会重写同一个生成文件,因此该产物会成为可预见的合并冲突热点。 + +与浏览生命周期/类别目录树或搜索仓库相比,这份集中式时间顺序清单提供的发现价值有限;但其生成器、渲染器、命令和新鲜度检查仍然构成维护负担。 + +## 决策 + +生命周期/类别文件系统目录树就是 Agent Note 清单。[README.md](../../README.md) 继续作为人工维护的入口和契约,普通的目录树浏览与仓库搜索负责内容发现。 + +`scripts/agent-note-tree.ts` 持有封闭的生命周期/类别集合与结构遍历器。`verify-agent-note-classification` 校验该目录树,并拒绝旧目录和根目录中的 `INDEX.md`,但不会渲染集中式清单或检查其新鲜度。 + +本决策取代已拒绝的[生成索引提案](../../rejected/process/2026-07-04-generate-agent-note-index-tables.md)。 + +## 备选方案 + +**保留提交到仓库的生成索引,并通过重新生成解决冲突。** 重新生成能让冲突解决过程机械化,但无法阻止无关分支修改同一产物,也不会减少由此产生的评审噪音。 + +**提供不提交到仓库的按需索引命令。** 这可以避免已提交文件的冲突,但仍需维护渲染器和命令,而目录树浏览与仓库搜索已经覆盖该发现路径。 + +**恢复人工维护的索引。** 它具有相同的共享文件争用问题,还会重新引入生成机制已经避免的完整性和排序错误。 + +## 影响 + +- 添加、移动或重命名 Agent Note 时,不再改动覆盖整个语料库的生成文件。 +- 分类门禁执行的工作更少,文档门禁拓扑也不会增加进程或阶段。 +- 读者不再获得单一的时间顺序页面,改用生命周期/类别目录树或仓库搜索。 diff --git a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.md b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.md new file mode 100644 index 0000000000..90c942411d --- /dev/null +++ b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.md @@ -0,0 +1,36 @@ +# Agent Note: Generate the Agent Note index tables + +Status: rejected — a centralized generated list is merge-prone and adds little discovery value + +## Problem + +Per-lifecycle/per-class tables would list facts that are fully derivable: an Agent Note's path encodes lifecycle and class, its filename encodes the first-proposed date, and its H1 carries the title. A hand-maintained copy of those facts would also be a high-contention docs hotspot because concurrent Agent Note branches append rows to the same few lines. [The classification Agent Note](../../implemented/process/2026-06-20-agent-note-classification.md) makes the tree itself authoritative. + +## Proposal + +Keep the curated prose and generate the list as a fully generated `.agents/notes/INDEX.md`. A shared `scripts/agent-note-index.ts` module would own both the tree walker and the renderer. Two thin consumers would share it: + +- `scripts/gen-agent-note-index.ts` (`pnpm run gen-agent-note-index`) would rewrite INDEX.md in full from the tree. +- `scripts/verify-agent-note-classification.ts` would check structure and assert that the committed INDEX.md byte-matches a fresh render. + +Adding, moving, or deleting an Agent Note would mean editing the Agent Note file and running the generator. + +## Alternatives considered + +### Why not marker-delimited regions inside README.md? + +Marker-delimited tables inside README.md would mix generated and curated text, requiring splice mechanics and protection for the surrounding contract. A dedicated generated file would at least keep those concerns separate. + +### Why not the verifier-only model? + +It catches mistakes but still makes every proposal edit a shared hotspot in a hand-maintained table. The author has already named and placed the file, so the index copy adds no information. This is the same hand-list-versus-derivation judgment the [package-inventory proposal](../../proposed/process/2026-06-20-discover-package-inventory.md) applies to tsconfig references and knip stanzas. + +## Consequences + +- The generated file would be explicit and contain no curated region. +- A malformed or missing H1 would be a hard error because the H1 supplies each row title. +- Concurrent branches would still modify the same committed artifact, even if conflicts could be resolved by rerunning the generator. + +## Related + +The implemented [no-index decision](../../implemented/process/2026-07-19-remove-generated-agent-note-index.md) keeps the tree and repository search as the discovery mechanisms. diff --git a/.agents/skills/dsh-code-review/SKILL.md b/.agents/skills/dsh-code-review/SKILL.md index c980ad444c..814132d481 100644 --- a/.agents/skills/dsh-code-review/SKILL.md +++ b/.agents/skills/dsh-code-review/SKILL.md @@ -14,7 +14,7 @@ description: Use when reviewing a pull request in the deepseek-harness repo — - [docs/AGENTS.md](../../../docs/AGENTS.md): documentation placement and prose discipline. - [dsh-prose-standard](../dsh-prose-standard/SKILL.md): required coverage and editorial judgment for comments, docs, prompts, and visible strings. - [docs/testing.md](../../../docs/testing.md) and the [quality-gates Agent Note](../../notes/implemented/process/2026-06-11-quality-gates.md): required test tiers and gates. -- [Agent Note index](../../notes/README.md): design rationale. Treat disagreement with an Agent Note as a design discussion, not an automatic veto. +- [Agent Notes](../../notes/README.md): design rationale. Treat disagreement with an Agent Note as a design discussion, not an automatic veto. - For bilingual changes, read [translation-rules.md](../../../docs/i18n/translation-rules.md), [terminology.md](../../../docs/i18n/terminology.md), and [dsh-translate-docs](../dsh-translate-docs/SKILL.md). ## Blocking requirements diff --git a/.agents/skills/dsh-find-simplifications/SKILL.md b/.agents/skills/dsh-find-simplifications/SKILL.md index ae1f3b60d1..2ce80f3f74 100644 --- a/.agents/skills/dsh-find-simplifications/SKILL.md +++ b/.agents/skills/dsh-find-simplifications/SKILL.md @@ -11,7 +11,7 @@ This skill helps turn a broad "find things to simplify" request into evidence-ba - Read `AGENTS.md`, especially the pre-release stance and the conventions (including the tests-are-not-golden-truth and Agent Notes-are-not-golden-truth doctrines), plus [docs/defensive-patterns.md](../../../docs/defensive-patterns.md) and [docs/testing.md](../../../docs/testing.md). - Skim [docs/architecture.md](../../../docs/architecture.md) before judging anything under `packages/`; simplifications that fight the service map or event taxonomy need extra evidence. -- Use the Agent Note index ([.agents/notes/README.md](../../notes/README.md)) to understand intentional architecture. The most relevant implemented examples are [drop mutable session summary](../../notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.md), [shared persistence write coordinator](../../notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md), [capability seams](../../notes/implemented/architecture/2026-06-13-capability-seams.md), and the twin adapter / dual persistence backend Agent Notes. +- Use the Agent Note tree and its [contract](../../notes/README.md) to understand intentional architecture. The most relevant implemented examples are [drop mutable session summary](../../notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.md), [shared persistence write coordinator](../../notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md), [capability seams](../../notes/implemented/architecture/2026-06-13-capability-seams.md), and the twin adapter / dual persistence backend Agent Notes. - Treat dual LLM adapters and dual persistence backends as intentional by default. Do not propose deleting either twin/backend as "low effort" unless the user explicitly overrides that constraint. Removing an unused method or hook inside a protected seam can still be valid if it does not collapse the protected design. ## What Counts As A Strong Candidate @@ -68,7 +68,7 @@ Reject or downgrade a candidate when: ## Write The Agent Note -Create one file per durable proposal under `.agents/notes/<lifecycle>/<class>/yyyy-mm-dd-topic.md`, following the lifecycle/classification contract in `.agents/notes/README.md`. Regenerate `.agents/notes/INDEX.md`; never add a manual Agent Note table to the README. Keep prose paragraphs on one physical line and use relative Markdown links. +Create one file per durable proposal under `.agents/notes/<lifecycle>/<class>/yyyy-mm-dd-topic.md`, following the lifecycle/classification contract in `.agents/notes/README.md`. Keep prose paragraphs on one physical line and use relative Markdown links. Prefer this shape, adjusting when the idea needs it: diff --git a/docs/development.i18n.yaml b/docs/development.i18n.yaml index 8036d11e0b..2ca3f14fbc 100644 --- a/docs/development.i18n.yaml +++ b/docs/development.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -development.md: 31d9f76b6f32b1d26e7b61cdbc2a09aa3504fd6a -development.zh.md: 57d9ca376ed85c212cfd075e1b056882f6449e05 +development.md: 94eb4f03329b574862a1ac1de2f8c1d4db4f4a0a +development.zh.md: b533aff43a66ff7cfc5dc61e5b9b224a01c51f12 diff --git a/docs/development.md b/docs/development.md index 31d9f76b6f..94eb4f0332 100644 --- a/docs/development.md +++ b/docs/development.md @@ -86,7 +86,6 @@ pnpm run verify-cordis-catalog # fail if either cordis catalog is stale pnpm run verify-export-jsdoc # fail if a module-level package export lacks complete JSDoc pnpm run gen-doc-graphs # regenerate generated relationship docs from source and curated graph definitions pnpm run verify-doc-graphs # fail if generated relationship docs are stale -pnpm run gen-agent-note-index # regenerate .agents/notes/INDEX.md from the Agent Note tree pnpm run verify-md-wrap # fail on hard-wrapped prose paragraphs in docs/README markdown pnpm run verify-mermaid # fail if a ```mermaid diagram has invalid Mermaid syntax pnpm run verify-type-equiv # fail if a ```ts type-equiv doc block drifts from its source type diff --git a/docs/development.zh.md b/docs/development.zh.md index 57d9ca376e..b533aff43a 100644 --- a/docs/development.zh.md +++ b/docs/development.zh.md @@ -86,7 +86,6 @@ pnpm run verify-cordis-catalog # fail if either cordis catalog is stale pnpm run verify-export-jsdoc # fail if a module-level package export lacks complete JSDoc pnpm run gen-doc-graphs # regenerate generated relationship docs from source and curated graph definitions pnpm run verify-doc-graphs # fail if generated relationship docs are stale -pnpm run gen-agent-note-index # regenerate .agents/notes/INDEX.md from the Agent Note tree pnpm run verify-md-wrap # fail on hard-wrapped prose paragraphs in docs/README markdown pnpm run verify-mermaid # fail if a ```mermaid diagram has invalid Mermaid syntax pnpm run verify-type-equiv # fail if a ```ts type-equiv doc block drifts from its source type diff --git a/package.json b/package.json index 42988ca5ad..ad4704bf98 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "verify-runtime-closure": "tsx scripts/verify-runtime-closure.ts", "verify-cordis-config": "tsx scripts/verify-cordis-config.ts", "gen-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts", - "gen-agent-note-index": "tsx scripts/gen-agent-note-index.ts", "verify-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts --check", "gen-cordis-api": "tsx scripts/gen-cordis-api.ts", "verify-cordis-api": "tsx scripts/gen-cordis-api.ts --check", diff --git a/scripts/agent-note-index.ts b/scripts/agent-note-index.ts deleted file mode 100644 index e5006eab80..0000000000 --- a/scripts/agent-note-index.ts +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Shared source of truth for the Agent Note index: the tree walker (structure rules) and the README - * table renderer. `gen-agent-note-index.ts` writes the generated regions; - * `verify-agent-note-classification.ts` checks structure and asserts the committed regions are fresh. - * Lifecycle and class sets are closed under `.agents/notes/README.md`; rows derive - * from path, H1, and filename date and sort deterministically. Import is pure. - */ - -import { readFileSync, readdirSync } from 'node:fs' -import { resolve, sep } from 'node:path' -import { globSync } from 'node:fs' - -export const agentNoteRoot = resolve(import.meta.dirname, '../.agents/notes') - -/** The closed set of Agent Note lifecycles (top-level folders under .agents/notes/). */ -const LIFECYCLES = ['proposed', 'implemented', 'rejected'] as const - -/** - * The closed set of Agent Note classes (nested folder under each lifecycle). Adding a - * class is a deliberate act: extend this list AND the README's Classification - * section. The gate rejects any folder not listed here. - */ -const CLASSES = ['feature', 'bug-fix', 'simplification', 'architecture', 'process', 'testing'] as const - -/** Non-Agent Note Markdown allowed to sit directly at a lifecycle root. */ -const ROOT_ALLOWLIST = new Set(['AGENTS.md', 'CLAUDE.md']) - -/** Title-case a class/lifecycle folder name for a README heading. */ -const heading = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1) - -/** One Agent Note file, as discovered by the walker. */ -export interface AgentNote { - lifecycle: string - cls: string - base: string - /** Path relative to .agents/notes — the README link target. */ - rel: string - /** H1 text with any `Agent Note: ` prefix stripped — the README row title. */ - title: string - /** `yyyy-mm-dd` from the filename — the "First proposed" column. */ - date: string -} - -/** - * Walk the Agent Note tree, enforcing the structure rules. Returns every valid Agent Note - * plus one error string per violation (unknown lifecycle or class folder, bad - * depth, bad filename, missing/malformed H1). Callers treat a non-empty error - * list as fatal — the index is only generated from a structurally valid tree. - */ -export function walkAgentNoteTree(): { notes: AgentNote[]; errors: string[] } { - const notes: AgentNote[] = [] - const errors: string[] = [] - // The lifecycle set is closed too: any directory under .agents/notes/ that is not - // a known lifecycle would otherwise hold Agent Notes invisible to the walk below. - for (const entry of readdirSync(agentNoteRoot, { withFileTypes: true })) { - if (entry.isDirectory() && !(LIFECYCLES as readonly string[]).includes(entry.name)) { - errors.push(`structure: ${entry.name}/ — unknown lifecycle folder (allowed: ${LIFECYCLES.join(', ')})`) - } - } - for (const lifecycle of LIFECYCLES) { - for (const match of globSync(`${lifecycle}/**/*.md`, { cwd: agentNoteRoot }).map(path => path.split(sep).join('/')).sort()) { - const segs = match.split('/') - // Allowlisted file directly at the lifecycle root (e.g. implemented/AGENTS.md). - if (segs.length === 2 && ROOT_ALLOWLIST.has(segs[1] ?? '')) continue - // A Chinese counterpart (foo.zh.md, docs/i18n/README.md) is the SAME Agent Note, - // indexed via its English filename; the pairing gate owns its consistency. - if (match.endsWith('.zh.md')) continue - const cls = segs[1] - const base = segs[2] - if (segs.length !== 3 || cls === undefined || base === undefined) { - errors.push(`structure: ${match} — expected {lifecycle}/{class}/file.md (got depth ${segs.length})`) - continue - } - if (!(CLASSES as readonly string[]).includes(cls)) { - errors.push(`structure: ${match} — unknown class folder "${cls}" (allowed: ${CLASSES.join(', ')})`) - continue - } - if (!/^\d{4}-\d{2}-\d{2}-.+\.md$/.test(base)) { - errors.push(`structure: ${match} — filename must be yyyy-mm-dd-topic.md`) - continue - } - const firstLine = readFileSync(resolve(agentNoteRoot, match), 'utf8').split('\n', 1)[0] ?? '' - const h1 = /^#\s+(?:Agent Note:\s+)?(.+?)\s*$/.exec(firstLine) - if (!h1?.[1]) { - errors.push(`title: ${match} — first line must be an H1 (\`# Agent Note: <title>\` or \`# <title>\`), got: ${JSON.stringify(firstLine)}`) - continue - } - notes.push({ lifecycle, cls, base, rel: match, title: h1[1], date: base.slice(0, 10) }) - } - } - return { notes, errors } -} - -/** - * Render one lifecycle's section body: a `### {Class}` heading plus a - * `| Title | First proposed |` table for every non-empty class, in CLASSES - * order, rows sorted by date then filename. - */ -function renderLifecycle(notes: AgentNote[], lifecycle: string): string { - const sections: string[] = [] - for (const cls of CLASSES) { - const rows = notes - .filter(r => r.lifecycle === lifecycle && r.cls === cls) - .sort((a, b) => a.date.localeCompare(b.date) || a.base.localeCompare(b.base)) - if (rows.length === 0) continue - const table = rows.map(r => `| [${r.title}](${r.rel}) | ${r.date} |`).join('\n') - sections.push(`### ${heading(cls)}\n\n| Title | First proposed |\n|---|---|\n${table}`) - } - return sections.join('\n\n') -} - -/** - * Render the complete `.agents/notes/INDEX.md` content: a generated-file banner - * followed by one `## {Lifecycle}` section per lifecycle in canonical order. - * The whole file is generated state — there is no curated region to preserve. - */ -export function renderIndex(notes: AgentNote[]): string { - const parts = [ - '# Agent Note index', - '', - 'Generated by `pnpm run gen-agent-note-index` from the Agent Note tree — never edit by hand; `verify-agent-note-classification` fails when this file is stale. The curated front door — layout, classification, when to write one, and the in-file format — is [README.md](README.md).', - ] - for (const lifecycle of LIFECYCLES) { - parts.push('', `## ${heading(lifecycle)}`, '', renderLifecycle(notes, lifecycle)) - } - return `${parts.join('\n')}\n` -} - -/** Matches an index-shaped table row (a `| [title](lifecycle/…) |` line) — generated state that must not appear in curated prose. */ -export const INDEX_ROW = /^\|\s*\[[^\]]+\]\((?:proposed|implemented|rejected)\// diff --git a/scripts/agent-note-tree.ts b/scripts/agent-note-tree.ts new file mode 100644 index 0000000000..1dff5aab22 --- /dev/null +++ b/scripts/agent-note-tree.ts @@ -0,0 +1,78 @@ +/** + * Shared structural source of truth for the Agent Note tree. Lifecycle and class + * sets are closed under `.agents/notes/README.md`; importing this module is pure. + */ + +import { globSync, readdirSync } from 'node:fs' +import { resolve, sep } from 'node:path' + +export const agentNoteRoot = resolve(import.meta.dirname, '../.agents/notes') + +/** The closed set of Agent Note lifecycles (top-level folders under .agents/notes/). */ +const LIFECYCLES = ['proposed', 'implemented', 'rejected'] as const + +/** + * The closed set of Agent Note classes (nested folder under each lifecycle). Adding a + * class is a deliberate act: extend this list AND the README's Classification + * section. The gate rejects any folder not listed here. + */ +const CLASSES = ['feature', 'bug-fix', 'simplification', 'architecture', 'process', 'testing'] as const + +/** Non-Agent Note Markdown allowed to sit directly at a lifecycle root. */ +const ROOT_ALLOWLIST = new Set(['AGENTS.md', 'CLAUDE.md']) + +/** One Agent Note file, as discovered by the walker. */ +export interface AgentNote { + lifecycle: string + /** Path relative to .agents/notes. */ + rel: string + /** `yyyy-mm-dd` from the filename. */ + date: string +} + +/** + * Walk the Agent Note tree, enforcing the structure rules. Returns every valid Agent Note + * plus one error string per violation (unknown lifecycle or class folder, bad + * depth, or bad filename). Callers treat a non-empty error list as fatal. + */ +export function walkAgentNoteTree(): { notes: AgentNote[]; errors: string[] } { + const notes: AgentNote[] = [] + const errors: string[] = [] + // The lifecycle set is closed too: any directory under .agents/notes/ that is not + // a known lifecycle would otherwise hold Agent Notes invisible to the walk below. + for (const entry of readdirSync(agentNoteRoot, { withFileTypes: true })) { + if (entry.name === 'INDEX.md') { + errors.push('structure: INDEX.md — centralized Agent Note indexes are forbidden; browse the lifecycle/class tree or search the repository') + continue + } + if (entry.isDirectory() && !(LIFECYCLES as readonly string[]).includes(entry.name)) { + errors.push(`structure: ${entry.name}/ — unknown lifecycle folder (allowed: ${LIFECYCLES.join(', ')})`) + } + } + for (const lifecycle of LIFECYCLES) { + for (const match of globSync(`${lifecycle}/**/*.md`, { cwd: agentNoteRoot }).map(path => path.split(sep).join('/')).sort()) { + const segs = match.split('/') + // Allowlisted file directly at the lifecycle root (e.g. implemented/AGENTS.md). + if (segs.length === 2 && ROOT_ALLOWLIST.has(segs[1] ?? '')) continue + // A Chinese counterpart (foo.zh.md, docs/i18n/README.md) is the SAME Agent Note, + // indexed via its English filename; the pairing gate owns its consistency. + if (match.endsWith('.zh.md')) continue + const cls = segs[1] + const base = segs[2] + if (segs.length !== 3 || cls === undefined || base === undefined) { + errors.push(`structure: ${match} — expected {lifecycle}/{class}/file.md (got depth ${segs.length})`) + continue + } + if (!(CLASSES as readonly string[]).includes(cls)) { + errors.push(`structure: ${match} — unknown class folder "${cls}" (allowed: ${CLASSES.join(', ')})`) + continue + } + if (!/^\d{4}-\d{2}-\d{2}-.+\.md$/.test(base)) { + errors.push(`structure: ${match} — filename must be yyyy-mm-dd-topic.md`) + continue + } + notes.push({ lifecycle, rel: match, date: base.slice(0, 10) }) + } + } + return { notes, errors } +} diff --git a/scripts/gen-agent-note-index.ts b/scripts/gen-agent-note-index.ts deleted file mode 100644 index df54300a19..0000000000 --- a/scripts/gen-agent-note-index.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Regenerate `.agents/notes/INDEX.md` — the fully generated Agent Note index — from the - * Agent Note tree (see [agent-note-index.ts](./agent-note-index.ts) for the layout contract and - * rendering rules). The whole file is generated state; the curated prose lives - * in `.agents/notes/README.md`. Freshness is asserted by - * `verify-agent-note-classification.ts` (a `doc-sync` member), so a stale committed - * index fails CI. - * - * Run: `pnpm run gen-agent-note-index`. - */ - -import { readFileSync, writeFileSync } from 'node:fs' -import { resolve } from 'node:path' -import { agentNoteRoot, renderIndex, walkAgentNoteTree } from './agent-note-index.ts' - -const { notes, errors } = walkAgentNoteTree() -if (errors.length > 0) { - console.error('gen-agent-note-index: refusing to generate from a structurally invalid tree:') - for (const e of errors) console.error(` ${e}`) - process.exit(1) -} - -const indexPath = resolve(agentNoteRoot, 'INDEX.md') -const next = renderIndex(notes) -let current: string | undefined -try { - current = readFileSync(indexPath, 'utf8') -} catch { - // Missing INDEX.md is the fresh-generation case, not an error: fall through and write it. -} -if (next === current) { - console.log(`gen-agent-note-index: .agents/notes/INDEX.md is up to date (${notes.length} Agent Notes).`) -} else { - writeFileSync(indexPath, next) - console.log(`gen-agent-note-index: .agents/notes/INDEX.md regenerated (${notes.length} Agent Notes).`) -} diff --git a/scripts/verify-agent-note-classification.ts b/scripts/verify-agent-note-classification.ts index 81cc79c5f5..776e155f4f 100644 --- a/scripts/verify-agent-note-classification.ts +++ b/scripts/verify-agent-note-classification.ts @@ -1,13 +1,12 @@ /** - * Enforce Agent Note lifecycle/class paths, dated filenames, and titles; verify the - * generated index and reject index rows in the curated README. Structural rules - * and rendering are shared with `agent-note-index.ts`; the closed classification - * contract lives in `.agents/notes/README.md`. + * Enforce Agent Note lifecycle/class paths and dated filenames. Structural rules + * are shared with `agent-note-tree.ts`; the closed classification contract lives + * in `.agents/notes/README.md`. */ -import { existsSync, readFileSync } from 'node:fs' +import { existsSync } from 'node:fs' import { resolve } from 'node:path' -import { agentNoteRoot, INDEX_ROW, renderIndex, walkAgentNoteTree } from './agent-note-index.ts' +import { walkAgentNoteTree } from './agent-note-tree.ts' const { notes, errors } = walkAgentNoteTree() @@ -19,25 +18,7 @@ for (const legacyRoot of ['docs/rfc', 'docs/rfcs']) { } if (errors.length === 0) { - let index: string | undefined - try { - index = readFileSync(resolve(agentNoteRoot, 'INDEX.md'), 'utf8') - } catch { - // A missing INDEX.md is reported below as staleness, exactly like a drifted one. - } - if (renderIndex(notes) !== index) { - errors.push('index: .agents/notes/INDEX.md is stale or missing — run `pnpm run gen-agent-note-index` and commit the result') - } - const readme = readFileSync(resolve(agentNoteRoot, 'README.md'), 'utf8') - for (const line of readme.split('\n')) { - if (INDEX_ROW.test(line)) { - errors.push(`readme: index-shaped row in the curated README (the list lives in INDEX.md): ${JSON.stringify(line.slice(0, 80))}`) - } - } -} - -if (errors.length === 0) { - console.log(`verify-agent-note-classification: ${notes.length} Agent Note(s) checked, structure and index consistent.`) + console.log(`verify-agent-note-classification: ${notes.length} Agent Note(s) checked, structure consistent.`) process.exit(0) } diff --git a/scripts/verify-agent-note-format.ts b/scripts/verify-agent-note-format.ts index b38c6225bd..39018588e6 100644 --- a/scripts/verify-agent-note-format.ts +++ b/scripts/verify-agent-note-format.ts @@ -7,7 +7,7 @@ import { readFileSync } from 'node:fs' import { resolve } from 'node:path' -import { agentNoteRoot, walkAgentNoteTree } from './agent-note-index.ts' +import { agentNoteRoot, walkAgentNoteTree } from './agent-note-tree.ts' /** The date the format contract landed; the grandfather comment is valid only before it. */ const FORMAT_ADOPTED = '2026-07-05'