Files
deepseek-harness/docs/rfc/implemented/2026-06-11-custom-schema-dsl.md
Tianyi Cui 7c400e9c02 docs: unify ADR/RFC trees into one lifecycle-organized RFC tree
Collapse docs/adr/ and docs/rfc/ into a single docs/rfc/ with proposed/,
implemented/, and rejected/ subfolders. Every file is renamed to
yyyy-mm-dd-topic-title.md, where the date is when the topic was first
proposed (from git history). ADRs and RFCs that covered exactly the same
topic are merged (property-based testing, session persistence); the
umbrella RFC 005 stays split across its three implemented decisions, and
RFC 006's deferred part-3 (API extractor reports) splits into its own
proposed RFC. All cross-references become machine-checkable relative
links instead of bare "ADR NNNN" / "RFC NNN" prose.

Add a verify-md-links doc-sync gate (scripts/verify-md-links.ts) that
checks every relative Markdown cross-link resolves, wired into doc-sync
alongside verify-md-wrap. This makes the reorganization self-verifying:
the same change that rewrote ~forty inter-doc links adds the check that
proves none dangle. Document the cross-link convention in a new
docs/AGENTS.md and record the gate as an implemented RFC.

doc-sync, typecheck, lint, and the full test suite (667) all pass.
2026-06-18 02:18:24 +08:00

1.7 KiB

RFC: Custom typed tool-schema DSL instead of schemastery

Status: implemented (accepted 2026-06-11)

Context

Tool parameters must reach the model as standard JSON Schema (the wire format), and tool authors deserve typed execute(args) without casts. The repo already vendors schemastery (used for plugin Config), so reusing it was the obvious candidate. The user also explicitly preferred per-property required: true booleans over JSON Schema's separate required array.

Decision

A small custom DSL in dsh-tools: SchemaSpec (per-property specs with required: true booleans), type-level InferArgs<S> mapping a spec to the argument type (required keys non-optional, others genuinely optional via ?), a runtime schemaSpecToJsonSchema() converter, and defineTool() tying them together. Raw JSON-Schema ToolDefinitions remain accepted by ToolRegistry.register() — that's how MCP-sourced tools arrive.

Schemastery was evaluated and rejected for this use: it targets validation / transformation against StandardSchema, not JSON Schema generation, so it would add indirection without producing the wire format cleanly.

Consequences

  • First-party tool authors get zero-cast typed args; the type gymnastics cost stays inside the core package (sanctioned by the AGENTS.md type-safety policy).
  • The DSL is deliberately small (string/number/boolean/object/array, enum, default, nested properties/items). Gaps vs full JSON Schema (unions, formats, constraints) are accepted until real tools demand them.
  • The InferArgs mapping is regression-tested at the type level (expectTypeOf) after an early optionality bug shipped and was caught by review.