mk:sprint-contract — File-Based Sprint Contract Protocol
Negotiation protocol between generator and evaluator. Produces a signed contract file at tasks/contracts/{date}-{slug}-sprint-{N}.md BEFORE the generator writes any source code. Enforced by gate-enforcement.sh (Phase 4 extension).
For single-task plan validation (cook flow), usemk:validate-planinstead.mk:sprint-contractis for product-level specs feeding intomk:autobuildonly.
When to Use
Activate when:
- User runs
/mk:sprint-contract <action> [task-slug] - Harness (Phase 5) needs to negotiate a sprint before invoking the generator
- Generator agent needs to read a signed contract before starting implementation
- A previously signed contract needs amendment due to mid-build scope discovery
Skip when:
MEOWKIT_AUTOBUILD_MODE=LEAN(adaptive density bypass for COMPLEX/Opus 4.6 tier)- The plan is
--fastmode (overhead exceeds value) - The task is
/mk:fix simple(Gate 1 already bypassed; contract bypass too)
Subcommands
| Subcommand | Owner | Effect | |---|---|---| | propose | generator (developer agent) | Drafts a contract from the product spec + rubric preset; status: draft → negotiating | | review | evaluator | Critiques the proposed contract for testability + scope clarity; produces clarification requests | | amend | generator | Iterates on the contract per evaluator feedback; status stays negotiating; rounds += 1 | | sign | both | Both agents commit to the contract via git commit messages; status: negotiating → signed | | validate | anyone | Runs validate-contract.sh to check schema conformance | | sprint-goal | user | Writes/reads/aligns sprint-LEVEL goal in tasks/contracts/sprint-state-{date}-sprint-{N}.md (Agile mode) |
Workflow (Inline — monolithic, < 150 lines)
propose (generator)
- Read active product spec from newest
tasks/plans/*/plan.md - Load rubric preset via
mk:rubric/scripts/load-rubric.sh --preset {preset} - Determine sprint
N: max of existingtasks/contracts/-{slug}-sprint-.md+ 1, default 1 - Copy
assets/contract-template.md→tasks/contracts/{YYMMDD-HHMM}-{slug}-sprint-{N}.md - Populate: 5–15 ACs in Given/When/Then form, each bound to one preset rubric, each with a Verification line. Every preset rubric should have ≥1 AC binding
- Set frontmatter:
status: negotiating,rounds: 0,created: {YYMMDD-HHMM} - Run
validate-contract.sh; fix and re-validate until clean - Print:
"Contract proposed at {path}. Awaiting evaluator review."
review (evaluator)
- Read newest
negotiatingcontract for the active task - Per AC check: Testable? (probable via browser/curl/CLI) Rubric-aligned? (binding matches content) Scope clear? (no ambiguity)
- For each weak AC, append
Round {N+1} (reviewer): AC-{NN} {clarification}to Negotiation Log - If clean, write
Round {N+1} (reviewer): acceptedand proceed tosign - If clarifications added, increment
roundsand signal generator toamend - HARD CAP: 2 negotiation rounds. Round 3 escalates to human via AskUserQuestion
amend (generator)
- Address every clarification from the previous round in the relevant ACs (replace, don't delete)
- Append
Round {N+1} (proposer): {summary of changes}to the log - Re-run
validate-contract.sh - Signal evaluator to
reviewagain
sign (both agents in sequence)
The signature workflow uses two commits per agent to avoid the chicken-and-egg of "the SHA must be inside the file but the file's commit hasn't happened yet."
- Generator (commit 1):
git add tasks/contracts/{path}.md && git commit -m "contract: generator commits sprint {N} for {slug}". The contract file is committed withgenerator_signed: pending. - Generator (commit 2 — capture SHA):
gen_sha=$(git rev-parse HEAD). Edit the frontmatter:generator_signed: $gen_sha. Thengit add+git commit -m "contract: generator signs sprint {N} for {slug} (sha=$gen_sha)". The captured SHA references the COMMIT THAT EXISTED WHEN THE GENERATOR APPROVED — its own first commit. - Evaluator (commit 1): verify the contract is unchanged from commit 2 above. Then
git add+git commit -m "contract: evaluator commits sprint {N} for {slug}". - Evaluator (commit 2 — capture SHA):
eval_sha=$(git rev-parse HEAD). Edit the frontmatter:evaluator_signed: $eval_sha,status: signed. Thengit add+git commit -m "contract: evaluator signs sprint {N} for {slug} (sha=$eval_sha)". - The git log IS the audit trail — every signature commit is verifiable via
git log --oneline tasks/contracts/{path}.md. - After both sign,
gate-enforcement.shallows source edits for this sprint.
Validator enforcement: check-contract-signed.sh rejects placeholder values (null, pending, todo, empty, quoted variants of these). Only a real git rev-parse HEAD SHA passes.
validate
.claude/skills/sprint-contract/scripts/validate-contract.sh tasks/contracts/{path}.md
sprint-goal (Agile mode — gated by agile-sprint-commitment.md 1)
Sprint-LEVEL goal management. Writes to tasks/contracts/sprint-state-{date}-sprint-{N}.md — distinct from per-story sprint-CONTRACT files.
| Action | Form | Effect | |---|---|---| | set | mk:sprint-contract sprint-goal set "<text>" --sprint N | Writes sprint_goal: (≤120 chars) to tasks/contracts/sprint-state-{YYMMDD}-sprint-{N}.md. Creates the file from assets/sprint-state-template.md if absent | | show | mk:sprint-contract sprint-goal show --sprint N | Prints current sprint_goal: from the newest sprint-state file matching --sprint N | | align | mk:sprint-contract sprint-goal align --plan <path> | Renders alignment between plan goal (frontmatter goal: or first H1) and sprint goal. Advisory — never blocks |
Concurrent-write safety: sprint-goal set MUST acquire flock on the sprint-state file before any read-modify-write. YAML frontmatter append is non-atomic across shells; lock is the only mitigation. Release on completion or error.
Validator scope: the existing validate-contract.sh is for sprint-CONTRACT files only. Sprint-STATE files have NO validator; YAML is parsed inline by consuming skills (this skill, mk:agent-detector Step 0b, mk:jira-agile).
Why this lives here: tasks/contracts/ already belongs to this skill; co-locating sprint-goal avoids creating a sibling skill that duplicates path discipline.
Mid-build amendment (post-sign)
The amendment flow MUST null both signature fields BEFORE adding the amendment block. Otherwise stale SHAs from the prior signing round would falsely pass check-contract-signed.sh.
- Generator opens amendment:
- Edit the frontmatter:
status: amended,generator_signed: null,evaluator_signed: null - Append
### Amendment N — {YYMMDD-HHMM}under## Amendmentsdescribing the change - DO NOT edit the original signed criteria — append the revised version as a new AC or override note
git commit -m "contract: amendment N for sprint {N} ({slug})"- Both agents re-sign following the same two-commit pattern from
signaction above. New SHAs replace the nulled fields. gate-enforcement.shenforcement: between step 1 and step 2 (sigs are null but status isamended), source edits are BLOCKED. The check-contract-signed.sh script rejects amended-status contracts that have null/placeholder sigs. This is the intended discipline — you can't push source code while an amendment is in-flight.
Original signed criteria stay visible — amendments are append-only history.
Adaptive Density Skip
When MEOWKIT_AUTOBUILD_MODE=LEAN:
- The contract negotiation is skipped entirely (per Phase 5 adaptive density policy for COMPLEX/Opus 4.6 tier — capable models self-derive criteria from the product spec)
gate-enforcement.shhonors the env var and allows source edits without contract verification- LEAN bypasses are lo