@mutmutco/claude-plugin 4.5.173 → 4.5.175
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/.claude-plugin/plugin.json +1 -1
- package/cli/dist/main.cjs +481 -268
- package/cli/package.json +1 -1
- package/package.json +1 -1
- package/skills/board/SKILL.md +36 -105
- package/skills/board/reference.md +66 -0
- package/skills/bootstrap/SKILL.md +34 -120
- package/skills/bootstrap/reference.md +65 -0
- package/skills/epic/SKILL.md +33 -78
- package/skills/hotfix/SKILL.md +22 -42
- package/skills/hotfix/recovery.md +10 -0
- package/skills/rcand/SKILL.md +18 -24
- package/skills/rcand/recovery.md +8 -0
- package/skills/release/SKILL.md +11 -73
- package/skills/release/verification.md +71 -0
- package/skills/secrets/SKILL.md +18 -80
- package/skills/secrets/reference.md +41 -0
- package/skills/stage/SKILL.md +20 -74
- package/skills/stage/reference.md +49 -0
package/skills/release/SKILL.md
CHANGED
|
@@ -5,115 +5,53 @@ description: Ship rc or direct-track development to main and production.
|
|
|
5
5
|
|
|
6
6
|
**Host-native invocation:** Claude `/mmi:release` · Codex `$mmi:release` · jervcode `/release` · Hermes skill_view. A backticked `/name` in this doc names the matching workflow (this skill or a sibling), not a literal command.
|
|
7
7
|
|
|
8
|
-
**Argument:** `/release minor`, `/release major`, or `/release patch` — a bare bump word, never a `--flag` or env var. No argument → `patch`; a `/release patch` from development is a legitimate ordinary release, `/hotfix` stays the cherry-pick promotion lane.
|
|
9
|
-
|
|
10
|
-
**Bump rules** ([docs/versioning.md](../../docs/versioning.md)): patch is the default and needs nothing. `minor` only for a real feature or significant change, with a one-line reason exported as `MMI_BUMP_REASON`. `major` only with Jervaise's fresh approval in this turn: export `MMI_BUMP_REASON` and `MMI_MAJOR_APPROVED=<exact target version>` (e.g. `5.0.0`) only after that approval, never earlier or from a prior turn. A breaking signal in the range (`feat!:`, `BREAKING CHANGE:`) makes the train refuse until it is shimmed (patch) or declared an owner-gated major.
|
|
11
|
-
|
|
12
8
|
# /release — ship to main + prod
|
|
13
9
|
|
|
14
|
-
|
|
10
|
+
Bare `minor|major|patch` (default `patch`), never a flag; needs Jervaise's yes (principle 12). `minor`: `MMI_BUMP_REASON`. `major`: also `MMI_MAJOR_APPROVED=<exact version>` after the yes ([docs/versioning.md](../../docs/versioning.md)).
|
|
15
11
|
|
|
16
12
|
## Lane
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
Read META and name the lane before describing or executing anything:
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
mmi-cli oracle org project get {owner}/{repo} --json
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
`releaseTrack: direct` → `development → main`, no `/rcand`. Absent → full (`rc → main`), except MMI-Hub, which is direct by the Hub-control special case. Full-track `--dev` ships `development → main` skipping rc and fails closed when `origin/rc` carries content not in `development`. Unreadable META → stop; never infer the lane from branch names, tags or release history.
|
|
27
|
-
|
|
28
|
-
For `deployModel: vercel`, read [vercel.md](vercel.md) before applying or interpreting deployment status.
|
|
14
|
+
Read `mmi-cli oracle org project get {owner}/{repo} --json` and name the lane ([verification.md](verification.md) Lane rules); unreadable META → stop. [suite.md](suite.md) for MM-Work; [vercel.md](vercel.md) for Vercel.
|
|
29
15
|
|
|
30
16
|
## Preflight
|
|
31
17
|
|
|
32
|
-
|
|
33
|
-
mmi-cli devops train doctor --lane release --heal --json
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
The JSON is on stdout alone; a stale CLI first prints its self-update notice on stderr and re-runs itself, so parse stdout only, never `2>&1`. Read `ready`, then `findings[]`: each carries `code`, `severity` (`blocker` · `warning` · `healed` · `info`), `source` (`local` · `origin`), `remedy` and `anchor`. `ready: false` → stop and quote every blocker's `code` and `remedy`; an unread origin is never green. `--apply` re-runs this doctor as its step 0 with heal on.
|
|
18
|
+
`mmi-cli devops train doctor --lane release --heal --json` (stdout only): `ready`, `findings[]` (`code`, `severity`, `source`, `remedy`, `anchor`). `ready: false` → quote blockers' `code` and `remedy`.
|
|
37
19
|
|
|
38
20
|
## Apply
|
|
39
21
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Two cases need a summary file. (1) **MMI-Hub** — always: write a fresh 3–6 line neutral summary to `f=$(mkdir -p .jerv/tmp && mktemp .jerv/tmp/release-summary.XXXXXX)` — sourced from the range `origin/main..origin/development`, rewritten in Hub-subsystem terms, never a product or brand name, and never a Jerv-side project (the train refuses such a line). Hub scope is only `mutmutco/MMI-Hub`: never a product's board or a product's deploy state. **Build and verify every line from ONE command's output**, never from commit subjects or PR titles alone: `git log --stat --format='%h %s%n%b' origin/main..origin/development` gives each commit's subject, its full body (where a bundled PR records `Closes #N`) and the files it changed in a single pass. A line whose claim you cannot point to in that output does not go in the file, and every `#N` a Hub line cites must appear there: the train refuses `--apply` on a citation that ships in no commit of the cut. (2) **Any product repo whose META carries `releaseChannel`** (`mmi-cli oracle org project get {owner}/{repo} --json`) — required too: read `releaseLanguage` (default `en`) and write 3–6 lines IN THAT LANGUAGE, in plain words for the project's audience: what changed and why it matters to a user; no commit prefixes, no issue or PR numbers, no file names, no product-internal jargon. The train refuses `--apply` without the file, and raw release notes are never posted to a project channel. A repo with no `releaseChannel` announces nothing, but an mm-work suite repo still requires the summary for its GitHub Release. An mm-work suite repo's summary follows the update-notes template below instead of the 3–6 line rule.
|
|
22
|
+
From the primary checkout on the lane's start branch (Lane rules). Export `MMI_BUMP_INTENT`. MMI-Hub and `releaseChannel` products need a summary file ([verification.md](verification.md)); the Hub's is sourced from the range `origin/main..origin/development`, never a product or brand name, never a product's board.
|
|
43
23
|
|
|
44
24
|
```bash
|
|
45
25
|
mkdir -p .jerv/tmp
|
|
46
26
|
mktemp .jerv/tmp/release-receipt.XXXXXX
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Scratch lives under `.jerv/tmp` in every repo: a repo-root `tmp/` may not exist at all, and an agent host guards the primary checkout against root writes outside `.jerv/tmp` — either one aborts the release before its first command runs.
|
|
50
|
-
|
|
51
|
-
Copy the returned pathname into `<result-path>` below; do not rely on shell variables surviving another tool call. For a product without a release channel:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
mmi-cli devops release --apply --watch --json --out "<result-path>"
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
For MMI-Hub or a product with a release channel, also substitute the saved summary pathname:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
27
|
mmi-cli devops release --apply --watch --announce-summary-file "<summary-path>" --json --out "<result-path>"
|
|
61
28
|
```
|
|
62
29
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
**Progress narration.**
|
|
66
|
-
|
|
67
|
-
Describe the release in plain words before each command: “Preparing release”, “Waiting for checks”, “Waiting for publishing”, or “Finishing the existing release”. Keep temporary-file preparation separate from the long-running release command so its tool title cannot become a temporary filename; carry the returned path explicitly into the release command when tool calls do not share shell variables. Keep stderr visible: the CLI prints `Release: ` stages and elapsed updates every 30 seconds during long operations, while JSON and `--out` remain the verification record. Never redirect both streams into the result file.
|
|
68
|
-
|
|
69
|
-
Use the actual current stage, never a guessed sequence. Explain a pending result as “Publishing is still pending” or name the unfinished step, then narrate the sanctioned resume command as “Checking the remaining release steps”. Say “Release complete” only after the status fields prove every required follow-up complete. Temporary filenames, `XXXXXX`, receipts, and ledger folding are internal bookkeeping, never a user-facing status.
|
|
30
|
+
Run mktemp alone, copy its path; no channel: drop the summary flag. `mmi-cli devops release --apply --ack <sha>` only for a verified main-only commit the hotfix-coverage guard refused. It runs the version fold (automatic, inside `mmi-cli devops release --apply`) bumping manifests unconditionally, pushes the tag first (`gate.yml` runs on `v*` tags), deploys (`tenant-deploy.yml` for tenant-container), announces. Nothing by hand.
|
|
70
31
|
|
|
71
32
|
## Verify
|
|
72
33
|
|
|
73
|
-
|
|
74
|
-
Never install AWS, ask for AWS credentials, or copy the shared Slack key to unblock a developer.
|
|
75
|
-
The Hub chooses the registered channel and checks project authority. A failed announcement keeps
|
|
76
|
-
its summary file; an uncertain delivery is never automatically replayed.
|
|
77
|
-
|
|
78
|
-
Read the saved result, never the exit code (exit `1` = a follow-up failed after promotion; a pending follow-up exits `0`, so a clean exit alone never means every leg resolved):
|
|
79
|
-
|
|
80
|
-
- `releaseVerdict.releaseStatus` + `followUpStatus` — `succeeded` + `pending` is shipped with the follow-up unresolved: neither failed nor done. A `--resume` receipt carries the same `releaseVerdict` (`command: release-resume`), plus its own `mode` and `state`.
|
|
81
|
-
- `deployStatus` — `pending` is never terminal; `promoted: true` holds even when a deploy failed.
|
|
82
|
-
- For a `served-channel(<product>)` row, read [verification.md](verification.md) and verify the installer channel before declaring completion.
|
|
83
|
-
|
|
84
|
-
- `workflowRuns` — every run on the release SHA (deploy-model runs, any `push: main` deploy, the repo's own `gate`). On this host, discover them with the bounded run-list read below; filter locally by the exact receipt SHA. If the list hits its 100-row cap or returns no matching SHA, treat the run set as unverified and stop rather than infer completeness. Watch each matching non-success entry to conclusion: `gh run watch <run-id> --repo {owner}/{repo} --exit-status --interval 30`. Name which run is red: `deploy.yml` / `publish.yml` / `tenant-deploy.yml` / `jerv-gateway` is a deploy or publish verdict; a `gate` push run is ordinary CI sharing the SHA.
|
|
85
|
-
- With `--watch`, require every follow-up complete before declaring the cut done. For any pending ledger leg, read [recovery.md](recovery.md) before continuing or starting a new train.
|
|
86
|
-
- `announceNote` — `announced` (to the alerts channel for the Hub, to the project release channel for a product repo), `skipped`, `not announced` (deploy or publish not green; the note says whether a `--resume` carrying the same `--announce-summary-file` will post it), or the failure note. The channel id itself is never printed.
|
|
87
|
-
- `devRollForward` / `rcAlignment` — `pushed`, or `pr-pending` with the alignment PR to land by true merge (Merge floor). An enqueued auto-merge is not evidence of the method; before reporting, read the enqueued method back — `gh pr view <n> --json autoMergeRequest --jq .autoMergeRequest.mergeMethod` — and prove it is `MERGE`. An enqueued `SQUASH` is a stop under the Merge floor, not something to wait out.
|
|
88
|
-
- `versionFold`, `rcRetirement`, `checkout` — `returned`, or the named reason you are still on `main`.
|
|
89
|
-
- `localInstall` (MMI-Hub) — the train installs the release on this machine via `mmi-hub update`; never run `npm i -g`.
|
|
90
|
-
For a private npm surface, read [verification.md](verification.md) before interpreting authentication or package visibility.
|
|
91
|
-
|
|
92
|
-
Then verify Latest with this bounded one-row read; require `isLatest: true` and `tagName` equal to the resolved tag: `gh release list --repo {owner}/{repo} --limit 1 --json tagName,isLatest,publishedAt`.
|
|
93
|
-
|
|
94
|
-
For the independent run recheck, read [verification.md](verification.md) and use its bounded release-window recipe.
|
|
95
|
-
|
|
96
|
-
Four facts close the verdict: the `origin/main..origin/development` count, the tag on origin, Latest, and green runs on the release SHA.
|
|
34
|
+
Receipt fields (`served-channel`, npm, `jerv-gateway`): [verification.md](verification.md). Latest: `gh release list --repo {owner}/{repo} --limit 1 --json tagName,isLatest,publishedAt` → `isLatest: true`, resolved tag. Close on: `origin/main..origin/development` count, tag on origin, Latest, green runs on the SHA.
|
|
97
35
|
|
|
98
36
|
## Recovery
|
|
99
37
|
|
|
100
|
-
On
|
|
38
|
+
On failure or a pending ledger leg: [recovery.md](recovery.md).
|
|
101
39
|
|
|
102
40
|
## Merge floor
|
|
103
41
|
|
|
104
|
-
- **Never squash-merge a tagged commit (#3167).** A squash re-mints the SHA and orphans the tag
|
|
42
|
+
- **Never squash-merge a tagged commit (#3167).** A squash re-mints the SHA and orphans the tag, so tag-anchored checks mis-read. Any merge that carries an already-tagged commit — the `main → development` roll-forward, an alignment PR, a hotfix fold PR — lands as a true merge: `mmi-cli devops pr merge <number> --auto --merge` (or `--wait --merge`); `--wait` alone still squashes. The hotfix main-base PR itself may squash: its tag lands after, on the merged `main` HEAD, and the `-x` trailer must survive the squash message.
|
|
105
43
|
- **A refused train is a stop, never a license to finish by hand.** Every fail-closed halt — doctor blocker, authority probe, coverage guard, untolerated conflict, required checks, stray tag, ledger — ends the run. Fix the cause on `development` through a normal PR and rerun the train; never hand-resolve on `main`, hand-cherry-pick, bare-push a train branch, ack to save time, or bypass a check.
|
|
106
44
|
- **Version probes anchor on the latest Release tag, not a branch (#2734).** A branch manifest or a stale local tag is not a version source; a surviving local tag silently mints the next version.
|
|
107
45
|
- **One train at a time on a repo (#5380).** Two overlapping runs race the shared tag namespace; the ledger refuses the second — never start one to help the first.
|
|
108
|
-
- **Tag and Release deletion
|
|
46
|
+
- **Tag and Release deletion need Jervaise's yes (principle 12),** named in the guide entry that prescribes it.
|
|
109
47
|
|
|
110
48
|
## Report
|
|
111
49
|
|
|
112
|
-
|
|
50
|
+
Verdict first: the resolved tag (never a placeholder like `vX.Y.0`), Release URL, `releaseStatus`, `followUpStatus`, `deployStatus`, `promoted`, each run's conclusion and URL (or the no-run-URL note), which run is red (deploy/publish verdict or ordinary CI), `announceNote`, the alignment note (`devRollForward`, `rcAlignment` or the fold PR), `checkout`, the dispatch used. Pending is unverified, never success. Product names only when releasing that product's repo.
|
|
113
51
|
|
|
114
52
|
## Retro
|
|
115
53
|
|
|
116
|
-
Before the final report
|
|
54
|
+
Before the final report: did this skill misfire? Process only. If yes, file one lesson (hard cap: one per run); a clean run is silent; if the call fails, note it and continue. Lessons are deduplicated on the owning board and change the skill only by reviewed PR, never live; no issue references outside Merge floor.
|
|
117
55
|
|
|
118
56
|
```bash
|
|
119
57
|
mmi-cli learning skill-lesson --skill release --title "<what misfired>" --body "<what; evidence; proposed amendment>"
|
|
@@ -5,3 +5,74 @@ Do not use the raw `releases/latest` API route, a `--jq` formatter, or `gh run l
|
|
|
5
5
|
- A `private` npm surface (`surfaces.json`): the doctor's `npm-token-rejected` finding comes first. A 401 from `npm whoami` through the `_org` `npm/NPM_TOKEN` vault hop means the token is rejected, and every authenticated `npm view` then 404s exactly like an absent package — rotate the token; only after a login is a restricted 404 "unverifiable from here", never "not published" (`publish-private-package`). On a repo whose workflows publish through Trusted Publishing and name no registry token, that row is `info`, not a warning: no lane consumes the org token, so it constrains your manual read only.
|
|
6
6
|
|
|
7
7
|
- `served-channel(<product>)` row — the release's proof that new installs get it: the public `/release/version` pointer of the releasing repo's OWN channel (the Hub's `mmi`, or the product its registry `installer` declaration names; no declaration → no row), read after deploy and publish are green. `success` names the version read. `failure` is either a channel still on the previous version or a stale served process (the route answers 401/404): the note names what moves that channel and the exact remedy; run it, then re-read the pointer. `pending` means not probed (legs not green) or unreadable, never proof. The row is receipt evidence only, never a ledger leg, so it never blocks the next train.
|
|
8
|
+
|
|
9
|
+
## Release summary file
|
|
10
|
+
|
|
11
|
+
Required for MMI-Hub and any product whose META carries `releaseChannel`; an mm-work suite repo needs one for its GitHub Release, following the update-notes template in [suite.md](suite.md). Write 3–6 lines to `f=$(mkdir -p .jerv/tmp && mktemp .jerv/tmp/release-summary.XXXXXX)`.
|
|
12
|
+
|
|
13
|
+
- MMI-Hub: neutral Hub-subsystem terms, never a product or brand name or a Jerv-side project (the train refuses one). Build every line from `git log --stat --format='%h %s%n%b' origin/main..origin/development`; a line you cannot point to there stays out, and every cited `#N` must appear there.
|
|
14
|
+
- Product: in `releaseLanguage` (default `en`), plain words on what changed and why it matters; no prefixes, issue/PR numbers, file names or jargon.
|
|
15
|
+
|
|
16
|
+
## Receipt fields
|
|
17
|
+
|
|
18
|
+
Read the saved result, never the exit code (`1` = a follow-up failed after promotion; pending exits `0`).
|
|
19
|
+
|
|
20
|
+
- `releaseVerdict.releaseStatus` + `followUpStatus`: `succeeded` + `pending` is shipped, follow-up unresolved. `--resume` receipts carry the same `releaseVerdict` (`command: release-resume`) plus `mode` and `state`.
|
|
21
|
+
- `deployStatus`: `pending` is never terminal; `promoted: true` holds even when a deploy failed.
|
|
22
|
+
- `workflowRuns`: every run on the release SHA; `parallel: true` marks legs run together. Name the red run: `deploy.yml`, `publish.yml`, `tenant-deploy.yml` and `jerv-gateway` are deploy/publish verdicts; a `gate` push run is ordinary CI.
|
|
23
|
+
- `announceNote`: `announced`, `skipped`, `not announced` (deploy/publish not green; a `--resume` with the same `--announce-summary-file` posts it), or the failure note. A failed announcement keeps its summary file; an uncertain delivery is never replayed automatically. Never install AWS, ask for AWS credentials, or copy the Slack key.
|
|
24
|
+
- `devRollForward` / `rcAlignment`: `pushed`, or `pr-pending` with an alignment PR to land by true merge; read the method back with `gh pr view <n> --json autoMergeRequest --jq .autoMergeRequest.mergeMethod`: it must be `MERGE`, and `SQUASH` is a stop.
|
|
25
|
+
- `versionFold`, `rcRetirement`, `checkout`: `returned`, or the reason you are still on `main`.
|
|
26
|
+
- `localInstall` (MMI-Hub): the train installs via `mmi-hub update`; never `npm i -g`.
|
|
27
|
+
|
|
28
|
+
## Lane rules
|
|
29
|
+
|
|
30
|
+
Full track ships exactly what is on `rc` (never `development`): `rc → main`. Direct track ships `development → main`, no `/rcand`; `releaseTrack: direct` in META, absent = full, and MMI-Hub is always direct. `--dev` on a full track ships `development → main` skipping rc and fails closed when `origin/rc` has content not in `development`. Never infer the lane from branch names, tags or history. Start branch: `rc`; `development` for direct-track and `--dev`. MMI-Hub release on Windows runs under Git Bash (`"C:/Program Files/Git/bin/bash.exe" -lc "…"`); the train refuses `--apply` otherwise. Export `MMI_RELEASE_VERSION=X.Y.Z` only for a target the tag math cannot derive. A breaking signal in the range (`feat!:`, `BREAKING CHANGE:`) makes the train refuse until shimmed (patch) or declared a major.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Detail moved from SKILL.md (verbatim)
|
|
34
|
+
|
|
35
|
+
**Argument:** `/release minor`, `/release major`, or `/release patch` — a bare bump word, never a `--flag` or env var. No argument → `patch`; a `/release patch` from development is a legitimate ordinary release, `/hotfix` stays the cherry-pick promotion lane.
|
|
36
|
+
|
|
37
|
+
**Bump rules** ([docs/versioning.md](../../docs/versioning.md)): patch is the default and needs nothing. `minor` only for a real feature or significant change, with a one-line reason exported as `MMI_BUMP_REASON`. `major` only with Jervaise's fresh approval in this turn: export `MMI_BUMP_REASON` and `MMI_MAJOR_APPROVED=<exact target version>` (e.g. `5.0.0`) only after that approval, never earlier or from a prior turn. A breaking signal in the range (`feat!:`, `BREAKING CHANGE:`) makes the train refuse until it is shimmed (patch) or declared an owner-gated major.
|
|
38
|
+
|
|
39
|
+
Full-track repos ship exactly what is on `rc` (never `development`): merge `rc → main`, tag `vX.Y.0`, publish the GitHub Release, deploy prod, roll `development` forward. Direct-track repos ship `development → main`, and the release event fires the repo's own deploy/publish workflow (MMI-Hub: `deploy.yml` + `publish.yml`). `rc` is ephemeral: `/rcand` creates its runtime, `/release` retires it after a confirmed prod deploy (`rcRetirement`). A prod release needs Jervaise's yes (principle 12). The board needs no touch: items reached `Done` when their PRs merged to `development`.
|
|
40
|
+
|
|
41
|
+
The JSON is on stdout alone; a stale CLI first prints its self-update notice on stderr and re-runs itself, so parse stdout only, never `2>&1`. Read `ready`, then `findings[]`: each carries `code`, `severity` (`blocker` · `warning` · `healed` · `info`), `source` (`local` · `origin`), `remedy` and `anchor`. `ready: false` → stop and quote every blocker's `code` and `remedy`; an unread origin is never green. `--apply` re-runs this doctor as its step 0 with heal on.
|
|
42
|
+
|
|
43
|
+
Run from the primary checkout on the lane's start branch (`rc`; `development` for direct-track and `--dev`). A Jerv-Hub release on Windows must run under Git Bash (`"C:/Program Files/Git/bin/bash.exe" -lc "…"`) — the train refuses `--apply` before tagging when it is not. Export the bump intent once from the bare argument — `MMI_BUMP_INTENT=minor|major|patch`, unset → `patch`; `MMI_RELEASE_VERSION=X.Y.Z` only for an exact target the tag math cannot derive.
|
|
44
|
+
|
|
45
|
+
Two cases need a summary file. (1) **MMI-Hub** — always: write a fresh 3–6 line neutral summary to `f=$(mkdir -p .jerv/tmp && mktemp .jerv/tmp/release-summary.XXXXXX)` — sourced from the range `origin/main..origin/development`, rewritten in Hub-subsystem terms, never a product or brand name, and never a Jerv-side project (the train refuses such a line). Hub scope is only `mutmutco/MMI-Hub`: never a product's board or a product's deploy state. **Build and verify every line from ONE command's output**, never from commit subjects or PR titles alone: `git log --stat --format='%h %s%n%b' origin/main..origin/development` gives each commit's subject, its full body (where a bundled PR records `Closes #N`) and the files it changed in a single pass. A line whose claim you cannot point to in that output does not go in the file, and every `#N` a Hub line cites must appear there: the train refuses `--apply` on a citation that ships in no commit of the cut. (2) **Any product repo whose META carries `releaseChannel`** (`mmi-cli oracle org project get {owner}/{repo} --json`) — required too: read `releaseLanguage` (default `en`) and write 3–6 lines IN THAT LANGUAGE, in plain words for the project's audience: what changed and why it matters to a user; no commit prefixes, no issue or PR numbers, no file names, no product-internal jargon. The train refuses `--apply` without the file, and raw release notes are never posted to a project channel. A repo with no `releaseChannel` announces nothing, but an mm-work suite repo still requires the summary for its GitHub Release. An mm-work suite repo's summary follows the update-notes template below instead of the 3–6 line rule.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
mkdir -p .jerv/tmp
|
|
49
|
+
mktemp .jerv/tmp/release-receipt.XXXXXX
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Scratch lives under `.jerv/tmp` in every repo: a repo-root `tmp/` may not exist at all, and an agent host guards the primary checkout against root writes outside `.jerv/tmp` — either one aborts the release before its first command runs.
|
|
53
|
+
|
|
54
|
+
Copy the returned pathname into `<result-path>` below; do not rely on shell variables surviving another tool call. For a product without a release channel:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
mmi-cli devops release --apply --watch --json --out "<result-path>"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
mmi-cli devops release --apply --watch --announce-summary-file "<summary-path>" --json --out "<result-path>"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Add `--dev` for a full-track dev → main release. Keep `--watch` to block on the deploy/publish runs. `mmi-cli devops release --apply --ack <sha>[,<sha>…]` only when Jervaise has verified that a main-only commit the hotfix-coverage guard refused is already in the candidate — never ack to save time. The one command merges, runs the version fold (automatic, inside `mmi-cli devops release --apply`) that bumps the manifests unconditionally before the tag, pushes the tag first (`gate.yml` runs on `v*` tags, so the fold commit earns its required checks), waits for the required contexts, pushes `main`, publishes the Release, dispatches or correlates the deploy (`tenant-deploy.yml` only for tenant-container), announces only after the deploy and publish runs are green (the org alerts channel for the Hub; the project's own release channel for a product repo), re-syncs project info, and rolls `development` and `rc` forward. Independent legs run at the same time: deploy and publish are watched together, and once both settle the announcement, the alignment wait and the served-channel legs overlap; a `workflowRuns` row joined that way carries `parallel: true` beside its own conclusion. Nothing here is done by hand.
|
|
65
|
+
|
|
66
|
+
Describe the release in plain words before each command: “Preparing release”, “Waiting for checks”, “Waiting for publishing”, or “Finishing the existing release”. Keep temporary-file preparation separate from the long-running release command so its tool title cannot become a temporary filename; carry the returned path explicitly into the release command when tool calls do not share shell variables. Keep stderr visible: the CLI prints `Release: ` stages and elapsed updates every 30 seconds during long operations, while JSON and `--out` remain the verification record. Never redirect both streams into the result file.
|
|
67
|
+
|
|
68
|
+
Use the actual current stage, never a guessed sequence. Explain a pending result as “Publishing is still pending” or name the unfinished step, then narrate the sanctioned resume command as “Checking the remaining release steps”. Say “Release complete” only after the status fields prove every required follow-up complete. Temporary filenames, `XXXXXX`, receipts, and ledger folding are internal bookkeeping, never a user-facing status.
|
|
69
|
+
|
|
70
|
+
- `workflowRuns` — every run on the release SHA (deploy-model runs, any `push: main` deploy, the repo's own `gate`). On this host, discover them with the bounded run-list read below; filter locally by the exact receipt SHA. If the list hits its 100-row cap or returns no matching SHA, treat the run set as unverified and stop rather than infer completeness. Watch each matching non-success entry to conclusion: `gh run watch <run-id> --repo {owner}/{repo} --exit-status --interval 30`. Name which run is red: `deploy.yml` / `publish.yml` / `tenant-deploy.yml` / `jerv-gateway` is a deploy or publish verdict; a `gate` push run is ordinary CI sharing the SHA.
|
|
71
|
+
- With `--watch`, require every follow-up complete before declaring the cut done. For any pending ledger leg, read [recovery.md](recovery.md) before continuing or starting a new train.
|
|
72
|
+
- `announceNote` — `announced` (to the alerts channel for the Hub, to the project release channel for a product repo), `skipped`, `not announced` (deploy or publish not green; the note says whether a `--resume` carrying the same `--announce-summary-file` will post it), or the failure note. The channel id itself is never printed.
|
|
73
|
+
- `devRollForward` / `rcAlignment` — `pushed`, or `pr-pending` with the alignment PR to land by true merge (Merge floor). An enqueued auto-merge is not evidence of the method; before reporting, read the enqueued method back — `gh pr view <n> --json autoMergeRequest --jq .autoMergeRequest.mergeMethod` — and prove it is `MERGE`. An enqueued `SQUASH` is a stop under the Merge floor, not something to wait out.
|
|
74
|
+
- `versionFold`, `rcRetirement`, `checkout` — `returned`, or the named reason you are still on `main`.
|
|
75
|
+
- `localInstall` (MMI-Hub) — the train installs the release on this machine via `mmi-hub update`; never run `npm i -g`.
|
|
76
|
+
For a private npm surface, read [verification.md](verification.md) before interpreting authentication or package visibility.
|
|
77
|
+
|
|
78
|
+
Then verify Latest with this bounded one-row read; require `isLatest: true` and `tagName` equal to the resolved tag: `gh release list --repo {owner}/{repo} --limit 1 --json tagName,isLatest,publishedAt`.
|
package/skills/secrets/SKILL.md
CHANGED
|
@@ -7,101 +7,39 @@ description: Manage the project vault and granted org-infra secrets.
|
|
|
7
7
|
|
|
8
8
|
# /secrets — two-tier project secrets
|
|
9
9
|
|
|
10
|
-
**Authority:** a project-admin self-serves their own
|
|
11
|
-
role` → `project-admin` + `train`): stageless, `dev`, `rc`, and `main`. Do not redirect them to master for
|
|
12
|
-
an own-project coordinate. Only org-infra grants and cross-project administration stay master-only.
|
|
13
|
-
|
|
14
|
-
Secrets in the org split by **blast radius + who manages them** (not by storage — both tiers are SSM
|
|
15
|
-
SecureString + KMS, and **a value is never echoed to chat or logs**):
|
|
16
|
-
|
|
17
|
-
- **YOUR REPO** — `/mmi-future/<slug>/<KEY>` (the stageless canonical) plus
|
|
18
|
-
`/mmi-future/<slug>/{dev,rc,main}/*` (staged per-stage overrides) for a repo you are project-admin of.
|
|
19
|
-
You **self-serve your own repo's full tree** — the canonical root, dev, rc, AND main prod secrets — via
|
|
20
|
-
`/secrets`, on your **GitHub role alone**, no AWS, no waiting on the master (#2032).
|
|
21
|
-
- **ORG-INFRA** — the shared/infra namespaces (`/mmi-future/{shared,cloudflare,docs,mmi-hub}/*`), at
|
|
22
|
-
**every** tier (their `dev/` holds Hetzner/AWS/CF tokens + Hub tooling). **Crown jewels, master-only.**
|
|
23
|
-
A project-admin reaches one of these only via a master **grant**; the master is unrestricted (master ⊇
|
|
24
|
-
project-admin).
|
|
25
|
-
|
|
26
|
-
For org-infra grants (including read-only wildcards), read [reference.md](reference.md) before granting access.
|
|
27
|
-
|
|
28
|
-
A bare `<KEY>` is the **stageless canonical** at the slug root — one value every stage shares (#2244)
|
|
29
|
-
and the path deploys resolve (#2523). A staged `dev/<KEY>` is a **per-stage override** and WINS for that
|
|
30
|
-
stage at deploy (#2522); `set`/`use` warn (names only) when an override shadows the canonical. The
|
|
31
|
-
`dev`/non-`dev` `tier` field in older JSON is compatibility metadata, not an authority boundary: an
|
|
32
|
-
own-project `main/SECRET_KEY_BASE` or `rc/DB_URL` remains project-admin self-service.
|
|
33
|
-
|
|
34
|
-
**Declare-first (#2528):** the registry catalog is the SSOT; SSM is a projection of it. A `set` to a
|
|
35
|
-
coordinate not declared in the catalog is **rejected** — the error names the attempted path and the fix.
|
|
36
|
-
Declare the key first via `mmi-cli oracle org project set <owner/repo> --secrets-file <catalog.json>` (`stages: []`
|
|
37
|
-
= the shared stageless canonical, `stages: ["dev"]` = a per-stage override), then retry. See what is
|
|
38
|
-
declared with `mmi-cli vault secrets catalog` or `secrets list`; ask for a key you lack via `mmi-cli vault secrets
|
|
39
|
-
request <KEY>`. There is no master bypass. `rm` of an undeclared path stays allowed, so cleanup keeps
|
|
40
|
-
working. Google OAuth is one stageless pair per repo: bare `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET`
|
|
41
|
-
at the slug root (the staged `{dev,rc,main}/GOOGLE_*` shape is retired; `org oauth set-creds` writes the
|
|
42
|
-
bare keys).
|
|
43
|
-
|
|
44
|
-
All ops run through `mmi-cli vault secrets …`, which calls the org backend with the caller's `gh` token; the
|
|
45
|
-
backend re-verifies **project-admin-of-this-repo** and the **vault namespace** server-side and does the scoped
|
|
46
|
-
SSM op. This skill never touches AWS.
|
|
10
|
+
**Authority:** a project-admin (`mmi-cli oracle org access role` → `project-admin` + `train`) self-serves their own repo's full vault tree: stageless, `dev`, `rc`, `main`. Project-admin = repo `admin`, or `write`/`maintain` plus the registry `projectAdmins` entry; master = org owner. The backend checks both server-side. Only org-infra grants and cross-project administration are master-only. Every write is attributable (actor + repo + KEY name, never the value). A value is never shown (principle 11).
|
|
47
11
|
|
|
48
|
-
|
|
12
|
+
- **YOUR REPO** — `/mmi-future/<slug>/<KEY>` (stageless canonical, one value for every stage, the path deploys resolve) plus `/mmi-future/<slug>/{dev,rc,main}/*` (per-stage overrides). A staged `dev/<KEY>` WINS for that stage at deploy; `set`/`use` warn (names only) when an override shadows the canonical. The `dev`/non-`dev` `tier` field in older JSON is compatibility metadata, not an authority boundary.
|
|
13
|
+
- **ORG-INFRA** — `/mmi-future/{shared,cloudflare,docs,mmi-hub}/*` at every tier. Master-only; a project-admin reaches one only via a master **grant**. For grants (including read-only wildcards), read [reference.md](reference.md) first.
|
|
14
|
+
|
|
15
|
+
**Declare-first:** the registry catalog is the SSOT; SSM is its projection. A `set` to an undeclared coordinate is rejected (the error names the path and fix); no master bypass. Declare with `mmi-cli oracle org project set <owner/repo> --secrets-file <catalog.json>` (`stages: []` = stageless canonical, `stages: ["dev"]` = override), then retry. See declared keys with `mmi-cli vault secrets catalog` or `secrets list`; ask for a missing key with `mmi-cli vault secrets request <KEY>`. `rm` of an undeclared path stays allowed. Google OAuth is one stageless pair at the slug root, bare `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` (`org oauth set-creds` writes them; the staged shape is retired).
|
|
49
16
|
|
|
50
|
-
|
|
51
|
-
|
|
17
|
+
All ops run through `mmi-cli vault secrets …`, which calls the org backend with the caller's `gh` token; the backend re-verifies project-admin and namespace and does the scoped SSM op. This skill never touches AWS.
|
|
18
|
+
|
|
19
|
+
## Step 0 — orient
|
|
52
20
|
|
|
53
21
|
```bash
|
|
54
|
-
mmi-cli vault secrets list
|
|
22
|
+
mmi-cli vault secrets list # names + tier + * on those you can write; never values
|
|
55
23
|
```
|
|
56
24
|
|
|
57
|
-
`secrets: no registry META` or `Hub API unreachable` →
|
|
58
|
-
is missing, or the Hub API is unavailable. Run `mmi-cli oracle org project get <owner/repo>` to distinguish those cases;
|
|
59
|
-
a master-admin backfills the registry before secrets can be resolved.
|
|
25
|
+
`secrets: no registry META` or `Hub API unreachable` → repo unregistered, GitHub auth missing, or Hub down. Run `mmi-cli oracle org project get <owner/repo>` to tell which; a master-admin backfills the registry.
|
|
60
26
|
|
|
61
27
|
## Step 1 — the verb
|
|
62
28
|
|
|
63
|
-
|
|
29
|
+
Current repo by default; `--repo owner/Name` targets another (you must be its project-admin).
|
|
64
30
|
|
|
65
31
|
```bash
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
mmi-cli vault secrets
|
|
69
|
-
|
|
70
|
-
# Write / rotate — the VALUE is read from stdin, NEVER an argument (so it can't leak into shell history
|
|
71
|
-
# or process args). Pipe it in:
|
|
72
|
-
printf %s "$THE_VALUE" | mmi-cli vault secrets set SCRAPER_API_KEY
|
|
73
|
-
|
|
74
|
-
# Validate a known provider key without printing its value:
|
|
75
|
-
mmi-cli vault secrets verify RECALL_API_KEY
|
|
76
|
-
|
|
77
|
-
# Remove:
|
|
32
|
+
mmi-cli vault secrets use SCRAPER_API_KEY -- <cmd> # consume keyless: injected into env, never printed
|
|
33
|
+
printf %s "$THE_VALUE" | mmi-cli vault secrets set SCRAPER_API_KEY # write/rotate: value from stdin, never an argument
|
|
34
|
+
mmi-cli vault secrets verify RECALL_API_KEY # validate a known provider key
|
|
78
35
|
mmi-cli vault secrets rm SCRAPER_API_KEY
|
|
79
36
|
```
|
|
80
37
|
|
|
81
|
-
|
|
82
|
-
confirmation prints the **name and tier only**, never the value.
|
|
83
|
-
|
|
84
|
-
On Windows, read [reference.md](reference.md) before wrapping a multiline command.
|
|
85
|
-
|
|
86
|
-
For rotation, org-infra elevation, new-key coordinates, or tier-to-tier copies, read [reference.md](reference.md) before the operation.
|
|
38
|
+
There is no value argument; confirmation prints name and tier only. On Windows, read [reference.md](reference.md) before wrapping a multiline command. For rotation, org-infra elevation, new-key coordinates, or tier-to-tier copies, read [reference.md](reference.md) first.
|
|
87
39
|
|
|
88
|
-
|
|
40
|
+
Runtime consumes declared keys through its scoped broker token (central deploy injects the declared stage set, no repo `.env`); CI reads keylessly through its OIDC role. Treat every secret as write-once.
|
|
89
41
|
|
|
90
|
-
|
|
91
|
-
consume one keyless with `secrets use <KEY> -- <cmd>` (#2844). Treat every secret as write-once.
|
|
92
|
-
- Authority is **GitHub**: project-admin = repo `admin`, or repo `write`/`maintain` plus the registry `projectAdmins` entry; master =
|
|
93
|
-
org owner. The backend checks both with the org App token, so the decision is server-side (your token
|
|
94
|
-
scope can't widen it).
|
|
95
|
-
- Runtime consumes declared keys through its scoped broker token (and central deploy injects the declared
|
|
96
|
-
stage set without a repo `.env`); CI reads keylessly through its OIDC role. Neither uses raw `/secrets`
|
|
97
|
-
output. `secrets use <KEY>` is the safe local command-consumption path.
|
|
98
|
-
- Every self-service write is **attributable** — the backend logs actor + repo + KEY name (never the value).
|
|
42
|
+
## Retro
|
|
99
43
|
|
|
100
|
-
|
|
101
|
-
Before your final report, answer one question honestly: did **this skill's own instructions** misfire
|
|
102
|
-
this run — ambiguous wording, a misleading message, or an environment failure it should have warned
|
|
103
|
-
about? (Process only — never the user's code or task; e.g. a canonical-name or tier mix-up, or a step
|
|
104
|
-
that risked echoing a value.) If yes, file **one** lesson and move on; a clean run is silent (hard cap:
|
|
105
|
-
one per run). It lands on the owning board (deduped) and is fixed only via a reviewed PR — never edit the
|
|
106
|
-
skill live; the retro is advisory, so if the call fails, note it and continue. File through MMI:
|
|
44
|
+
If this skill's instructions misfired (process only, e.g. a canonical-name or tier mix-up), file one lesson (one per run; if the call fails, note it and continue):
|
|
107
45
|
`mmi-cli learning skill-lesson --skill secrets --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
|
|
@@ -65,3 +65,44 @@ mmi-cli vault secrets copy --from rc --to dev --keys RECALL_API_KEY --dry-run
|
|
|
65
65
|
```
|
|
66
66
|
Prefer this over manual copy piping — audit-logged, blocklist enforced.
|
|
67
67
|
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## Detail moved from SKILL.md (verbatim)
|
|
71
|
+
|
|
72
|
+
**Authority:** a project-admin self-serves their own product repo's full vault tree (`mmi-cli oracle org access
|
|
73
|
+
role` → `project-admin` + `train`): stageless, `dev`, `rc`, and `main`. Do not redirect them to master for
|
|
74
|
+
an own-project coordinate. Only org-infra grants and cross-project administration stay master-only.
|
|
75
|
+
|
|
76
|
+
A bare `<KEY>` is the **stageless canonical** at the slug root — one value every stage shares (#2244)
|
|
77
|
+
and the path deploys resolve (#2523). A staged `dev/<KEY>` is a **per-stage override** and WINS for that
|
|
78
|
+
stage at deploy (#2522); `set`/`use` warn (names only) when an override shadows the canonical. The
|
|
79
|
+
`dev`/non-`dev` `tier` field in older JSON is compatibility metadata, not an authority boundary: an
|
|
80
|
+
own-project `main/SECRET_KEY_BASE` or `rc/DB_URL` remains project-admin self-service.
|
|
81
|
+
|
|
82
|
+
**Declare-first (#2528):** the registry catalog is the SSOT; SSM is a projection of it. A `set` to a
|
|
83
|
+
coordinate not declared in the catalog is **rejected** — the error names the attempted path and the fix.
|
|
84
|
+
Declare the key first via `mmi-cli oracle org project set <owner/repo> --secrets-file <catalog.json>` (`stages: []`
|
|
85
|
+
= the shared stageless canonical, `stages: ["dev"]` = a per-stage override), then retry. See what is
|
|
86
|
+
declared with `mmi-cli vault secrets catalog` or `secrets list`; ask for a key you lack via `mmi-cli vault secrets
|
|
87
|
+
request <KEY>`. There is no master bypass. `rm` of an undeclared path stays allowed, so cleanup keeps
|
|
88
|
+
working. Google OAuth is one stageless pair per repo: bare `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET`
|
|
89
|
+
at the slug root (the staged `{dev,rc,main}/GOOGLE_*` shape is retired; `org oauth set-creds` writes the
|
|
90
|
+
bare keys).
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# CONSUME a secret keyless — injected into the command's env, NEVER printed (raw `secrets get` was
|
|
94
|
+
# removed, the floor wins, #2844):
|
|
95
|
+
mmi-cli vault secrets use SCRAPER_API_KEY -- <cmd>
|
|
96
|
+
|
|
97
|
+
**Never** pass a value as an argument (`secrets set KEY thevalue` is wrong — there is no value arg). The
|
|
98
|
+
confirmation prints the **name and tier only**, never the value.
|
|
99
|
+
|
|
100
|
+
- **Never echo a value** — not in chat, a commit, a log, or an issue. No command emits a value to stdout;
|
|
101
|
+
consume one keyless with `secrets use <KEY> -- <cmd>` (#2844). Treat every secret as write-once.
|
|
102
|
+
- Authority is **GitHub**: project-admin = repo `admin`, or repo `write`/`maintain` plus the registry `projectAdmins` entry; master =
|
|
103
|
+
org owner. The backend checks both with the org App token, so the decision is server-side (your token
|
|
104
|
+
scope can't widen it).
|
|
105
|
+
- Runtime consumes declared keys through its scoped broker token (and central deploy injects the declared
|
|
106
|
+
stage set without a repo `.env`); CI reads keylessly through its OIDC role. Neither uses raw `/secrets`
|
|
107
|
+
output. `secrets use <KEY>` is the safe local command-consumption path.
|
|
108
|
+
- Every self-service write is **attributable** — the backend logs actor + repo + KEY name (never the value).
|
package/skills/stage/SKILL.md
CHANGED
|
@@ -7,26 +7,11 @@ description: Run a local test stage or personal cloud dev stage with --live.
|
|
|
7
7
|
|
|
8
8
|
# /stage — local test environment
|
|
9
9
|
|
|
10
|
-
A throwaway **local** environment
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Use `/stage` as the normal path for local previews, smoke tests, and Playwright targets. If the user
|
|
16
|
-
already asked to run or preview the app, that is enough authorization to start it; when intent is unclear,
|
|
17
|
-
ask before creating or destroying a stage. Manual dev-server commands are allowed when the user explicitly
|
|
18
|
-
wants a bypass or when a bounded diagnostic needs one, but say why. If the stage path itself fails, diagnose
|
|
19
|
-
from `mmi-cli stage --json`, `tmp/stage/state.json`, process/port/container evidence, and file Hub/org-default
|
|
20
|
-
friction instead of silently working around it.
|
|
21
|
-
|
|
22
|
-
The stage recipe is the **registry-derived default** for plumbing-free product repos: a `tenant-container`
|
|
23
|
-
repo that ships `docker-compose.yml` and has a Hub registry `portRange` needs **no committed config**.
|
|
24
|
-
`mmi-cli stage` derives a default compose stage — run `docker compose build --no-cache`, run `docker compose
|
|
25
|
-
up -d`, choose a free port from the registry range, and report the local URL (e.g. `http://127.0.0.1:3700/`).
|
|
26
|
-
The commands are shell-aware and `--apply` runs them cross-shell. Board, deploy, secret, and project registry
|
|
27
|
-
facts all live in the Hub registry — no repo-local control-plane file.
|
|
28
|
-
|
|
29
|
-
For vault/env passthrough or build-time secret setup, read [reference.md](reference.md) before running the stage.
|
|
10
|
+
A throwaway **local** environment (dev server or local stack, plus Playwright where used) for the current branch. Off the promotion train: no version effect, no deploy. It lives in a gitignored workspace, force-kills the previous stage in this worktree before starting, and is decommissioned when done.
|
|
11
|
+
|
|
12
|
+
`/stage` is the normal path for previews, smoke tests and Playwright targets; a request to run or preview the app is enough to start it. A manual dev-server command is fine for a bounded diagnostic or a requested bypass; say why. If the stage path fails, diagnose from `mmi-cli stage --json`, `tmp/stage/state.json` and process/port/container evidence, and file Hub/org-default friction instead of silently working around it.
|
|
13
|
+
|
|
14
|
+
A `tenant-container` repo with `docker-compose.yml` and a Hub registry `portRange` needs no committed config: `mmi-cli stage` derives `docker compose build --no-cache`, `docker compose up -d`, a free port from the range, and the local URL (e.g. `http://127.0.0.1:3700/`). Board, deploy, secret and project facts live in the Hub registry, not a repo file. For vault/env passthrough or build-time secrets, read [reference.md](reference.md).
|
|
30
15
|
|
|
31
16
|
## Step 0 — inspect the plan
|
|
32
17
|
|
|
@@ -34,48 +19,21 @@ For vault/env passthrough or build-time secret setup, read [reference.md](refere
|
|
|
34
19
|
mmi-cli stage --json
|
|
35
20
|
```
|
|
36
21
|
|
|
37
|
-
|
|
38
|
-
means neither a usable local recipe nor a derivable default exists — the message names the missing fact
|
|
39
|
-
(deployModel, `docker-compose.yml`, or registry `portRange`; `.env.example` is **not** required — #2655).
|
|
40
|
-
On a `deployModel: vercel` repo the receipt also carries `preview` — the current branch's latest
|
|
41
|
-
Vercel **Preview** deployment (`state`, `url`) read from the GitHub Deployments the Vercel GitHub app
|
|
42
|
-
posts — and the text output ends with a `vercel preview (<branch>)` line. Report that URL as the branch
|
|
43
|
-
preview alongside the local stage; no `preview.deployment` means the branch was not pushed yet or the
|
|
44
|
-
Vercel GitHub app is not connected. There is no box stage on a vercel repo: `--live` refuses.
|
|
45
|
-
When the gap is a missing Hub registry `portRange`, the JSON receipt also carries `recovery` with
|
|
46
|
-
`mmi-cli stage port-range <owner/repo>` (#5539) — assign the block, then re-run `/stage`. That gap does not
|
|
47
|
-
mean the repo's Hub registry/org project setup is missing; it means local stage derivation cannot pick a
|
|
48
|
-
collision-safe port until META.portRange exists.
|
|
49
|
-
|
|
50
|
-
## Step 1 — run the stage
|
|
51
|
-
|
|
52
|
-
A stage is **per worktree**. The CLI force-stops only the previous stage **in this worktree**, runs
|
|
53
|
-
`stage.build`, starts `stage.up`, records `tmp/stage/state.json`, picks a free port from the registry
|
|
54
|
-
range (skipping ports reserved by sibling worktrees), and polls `stage.healthUrl` when configured.
|
|
55
|
-
Recipes run in Bash, including Git Bash on Windows. Use Bash syntax for build, up and teardown;
|
|
56
|
-
legacy cmd `set VAR=value` and PowerShell `$env:VAR` recipes must be converted to Bash or Node scripts.
|
|
57
|
-
Windows requires Git Bash or an absolute `SHELL` path to its `bash.exe`; there is no cmd fallback.
|
|
58
|
-
Use `--port` to pin a port when needed:
|
|
22
|
+
`source` is `derived`/`local`/`none`; when derived, `url` is the local URL. `none` means no usable recipe or derivable default; the message names the missing fact (deployModel, `docker-compose.yml`, or registry `portRange`; `.env.example` is not required). A missing `portRange` adds `recovery` with `mmi-cli stage port-range <owner/repo>`: assign the block, re-run `/stage` (the Hub registry itself is fine; stage just cannot pick a collision-safe port).
|
|
59
23
|
|
|
60
|
-
|
|
61
|
-
mmi-cli stage run --apply
|
|
62
|
-
mmi-cli stage run --apply --port 5180
|
|
63
|
-
```
|
|
24
|
+
On `deployModel: vercel` the receipt carries `preview` (latest Vercel Preview `state`, `url` from GitHub Deployments); report that URL as the branch preview. No `preview.deployment` = branch unpushed or Vercel GitHub app not connected. There is no box stage on vercel: `--live` refuses.
|
|
64
25
|
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
mmi-cli stage run --apply --timeout-ms 120000
|
|
68
|
-
```
|
|
26
|
+
## Step 1 — run
|
|
69
27
|
|
|
70
|
-
|
|
71
|
-
— never tracked.
|
|
28
|
+
A stage is per worktree: the CLI stops this worktree's previous stage, runs `stage.build`, starts `stage.up`, records `tmp/stage/state.json` (cwd, branch, commit), picks a free port from the registry range (skipping sibling worktrees' ports), and polls `stage.healthUrl` if set. Sibling worktrees keep their own stages; no need to stop one first. Recipes run in Bash (Git Bash on Windows, or an absolute `SHELL` path to its `bash.exe`; no cmd fallback), so convert `set VAR=value` or `$env:VAR` recipes to Bash or Node. For `jervaise`, continuity keys on branch; use a distinct North Star slug per parallel grind.
|
|
72
29
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
30
|
+
```bash
|
|
31
|
+
mmi-cli stage run --apply
|
|
32
|
+
mmi-cli stage run --apply --port 5180 # pin a port
|
|
33
|
+
mmi-cli stage run --apply --timeout-ms 120000 # slow stacks
|
|
34
|
+
```
|
|
77
35
|
|
|
78
|
-
When grinding or issue acceptance criteria exist, read [smoke.md](smoke.md) and run its post-smoke panel before teardown.
|
|
36
|
+
All artifacts (build output, screenshots, traces, local DB files) stay under untracked `tmp/stage/`. When grinding or issue acceptance criteria exist, read [smoke.md](smoke.md) and run its post-smoke panel before teardown.
|
|
79
37
|
|
|
80
38
|
## Step 2 — stop when done
|
|
81
39
|
|
|
@@ -83,27 +41,15 @@ When grinding or issue acceptance criteria exist, read [smoke.md](smoke.md) and
|
|
|
83
41
|
mmi-cli stage stop --apply
|
|
84
42
|
```
|
|
85
43
|
|
|
86
|
-
Stop
|
|
87
|
-
If the user clearly wants the preview to stay up, leave it running and report that. The next `/stage` also
|
|
88
|
-
stops the previous recorded stage before starting, so a stale server does not linger between runs. For the
|
|
89
|
-
registry-derived Docker Compose default, stop also runs the recorded compose teardown (`docker compose down`)
|
|
90
|
-
from the original stage working directory. Stop re-fetches the declared dev runtime secrets so that `down`
|
|
91
|
-
can interpolate the same file (`${POSTGRES_PASSWORD:?}`, `${PORT:?}`) — secrets never come from the state
|
|
92
|
-
file (#6351). A vault-native repo with no `.env` gets `PORT` defaulted to the bound stage port.
|
|
44
|
+
Stop when work is done, before switching context, or before another stage; leave it up if the user wants the preview, and report that. For the Docker Compose default, stop runs `docker compose down` from the original working directory, re-fetching the declared dev runtime secrets so `${POSTGRES_PASSWORD:?}` and `${PORT:?}` interpolate (secrets never come from the state file); a vault-native repo with no `.env` gets `PORT` defaulted to the bound port.
|
|
93
45
|
|
|
94
|
-
For a personal cloud dev stage (`--live`), read [live.md](live.md) before offering, applying
|
|
46
|
+
For a personal cloud dev stage (`--live`), read [live.md](live.md) before offering, applying or tearing it down.
|
|
95
47
|
|
|
96
48
|
## Step 3 — report
|
|
97
49
|
|
|
98
|
-
|
|
50
|
+
Stage URL, what's running, workspace path (`tmp/stage/`), teardown command. For Playwright output placement, extra services, or stale Docker/env troubleshooting, read [reference.md](reference.md) Notes.
|
|
99
51
|
|
|
100
|
-
|
|
52
|
+
## Retro
|
|
101
53
|
|
|
102
|
-
|
|
103
|
-
Before your final report, answer one question honestly: did **this skill's own instructions** misfire
|
|
104
|
-
this run — ambiguous wording, a misleading message, or an environment failure it should have warned
|
|
105
|
-
about? (Process only — never the user's code or task; e.g. a teardown that left a port bound, or a
|
|
106
|
-
Playwright output path aimed at the repo root.) If yes, file **one** lesson and move on; a clean run is
|
|
107
|
-
silent (hard cap: one per run). It lands on the owning board (deduped) and is fixed only via a reviewed PR —
|
|
108
|
-
never edit the skill live; the retro is advisory, so if the call fails, note it and continue. File through MMI:
|
|
54
|
+
If this skill's instructions misfired (process only, e.g. a teardown that left a port bound), file one lesson (one per run; if the call fails, note it and continue):
|
|
109
55
|
`mmi-cli learning skill-lesson --skill stage --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
|
|
@@ -47,3 +47,52 @@ or print the PAT.
|
|
|
47
47
|
from an updated `.env.example` — it warns on stderr and keeps the stale file. Delete `.env` (or merge in the
|
|
48
48
|
new keys by hand) when `.env.example` changes, then re-run `/stage`.
|
|
49
49
|
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## Detail moved from SKILL.md (verbatim)
|
|
53
|
+
|
|
54
|
+
The stage recipe is the **registry-derived default** for plumbing-free product repos: a `tenant-container`
|
|
55
|
+
repo that ships `docker-compose.yml` and has a Hub registry `portRange` needs **no committed config**.
|
|
56
|
+
`mmi-cli stage` derives a default compose stage — run `docker compose build --no-cache`, run `docker compose
|
|
57
|
+
up -d`, choose a free port from the registry range, and report the local URL (e.g. `http://127.0.0.1:3700/`).
|
|
58
|
+
The commands are shell-aware and `--apply` runs them cross-shell. Board, deploy, secret, and project registry
|
|
59
|
+
facts all live in the Hub registry — no repo-local control-plane file.
|
|
60
|
+
|
|
61
|
+
The JSON reports `source` (`derived` / `local` / `none`) and, when derived, the local `url`. `source: none`
|
|
62
|
+
means neither a usable local recipe nor a derivable default exists — the message names the missing fact
|
|
63
|
+
(deployModel, `docker-compose.yml`, or registry `portRange`; `.env.example` is **not** required — #2655).
|
|
64
|
+
On a `deployModel: vercel` repo the receipt also carries `preview` — the current branch's latest
|
|
65
|
+
Vercel **Preview** deployment (`state`, `url`) read from the GitHub Deployments the Vercel GitHub app
|
|
66
|
+
posts — and the text output ends with a `vercel preview (<branch>)` line. Report that URL as the branch
|
|
67
|
+
preview alongside the local stage; no `preview.deployment` means the branch was not pushed yet or the
|
|
68
|
+
Vercel GitHub app is not connected. There is no box stage on a vercel repo: `--live` refuses.
|
|
69
|
+
When the gap is a missing Hub registry `portRange`, the JSON receipt also carries `recovery` with
|
|
70
|
+
`mmi-cli stage port-range <owner/repo>` (#5539) — assign the block, then re-run `/stage`. That gap does not
|
|
71
|
+
mean the repo's Hub registry/org project setup is missing; it means local stage derivation cannot pick a
|
|
72
|
+
collision-safe port until META.portRange exists.
|
|
73
|
+
|
|
74
|
+
A stage is **per worktree**. The CLI force-stops only the previous stage **in this worktree**, runs
|
|
75
|
+
`stage.build`, starts `stage.up`, records `tmp/stage/state.json`, picks a free port from the registry
|
|
76
|
+
range (skipping ports reserved by sibling worktrees), and polls `stage.healthUrl` when configured.
|
|
77
|
+
Recipes run in Bash, including Git Bash on Windows. Use Bash syntax for build, up and teardown;
|
|
78
|
+
legacy cmd `set VAR=value` and PowerShell `$env:VAR` recipes must be converted to Bash or Node scripts.
|
|
79
|
+
Windows requires Git Bash or an absolute `SHELL` path to its `bash.exe`; there is no cmd fallback.
|
|
80
|
+
Use `--port` to pin a port when needed:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
mmi-cli stage run --apply
|
|
84
|
+
mmi-cli stage run --apply --port 5180
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
A local stage is bound to the worktree that started it. Concurrent worktrees on one machine each keep
|
|
88
|
+
their own stage on separate ports — you do not need to stop one before starting another. For `jervaise`, continuity
|
|
89
|
+
keys on branch; use a distinct North Star slug per parallel grind or feature. Stage JSON/state records
|
|
90
|
+
the starting `cwd` plus git branch/commit when available.
|
|
91
|
+
|
|
92
|
+
Stop the stage when the work is done, before switching context, or before replacing it with another stage.
|
|
93
|
+
If the user clearly wants the preview to stay up, leave it running and report that. The next `/stage` also
|
|
94
|
+
stops the previous recorded stage before starting, so a stale server does not linger between runs. For the
|
|
95
|
+
registry-derived Docker Compose default, stop also runs the recorded compose teardown (`docker compose down`)
|
|
96
|
+
from the original stage working directory. Stop re-fetches the declared dev runtime secrets so that `down`
|
|
97
|
+
can interpolate the same file (`${POSTGRES_PASSWORD:?}`, `${PORT:?}`) — secrets never come from the state
|
|
98
|
+
file (#6351). A vault-native repo with no `.env` gets `PORT` defaulted to the bound stage port.
|