Skip to content

Contract Hash

Specs carry a contractHash stamped over intent, outcomes, redaction:, and coversSymbol (when set). Glyphrun refuses to run a spec whose on-disk content does not match the hash. The point is to detect silent contract drift: a contributor edits an outcome to make a flaky test pass, the hash stops matching, the run aborts, and the change shows up in code review.

What the hash covers

The hash is sha256 over the canonical JSON of the contract fields — intent, outcomes, redaction:, and coversSymbol. Map keys are sorted by Go's encoding/json, so the hash is stable across editors that reorder YAML keys. steps are deliberately not covered: they are repairable hints, not the contract.

Workflow

  1. Re-stamp after an intentional change. glyph spec verify <spec> --stamp regenerates the hash after intent/outcomes/redaction/coversSymbol deliberately changed.
  2. Run compares the stamp. glyph run <spec> compares the stamped hash against the on-disk content. On mismatch, no PTY is started and no artifacts are written; the CLI prints the expected and actual hashes plus a hint pointing at the intent / outcomes / redaction blocks.
  3. CI gate. A glyph spec verify <dir> --format json step in the pipeline catches drift before merge.
bash
glyph spec verify specs/smoke.yml --format json     # check
glyph spec verify specs/smoke.yml --stamp           # re-stamp after an intentional change

Never edit contractHash by hand — always use --stamp. See CLI Reference.

Exit codes

CodeMeaning
0pass
1outcome failure
2runtime error
3target timeout
4spec parse / schema error
6contract-hash mismatch
7unsupported terminal (alternate-screen required, not entered)

Error classification (errorKind + diagnostic)

Every errored run — and any failed run with a runner-level cause — carries an errorKind and diagnostic in the run.json / --format json envelope so agents can pick an actionable next step instead of treating the error as ambiguous:

errorKindMeaningNext step
target_startthe target command could not startfix cmd/cwd or ensure the binary exists
timeoutthe target or a step exceeded its timeoutraise timeoutMs
target_exitedthe target exited while a screen wait was still unsatisfiedinspect diagnostic / raw/pty.raw.log and fix the target (not timeoutMs)
contract_hash_mismatchthe stamped hash doesn't match the computed onere-stamp with glyph spec verify --stamp
unsupported_terminalthe terminal behavior isn't supported by the active profileswitch terminal.profile
step_failurea step errored (non-timeout, non-terminal)inspect diagnostics/failure.md
preconditiona preconditions command or secret resolution failedfix the precondition or secret config
spec_parsethe spec failed schema validation or parsingfix the YAML/schema error

On exit 4 (parse) and exit 6 (contract-hash mismatch), the structured JSON envelope is printed to stdout — not only stderr — so glyph run / glyph spec verify consumers decoding stdout never see an empty payload. For contract_hash_mismatch the envelope also includes contractHash (computed) and expectedHash (stamped).

Every errored run also carries an additive nextActions array — one actionable next step per errorKind (e.g. contract_hash_mismatchglyph run <spec> --update-snapshots). Each action has a command, a reason, and safeToAutoRun (always false — no repair is safe to run without the operator, since re-stamping changes files). Non-errored runs omit nextActions entirely.

The contract/repair split is core to how Glyphrun thinks about specs: intent + outcomes are the durable behavior contract; steps are repairable hints. See Authoring and glyph repair.

Released under the MIT License.