Change with contracts
Claude Code plugin: represent a project as a tree of documented modules with boundary contracts, so an agent stays oriented in large codebases and makes boundary changes a deliberate preserve-vs-cascade decision.
npx -y skills add nicolasapr/contract-tree --skill change-with-contractsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 21 days oldThe repository was created 21 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when about to change code in a repo that has a contract tree. Locates the affected module via `.contract-tree/tree.md`, classifies whether the change touches the module boundary, computes the downstream blast radius, and requires an explicit preserve-vs-cascade decision from the user before touching boundary-affecting code.
SKILL.md
4.3 KB, 955 tokens by cl100k_base, as published. Nobody here has run it
Change With Contracts
The procedure for changing code in a repo that has a contract tree. It keeps you oriented with cheap reads and turns any boundary change into a deliberate, visible decision.
Hard rule: this skill NEVER cascades on its own. When a change would alter a module's boundary, you present the blast radius and let the user choose preserve-vs-cascade. No boundary-affecting code is touched before that choice.
If the repo has no .contract-tree/ yet, run map-modules first (at least for
the area you're touching), then return here.
The six steps
1. Locate
Read .contract-tree/tree.md. Find the module(s) where the task lives. Open only
those CONTRACT.md files — read their purpose, io, invariants, and
entrypoints. Do not scan the whole tree.
2. Classify the change
Read io.input as the module's precondition, io.output as its postcondition,
and each invariant as a boundary guarantee (Design by Contract). Then classify into three —
see ../contract-tree/references/principles.md
for the compatibility rule and taxonomy:
- Internal (SemVer PATCH) — internals only; precondition, postcondition, and every
invariant stay true. → Implement freely. On finish, re-check invariants; update
CONTRACT.mdonly if something it declares actually changed. No cascade. - Additive (SemVer MINOR) — the contract changes but stays backward compatible: it
weakens the precondition (accepts more), strengthens the postcondition (guarantees
more), or adds a new optional output/entrypoint. Existing consumers still work. →
Update the
CONTRACT.md; no cascade. This is also the target of a "preserve". - Breaking (SemVer MAJOR) — it strengthens the precondition (demands more of callers), weakens the postcondition (guarantees less), removes/renames required I/O, or breaks a declared invariant. → Go to step 3.
When unsure whether a change is additive or breaking, treat it as breaking and compute the radius; a false alarm is cheap, a missed break is not.
3. Compute the blast radius
Follow references/blast-radius.md: from tree.md, follow → edges
transitively from the changed module to collect all downstream modules, then open
each one's CONTRACT.md to see how it consumes the changing output. Note which
are genuinely affected and how.
4. Present the radius and let the user decide
Show the user: what boundary changes, which downstream modules are affected, and their concrete use points. Then offer the two paths explicitly:
- Preserve — find an additive path to the same goal so the provider evolves without consumers jumping in lockstep (consumer-driven evolution): add a new field/overload instead of changing an existing one, introduce an extension point, adapt at the edge, or deprecate-before-removing. The radius collapses to zero downstream work.
- Cascade — accept the breaking change and propagate it through the affected downstream modules.
When you present the radius, note how each downstream module is coupled to the changing output (its connascence — a renamed field is weak; a relied-on meaning like "meters" or a positional/algorithmic dependency is strong). Stronger coupling means a costlier cascade and a stronger reason to preserve.
Stop and wait for the user's choice. Do not touch boundary-affecting code before it.
5. Execute the chosen path
- Preserve — implement the boundary-safe alternative in the module. Downstream is untouched.
- Cascade — change the root module, then each affected downstream module in
graph order (upstream before downstream), updating each module's
CONTRACT.mdas its boundary changes.
6. Close
Update every CONTRACT.md whose boundary changed, and regenerate the affected
part of .contract-tree/tree.md if the dependency graph changed. An updated
contract is part of "done" — leaving it stale is a bug, because the next task
trusts it.
What ships with it: 1 file
3.4 KB alongside SKILL.md
references/
- blast-radius.md3.4 KB