| name | contract-promote |
| description | Freeze a verified contract into an immutable revision and start the SLA timer. Use when the user says "promote contract", "ship this PRD", "start the pipeline", or invokes `/contract promote <ID>`. Creates a JIRA epic, opens a tracking issue, kicks off implementation. |
| requiredScopes | ["github:issues:write","github:contents:write","atlassian:write","slack:chat:write"] |
Contract promoter
Promote freezes a verified contract into a revision and starts the
build phase. The hard gate is blockers, not warnings: promote any
contract that is promotable (zero open blockers). Warnings and info
are advisory — they don't block promotion, so a dev is never stuck
chasing run-to-run-variable warnings to zero. Surface the open warnings
so the human is choosing knowingly; they can fix or acknowledge them,
but they don't have to.
Precondition: verify required scopes BEFORE making changes
Before doing ANYTHING that writes, check the scopes this skill needs
(declared in frontmatter requiredScopes). If a required scope is
missing, STOP and tell the user exactly which scope is missing and
which step it would have broken — do NOT proceed and let a later step
fail silently.
Specifically:
github:issues:write is REQUIRED — the tracking issue is core. If
the GitHub token lacks it, refuse the whole promote with:
"Cannot promote: GitHub token lacks issues:write, needed to open
the tracking issue. Grant it (or re-auth) and retry."
github:contents:write is REQUIRED — to commit the revision file.
atlassian:write and slack:chat:write are OPTIONAL — if missing,
proceed but SKIP those steps and tell the user they were skipped
(e.g., "Promoted; skipped JIRA epic — Atlassian not connected.").
Never silently skip; always report what didn't happen and why.
Run /setup (setup-check skill) to introspect granted scopes. If
scope introspection isn't available in the runtime, attempt the
write and treat a permission error as a hard, reported failure — not
a silent pass.
Precondition: require a valid Ready Check (the PM gate)
"No code, no grooming." /contract pickup already verifies the PM's
Ready Check code automatically and records it as readyCheck: RC-… in
the frontmatter. Promote just confirms that stamp is present:
readyCheck: RC-… present → proceed.
- Missing → refuse: "This contract hasn't cleared the PM Ready Check. Run
/ready-check <source> first — grooming shouldn't start on an unready
PRD." (See reference/READY-CHECK-RUBRIC.md.)
- Only re-verify (
ready-check.mjs --verify) if the contract's own
requirement text changed since pickup — a STALE result means re-run
/ready-check for a fresh code.
- Teams piloting Ready Check may set
conventions.requireReadyCheck: false
in repos.yml to warn instead of block during rollout. Default is to
block once the team has adopted it.
This turns the team rule into a pipeline gate — with no extra step for
the dev; the PM is the only one who handles the code.
Process
-
Read .manifest/contracts/<ID>.md. Confirm it is promotable
— the latest verify's readiness has promotable: true (zero open
blockers) — and complexity is one of small | medium | large. If
there are open blockers, refuse and list them: those are the finite,
stable set that must be resolved. If there are open warnings, list
them too but proceed (note: "promoting with N advisory warnings — fix
or acknowledge later if you want"). Do NOT require warnings to be
zero.
Reject a fast-only verify. Check the latest
<ID>.findings.md frontmatter: if verifyMode: fast, the contract
was only checked by the quick draft-loop (edge-cases + security, no
regression scan, no localized critics). Refuse: "This contract's
last verify was --fast (partial). Run a full /contract verify <ID> before promoting." A fast verify is for iteration, not the
promote gate.
-
If Large, route to decomposition — don't refuse. A Large
contract can't be agent-shipped on a timer, but it shouldn't be
abandoned either. Invoke the contract-decompose skill (or tell
the user to run /contract decompose <ID>): it breaks the Large
contract into a dependency-ordered set of Small/Medium child
contracts, with risky parts (migrations, auth) flagged human-led.
Each child then promotes normally. Do NOT promote the Large
contract itself into the build phase.
-
Create the revision. Copy the current contract to
.manifest/contracts/<ID>.r<N>.md where N is revision. This is the
immutable snapshot the build phase reads against. Future edits to the
main contract fork a new revision.
-
Compute SLA deadline:
- small → now + 24 hours
- medium → now + 72 hours
-
Update frontmatter of the main contract:
status: promoted
slaDeadline: <ISO datetime>
-
Create the JIRA ticket(s) — the planning tracker, before implementation.
This is an explicit option the dev confirms, not automatic. Ask:
"Create the JIRA tickets for this now, in project <KEY>? (1 epic
Confirm the project key and issue type first (getVisibleJiraProjects
/ getJiraProjectIssueTypesMetadata); never guess the project. On yes, follow
reference/JIRA-SYNC.md §2 — the generated epic carries the full detail
(problem/goal, the ACs as a checklist, platforms/scope, design link, success
metric, the Ready-Check: gate code, and a link to the contract markdown),
duedate = slaDeadline, labels manifest + size, assignee = owner if set.
Create a sub-task per acceptance criterion, linked to the epic.
- If the contract came from a JIRA link (
jira.issue already set), prefer
updating that ticket (editJiraIssue) over making a new one — no dupes.
- Store keys in frontmatter:
jira: { epic: <KEY>, issue: <KEY>, project: <KEY> }
(keep jiraEpic too for back-compat). These are what the update steps
(implement / verify / launch) write to later.
- Not connected / dev declines → skip cleanly and report it
("Promoted; skipped JIRA — not connected"). Never block promote on the tracker.
-
Open a GitHub tracking issue with the contract title, the SLA
deadline visible at the top, a link to the revision file, and a
checklist of stages (Implement / PR Review / QA / Pre-prod / Prod /
Land). The issue body has a "How to use" section:
- "From a PR, comment
@claude /implement <ID> to start the Implementer."
- "The Verifier runs on every push automatically."
- "Launch reports start at day 1 post-deploy."
-
Commit and push the contract changes and the new revision file.
-
Post the Slack ANCHOR message (if Slack MCP is connected).
This is the ONE top-level message for this contract — every later
update threads under it (see reference/CONTRACT-FORMAT.md Slack
threading). Channel is #manifest by convention; user can override.
🚀 (<ID>) promoted — <complexity> · ⏳ SLA: 24h left (due <IST / UTC>)
· ·
Generate the SLA line with
node <plugin-root>/scripts/validate.mjs --sla .manifest/contracts/<ID>.md
(just after stamping promotedAt + slaDeadline).
Capture the posted message's thread_ts and stamp it on the
contract as slackThreadTs (and slackChannel). All later skills
reply into this thread so the channel stays one-line-per-contract.
-
Tell the user what's done, the SLA countdown, and the next
manual step: invite the assigned engineer to comment
@claude /implement <ID> on their PR.
Refuse conditions
- Contract is not promotable — it has open blockers. (Open warnings
do NOT block promotion; they're advisory.)
- The latest verify was
--fast (verifyMode: fast) — run a full verify first.
- Complexity is
large or not set.
- The revision file already exists (means someone promoted in parallel).