kadence
Decisions

ADR-009 — The agent contract

Entry points, error codes and a published schema — accepted 2026-09-07.

Date: 2026-09-07 · Status: accepted · Scope: CLI contract, init, agent interface

Context

kadence promised that init "writes a guide the AI agent finds on its own". Research on 2026-09-07 found the promise did not hold, and that two related claims were thinner than they read:

  1. init wrote only AGENTS.md. That is the cross-tool convention — 30+ agents read it, 60,000+ repositories carry it — but Claude Code loads CLAUDE.md and does not read AGENTS.md. Verified directly: in the session that produced the research, CLAUDE.md was in context and AGENTS.md was not. For the largest agent audience, init created no entry point that loads on its own.
  2. A failed --json call returned one English sentence. An agent could tell that something failed and nothing else. The most likely agent error is a wrong status — and statuses are configured per project, so no amount of reading the documentation tells an agent the valid set.
  3. schema: "kadence/v1" was a label. Nothing published what the fields are, and nothing failed if one was renamed. It was called "a contract an agent can rely on"; it was a version string that a test asserted the presence of.

Options considered

Entry points

OptionProsCons
AGENTS.md only (status quo)one file, one conventioninvisible to Claude Code — the largest audience, and the agent we build with
CLAUDE.md containing @AGENTS.mdthe vendor-documented bridge; one source of truththe import pulls someone else's entire instruction file into every session
The same short section in both, regenerated on every initworks everywhere; the upsert prevents drift; ambient cost stays at a few linestwo files carry the same paragraph
A file per agent (.cursor/rules, copilot-instructions, GEMINI.md, …)maximum reachfour more files written into someone's repository to advertise ourselves; those tools read AGENTS.md already

Error detail

OptionProsCons
Message only (status quo)nothing to maintainagent cannot branch, cannot self-correct
code + received + allowed + hintagent fixes its own input in one step; allowed is the only way to learn configured statusesthe code list becomes part of the contract
Adding retryable / recoverablematches the pattern the literature recommendsthere is no network and no lock here: the same input always fails identically, so the field would be a constant presented as information

Publishing the schema

OptionProsCons
Document the fields in .kadence/README.mdno codeprose drifts from behaviour, silently
Ship a static JSON Schema filestandard format, existing validatorsa second artefact to keep in step; a dependency to validate it
kadence schema --json, checked against real output in CIthe tool is the source of truth; zero dependencies; the check fails the build on a renameour own shape, not JSON Schema — a consumer wanting formal validation must convert

Decision

Write the same section into both AGENTS.md and CLAUDE.md. No @AGENTS.md import: it would drag an arbitrary amount of someone else's context into every session. No per-vendor files.

Give every failure a code, from a closed list, with received, allowed and hint where each is knowable. No retryable — and the absence is asserted by a test, so it is not added absent-mindedly later.

Publish the contract as kadence schema --json. It works outside a repository. Three tests keep it honest: the published error codes must equal the ones the code emits, every required field must appear in real command output, and every command named must actually run.

The contract is deliberately narrower than the output. Fields we emit but do not list may still change; what is listed is a promise. Within kadence/v1, fields and codes may be added, never renamed or removed.

Consequences

  • Positive: the promise is now true for Claude Code users. An agent that sends a wrong status is told the configured set and fixes itself in one step. Renaming a task field fails the build instead of breaking consumers quietly.
  • Cost: init now writes a second file into the user's repository root — the most intrusive thing kadence does, which is why the section is short and the upsert leaves human text untouched. The error-code list and the schema are both public surface: additive changes only, forever.
  • Measured: bundle 29 KB (was 30 KB), schema --json under 4 KB of output, performance budgets unchanged.
  • Revisit if: Claude Code adds native AGENTS.md support — then the second file becomes redundant and should be dropped rather than kept out of habit. Or if consumers ask for formal JSON Schema, at which point the contract we already publish is the thing to generate it from.

This record was written in English in the product repository; the canonical copy is 009-the-agent-contract.md.

On this page