contract-driven
Use when crossing a public API boundary, guarding complex invariants, or hardening untrusted input or integration seams. Not for remote or irreversible changes.
Install
npx skills add https://github.com/OutlineDriven/odin-claude-plugin/tree/main/plugins/odin-code/skills/contract-driven
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install outlinedriven-odin-claude-plugin@llmmart
git clone https://github.com/OutlineDriven/odin-claude-plugin.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole outlinedriven/odin-claude-plugin collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Contract-driven
Contract
| Field | Bound contract |
|---|---|
| Trigger | Crossing a public API boundary, guarding complex invariants, or hardening untrusted input or integration seams. |
| Authority | Reversible local: writes only named local types, assertions, validators, and tests at contract boundaries; rollback is undo (delete the added code or revert the boundary change). No remote mutation. |
| Side effect | Adds or refines local types, assertions, validators, and tests at contract boundaries. |
| Done | Every planned contract is implemented at the appropriate static/test/debug/runtime layer and violations fail explicitly at the boundary. |
Inputs
Required:
- The requirements or specification for the operation whose contract is being designed.
- The target source file or module containing the public API boundary, invariant, or untrusted seam.
Optional:
- Existing tests that must continue to pass.
Procedure
- Plan: extract PRE/POST/INV from the requirements. Give each contract an ID and a one-line description (e.g. PRE-1: amount > 0; POST-1: balance == old(balance) - amount; INV-1: balance >= 0). Do not begin implementation until every planned contract has an ID. Done when: every planned contract has an ID and a one-line description.
- Select verification level: choose the strongest layer that can enforce each contract, preferring static over runtime:
- Static type system or static_assert for type size, alignment, null/type safety, and exhaustiveness.
- Test assertions for expensive O(n)+ properties.
- Debug-only invariants for internal invariants.
- Runtime guards for public API input, and always for external or untrusted input. If a property can be verified statically, do not add a runtime contract. Done when: every contract has a selected verification level, static preferred over runtime.
- Create: implement every PRE, POST, INV at its chosen level in the target local code. Runtime contracts, where used, must be active and not compiled out or disabled. Done when: every contract is implemented at its chosen level and runtime contracts are active.
- Verify: run the type checker, static analysis, and build. Contracts must compile and lint. Done when: the type checker, static analysis, and build pass with all contracts.
- Test: write one violation test per PRE/POST/INV proving the contract catches bad input or bad state. Static contracts are verified by the type checker; runtime contracts by violation tests that assert the boundary fails explicitly. Done when: one violation test per contract passes, proving the boundary fails on bad input or state.
Failure and recovery
- Contract lint or build fails: fix the contract or implementation; do not disable or compile out the runtime contract to make it pass.
- A violation test does not fire: the contract is not enforced at the chosen layer; re-select the layer or strengthen the check; never delete the test to make it pass.
- A contract restates the implementation trivially (e.g. ensures(result == x - y) for subtract(x, y)): delete that contract; it is contract fatigue, not a boundary guarantee.
- Partial result: if some contracts cannot be implemented because a requirement is missing, stop and report the missing requirement; do not invent contracts or widen scope.
- Rollback: delete the added local types, assertions, validators, or tests, or revert the boundary change; no remote, credential, published, or deployed artifact is touched.
Output
Local code with every planned PRE/POST/INV contract implemented at its verification layer, plus one violation test per contract. Violations fail explicitly at the boundary. Each contract traces to a requirement by ID.
Files (odin-claude-plugin)
-
agents
-
openai.yaml 189 B
interface: display_name: "Contract Driven" short_description: "Use when crossing a public API boundary, guarding complex invariants, or hardening untrusted input or integration seams."
-
-
references
-
examples.md 3.7 KB
# Contract patterns by language These brief annotation patterns show a precondition, postcondition, and invariant for each language. ## Python ```python @deal.inv(lambda self: self.balance >= 0) class Account: @deal.pre(lambda self, amount: amount > 0) @deal.pre(lambda self, amount: amount <= self.balance) @deal.ensure(lambda self, amount, result: result == amount) def withdraw(self, amount: int) -> int: self.balance -= amount return amount ``` ## Rust ```rust pub fn withdraw(&mut self, amount: u64) -> Result<u64, Error> { assert!(amount > 0, "PRE: amount must be positive"); assert!(amount <= self.balance, "PRE: insufficient funds"); let old_balance = self.balance; self.balance -= amount; debug_assert!(self.balance == old_balance - amount, "POST: balance delta"); debug_assert!(self.balance >= 0, "INV: non-negative balance"); Ok(amount) } ``` ## TypeScript ```typescript const WithdrawInput = z.object({ amount: z.number().positive().max(MAX_BALANCE), }); function withdraw(account: Account, input: z.infer<typeof WithdrawInput>): number { invariant(input.amount <= account.balance, 'PRE: insufficient funds'); const oldBalance = account.balance; account.balance -= input.amount; invariant(account.balance === oldBalance - input.amount, 'POST: balance delta'); return input.amount; } ``` ## Kotlin ```kotlin fun withdraw(amount: Int): Int { require(amount > 0) { "PRE: amount must be positive" } require(amount <= balance) { "PRE: insufficient funds" } val oldBalance = balance balance -= amount check(balance == oldBalance - amount) { "POST: balance delta" } check(balance >= 0) { "INV: non-negative balance" } return amount } ``` ## Java ```java public int withdraw(int amount) { Preconditions.checkArgument(amount > 0, "PRE: positive amount"); Preconditions.checkArgument(amount <= balance, "PRE: insufficient funds"); int oldBalance = balance; balance -= amount; Verify.verify(balance == oldBalance - amount, "POST: balance delta"); return amount; } ``` ## C# ```csharp public int Withdraw(int amount) { Guard.Against.NegativeOrZero(amount, nameof(amount)); Guard.Against.OutOfRange(amount, nameof(amount), 0, Balance); var oldBalance = Balance; Balance -= amount; Debug.Assert(Balance == oldBalance - amount, "POST: balance delta"); return amount; } ``` ## Go ```go func (a *Account) Withdraw(amount int) (int, error) { if amount <= 0 { return 0, fmt.Errorf("PRE: amount must be positive") } if amount > a.balance { return 0, fmt.Errorf("PRE: insufficient funds") } oldBalance := a.balance a.balance -= amount if a.balance != oldBalance-amount { panic("POST: balance delta violated") } return amount, nil } ``` ## C++ ```cpp int Account::withdraw(int amount) { Expects(amount > 0); // GSL precondition Expects(amount <= balance_); auto old = balance_; balance_ -= amount; Ensures(balance_ == old - amount); // GSL postcondition return amount; } ``` ## Swift ```swift func withdraw(_ amount: Int) -> Int { precondition(amount > 0, "PRE: positive amount") precondition(amount <= balance, "PRE: insufficient funds") let oldBalance = balance balance -= amount assert(balance == oldBalance - amount, "POST: balance delta") return amount } ``` ## Scala ```scala def withdraw(amount: Int): Int = { require(amount > 0, "PRE: positive amount") require(amount <= balance, "PRE: insufficient funds") val oldBalance = balance balance -= amount assert(balance == oldBalance - amount, "POST: balance delta") assert(balance >= 0, "INV: non-negative balance") amount } ``` -
libraries.md 1.5 KB
# Contract libraries by language **Grounded: 2026-08-31** | Language | Library/Approach | Style | |----------|-----------------|-------| | Python | deal / beartype (O(1) runtime) | @deal.pre, @deal.post, validator annotations | | Rust | assert! + debug_assert! + newtypes | type-driven contracts | | TypeScript | Zod v4 + invariant / Effect-TS | z.refine(), invariant() | | Kotlin | Native | require(), check(), contract {} | | Java | Guava Preconditions / Bean Validation | checkArgument(), @Valid | | C# | FluentValidation / Guard clauses | Guard.Against.*() | | Go | Explicit checks + fmt.Errorf | convention-based | | C++ | GSL Expects/Ensures | Expects(x > 0) | | Swift | precondition() / guard | precondition(x > 0) | | Scala | require() / ensuring() | require(x > 0) | ## Notes - C++26 contracts (P2900R14, Feb 2025): Standardizing `[[pre]]`, `[[post]]`, `[[assert]]` with enforce/observe/quick-enforce/ignore semantics. GSL remains the bridge until compiler adoption. - Zod v4 (Aug 2025): the current line is 4.4.x. 14x faster parsing, z.templateLiteral(), @zod/mini for lightweight validation. Primary choice for TypeScript boundary contracts. - beartype (Python): O(1) runtime type checking via random sampling. Complements deal for performance-sensitive code. - Effect-TS: Provides branded types + Schema validation as an alternative to Zod for TypeScript contract enforcement. - Kotlin: `contract {}` provides compiler hints (smart casts after checks). `require()` = preconditions, `check()` = invariants.
-
-
SKILL.md 3.8 KB
--- name: contract-driven description: 'Use when crossing a public API boundary, guarding complex invariants, or hardening untrusted input or integration seams. Not for remote or irreversible changes.' --- # Contract-driven ## Contract | Field | Bound contract | |---|---| | Trigger | Crossing a public API boundary, guarding complex invariants, or hardening untrusted input or integration seams. | | Authority | Reversible local: writes only named local types, assertions, validators, and tests at contract boundaries; rollback is undo (delete the added code or revert the boundary change). No remote mutation. | | Side effect | Adds or refines local types, assertions, validators, and tests at contract boundaries. | | Done | Every planned contract is implemented at the appropriate static/test/debug/runtime layer and violations fail explicitly at the boundary. | ## Inputs Required: - The requirements or specification for the operation whose contract is being designed. - The target source file or module containing the public API boundary, invariant, or untrusted seam. Optional: - Existing tests that must continue to pass. ## Procedure 1. Plan: extract PRE/POST/INV from the requirements. Give each contract an ID and a one-line description (e.g. PRE-1: amount > 0; POST-1: balance == old(balance) - amount; INV-1: balance >= 0). Do not begin implementation until every planned contract has an ID. Done when: every planned contract has an ID and a one-line description. 2. Select verification level: choose the strongest layer that can enforce each contract, preferring static over runtime: - Static type system or static_assert for type size, alignment, null/type safety, and exhaustiveness. - Test assertions for expensive O(n)+ properties. - Debug-only invariants for internal invariants. - Runtime guards for public API input, and always for external or untrusted input. If a property can be verified statically, do not add a runtime contract. Done when: every contract has a selected verification level, static preferred over runtime. 3. Create: implement every PRE, POST, INV at its chosen level in the target local code. Runtime contracts, where used, must be active and not compiled out or disabled. Done when: every contract is implemented at its chosen level and runtime contracts are active. 4. Verify: run the type checker, static analysis, and build. Contracts must compile and lint. Done when: the type checker, static analysis, and build pass with all contracts. 5. Test: write one violation test per PRE/POST/INV proving the contract catches bad input or bad state. Static contracts are verified by the type checker; runtime contracts by violation tests that assert the boundary fails explicitly. Done when: one violation test per contract passes, proving the boundary fails on bad input or state. ## Failure and recovery - Contract lint or build fails: fix the contract or implementation; do not disable or compile out the runtime contract to make it pass. - A violation test does not fire: the contract is not enforced at the chosen layer; re-select the layer or strengthen the check; never delete the test to make it pass. - A contract restates the implementation trivially (e.g. ensures(result == x - y) for subtract(x, y)): delete that contract; it is contract fatigue, not a boundary guarantee. - Partial result: if some contracts cannot be implemented because a requirement is missing, stop and report the missing requirement; do not invent contracts or widen scope. - Rollback: delete the added local types, assertions, validators, or tests, or revert the boundary change; no remote, credential, published, or deployed artifact is touched. ## Output Local code with every planned PRE/POST/INV contract implemented at its verification layer, plus one violation test per contract. Violations fail explicitly at the boundary. Each contract traces to a requirement by ID.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.