ADR-0014: Dependency posture, and pydantic at the external-input boundary¶
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-06-08 |
| Authors | Roman Mednitzer |
Context¶
ADR-0001's "self-contained monorepo" rule was written at bootstrap to keep praxis
decoupled from the sibling fleet repositories: it must not import from, or take a
runtime dependency on, any other repository. That rule is sound and stays. It was
sometimes read more strongly, as "no third-party dependencies at all" or "implements
everything itself," which is not the actual constraint. The repository already
declares a third-party optional dependency (psycopg) for the Postgres backend, and
praxis is Apache-2.0, compatible with permissively-licensed libraries.
The over-absolute reading shaped the external-input boundary: each MCP tool kept a hand-authored JSON Schema dict separate from its hand-written argument parsing, and those two can drift; the same class of untrusted-input defects hardened by hand in ADR-0013 (UTF-8 boundaries, finite numbers, size caps, duplicate keys) would be expressed more safely and once if validation were declarative.
Decision¶
- Clarify the self-contained rule: it forbids coupling to any sibling fleet repository (no imports from, and no runtime dependency on, another repo), not the use of well-licensed third-party PyPI libraries. Third-party runtime dependencies are permitted under license and supply-chain review, kept minimal, pinned, and surfaced in the SBOM and dependency-audit CI jobs.
- Adopt pydantic (MIT) as a core runtime dependency for declarative validation at
the external-input trust boundary: the MCP tool arguments, the server
configuration, and the SKILL.md frontmatter. A typed model is the single source of
truth for both the advertised JSON Schema and the parse/validate step, removing the
schema-versus-parser drift and making boundary validation fail-closed (unknown tool
arguments are rejected,
extra='forbid'). - Keep the execution core (
patterns,policy,redaction,audit,contract,runner) and the fact model dependency-free. They are the sole security-review surface and take on no library; the SKILL.md hardened parser (ADR-0013, BL-057) is retained and pydantic validates its result, it does not replace it. - Record the clarification as an appended audit note on ADR-0001 (immutable) and supersede the over-absolute reading here.
Consequences¶
Positive: one source of truth for each tool's schema and validation, so they cannot drift; declarative, fail-closed validation at the trust boundary, which generalises the ADR-0013 untrusted-input hardening; and the dependency posture is now stated accurately across the docs. The execution core stays dependency-free.
Negative: the default install now pulls pydantic plus the compiled pydantic-core
wheel, a supply-chain item to vet, pin (pydantic>=2,<3), and SBOM. This is mitigated
by confining pydantic to the boundary and keeping the core clean.
Neutral: psycopg remains an optional extra; the default SQLite-over-stdio path still
needs no external services. The committed docs/schema/*.json are now generated from
the models rather than hand-authored.
Alternatives considered and rejected¶
- Dev-only schema generation: use pydantic only to generate the committed schemas while runtime validation stays stdlib. Rejected: it leaves the security-relevant runtime parsing hand-rolled and makes validation behaviour differ by install.
- Keep hand-rolled validation. Rejected: the schema-versus-parser drift and the recurring untrusted-input bug class are exactly what a validation library removes.
- Pull validators or models from a sibling repository. Rejected: that would breach the self-contained rule, which this ADR clarifies but upholds.
Revisit triggers¶
- The HTTP transport lands (BL-012): external JSON request bodies extend the boundary pydantic now covers, and a request/response model layer should follow.
- A pydantic major (v3) or a supply-chain advisory forces a pin change.
- The runtime dependency footprint grows beyond pydantic plus the optional psycopg without a superseding ADR.