create-spec-driven-app v0.7.0

The agent contract#

How a machine drives this CLI. The rules are fixed by ADR-0017; this document is generated from the source so it cannot drift from it.

The rules#

  1. One JSON document per invocation. In --json mode stdout carries exactly one JSON document. Prose, progress and warnings go to stderr, so cmd --json 2>/dev/null | jq . always parses.

  2. One diagnostic envelope, everywhere:

    {
      "severity": "error" | "warning" | "info",
      "code": "snake_case_stable_string",
      "message": "human sentence",
      "target": "the thing at fault (optional)",
      "fix": "one actionable sentence or command (optional)",
      "file": "relative/path.md (optional)",
      "line": 42
    }

    Branch on code, never on message. message is prose and may be reworded; code is the published surface.

  3. Failure carries the command's null-shape. A failure prints { ...nullShape, "status": [diagnostic] } and exits 1 — never bare stderr, never a partial document. A consumer never has to tell "it failed" apart from "it printed nothing".

  4. camelCase everywhere in command output. (The on-disk formats are not command output: pack.yaml keeps schema_version and .specops.lock keeps pack_id.)

  5. --json and --format json are the same flag. The second spelling predates the contract and keeps working.

Exit codes#

SituationExit
Success, including advisory warnings0
Command failure — one JSON document with status1
Gate failure (validate, doctor, change validate)1
Usage error — unknown flag, missing or malformed argument2
Required script missing (a broken installation)3
Cancelled by the user130

A gate command exits 1 when it finds something, which is not the same as failing to run. The status array tells the two apart: a gate that could not run reports an error about itself.

Commands#

CommandDocument keyGate
csda doctor --jsondoctoryes
csda status --jsonstatusno
csda alm pull --jsonpulledno
csda validate <dir> --jsonvalidationyes
csda plan --jsonplanno
csda report --jsonreportno
csda done <REQ> --jsonrequirementno
csda change list --jsonchangesno
csda change show <id> --jsonchangeno
csda change status --jsonartifactsno
csda change validate <id> --jsonchangeyes
csda change archive <id> --jsonarchiveyes
csda change instructions <artifact> --jsoninstructionsno
csda change author <id> --jsonchangeyes
csda specops diff --jsonchangesno
csda harness run --format jsonresultsno
csda harness report --jsonreportno

The document key is what the payload carries on success and what is set to null on failure. Every document also carries status: an array of diagnostics, empty when there is nothing to report.

Diagnostic codes#

Harvested from the source. A trailing * marks a family whose suffix is computed — strict_tdd_* covers strict_tdd_1 through strict_tdd_3.

CodeEmitted by
events_header_missingscripts/validate_specs.ts
feature_not_in_matrixscripts/validate_specs.ts
missing_required_filescripts/validate_specs.ts
no_featuresscripts/validate_specs.ts
requirement_cyclescripts/validate_specs.ts
self_dependencyscripts/validate_specs.ts
strict_tdd_1scripts/validate_specs.ts
strict_tdd_2scripts/validate_specs.ts
strict_tdd_3scripts/validate_specs.ts
traceability_unrecognizedscripts/validate_specs.ts
unknown_dependencyscripts/validate_specs.ts
use_cases_header_missingscripts/validate_specs.ts
archive_change_name_requiredscripts/cli/commands/change/ChangeCommand.ts
archive_spec_update_failedscripts/cli/commands/change/ChangeCommand.ts
author_agent_failedscripts/cli/commands/change/ChangeCommand.ts
author_agent_unsetscripts/cli/commands/change/ChangeCommand.ts
author_needs_gitscripts/cli/commands/change/ChangeCommand.ts
author_out_of_scopescripts/cli/commands/change/ChangeCommand.ts
author_tree_dirtyscripts/cli/commands/change/ChangeCommand.ts
change_errorscripts/cli/commands/change/ChangeCommand.ts
change_existsscripts/cli/commands/change/ChangeCommand.ts
change_id_requiredscripts/cli/commands/change/ChangeCommand.ts
change_not_foundscripts/cli/commands/change/ChangeCommand.ts
change_requiredscripts/cli/commands/change/ChangeCommand.ts
invalid_change_idscripts/cli/commands/change/ChangeCommand.ts
missing_proposalpackages/core/src/application/ValidateChangeUseCase.ts
no_deltaspackages/core/src/application/ValidateChangeUseCase.ts
delta_emptypackages/core/src/domain/DeltaSpec.ts
delta_unknown_sectionpackages/core/src/domain/DeltaSpec.ts
duplicate_requirementpackages/core/src/domain/DeltaSpec.ts
invalid_requirement_idpackages/core/src/domain/DeltaSpec.ts
no_rfc2119_keywordpackages/core/src/domain/DeltaSpec.ts
requirement_already_existspackages/core/src/domain/DeltaSpec.ts
requirement_without_scenariopackages/core/src/domain/DeltaSpec.ts
scenario_not_gherkinpackages/core/src/domain/DeltaSpec.ts
scenario_steps_unwrittenpackages/core/src/domain/DeltaSpec.ts
scenario_without_stepspackages/core/src/domain/DeltaSpec.ts
unknown_requirementpackages/core/src/domain/DeltaSpec.ts
archive_capability_retiredpackages/core/src/application/ArchiveChangeUseCase.ts
archive_change_not_foundpackages/core/src/application/ArchiveChangeUseCase.ts
archive_change_symlinkpackages/core/src/application/ArchiveChangeUseCase.ts
archive_feature_existspackages/core/src/application/ArchiveChangeUseCase.ts
archive_no_deltaspackages/core/src/application/ArchiveChangeUseCase.ts
archive_retire_not_declaredpackages/core/src/application/ArchiveChangeUseCase.ts
archive_target_existspackages/core/src/application/ArchiveChangeUseCase.ts
archive_tasks_incompletepackages/core/src/application/ArchiveChangeUseCase.ts
traceability_upgradedpackages/core/src/application/ArchiveChangeUseCase.ts
artifact_requiredscripts/change/instructions.ts
artifact_unknownscripts/change/instructions.ts
change_not_foundscripts/change/instructions.ts
project_not_foundscripts/change/instructions.ts
ambiguous_packscripts/cli/commands/specops/ContributeCommand.ts
change_has_no_deltasscripts/cli/commands/specops/ContributeCommand.ts
change_not_foundscripts/cli/commands/specops/ContributeCommand.ts
change_requiredscripts/cli/commands/specops/ContributeCommand.ts
contribute_not_pushedscripts/cli/commands/specops/ContributeCommand.ts
contribute_stage_failedscripts/cli/commands/specops/ContributeCommand.ts
no_lockfilescripts/cli/commands/specops/ContributeCommand.ts
nothing_to_contributescripts/cli/commands/specops/ContributeCommand.ts
pack_has_no_reposcripts/cli/commands/specops/ContributeCommand.ts
pack_not_foundscripts/cli/commands/specops/ContributeCommand.ts

Worked example#

csda change instructions specs --json 2>/dev/null | jq -r '.instructions.rules[]'

An agent that reads fix self-corrects; one that reads only message retries the same mistake. That is why a check without a fix is treated as unfinished.