just contract-generateproduces an in-memory snapshot of every command, every package, every manifest field. Pre-commit / pre-push / CI hooks run drift checks against this contract. The contract is the project's self-knowledge layer — what makes "the docs match the code" enforceable instead of aspirational.
The contract has three views:
just recipe with description + arguments.packages/<svc>/ with manifest summary.just contract-summary # high-level counts
# Contract summary:
# Modules: 24
# Commands: 654
# Packages: 12
# Generated: 2026-05-18T15:00:00Z
just contract-generate # generate, hold in memory (no file written)
just contract-generate --stdout # also dump YAML to stdout (debug)
In-memory by design (per ticket #3748) — eliminates "did you regenerate?"
churn from CI. The generator walks the repo and constructs the contract
fresh every invocation.
What it walks:
Justfile + *.just files → command names + descriptions + argspackages/*/manifest.yaml → package summariesservices.yaml → profiles + service registryCLAUDE.md → declared Golden Rules + section referencesjust contract-validate
# ✓ commands: 654 valid
# ✓ packages: 12 valid
# ✗ CLAUDE.md: line 142 references command 'just foo' which doesn't exist
# ✗ CLAUDE.md: line 287 references package 'bar' which doesn't exist
CLAUDE.md drift is the most-common contract-validate failure. Operators
update a recipe name; CLAUDE.md still references the old name. Contract
catches that.
Pre-commit hook (configured in .git/hooks/pre-commit or via husky):
just contract-validate || exit 1
CI also runs just contract-validate on every PR.
just contract-search "backup" # commands matching "backup"
just contract-search "redmine" --limit=5
just contract-commands lifecycle # commands in the 'lifecycle' module
just contract-modules # list all modules
just package-list # list all packages
just contract-search "user add"
# user-add-all - Create user in Authentik + all SSO-enabled services
# authentik-user-create - Create a new Authentik user
# erpnext-create-user - Create an ERPNext user
# ...
just contract-validate
# Catches stale references in CLAUDE.md, docs/, *.md
MCP server exposes command_list, command_search, command_modules —
backed by the contract. Agents can discover what they can do without
hardcoding command lists.
# .github/workflows/contract.yml
- run: just contract-validate
Drift = fail. Author fixes the docs (or the recipe) before merge.
Pre-ticket #3748 the contract was a generated YAML file
(contract.yaml) checked into git. Problems:
In-memory generation eliminated all of this. Generator is fast (~200ms);
runs on demand.
Contract validation is extensible. The validator walks a registry of
checks:
// scripts/contract/validate.ts
const checks = [
validateClaudeMdCommandRefs,
validateClaudeMdPackageRefs,
validateManifestSchema,
validateProfileMembership,
// add new check here
];
Each check returns { ok: boolean, errors: string[] }. New checks tend to
fall into: "this doc references this thing — does the thing exist?"
patterns.
To add a check: write the function, append to the array, document in
docs/framework/CONTRACT-SYSTEM.md.
The contract describes the static project state — what commands exist,
what packages exist. It does NOT describe:
just status.)just profile show.)asd net discover.)Contract is the project's source-of-truth-about-itself. Runtime state is
elsewhere.
/pma/internals/architecture — the Contract pillar in context./pma/reference/cli — recipes that use the contract (contract-*, command-*).docs/framework/CONTRACT-SYSTEM.md in the repo — full spec.