@mutmutco/kilo-plugin 3.79.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/reviewer.md +108 -0
- package/package.json +23 -0
- package/scripts/command-ladder-core.mjs +334 -0
- package/scripts/command-ladder-gate.mjs +126 -0
- package/scripts/deny-gate-crash.mjs +179 -0
- package/scripts/edit-tool-paths.mjs +113 -0
- package/scripts/env-write-lint.mjs +137 -0
- package/scripts/hook-io.mjs +17 -0
- package/scripts/hook-policy.mjs +73 -0
- package/scripts/hook-run.mjs +170 -0
- package/scripts/hook-trace.mjs +108 -0
- package/scripts/pretooluse-shell-gates.mjs +420 -0
- package/scripts/secret-echo-lint.mjs +170 -0
- package/scripts/secret-redact.mjs +537 -0
- package/scripts/throttle-core.mjs +324 -0
- package/scripts/validate-hook.mjs +156 -0
- package/scripts/vault-edit-gate.mjs +94 -0
- package/server.mjs +237 -0
- package/skills/bootstrap/SKILL.md +493 -0
- package/skills/bootstrap/seeds/Dockerfile.template +30 -0
- package/skills/bootstrap/seeds/README.template.md +36 -0
- package/skills/bootstrap/seeds/architecture.template.md +34 -0
- package/skills/bootstrap/seeds/decisions-readme.template.md +46 -0
- package/skills/bootstrap/seeds/docker-compose.template.yml +26 -0
- package/skills/bootstrap/seeds/gate.template.yml +90 -0
- package/skills/bootstrap/seeds/google-login.template.md +33 -0
- package/skills/bootstrap/seeds/manifest.json +26 -0
- package/skills/bootstrap/seeds/mmi-product-required-checks.template.json +23 -0
- package/skills/browser-automation/SKILL.md +93 -0
- package/skills/doctor/SKILL.md +76 -0
- package/skills/epic/SKILL.md +87 -0
- package/skills/hotfix/SKILL.md +113 -0
- package/skills/mmi/SKILL.md +400 -0
- package/skills/onboard/SKILL.md +70 -0
- package/skills/rcand/SKILL.md +194 -0
- package/skills/release/SKILL.md +546 -0
- package/skills/resume/SKILL.md +68 -0
- package/skills/secrets/SKILL.md +157 -0
- package/skills/stage/SKILL.md +151 -0
- package/skills/worktree/SKILL.md +86 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release
|
|
3
|
+
description: Ship rc or direct-track development to main and production.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /release — ship to main + prod
|
|
7
|
+
|
|
8
|
+
Full-track repos ship **exactly what is on `rc`** (never pulls `development`): merge `rc → main`, tag
|
|
9
|
+
`vX.Y.0`, publish a GitHub Release, dispatch the Hub central tenant deploy workflow for prod, then roll
|
|
10
|
+
`development` forward. Direct-track repos — product repos with `releaseTrack: direct`, plus MMI-Hub via the `isHubControlRepo` special-case (its `releaseTrack` stays unset) — skip rc: release
|
|
11
|
+
merges `development → main`, tags, publishes the GitHub Release, and the release event fires the repo's own
|
|
12
|
+
deploy/publish workflow (for MMI-Hub, `deploy.yml` + `publish.yml`).
|
|
13
|
+
`rc` is **ephemeral**: `/rcand` creates the rc runtime, `/release` retires it — after a confirmed full-track
|
|
14
|
+
prod deploy the train stops the rc stage (reported as `rcRetirement` in the result; never fatal to the
|
|
15
|
+
release). Full-track repos may also pass **`--dev`** to release `development → main` directly, skipping rc —
|
|
16
|
+
the default stays `rc → main`. `--dev` **fails closed** when `origin/rc` carries content not yet in
|
|
17
|
+
`development` (a dev → main release would drop it), and is a friendly no-op on direct-track repos.
|
|
18
|
+
**Train-authority gated (D14):** the repo's project-admin or the master; the Hub repo's train is
|
|
19
|
+
master-only. This is the **only** sanctioned prod path; a prod release still needs the authorized human's
|
|
20
|
+
explicit per-turn go — an agent never self-initiates it. The board needs no
|
|
21
|
+
touch — items reached `Done` when their PRs merged to `development`; `rc`/`main` are deploy stages, not lanes.
|
|
22
|
+
|
|
23
|
+
Authority is structural + server-checked: step 0 asks the Hub (`mmi-cli org access role`), and step 3 pushes
|
|
24
|
+
to the protected `main` branch, whose per-repo allowlist carries the same people (master + that repo's
|
|
25
|
+
project-admins; Hub: master + App only). Gate ordering: the tag lands the release SHA for checks, and
|
|
26
|
+
nothing deploys before the protected `main` push accepts that checked SHA.
|
|
27
|
+
|
|
28
|
+
## Merge floor (#3167 — non-negotiable, applies to every step below)
|
|
29
|
+
|
|
30
|
+
- **Never squash-merge a tagged commit.** A squash re-mints the SHA, so the tag's commit vanishes from the
|
|
31
|
+
branch's lineage and every tag-anchored check (coverage trailers, misalignment guard, version probes)
|
|
32
|
+
re-flags or mis-reads forever after. Any merge that carries an already-tagged commit — the Step 5
|
|
33
|
+
`main → development` roll-forward, any alignment PR — lands as a **true merge** (`--merge`), never squash.
|
|
34
|
+
- **A refused train is a stop, never a license to finish by hand.** Every fail-closed halt below — authority
|
|
35
|
+
probe, coverage guard, untolerated conflict, required checks, stray tag — ends the run. The recovery is
|
|
36
|
+
always to fix the cause and re-run the train; it is never hand-resolving on `main`, bare-pushing a train
|
|
37
|
+
branch, acking to save time, or bypassing a check.
|
|
38
|
+
- **Version probes anchor on the latest Release tag, not a branch.** `next-version.mjs` and the fold derive
|
|
39
|
+
the next version from tags; a branch manifest or a stale local tag is not a version source. (This is why a
|
|
40
|
+
stray tag must be deleted locally too — a surviving local tag silently mints the *next* version, Step 3.)
|
|
41
|
+
|
|
42
|
+
## Step 0 — confirm + probe
|
|
43
|
+
|
|
44
|
+
Confirm the human holding train authority for THIS repo authorized a prod release this turn. Probe:
|
|
45
|
+
```bash
|
|
46
|
+
mmi-cli org access role {owner}/{repo} --json # Hub-verified: { role, train }
|
|
47
|
+
```
|
|
48
|
+
`train: false` — or any error (fail closed) → stop: a product repo's train belongs to that repo's
|
|
49
|
+
project-admin or the master; the Hub train is master-only. **Two exceptions to fail-closed here, and both
|
|
50
|
+
mean "unverified — retry", never an authority verdict:**
|
|
51
|
+
|
|
52
|
+
- An `unknown command 'org'` error is a STALE CLI — the `org` namespace ships in newer trains, so an old
|
|
53
|
+
installed CLI can't even parse the probe. Jump to Step 0a, heal the CLI, then re-run this probe; never
|
|
54
|
+
conclude the command form is wrong from a pre-heal failure (#3150).
|
|
55
|
+
- A **TIMEOUT or network error** (`operation aborted due to timeout`, DNS/socket failures) is **not** a
|
|
56
|
+
`train: false` denial (#3321). Read the probe's own `verified` field: `verified: false` means the verdict
|
|
57
|
+
could not be established, so the `train: false` beside it carries NO authority meaning. The client
|
|
58
|
+
already retries transient failures internally, so a *persistent* timeout points at the local network
|
|
59
|
+
rather than the Hub — resolve the Hub API host first (fails in seconds and rules out the whole
|
|
60
|
+
local-network class), then re-run the probe. Conclude "no train authority" ONLY from a `verified: true`
|
|
61
|
+
response. Aborting a legitimate release on an unverified probe is the failure this carve-out exists to
|
|
62
|
+
prevent.
|
|
63
|
+
|
|
64
|
+
Then
|
|
65
|
+
preconditions: clean tree; full-track repos run from `rc` (or from `development` with `--dev`), while
|
|
66
|
+
direct-track repos run from `development`.
|
|
67
|
+
|
|
68
|
+
**Run from the checkout that already has that branch — never a fresh isolated worktree (#2770).** This is
|
|
69
|
+
a shared-branch train operation (merge/tag/push against origin's protected `main`/`rc`), not an isolated
|
|
70
|
+
feature-branch edit. A background-job harness that isolates every task into a fresh worktree by default
|
|
71
|
+
breaks here: the new worktree's branch is never literally named `development`/`rc`, and `git checkout
|
|
72
|
+
development` inside it fails outright when `development` is already checked out in the primary checkout (git
|
|
73
|
+
worktrees cannot have the same branch checked out twice). If you are in such a worktree, exit it first and
|
|
74
|
+
run the release from the primary checkout.
|
|
75
|
+
The clean-tree check rejects UNTRACKED scratch too, not just modified tracked files — if `--apply` stops
|
|
76
|
+
with `working tree must be clean before …`, run `git status` and gitignore the `??` scratch (or move it to a
|
|
77
|
+
gitignored path like `tmp/`) before retrying (#1472).
|
|
78
|
+
|
|
79
|
+
Full-track repos:
|
|
80
|
+
```bash
|
|
81
|
+
git fetch origin
|
|
82
|
+
git rev-list --count origin/main..origin/rc
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Direct-track repos (e.g. MMI-Hub):
|
|
86
|
+
```bash
|
|
87
|
+
git fetch origin
|
|
88
|
+
git rev-list --count origin/main..origin/development
|
|
89
|
+
```
|
|
90
|
+
`0` → stop ("nothing to release").
|
|
91
|
+
|
|
92
|
+
## Step 0a — stale CLI preflight (#1410)
|
|
93
|
+
|
|
94
|
+
Before local gates or `release --apply`, ensure the repo-local / PATH `mmi-cli` matches the released train
|
|
95
|
+
path — a stale checkout (e.g. 2.32.0 while 2.32.4 is released) fails release gates with opaque errors.
|
|
96
|
+
Self-heal in place without repo writes:
|
|
97
|
+
```bash
|
|
98
|
+
mmi-cli doctor --apply --no-repo-writes
|
|
99
|
+
```
|
|
100
|
+
**Read the checks, not the exit code.** `doctor` exits non-zero on any failed check it could have healed —
|
|
101
|
+
not just a version gap — so a red exit here does not by itself mean the train is blocked (#2962). The
|
|
102
|
+
inverse is also true since #3485: a run can exit **0** while printing ✗ lines, because three rows
|
|
103
|
+
(`worktree roots`, `schedules`, `docs-audit`) are ruled report-only — real faults the design deliberately
|
|
104
|
+
declines to gate on, since their remedy is a human review or lives in the owning repo. Neither direction
|
|
105
|
+
is a gate. Read the rows.
|
|
106
|
+
|
|
107
|
+
- **Blocking:** a red `mmi-cli` / `Claude plugin` version line, or a reported `minClientVersion` gap. Since
|
|
108
|
+
#3485 `--no-repo-writes` no longer blocks the env heals — the step above self-updates the npm global CLI
|
|
109
|
+
(#3272) and reinstalls the plugin (#3282), suppressing only repo-file writes — so the re-run should clear
|
|
110
|
+
it. If a gap persists, fix it — `mmi-cli doctor --apply`, or `npm install -g @mutmutco/cli` — before
|
|
111
|
+
continuing. Do **not** proceed to Step 0b while the installed CLI is behind the Hub's `minClientVersion`.
|
|
112
|
+
- **Not blocking:** every other red check is hygiene, not a train gate. Stale branches and scratch heal with
|
|
113
|
+
`mmi-cli doctor --apply`; `plugin cache` needs a different verb, `mmi-cli plugin prune --apply` — saying
|
|
114
|
+
`doctor --apply` cleared it was wrong. All three still exit 1 until you run the right verb. The three
|
|
115
|
+
report-only rows (`worktree roots`, `schedules`, `docs-audit`) print ✗ without moving the exit code
|
|
116
|
+
since #3485 — not because no verb exists, but because the design refuses to gate on a human review or
|
|
117
|
+
on a fault owned by another repo. Read them, then proceed.
|
|
118
|
+
|
|
119
|
+
Treating doctor's exit code as the gate halts a healthy train on cosmetic drift — or, worse, teaches an
|
|
120
|
+
operator to ignore doctor's exit code entirely.
|
|
121
|
+
|
|
122
|
+
**Then check the version yourself — do not rely on doctor having printed a row (#3674).** "Read the rows"
|
|
123
|
+
resolves to "proceed" when the row is *absent*, and doctor's version row is conditional. On 2026-07-27 this
|
|
124
|
+
step reported healthy with no version line while the installed CLI was 3.70.0 against a released 3.71.0;
|
|
125
|
+
`release --apply` refused one command later. Two lines, no dependency on another command's reporting
|
|
126
|
+
completeness:
|
|
127
|
+
```bash
|
|
128
|
+
mmi-cli --version
|
|
129
|
+
npm view @mutmutco/cli version # public package; a bare view is trustworthy here
|
|
130
|
+
```
|
|
131
|
+
Mismatch → `npm install -g @mutmutco/cli@<released>` before Step 0b, **regardless of what doctor's rows
|
|
132
|
+
said**. This is the check whose absence Step 0a's own title promises to cover, so it is not optional.
|
|
133
|
+
|
|
134
|
+
## Step 0b — registry + main secret-name preflight
|
|
135
|
+
|
|
136
|
+
Resolve the project META first; its `deployModel` decides the deploy path. `tenant-container` repos use the
|
|
137
|
+
central tenant deployer and therefore need DEPLOY# coords. `hub-serverless` (MMI-Hub), `serverless`,
|
|
138
|
+
`registry-publish`, and `solo-container` repos deploy from their own branch/release-triggered or model
|
|
139
|
+
workflow, so do **not** dispatch `tenant-deploy.yml` for them.
|
|
140
|
+
Verify META + required SSM secret names before touching `main`:
|
|
141
|
+
```bash
|
|
142
|
+
mmi-cli org project get {owner}/{repo}
|
|
143
|
+
mmi-cli secrets preflight --stage main --repo {owner}/{repo}
|
|
144
|
+
```
|
|
145
|
+
Missing META or secret names → stop and repair the registry/secrets first.
|
|
146
|
+
|
|
147
|
+
## Step 0c — hotfix-coverage guard (fail closed, #839, #958)
|
|
148
|
+
|
|
149
|
+
Full-track repos only. Direct-track repos skip this specific guard — not because they are exposed to no
|
|
150
|
+
risk, but because the risk this guard checks structurally cannot arise there: a direct-track `/hotfix`
|
|
151
|
+
cherry-picks straight from `development` onto `main`, so every hotfix trailer's source sha is *by
|
|
152
|
+
construction* an ancestor of `origin/development` — a trailer-ancestry check would be permanently green and
|
|
153
|
+
add no signal (#2786 — a literal port was considered and rejected as a false-confidence guard).
|
|
154
|
+
|
|
155
|
+
Hotfixes are cherry-picked from `development` to `main` with **no back-merge** (see `/hotfix`), so a
|
|
156
|
+
candidate cut *before* a fix landed on `development` would silently revert that hotfix in prod. The guard
|
|
157
|
+
proves every main-only commit is in the candidate before the `rc → main` merge.
|
|
158
|
+
|
|
159
|
+
**Direct-track repos are not risk-free, though — they carry a different, real failure mode:** a hotfix
|
|
160
|
+
freezes a snapshot of the files it cherry-picks (e.g. docs, a test assertion) while `development` keeps
|
|
161
|
+
evolving those same files afterward. Step 1's `development → main` merge preflight (untolerated-path
|
|
162
|
+
conflict check) is what actually catches this — a genuine content conflict on the **next** release is
|
|
163
|
+
expected when a hotfix's cherry-picked commits touched files `development` went on to rewrite
|
|
164
|
+
incompatibly. That is routine, working-as-designed friction, not a fluke or a misconfiguration (incident:
|
|
165
|
+
hotfix v3.16.1 #2765 cherry-picked #2762/#2768's doc sweep onto `main`; `development` then rewrote the same
|
|
166
|
+
files further via #2767/#2771; `/release` correctly stopped on 4 conflicted files, resolved by confirming
|
|
167
|
+
`development`'s side already represented the correct, current content and landing alignment PR #2784 — see
|
|
168
|
+
#2786). When Step 1 stops this way: run `git merge-tree` (or read the conflict content directly) to confirm
|
|
169
|
+
which side carries the correct current content, then land a true-merge alignment PR (never hand-resolve on
|
|
170
|
+
`main`) before rerunning release.
|
|
171
|
+
|
|
172
|
+
It runs **automatically inside `mmi-cli release --apply`** (Step 1+ below) — built into the CLI so it
|
|
173
|
+
works in every product repo with no repo-local script. You do not invoke it separately.
|
|
174
|
+
|
|
175
|
+
Per main-only commit it accepts: the `(cherry picked from commit <sha>)` trailer with that dev SHA an
|
|
176
|
+
ancestor of `origin/rc` (immune to conflict-resolved ports); a matching `git patch-id` on the rc side
|
|
177
|
+
(trailer-less picks); or a distribution-manifest-only bump (exempt — rc carries its own). Anything else
|
|
178
|
+
**fails the release closed** → **stop**: the right fix is a re-cut `/rcand` from `development`. Only when
|
|
179
|
+
the authorized human has manually verified the content is in the candidate, rerun with
|
|
180
|
+
`mmi-cli release --apply --ack <sha>[,<sha>…]` — the ack is recorded in the verdict. Never ack to save time.
|
|
181
|
+
|
|
182
|
+
## Step 0d — release-time surface freshness (repo-owned, source-only docs gate)
|
|
183
|
+
|
|
184
|
+
As early as the probe — the released diff (`origin/main..origin/development`, or `..rc`) is already
|
|
185
|
+
known — refresh the repo's own docs against **exactly what is shipping**. An agent reads the
|
|
186
|
+
shipping PRs and quickly scans the surfaces; most releases change nothing they describe, so most
|
|
187
|
+
releases do nothing here. It is **model-agnostic** — describe the work, not the model; under Claude,
|
|
188
|
+
**Sonnet latest (`claude-sonnet-5`)** is the right tier (never the release model, never Haiku).
|
|
189
|
+
Reviewed, repo-owned + release-triggered — never a central, scheduled, cross-repo keeper (that stays
|
|
190
|
+
retired, #2135).
|
|
191
|
+
|
|
192
|
+
**The two in-repo docs (`README.md`, `architecture.md`): in the released commit.**
|
|
193
|
+
Run this **at the probe, before Step 1**. First scan both against the shipping diff. **If nothing a
|
|
194
|
+
shipped change touches made them drift, skip this docs pass entirely — no PR, no wait** (the common case).
|
|
195
|
+
|
|
196
|
+
When a shipped change did make a doc drift, establish **where the drifted text comes from** before editing
|
|
197
|
+
it — from the repo's own tooling: a generator script, a "do not edit" header, a generated-region marker.
|
|
198
|
+
**If you cannot establish that a region is hand-written, treat it as generated.** Hand-written prose takes
|
|
199
|
+
the fast path below; a generated region does not, and never lands by hand.
|
|
200
|
+
|
|
201
|
+
**Hand-written prose — the fast docs-only path:**
|
|
202
|
+
- Edit the doc to current truth (no change-comments — AGENTS docs rule).
|
|
203
|
+
- Land it on `development`: open a PR touching **only** `README.md` /
|
|
204
|
+
`architecture.md` and auto-merge it (`mmi-cli pr merge <n> --auto --squash` — raw `gh pr merge` is
|
|
205
|
+
denied by the org command ladder, #2347). Because the PR touches only
|
|
206
|
+
those two docs, it runs **only the checks its paths trigger** — the repo's gate skips the code/test
|
|
207
|
+
jobs a docs change can't affect — so it normally goes green + merges in about a minute, with no
|
|
208
|
+
force-push and no protected-branch bypass (CI stays honest). (On the Hub that is the fast `docs` job
|
|
209
|
+
while `cli` / `infra` no-op; a single-gate repo short-circuits its one gate the same way.) A
|
|
210
|
+
docs-only PR also can't expand the release scope (it touches only those two files).
|
|
211
|
+
|
|
212
|
+
**Generated surface — fix the source, and default to the next cycle** (#2916). The Hub's compact README
|
|
213
|
+
agent loop and `docs/Architecture/agent-playbook.md` come from the CLI loop definitions via
|
|
214
|
+
`scripts/generate-agent-playbook.mjs`; CLI `--help` comes from Commander descriptions. There, the fast path
|
|
215
|
+
does not apply:
|
|
216
|
+
- **Never hand-edit the generated file.** It is a band-aid the next regen silently overwrites, and it
|
|
217
|
+
leaves `--help` — the surface users actually hit — still wrong.
|
|
218
|
+
- **Fix the source, not the artifact:** edit the loop in `cli/src/explain-command.ts` or the relevant
|
|
219
|
+
`.description()` in `cli/src/index.ts`, then rebuild/regenerate.
|
|
220
|
+
- **Do not race the train with it.** That fix touches code + built artifacts, so it runs the **full** gate,
|
|
221
|
+
and it would add a **code commit to the very diff Step 1 is about to cut**. This docs pass is freshness, not
|
|
222
|
+
a scope hatch. So **default to deferring it**: land the source fix on `development` as an ordinary
|
|
223
|
+
CI-gated PR **after** the release, note the deferral in the release report, and let it ship next cycle.
|
|
224
|
+
The drift is cosmetic and already shipped; one more cycle costs nothing.
|
|
225
|
+
- Only the **human release owner** may pull a generated-surface fix into the current release, and only by
|
|
226
|
+
saying so explicitly. An agent never makes that call on its own drift judgment, and never `--auto`-merges
|
|
227
|
+
a code-bearing PR at the probe.
|
|
228
|
+
|
|
229
|
+
**Bounded, never a hang (fast path):** wait for that docs-only auto-merge up to a short bound (~5 min). If
|
|
230
|
+
CI is contended and it has not merged in time, **do not block the train** — proceed with the release as-is.
|
|
231
|
+
Leave the auto-merge armed: the doc fix is not lost, it just lands whenever CI clears. Docs freshness
|
|
232
|
+
improves the release; it never holds it hostage.
|
|
233
|
+
|
|
234
|
+
Then **Step 1** cuts `development → main` from the current HEAD. Because an armed auto-merge can still land
|
|
235
|
+
between the bound and the cut, **re-check the PR's state right before Step 1** and report what actually
|
|
236
|
+
shipped — never predict it from the bound.
|
|
237
|
+
|
|
238
|
+
## Step 1 — merge to main (never force)
|
|
239
|
+
|
|
240
|
+
Full-track repos:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
git checkout main
|
|
244
|
+
git pull --ff-only origin main
|
|
245
|
+
git merge rc --no-edit
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Direct-track repos (e.g. MMI-Hub):
|
|
249
|
+
```bash
|
|
250
|
+
git checkout main
|
|
251
|
+
git pull --ff-only origin main
|
|
252
|
+
git merge development --no-edit
|
|
253
|
+
```
|
|
254
|
+
Conflict → abort + stop (the train is misaligned — investigate; don't hand-resolve on `main`). On a
|
|
255
|
+
direct-track repo, a conflict here right after a hotfix is expected friction, not a fluke — see Step 0c for
|
|
256
|
+
why (a hotfix freezes a snapshot that `development` can keep rewriting).
|
|
257
|
+
Alignment PRs are the exception to the org's squash default: land them with a true merge —
|
|
258
|
+
`mmi-cli pr merge <n> --auto --merge` (not squash; a squash discards the merge parentage, so the
|
|
259
|
+
misalignment guard re-flags the same divergence on the next run). `--auto` clears the checks the PR
|
|
260
|
+
triggers, which block an immediate merge right after a release.
|
|
261
|
+
|
|
262
|
+
**Exception — version-manifest and `.gitignore` paths.** `mmi-cli release --apply` tolerates
|
|
263
|
+
conflicts confined to the version-fold paths (Step 1b) and `.gitignore` (#1037 — a
|
|
264
|
+
repo bootstrapped before the managed-gitignore era still carries the legacy file on `main`; the candidate
|
|
265
|
+
carries the Hub-managed copy with project-local entries preserved). The org spine is no longer delivered per
|
|
266
|
+
repo (hub-v3 WS4), so a spine-path conflict is treated like any other untolerated path. A hotfix bumps the manifests +
|
|
267
|
+
committed CLI bundle on `main` only, so the next merge re-conflicts there even when the train is healthy —
|
|
268
|
+
and the fold rewrites those exact paths right after the merge. For all tolerated paths the CLI takes the
|
|
269
|
+
incoming side deterministically and continues. Any other conflicted path → abort + stop as above.
|
|
270
|
+
|
|
271
|
+
## Step 1b — version fold (automatic, inside `mmi-cli release --apply`)
|
|
272
|
+
|
|
273
|
+
Every release folds the version bump into the release itself (#976): after the merge onto local `main` and
|
|
274
|
+
before the tag, the CLI bumps the version manifests to the release version and commits — **unconditionally,
|
|
275
|
+
changed or not** — then the tag-first push (Step 3) earns that fresh commit its required checks. There is
|
|
276
|
+
no separate bump PR, no `development` prep cycle, and `development` never sits ahead of the published
|
|
277
|
+
version (the back-merge in Step 5 carries the bump back).
|
|
278
|
+
|
|
279
|
+
What the fold bumps, by repo:
|
|
280
|
+
- **Hub (`hub-serverless`):** the full locked distribution set via `scripts/release-distribution.mjs
|
|
281
|
+
prepare` — spine dogfood (`scripts/spine-dogfood.mjs`: verify docs/surfaces + the managed `.gitignore` block),
|
|
282
|
+
every registry-declared version holder, adapter payload synchronization, build output, and the public
|
|
283
|
+
artifact bill of materials — then verifies the set (`verify --skip-npm-view`). Publication and staging
|
|
284
|
+
both derive from `surfaces.json`; there is no second package list. Claude, Codex, Kimi, Cursor, and
|
|
285
|
+
Kilo are active.
|
|
286
|
+
- **App-style repos with a root `package.json`** (most products): the manifest + lockfile version via
|
|
287
|
+
`npm version --no-git-tag-version`, kept in lockstep with the release tag.
|
|
288
|
+
- **Repos with neither:** nothing to fold — the tag is the version.
|
|
289
|
+
|
|
290
|
+
Nothing to do by hand; the `--apply` result reports the fold outcome (`versionFold`).
|
|
291
|
+
|
|
292
|
+
## Step 2 — tag the release
|
|
293
|
+
|
|
294
|
+
Full-track repos drop the `-rc.N` suffix from the open cycle. Direct-track repos use the next cycle directly
|
|
295
|
+
because they have no rc tag:
|
|
296
|
+
```bash
|
|
297
|
+
TAG=$(node scripts/next-version.mjs release) # full-track repos -> vX.Y.0
|
|
298
|
+
TAG=$(node scripts/next-version.mjs cycle) # direct-track repos -> vX.Y.0
|
|
299
|
+
git tag "$TAG"
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Step 3 — push tag, wait for the REQUIRED checks, then push main (the gate)
|
|
303
|
+
|
|
304
|
+
Required status checks are **per-repo branch protection, not a fixed list** — MMI-Hub's `main` requires
|
|
305
|
+
`cli` · `infra` · `docs`, but a product repo may require different contexts or none at all (#1045). The
|
|
306
|
+
release SHA is always fresh (the Step 1b fold commits on local `main`), so when checks ARE required,
|
|
307
|
+
pushing the branch *first* is structurally rejected until CI catches up. Push the **tag first** (it lands
|
|
308
|
+
the SHA and triggers the repo's CI — in MMI-Hub `gate.yml` runs on `v*` tags — without touching the
|
|
309
|
+
protected ref), then probe what `main` actually requires and wait only for those contexts:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
git push origin "vX.Y.0" # lands the SHA + triggers the repo's CI
|
|
313
|
+
SHA=$(git rev-parse main)
|
|
314
|
+
# discover the REQUIRED contexts on main (classic protection + rulesets; 404 = none from that source):
|
|
315
|
+
gh api repos/{owner}/{repo}/branches/main/protection/required_status_checks --jq '[.contexts[]]'
|
|
316
|
+
gh api repos/{owner}/{repo}/rules/branches/main \
|
|
317
|
+
--jq '[.[]|select(.type=="required_status_checks")|.parameters.required_status_checks[].context]'
|
|
318
|
+
# ZERO required contexts -> push main immediately (the GitHub push gate is the backstop).
|
|
319
|
+
# Otherwise poll until every required context is "success" on $SHA — never a hard-coded list, and bound
|
|
320
|
+
# the wait (~10 min): on timeout, stop with a clear failure naming the pending/failed contexts.
|
|
321
|
+
gh api repos/{owner}/{repo}/commits/$SHA/check-runs \
|
|
322
|
+
--jq '[.check_runs[]|{name:.name,conclusion:.conclusion}]'
|
|
323
|
+
git push origin main
|
|
324
|
+
```
|
|
325
|
+
(`mmi-cli release --apply` performs this discovery + bounded wait itself.) A required context can only ever
|
|
326
|
+
resolve on a tag SHA if its workflow runs on `push: tags` (or is otherwise SHA-addressable) — a PR/issue-event
|
|
327
|
+
job (e.g. a stale hand-added `add-to-project` / `mark-merged-pr-done` board-automation check) structurally
|
|
328
|
+
never produces a check-run there. The train recognizes that fixed pair by name and, after a short grace
|
|
329
|
+
window, treats it as satisfied-for-the-tag instead of burning the full ~10-minute budget on a check-run that
|
|
330
|
+
can never appear (#2404). Any OTHER required context still waits the full budget and, on timeout, names
|
|
331
|
+
exactly which contexts never materialized vs. which were merely pending. If your repo's ruleset requires a
|
|
332
|
+
PR-only job outside that pair, fix the ruleset (drop it, or replace with a real gate) — don't rely on the
|
|
333
|
+
grace window for anything not on the allowlist.
|
|
334
|
+
Rejected → stop (nothing released).
|
|
335
|
+
|
|
336
|
+
**Halted on a FAILED required check (not merely pending)?** That is a **stray unreleased tag** (#2734): the
|
|
337
|
+
tag is pushed but `main` was not, no GitHub Release exists, and nothing deployed/published off it — so it can
|
|
338
|
+
never go forward (a failed check will not pass on that SHA). This is the **opposite** of a *resumable* partial
|
|
339
|
+
state (checks passing/pending, only the branch push / Release / deploy left, where the recovery is to finish
|
|
340
|
+
forward and you must NOT delete the tag). Here: fix the cause on `development` via a CI-gated PR, then **delete
|
|
341
|
+
the stray tag** — `git push origin --delete vX.Y.0` **and** `git tag -d vX.Y.0` (delete the local tag too; a
|
|
342
|
+
surviving local tag makes `next-version cycle` silently mint the *next* version) — and re-run `mmi-cli release
|
|
343
|
+
--apply` (the fold re-tags the same version on the fixed HEAD). **Tag deletion is deletion-class → it needs the
|
|
344
|
+
authorized human's explicit per-turn go.** Exception: if a publish/deploy DID run off the stray tag, do **not**
|
|
345
|
+
delete — mint the next version with `MMI_RELEASE_VERSION` instead. The CLI already classifies this
|
|
346
|
+
(`isStrayUnreleasedTag`, `cli/src/train-apply.ts`); this note surfaces the doctrine so a halted operator does
|
|
347
|
+
not re-derive it from source.
|
|
348
|
+
|
|
349
|
+
## Step 4 — GitHub Release + start prod deploy (non-blocking)
|
|
350
|
+
|
|
351
|
+
For `tenant-container` repos, publish the GitHub Release and dispatch the central tenant deploy.
|
|
352
|
+
```bash
|
|
353
|
+
gh release create "vX.Y.0" --target main --generate-notes --latest
|
|
354
|
+
gh workflow run tenant-deploy.yml --repo mutmutco/MMI-Hub \
|
|
355
|
+
-f slug={slug} -f repo={owner}/{repo} -f ref=main -f stage=main
|
|
356
|
+
gh run watch "$(gh run list --workflow tenant-deploy.yml --limit 1 --json databaseId -q '.[0].databaseId')" \
|
|
357
|
+
--exit-status # the central prod-deploy run — run this in the BACKGROUND (Bash run_in_background)
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
For `hub-serverless` (MMI-Hub), publish the GitHub Release but do **not** dispatch `tenant-deploy.yml`:
|
|
361
|
+
the release event auto-fires `deploy.yml` for prod and `publish.yml` for the
|
|
362
|
+
plugin/CLI package. A missing `DEPLOY#main` registry row for MMI-Hub is expected, not a tenant stack repair
|
|
363
|
+
task. Watch/report the release-triggered `deploy.yml` and `publish.yml` runs instead.
|
|
364
|
+
|
|
365
|
+
For other direct-track repos, the train dispatches nothing centrally: a `registry-publish` repo's release
|
|
366
|
+
event fires its own `publish.yml` (npm / plugin marketplace); a `solo-container` repo deploys via its own
|
|
367
|
+
workflow. Publish the GitHub Release, then watch/report that repo's own release-triggered run.
|
|
368
|
+
|
|
369
|
+
`mmi-cli release --apply --json` returns the relevant run id/url data with `deployStatus`; `--watch` blocks
|
|
370
|
+
on the run(s) and resolves `deployStatus` to `success`/`failure`. For tenant-container repos, that is the
|
|
371
|
+
dispatched `tenant-deploy.yml` run. For Hub serverless, that is the auto-fired release `deploy.yml` and
|
|
372
|
+
`publish.yml` workflow pair — watched on `mutmutco/MMI-Hub`. For `registry-publish`, that is the target
|
|
373
|
+
repo's own release-triggered `publish.yml` run — watched on that repo, never dispatched, and never the
|
|
374
|
+
central `tenant-publish.yml` (#2428: dispatching both is a guaranteed npm E409 double-publish, since the
|
|
375
|
+
repo's own release-triggered publish always wins the version race).
|
|
376
|
+
`promoted: true` stays set even on a failed deploy — promotion and deploy are separate outcomes.
|
|
377
|
+
|
|
378
|
+
**`deployStatus: 'pending'` is NEVER a terminal, reportable state (#3322).** A release that returns
|
|
379
|
+
`pending` has an UNRESOLVED deploy, not a clean one. The report now prints `deploy: UNVERIFIED` instead of
|
|
380
|
+
omitting the deploy line entirely — which is exactly how a failed deploy once hid behind a "successful"
|
|
381
|
+
release (Jerv-PowerTools v1.22.0: the release-triggered `publish.yml` went green, a separate `push: main`
|
|
382
|
+
SAM deploy FAILED, and the train returned `deployStatus: pending`, so the run read as clean). Resolve it,
|
|
383
|
+
or report it as unverified-RED. Never as success.
|
|
384
|
+
|
|
385
|
+
**Read the `--apply` result's `workflowRuns` array — the train already enumerates every run on the release
|
|
386
|
+
SHA (#3699).** That enumeration includes `push: main` infra deploys (`deploy.yml`, SAM) the deploy model does
|
|
387
|
+
not name, and `deployStatus` is held at `pending` until they resolve. Any non-success entry — including
|
|
388
|
+
`pending` — keeps the release unverified: watch those listed runs to conclusion:
|
|
389
|
+
```bash
|
|
390
|
+
gh run watch <run-id> --repo {owner}/{repo} --exit-status
|
|
391
|
+
```
|
|
392
|
+
The one remaining caveat: `--watch` blocks only on deploy-model-named runs, not extra push-triggered
|
|
393
|
+
deploys — those you conclude from the `workflowRuns` list yourself. Any `failure` there is a failed release
|
|
394
|
+
deploy even when the train reported success — flag it loudly and fix it before calling the release healthy.
|
|
395
|
+
|
|
396
|
+
**Hub releases announce to Slack (#883).** Hub scope is **only** `mutmutco/MMI-Hub`: the commits/PRs on
|
|
397
|
+
`origin/main..origin/development`, this repo's `deploy.yml` + `publish.yml`, and Hub tooling (`mmi-cli`,
|
|
398
|
+
skills, plugin, registry, central workflows). Do **not** read another repo's board (`mmi-cli board` / `/mmi`
|
|
399
|
+
on a product), watch or dispatch `ds-propagate.yml`, run `design-system` / `doctor` design-system heals for
|
|
400
|
+
consumers, or treat a product's deploy state as part of this release — those belong to that product's own
|
|
401
|
+
`/release` or `/rcand`, never a Hub train.
|
|
402
|
+
|
|
403
|
+
Before running `--apply` for MMI-Hub, resolve the real tag first:
|
|
404
|
+
`TAG=$(node scripts/next-version.mjs cycle)` — always print `$TAG` (e.g. `v2.43.0`) in summaries, Slack,
|
|
405
|
+
chat, and the final report; never a placeholder like `vX.Y.0` or `v0.x.0`.
|
|
406
|
+
|
|
407
|
+
Write a curated summary — 3-6 very short plain lines, one change per line, dev-readable, no PR-dump —
|
|
408
|
+
to a fresh temp file (`f=$(mktemp tmp/release-summary.XXXXXX)`, so a stale prior summary is never reused).
|
|
409
|
+
Source from **Hub PR titles only** (`origin/main..origin/development` on `mutmutco/MMI-Hub`), but **rewrite**
|
|
410
|
+
each line in neutral Hub-subsystem terms (CLI, skills, plugin, workflows, registry, deploy hub) — **never**
|
|
411
|
+
a product or brand name (FoFu, Katip, etc.) anywhere in the summary file, Slack post, chat, or release
|
|
412
|
+
report. Product names are allowed only when releasing **that product's repo**. Then pass the file through:
|
|
413
|
+
`mmi-cli release --apply --announce-summary-file "$f"`. After the GitHub Release publishes, the CLI posts
|
|
414
|
+
the summary to the org alerts channel as the MMI-Future Slack app (token + channel from SSM at run time).
|
|
415
|
+
For a new MMI-Hub `--apply`, the CLI refuses before promotion when the file is missing, unreadable, or does
|
|
416
|
+
not contain 3–6 non-empty lines; generated-note fallback is not an agent release path. `--resume` never
|
|
417
|
+
requires or republishes a summary, and non-Hub repos skip the announcement automatically. After a valid
|
|
418
|
+
summary is accepted, Slack delivery remains best-effort: a transport failure is reported in the result and
|
|
419
|
+
never rolls back an otherwise completed release.
|
|
420
|
+
|
|
421
|
+
**Don't block on the deploy.** Start the watch as a background task and proceed to Steps 4b–5 (docs, project
|
|
422
|
+
info, branch alignment) while prod deploys. The verdict is collected in Step 6 — verification is not
|
|
423
|
+
skipped, only un-blocked. Deploy failure → report plainly, then **retry the existing promoted ref by deploy
|
|
424
|
+
model** once the runtime is repaired — never a re-tag or republish (`main` is already at the release, which is
|
|
425
|
+
correct). Read the model from the registry (`mmi-cli org project get {owner}/{repo}` → `deployModel`):
|
|
426
|
+
- **tenant-container** — the central tenant deployer owns the redeploy: `mmi-cli runtime tenant redeploy
|
|
427
|
+
{owner}/{repo} main --watch`.
|
|
428
|
+
- **repository-owned serverless / registry-publish** (e.g. Jerv-PowerTools' `Deploy Jerv Memory`) — there is
|
|
429
|
+
no `runtime tenant redeploy` for these; re-run the repo's OWN declared `workflow_dispatch` deploy workflow at
|
|
430
|
+
the promoted-equivalent ref: `gh workflow run <deploy-workflow> --repo {owner}/{repo} --ref <ref>`.
|
|
431
|
+
|
|
432
|
+
Name the sanctioned dispatch mechanism you used in the train report.
|
|
433
|
+
|
|
434
|
+
## Step 4b — re-sync project info (in-repo docs handled in Step 0d)
|
|
435
|
+
|
|
436
|
+
The two in-repo docs were already scanned against the shipping diff and, if they drifted, refreshed +
|
|
437
|
+
merged in **Step 0d** (fast docs-only path for hand-written prose; generated regions are fixed at
|
|
438
|
+
their source and deferred to the next cycle) — so the released commit already carries
|
|
439
|
+
current `README.md` / `architecture.md` (and, in the hub, `docs/org-readme.md` /
|
|
440
|
+
`docs/org-architecture.md`). The `distribution` gate also blocks empty/retired-term descriptions at PR
|
|
441
|
+
time. Nothing to author here. `mmi-cli release --apply` now re-syncs the **Project** short description +
|
|
442
|
+
thin README from those docs and the registry's current member repos through the command ladder. For a
|
|
443
|
+
manual repair or preview use:
|
|
444
|
+
```bash
|
|
445
|
+
mmi-cli org project sync-info --apply # omit --apply for the read-only plan
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## Step 5 — roll development forward
|
|
449
|
+
|
|
450
|
+
- Keep branches aligned: `mmi-cli release --apply` back-merges the released `main` (incl. the version
|
|
451
|
+
fold) into `development` and reports it as `devRollForward`. When `development` has no required checks it
|
|
452
|
+
pushes directly (`status: pushed`). When `development` *requires* checks (e.g. MMI-Hub needs
|
|
453
|
+
`cli`/`infra`/`docs`), the fresh merge commit carries no passing checks, so a direct push is structurally
|
|
454
|
+
rejected — the train instead **opens an alignment PR** `main → development` (`status: pr-pending`) and the
|
|
455
|
+
release report prints the exact land command. The release itself has already shipped; **land the alignment
|
|
456
|
+
PR with a true merge** — `mmi-cli pr merge <number> --auto --merge` (never squash — a squash drops the merge
|
|
457
|
+
parentage and the misalignment guard re-flags the divergence). `--auto` is what makes it land right after a
|
|
458
|
+
release: the alignment PR's own `cli`/`infra`/`docs` checks are still running, so a plain immediate merge is
|
|
459
|
+
policy-blocked — `--auto` merges once they pass. Never force.
|
|
460
|
+
- Full-track repos: `mmi-cli release --apply` already aligned `rc` to the released `main` (#1036 — the
|
|
461
|
+
push runs inside the authority-gated train; the result reports it as `rcAlignment`). No manual `rc`
|
|
462
|
+
push — if the result reports a failed alignment, investigate and rerun via the train, never bare-push.
|
|
463
|
+
- **Local branches never left stale (#2582).** A release advances `main`/`development`/`rc` on **origin**;
|
|
464
|
+
`mmi-cli release --apply` also fast-forwards the LOCAL train branches to match, so the checkout you
|
|
465
|
+
released from does not lag what you just pushed. The train restores + fast-forwards the start branch
|
|
466
|
+
(`checkout`, #2340) and fast-forwards the others (`localSync`) — non-destructively: only a true
|
|
467
|
+
fast-forward moves a branch; a diverged local branch is reported and left untouched (never a force).
|
|
468
|
+
The one branch it **cannot** sync at release time is a check-gated `development` whose roll-forward is a
|
|
469
|
+
`pr-pending` alignment PR (Hub) — that PR merges on origin *after* the release returns. That case is
|
|
470
|
+
healed automatically by the **next session**: `mmi-cli plugin session-start` (invoked by the resume
|
|
471
|
+
channel — #3630 took SessionStart off the hook surface) runs the
|
|
472
|
+
same fast-forward first thing, so a stale local `development`/`main`/`rc` self-heals to origin before you
|
|
473
|
+
work — no manual `git pull`. Nothing here ever blocks or fails the release.
|
|
474
|
+
|
|
475
|
+
## Step 6 — collect deploy verdict + report
|
|
476
|
+
|
|
477
|
+
Collect the backgrounded prod-deploy watch from Step 4 (it has typically finished by now). Confirm prod is
|
|
478
|
+
healthy (the central deploy workflow smoke step / a health check); **red** → report the failure prominently and flag
|
|
479
|
+
that the release shipped on a failed deploy (re-run just the deploy — `main` is already correct).
|
|
480
|
+
|
|
481
|
+
Hub releases always carry a distribution bump (the Step 1b fold), so the **publish workflow**
|
|
482
|
+
(`publish.yml`) ships every registry-declared public npm artifact on the GitHub Release from Step 4 —
|
|
483
|
+
don't publish by hand.
|
|
484
|
+
Watch it, then confirm npm caught up:
|
|
485
|
+
```bash
|
|
486
|
+
gh run watch "$(gh run list --workflow publish.yml --event release --limit 1 --json databaseId -q '.[0].databaseId')" --exit-status
|
|
487
|
+
node scripts/release-distribution.mjs verify "vX.Y.0" # asserts registry versions, BOM identities, and published npm artifacts
|
|
488
|
+
```
|
|
489
|
+
Run that verify from a checkout **at the tag** (`main` right after the release merge, `git checkout
|
|
490
|
+
"vX.Y.0"`, or a worktree at the tag) — verify checks the working tree and refuses any other commit once
|
|
491
|
+
the tag exists, so a stale `development`/`rc` checkout can't masquerade as a broken release.
|
|
492
|
+
Release-blocking for Hub tooling changes: every public artifact must match the registry version and BOM
|
|
493
|
+
identity. Manual fallback if CI can't publish: `node scripts/release-distribution.mjs publish "vX.Y.0"`
|
|
494
|
+
from a machine with npm auth.
|
|
495
|
+
|
|
496
|
+
**Private packages (#2405) — never trust a bare `npm view` to mean "not published".** An unauthenticated
|
|
497
|
+
`npm view <pkg>` returns a hard 404 on any package published with `publishConfig.access=restricted`
|
|
498
|
+
(private) — indistinguishable from "not published" — because npm masks private packages from anonymous
|
|
499
|
+
reads. Before verifying ANY npm publish (Hub's own, a `registry-publish` product repo's own `publish.yml`,
|
|
500
|
+
or a `publishRequired` product repo's companion `tenant-publish.yml`), check that surface's
|
|
501
|
+
`publishVisibility` in the target repo's `surfaces.json`
|
|
502
|
+
(`node -e "console.log(require('./surfaces.json').surfaces.find(s=>s.id==='<id>').publishVisibility)"`, or
|
|
503
|
+
the repo-agnostic reader `scripts/release-distribution.mjs` exports as `npmVerifyModeFor`):
|
|
504
|
+
- `public` → an unauthenticated `npm view <pkg>@<version> version` is a trustworthy verify signal.
|
|
505
|
+
- `private` → do **not** run a bare `npm view`. Verify from an authenticated source instead: the
|
|
506
|
+
release-triggered run's conclusion (`gh run watch … --exit-status` — the repo's own `publish.yml` for
|
|
507
|
+
`registry-publish`, #2428; the central `tenant-publish.yml` for a `publishRequired` companion publish) and
|
|
508
|
+
its logged `+ pkg@ver` / `"already on npm — nothing to do"` / `"already on npm ... treating as idempotent
|
|
509
|
+
success"` output (`gh run view <id> --log`), or `npm view` with a registry auth token in env. A 404 here is
|
|
510
|
+
"unverifiable from here", never "not published" — report it as such, don't block or alarm on it.
|
|
511
|
+
- `n/a` → nothing publishes to npm for that surface; skip.
|
|
512
|
+
Hub's registry-declared npm surfaces are public today, so `release-distribution.mjs verify` uses a bare
|
|
513
|
+
`npm view` for them — this changes only if a package's declared visibility changes.
|
|
514
|
+
|
|
515
|
+
**tenant-publish.yml E409 belt-and-braces (#2428).** The central `tenant-publish.yml` lane (the
|
|
516
|
+
`publishRequired` companion publish only — never dispatched for `registry-publish`, see above) already
|
|
517
|
+
treats a lost `npm publish` race as idempotent inside the run (a re-check `npm view` after a failed publish;
|
|
518
|
+
see the workflow file). `mmi-cli release --apply --watch` mirrors that at the CLI layer: a watched
|
|
519
|
+
`tenant-publish.yml` run that concludes `failure` is re-checked against that SAME run's own log (bounded
|
|
520
|
+
retries, visibility-agnostic — never a bare `npm view`) for the idempotent-success marker before the CLI
|
|
521
|
+
reports the publish as failed. A run whose log never shows the version landed stays a loud failure.
|
|
522
|
+
|
|
523
|
+
Report: Release `$TAG` (the resolved tag from Step 2 — never a placeholder) + the GitHub Release URL · prod
|
|
524
|
+
deploy run + URL + **green/red** · branch-alignment note · npm publish run + CLI version (Hub releases).
|
|
525
|
+
|
|
526
|
+
## Notes
|
|
527
|
+
|
|
528
|
+
- PATCH-level releases are `/hotfix` only (a hotfix always skips rc — it cherry-picks `development → main`
|
|
529
|
+
directly); planned releases are MINOR or MAJOR. Never force-push `main`.
|
|
530
|
+
- **`--dev` (full-track only):** releases `development → main` skipping rc, with the same fold/tag/Release/
|
|
531
|
+
deploy machinery plus the post-release rc retirement and rc alignment. Refuses (fail closed) when
|
|
532
|
+
`origin/rc` carries commits not in `development`; on direct-track repos it's a no-op (they already
|
|
533
|
+
release from `development`).
|
|
534
|
+
- **MAJOR / exact-target release:** to ship a version the tag math can't derive (a MAJOR like `2.0.0`, or
|
|
535
|
+
skipping a version already on npm), product repos export `MMI_RELEASE_VERSION=X.Y.Z` for **both** `/rcand`
|
|
536
|
+
and `/release`; MMI-Hub exports it for `/release` only. Steps 1b/2 then fold and tag exactly that
|
|
537
|
+
version. Unset, the train ships the open cycle.
|
|
538
|
+
|
|
539
|
+
## Retro — one check before you finish
|
|
540
|
+
Before your final report, answer one question honestly: did **this skill's own instructions** misfire
|
|
541
|
+
this run — ambiguous wording, a misleading message, or an environment failure it should have warned
|
|
542
|
+
about? (Process only — never the user's code or task; e.g. a misleading authority or gate message, or an
|
|
543
|
+
ambiguous version-fold or back-merge step.) If yes, file **one** lesson and move on; a clean run is silent
|
|
544
|
+
(hard cap: one per run). It lands on the Hub board (deduped) and is fixed only via a reviewed PR — never
|
|
545
|
+
edit the skill live; the retro is advisory, so if the call fails, note it and continue:
|
|
546
|
+
`mmi-cli skill-lesson --skill release --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: resume
|
|
3
|
+
description: Open a session — self-check, repo status, and the next actionable board item in one pass.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /resume — start of session
|
|
7
|
+
|
|
8
|
+
One flow to re-anchor at the top of a session: is the toolchain sound, what does this repo/worktree look
|
|
9
|
+
like right now, and what is the single next thing worth doing. Read-only — it renders the picture and gets
|
|
10
|
+
out of the way. `/mmi` is the board-only hello-to-work; `/resume` is the wider session open that folds in
|
|
11
|
+
the toolchain self-check and the current-branch snapshot.
|
|
12
|
+
|
|
13
|
+
## Step 0 — toolchain self-check
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
mmi-cli doctor --self
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`doctor --self` verifies the two things that silently break a session: CLI/plugin version parity against
|
|
20
|
+
the published version, and whether the active `gh` token can resolve this repo. It is fast, but it reads
|
|
21
|
+
npm and GitHub — it is not offline-safe, and it checks neither PATH nor hook wiring (#3485). On a **hard**
|
|
22
|
+
gap it points at the heal path — relay it and run it before working:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
mmi-cli plugin heal # only on a hard version/plugin gap; then restart Claude Code / reopen the workspace
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
A clean self-check is silent-enough — move straight on. Do not block the snapshot on a soft/advisory note.
|
|
29
|
+
|
|
30
|
+
## Step 1 — repo snapshot
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
mmi-cli status
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`status` is the unified current-state read for **this** checkout: branch, linked worktrees, your open PRs,
|
|
37
|
+
your claimed board items, and whether a local stage is running. It is the "where am I" line — render it,
|
|
38
|
+
don't re-derive it from raw `git`/`gh`.
|
|
39
|
+
|
|
40
|
+
## Step 2 — the next move
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
mmi-cli next
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`next` recommends the single most actionable claimable board item (unblocked, priority-ranked) and prints
|
|
47
|
+
the exact `mmi-cli board claim <n>` to take it. Offer it; do not claim on the user's behalf without a go.
|
|
48
|
+
For the full board partition (yours / claimable / taken) run `/mmi`.
|
|
49
|
+
|
|
50
|
+
## Step 3 — render, then stop
|
|
51
|
+
|
|
52
|
+
Lead with one line: toolchain OK (or the heal to run), the branch + what's in flight, and the one next
|
|
53
|
+
item with its claim command. Then stop. The user drives — claim, continue, or file when they say so.
|
|
54
|
+
|
|
55
|
+
## Notes
|
|
56
|
+
|
|
57
|
+
- `/resume` is read-only session orientation. It never claims, moves, or writes.
|
|
58
|
+
- Board status moves are automatic (claim, PR open, merge). Never suggest a manual status move.
|
|
59
|
+
- Slower, board-partition view → `/mmi`. Readiness-gate view for a new repo/first session → `/onboard`.
|
|
60
|
+
|
|
61
|
+
## Retro — one check before you finish
|
|
62
|
+
Before your final report, answer one question honestly: did **this skill's own instructions** misfire
|
|
63
|
+
this run — ambiguous wording, a misleading message, or an environment failure it should have warned
|
|
64
|
+
about? (Process only — never the user's code or task; e.g. a self-check that reported a false gap, or a
|
|
65
|
+
snapshot that named the wrong branch.) If yes, file **one** lesson and move on; a clean run is silent
|
|
66
|
+
(hard cap: one per run). It lands on the Hub board (deduped) and is fixed only via a reviewed PR — never
|
|
67
|
+
edit the skill live; the retro is advisory, so if the call fails, note it and continue:
|
|
68
|
+
`mmi-cli skill-lesson --skill resume --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
|