@mutmutco/opencode-mmi 2.48.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/dist/index.d.ts +35 -0
- package/dist/index.js +194 -0
- package/package.json +44 -0
- package/skills/_shared/doctrine.md +238 -0
- package/skills/bootstrap/SKILL.md +419 -0
- package/skills/bootstrap/seeds/Dockerfile.template +25 -0
- package/skills/bootstrap/seeds/README.template.md +36 -0
- package/skills/bootstrap/seeds/architecture.template.md +19 -0
- package/skills/bootstrap/seeds/components.json.template +31 -0
- package/skills/bootstrap/seeds/cursor-environment.template.json +3 -0
- package/skills/bootstrap/seeds/cursor-rules.template.mdc +11 -0
- package/skills/bootstrap/seeds/design-system.paths.template.json +8 -0
- package/skills/bootstrap/seeds/docker-compose.template.yml +17 -0
- package/skills/bootstrap/seeds/gate.template.yml +42 -0
- package/skills/bootstrap/seeds/google-login.template.md +35 -0
- package/skills/bootstrap/seeds/manifest.json +32 -0
- package/skills/bootstrap/seeds/mcp-playwright.template.json +13 -0
- package/skills/bootstrap/seeds/mmi-product-required-checks.template.json +23 -0
- package/skills/browser-automation/SKILL.md +137 -0
- package/skills/build/SKILL.md +237 -0
- package/skills/build/references/halt-report.md +38 -0
- package/skills/build/references/loops.md +13 -0
- package/skills/build/references/worked-example.md +18 -0
- package/skills/build/templates/campaign-northstar.md +40 -0
- package/skills/coop/SKILL.md +77 -0
- package/skills/grind/SKILL.md +469 -0
- package/skills/grind/references/auto.md +107 -0
- package/skills/grind/references/build-notes.md +56 -0
- package/skills/grind/references/routing.md +76 -0
- package/skills/grind/references/verify.md +83 -0
- package/skills/grind/templates/saga-snapshot.md +28 -0
- package/skills/grind/templates/synthesize-panel.md +104 -0
- package/skills/handoff/SKILL.md +67 -0
- package/skills/hotfix/SKILL.md +219 -0
- package/skills/mmi/SKILL.md +372 -0
- package/skills/rcand/SKILL.md +169 -0
- package/skills/release/SKILL.md +309 -0
- package/skills/secrets/SKILL.md +137 -0
- package/skills/stage/SKILL.md +150 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bootstrap
|
|
3
|
+
description: Provision a repo into the MMI org — branches, ruleset, the Project board, registry META, secrets + OIDC, the plugin, and doc seed. Master-admin only. Use when onboarding, adding, or provisioning a repo into the org, setting up a new project repo, making a repo a first-class org citizen, or invoking /bootstrap.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /bootstrap — provision a repo into the org
|
|
7
|
+
|
|
8
|
+
The one-time onboarding that turns a repo into a first-class org citizen. **Master-admin only, run from
|
|
9
|
+
`MMI-Hub` (the hub).** Every step operates org-level resources (Project, Ruleset, org secrets, member
|
|
10
|
+
access) **through the GitHub App's installation token** — not a human credential — so the gate is who may
|
|
11
|
+
invoke the skill (the master holds the App key), not the caller's GitHub role.
|
|
12
|
+
|
|
13
|
+
Bootstrap operates on the target repo entirely through the App — **no per-repo checkout**. The repo must
|
|
14
|
+
already be named on the taxonomy `<CATEGORY>-<PascalName>`.
|
|
15
|
+
|
|
16
|
+
## Seed sources + create-vs-upgrade
|
|
17
|
+
|
|
18
|
+
The org-standard scaffolding is a **machine-readable manifest** — `skills/bootstrap/seeds/manifest.json`
|
|
19
|
+
(loaded by the CLI; `mmi-cli bootstrap --apply` consumes it). Every seed carries an **ownership**:
|
|
20
|
+
|
|
21
|
+
- **`org`** — org-delivered, **overwritten on upgrade** (the org owns it): `.claude/settings.json`, the issue
|
|
22
|
+
templates, and the spine `AGENTS.md`/`CLAUDE.md`. `source: self` = copied verbatim from MMI-Hub's own
|
|
23
|
+
current file, so the spine is **seeded at bootstrap** (a fresh repo verifies green immediately, #927); the
|
|
24
|
+
fanout pipeline (`.github/fanout-targets.json`) still owns ongoing spine-change **updates**. Board
|
|
25
|
+
moves are central (the Hub webhook), so **no per-repo board workflow is stamped**.
|
|
26
|
+
- **`repo`** — created **once on a fresh bootstrap**, **never clobbered on upgrade** (the repo owns its
|
|
27
|
+
content): `README.md`, `architecture.md`, `.cursor/environment.json`, `.cursor/rules/<slug>.mdc`.
|
|
28
|
+
These render `seeds/*.template.*` with `{{PLACEHOLDERS}}`.
|
|
29
|
+
|
|
30
|
+
So **create** stamps every seed; **upgrade** refreshes the `org` seeds and adds any *missing* `repo` seeds
|
|
31
|
+
without overwriting existing repo-owned files (D35: legacy docs are archived + written fresh, never carried
|
|
32
|
+
over verbatim). The manifest's `labels` list is the canonical 7-label set. The per-step instructions below
|
|
33
|
+
are the manual path; `--apply` automates them from this manifest.
|
|
34
|
+
|
|
35
|
+
**CLI-release gap.** A new topology value (a `--project-type`, `--deploy-model`, or `--release-track` added
|
|
36
|
+
since the last release train) lands on `development` but is not in the published/installed `mmi-cli` until a
|
|
37
|
+
release train ships it. So bootstrapping a repo that needs a just-merged topology requires a CLI that
|
|
38
|
+
includes it: run a `/release` train first, **or** invoke a local dev build —
|
|
39
|
+
`node <MMI-Hub checkout>/cli/dist/index.cjs bootstrap apply ...` from a `development` checkout (rebuild
|
|
40
|
+
`dist` first: `npm --prefix cli ci && npm --prefix cli run build`) — instead of the installed `mmi-cli`. The
|
|
41
|
+
installed CLI rejects an unknown enum with no hint that it merely lags `development`.
|
|
42
|
+
|
|
43
|
+
## Step 0 — capability shape (confirm the four axes before any mutation)
|
|
44
|
+
|
|
45
|
+
Bootstrap is **destructive to undo**: a wrong shape means converting in place later — deleting protected
|
|
46
|
+
branches, temporarily disabling the org-wide `mmi-train-floor` ruleset (which affects every repo for that
|
|
47
|
+
window), and tearing down train artifacts (#1450, the MMD-UI case). So **before Step 0a touches anything**,
|
|
48
|
+
surface and **confirm all four topology axes with the master** — present the recommended default for each,
|
|
49
|
+
never apply it silently. Use the structured-question UI; one question per axis (or one grouped confirm).
|
|
50
|
+
|
|
51
|
+
- **`class`** — `deployable` (ships an app/service; full or direct train) · `content` (KB/docs/design-system;
|
|
52
|
+
trunk, `main`-only). *Controls the branch model.* Recommend from what the repo **is**, not a fixed default.
|
|
53
|
+
- **`project-type`** — e.g. `web-app`, `cli-tool`, `worker`, `desktop-game`, `content`. *Controls which Hub
|
|
54
|
+
services attach.*
|
|
55
|
+
- **`deploy-model`** — e.g. `tenant-container`, `none`, `content`. *Controls the deploy path.*
|
|
56
|
+
- **`release-track`** — `full` (development·rc·main) · `direct` (development·main, skips rc) · `trunk`
|
|
57
|
+
(`main` only). *The branch set follows the track, not just the class (#1097).*
|
|
58
|
+
|
|
59
|
+
**Dashboard opt-in (`--dashboard`, #1452).** Orthogonal to the four axes — an **additive** flag, not a new
|
|
60
|
+
type. Pass `--dashboard` when the repo is an MMI dashboard that consumes the `@mutmutco` design system; it
|
|
61
|
+
persists `dashboard: true` on the registry META and seeds one extra repo-owned file, `components.json`,
|
|
62
|
+
pre-pointed at the registry (`https://ui.mutatismutandis.co/r/{name}.json`) plus `design-system.paths.json`
|
|
63
|
+
(tsconfig path aliases → the gitignored `.mmi/design-system/components/` cache doctor maintains). Registry
|
|
64
|
+
component **files are not committed** — `mmi-cli doctor --apply` pulls them into `.mmi/` when stale. List
|
|
65
|
+
desired components in `components.json` → `mmi.installed`. It changes **no** other
|
|
66
|
+
axis — a dashboard is still the standard deployable `web-app` / `tenant-container` (commonly `direct` track,
|
|
67
|
+
like MMD-UI). The app UI itself is scaffolded from the MMD-UI `apps/starter` (a separate step), not copied by
|
|
68
|
+
bootstrap. Recommend it for a new dashboard repo; omit it everywhere else (a plain repo's META and seed set
|
|
69
|
+
are byte-identical to before this flag existed). After register, registry META `dashboard` is the SSOT —
|
|
70
|
+
`bootstrap apply` re-seeds dashboard-gated files when META is true (no `--dashboard` needed); toggle with
|
|
71
|
+
`mmi-cli project set <repo> --var dashboard=true|false` (project-admin or master). See the dashboard guide:
|
|
72
|
+
MM-KB `kb/guides/dashboard-ui.md`.
|
|
73
|
+
|
|
74
|
+
For a **deployable** repo, also capture the **gate runtime** (`node` | `python`), the **check command**, and
|
|
75
|
+
the **working directory** — these feed the product gate (`--var GATE_RUNTIME=`, `--var GATE_CMD=`,
|
|
76
|
+
`--var GATE_WORKDIR=`, and `--var GATE_CACHE_DEP_PATH=` for a non-root Node lockfile; see Step 5 / the
|
|
77
|
+
"Product gate + required checks" note below). Default to `node` at the repo root; recommend `python` when the
|
|
78
|
+
repo's app is Python.
|
|
79
|
+
|
|
80
|
+
A **content/trunk** choice provisions: `main`-only (no `rc`), **no** `.github/workflows/gate.yml` and **no**
|
|
81
|
+
product required-check ruleset, and a `projects.json` entry with `branch: main` (which derives the content
|
|
82
|
+
fanout lane). A clean content repo then verifies green — `bootstrap verify --class content` no longer reports
|
|
83
|
+
the deployable gate checks as FAIL (#1450).
|
|
84
|
+
|
|
85
|
+
Record the confirmed axes; Step 0a runs `verify --class <confirmed>`, Step 0b creates the repo on the
|
|
86
|
+
track's default branch, and the apply flags (`--project-type` / `--deploy-model` / `--release-track`) carry
|
|
87
|
+
the confirmed values — no silent defaulting.
|
|
88
|
+
|
|
89
|
+
## Step 0a — no-mutation verifier
|
|
90
|
+
|
|
91
|
+
Before mutating anything, run the verifier so the current gaps are concrete:
|
|
92
|
+
```bash
|
|
93
|
+
mmi-cli bootstrap verify "$OWNER/$REPO" --class deployable --json
|
|
94
|
+
# or for content repos:
|
|
95
|
+
mmi-cli bootstrap verify "$OWNER/$REPO" --class content --json
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Run it again after Step 7. A repo is not ready for real developers until every check is green, or the report
|
|
99
|
+
names an explicitly manual-only item that the master has accepted for that repo.
|
|
100
|
+
|
|
101
|
+
## Step 0b — create the repo (when it does not exist yet)
|
|
102
|
+
|
|
103
|
+
If `$OWNER/$REPO` is not on GitHub yet, create it and seed an initial commit **before** Step 1 — a brand-new
|
|
104
|
+
repo has no commits, so there is no `development` branch to push and no default branch to set:
|
|
105
|
+
```bash
|
|
106
|
+
gh repo create "$OWNER/$REPO" --private --confirm
|
|
107
|
+
tmpdir=$(mktemp -d)
|
|
108
|
+
git -C "$tmpdir" init -b development
|
|
109
|
+
git -C "$tmpdir" commit --allow-empty -m "chore: initial commit"
|
|
110
|
+
git -C "$tmpdir" remote add origin "https://github.com/$OWNER/$REPO.git"
|
|
111
|
+
git -C "$tmpdir" push -u origin development
|
|
112
|
+
rm -rf "$tmpdir"
|
|
113
|
+
gh repo edit "$OWNER/$REPO" --default-branch development
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
For a **content** repo (`trunk` track), use `-b main` and push `main` instead. Skip this step when the repo
|
|
117
|
+
already exists with the track's default branch.
|
|
118
|
+
|
|
119
|
+
## Step 1 — branches
|
|
120
|
+
|
|
121
|
+
Determine the repo's **release track** first — the branch set follows the track, not just the class (#1097),
|
|
122
|
+
so a direct-track repo never gets a stray `rc` the `mmi-train-floor` ruleset can't clean up:
|
|
123
|
+
|
|
124
|
+
- **full** (deployable default) — three permanent branches, default `development`: `development`, `rc`, `main`.
|
|
125
|
+
- **direct** (deployable, skips rc — e.g. cli-tool/worker/Hub) — two permanent branches, default
|
|
126
|
+
`development`: `development`, `main`.
|
|
127
|
+
- **trunk** (content) — one permanent branch, default `main`: `main` only.
|
|
128
|
+
|
|
129
|
+
Ensure exactly the track's permanent branches exist and set the default branch — create only what the track
|
|
130
|
+
uses; never push an `rc` for a direct-track repo:
|
|
131
|
+
```bash
|
|
132
|
+
# full
|
|
133
|
+
git push origin development rc main # create any missing
|
|
134
|
+
gh repo edit "$OWNER/$REPO" --default-branch development
|
|
135
|
+
|
|
136
|
+
# direct
|
|
137
|
+
git push origin development main # create any missing — NO rc
|
|
138
|
+
gh repo edit "$OWNER/$REPO" --default-branch development
|
|
139
|
+
|
|
140
|
+
# trunk (content)
|
|
141
|
+
git push origin main # create if missing
|
|
142
|
+
gh repo edit "$OWNER/$REPO" --default-branch main
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Step 2 — authority (org Ruleset)
|
|
146
|
+
|
|
147
|
+
Confirm the org-level rulesets already target this repo (they apply org-wide): **`mmi-branch-protection`**
|
|
148
|
+
PR-gates `development` and blocks force-push/deletion there (bypass = org admins + the GitHub App 3026732),
|
|
149
|
+
and **`mmi-train-floor`** blocks force-push/deletion on `rc`/`main` (no PR rule — the train pushes merges and
|
|
150
|
+
tags directly; no bypass). (Definitions mirror live in `.github/rulesets/mmi-branch-protection.json` and
|
|
151
|
+
`.github/rulesets/mmi-train-floor.json`.) MMI-Hub additionally has its own repository ruleset,
|
|
152
|
+
`.github/rulesets/mmi-hub-required-checks.json`, for the Hub-only `cli`, `infra`, and `docs` jobs; do not
|
|
153
|
+
apply those contexts org-wide unless every target repo exposes them.
|
|
154
|
+
|
|
155
|
+
## Step 2b — lock the train branches (who can push)
|
|
156
|
+
|
|
157
|
+
The ruleset says *a PR is required*; this says *who may merge it*. Apply classic branch protection on
|
|
158
|
+
`development`/`rc`/`main` for deployable repos, or just `main` for content repos, with **"Restrict who can
|
|
159
|
+
push"** = the master + the App (the repo's full-write people get added at Step 4b). Everyone else is
|
|
160
|
+
`write`-locked on protected branches: they push feature branches and open PRs but cannot merge there. Run per
|
|
161
|
+
protected branch (App token):
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
BRANCHES="development rc main" # full
|
|
165
|
+
BRANCHES="development main" # direct (no rc)
|
|
166
|
+
BRANCHES="main" # trunk / content
|
|
167
|
+
|
|
168
|
+
mapfile -t MASTER_USERS < <(gh api --paginate "orgs/$OWNER/members?role=admin" --jq '.[].login')
|
|
169
|
+
if [ "${#MASTER_USERS[@]}" -eq 0 ]; then
|
|
170
|
+
echo "No org owners resolved for $OWNER; stop before writing branch protection." >&2
|
|
171
|
+
exit 1
|
|
172
|
+
fi
|
|
173
|
+
USERS_JSON=$(printf '%s\n' "${MASTER_USERS[@]}" | node -e "const fs=require('fs'); const users=fs.readFileSync(0,'utf8').trim().split(/\r?\n/).filter(Boolean); process.stdout.write(JSON.stringify(users));")
|
|
174
|
+
|
|
175
|
+
for b in $BRANCHES; do
|
|
176
|
+
node - "$USERS_JSON" <<'NODE' | gh api --method PUT repos/$OWNER/$REPO/branches/$b/protection --input -
|
|
177
|
+
const users = JSON.parse(process.argv[2]);
|
|
178
|
+
process.stdout.write(JSON.stringify({
|
|
179
|
+
required_status_checks: null,
|
|
180
|
+
enforce_admins: false,
|
|
181
|
+
required_pull_request_reviews: null,
|
|
182
|
+
restrictions: { users, teams: [], apps: ['mmi-github-app'] },
|
|
183
|
+
}, null, 2));
|
|
184
|
+
NODE
|
|
185
|
+
done
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Only the master (sole repo `admin`) can change this afterward. Full grant/lock mechanics + inspect commands:
|
|
189
|
+
`docs/Guides/repo-access.md`.
|
|
190
|
+
|
|
191
|
+
## Step 3 — attach to the configured Project (default by prefix; confirm)
|
|
192
|
+
|
|
193
|
+
Division boards exist as defaults — the repo's `<CATEGORY>` prefix picks the starting recommendation
|
|
194
|
+
(`MMI-*` → the **MMI** project, `MMG-*` → **MMG**, `MMS`/`MMD`/`MMC` likewise, `MM-*` → **MM**). **Confirm
|
|
195
|
+
with the master** whether the repo joins that board, joins another existing board, or gets a dedicated
|
|
196
|
+
product/initiative board; repos/projects are **not 1:1**.
|
|
197
|
+
```bash
|
|
198
|
+
gh project list --owner "$PROJECT_OWNER" --format json # existing boards to choose from
|
|
199
|
+
```
|
|
200
|
+
- **Attach** to the chosen project:
|
|
201
|
+
```bash
|
|
202
|
+
gh project link "$PROJECT_NUMBER" --owner "$PROJECT_OWNER" --repo "$OWNER/$REPO"
|
|
203
|
+
```
|
|
204
|
+
- **Create** the chosen board if it doesn't exist yet — clone an existing board so the 4-lane `Status` field
|
|
205
|
+
(`Todo · In Progress · In Review · Done`) **and its built-in workflows carry over**:
|
|
206
|
+
```bash
|
|
207
|
+
gh project copy <existing-project#> --source-owner "$PROJECT_OWNER" \
|
|
208
|
+
--target-owner "$PROJECT_OWNER" --title "<Project>"
|
|
209
|
+
```
|
|
210
|
+
Then **interview the master** for the seed short description + README (what it tracks, member repos, links
|
|
211
|
+
to the repos' `README.md`/`architecture.md`); set them via the `updateProjectV2` mutation
|
|
212
|
+
(`shortDescription`, `readme`). If cloning, verify the built-in workflows survived (next note).
|
|
213
|
+
- **Built-in workflows:** `mmi-cli bootstrap verify` checks these Project workflows are enabled:
|
|
214
|
+
`Auto-add sub-issues to project`, `Auto-archive items`, `Item added to project`, and `Item closed`. The
|
|
215
|
+
Todo/In Progress/In Review moves are **central** (the Hub webhook); the built-in `Item closed` sets `Done`
|
|
216
|
+
on merge. GitHub's public GraphQL schema exposes delete/read surfaces for Project workflows but no
|
|
217
|
+
create/update/enable mutation; if any required workflow is missing or disabled, repair it in the project's
|
|
218
|
+
**Workflows** settings before calling the repo ready for developers.
|
|
219
|
+
|
|
220
|
+
Record the chosen `projectNumber`/`projectId` plus Status/Priority field ids in the Hub registry META
|
|
221
|
+
(`PROJECT#<slug>`) via `mmi-cli bootstrap apply --execute` or `mmi-cli project set` after the board is
|
|
222
|
+
known. Going forward the thin Lambda adds each new issue to that project on `issues.opened` and sets
|
|
223
|
+
`Status: Todo`.
|
|
224
|
+
|
|
225
|
+
**Register the project for cloud agents.** The same registry META row carries `{name, slug, projectId,
|
|
226
|
+
wikiRepo, repos[]}`; do not append to a committed `projects.json`. This is what makes `wiki-keeper` run for
|
|
227
|
+
the project (the launcher fans one run per registered project, generating its wiki + refreshing its board).
|
|
228
|
+
`kb-keeper`, `saga-keeper`, and `northstar-keeper` are org-wide and need no per-project entry. If attaching this repo to an
|
|
229
|
+
existing project, merge this repo into that project's `repos[]` instead of creating a new project.
|
|
230
|
+
|
|
231
|
+
## Step 4 — vault tiers + deploy substrate
|
|
232
|
+
|
|
233
|
+
Provision the repo's vault namespace and deploy substrate from the Hub, not from repo-local Actions
|
|
234
|
+
secrets. Runtime config names live in the two-tier vault (`/mmi-future/<slug>/dev|rc|main/*`) and are
|
|
235
|
+
managed through `/secrets`; never use `gh secret set` for product runtime config.
|
|
236
|
+
|
|
237
|
+
The default `tenant-container` substrate is a **Hetzner box** (`hetzner-ssh`): the box writes the release
|
|
238
|
+
`.env` from the registry + vault and runs the container via docker-compose, deployed over the Hub's bounded
|
|
239
|
+
SSH lane. Do **not** create an AWS OIDC deploy role or a repo deploy Action for it. **Ask the master for the
|
|
240
|
+
box assignment** — the `sshHost` (and the loopback port) per stage — then write the `DEPLOY#<stage>` rows with
|
|
241
|
+
`mmi-cli project set-deploy <owner/repo> --stage <dev|rc|main> --ssh-host <host> [--port <p>]` (defaults:
|
|
242
|
+
`substrate: hetzner-ssh`, deploy path `/opt/mmi/<slug>/<stage>`, service = slug, ssh-user `root`). Without those
|
|
243
|
+
rows the tenant cannot deploy (`tenant-deploy.yml` errors on missing `DEPLOY#` coords), so do not skip this.
|
|
244
|
+
Keep every runtime config value in the vault; never paste secret values into logs.
|
|
245
|
+
|
|
246
|
+
Only an AWS `tenant-container` (the exception) provisions the reusable tenant stack: release bucket,
|
|
247
|
+
per-stage OIDC deploy role, and constrained service-control role/document. Either way the deploy path
|
|
248
|
+
trusts the Hub's central `tenant-deploy.yml` / `tenant-control.yml` environments, not a product repo deploy
|
|
249
|
+
workflow.
|
|
250
|
+
|
|
251
|
+
## Step 4b — developer access
|
|
252
|
+
|
|
253
|
+
Grant each developer their **org membership + repo access** through the App (`gh api` with the App token):
|
|
254
|
+
`write` for a developer; for a **full-write** member ("project-admin") also add them to the train-branch
|
|
255
|
+
push allowlist from Step 2b (so they can merge protected development PRs). GitHub's
|
|
256
|
+
collaborator list + the per-branch allowlist are the record — no separate roster. Exact commands:
|
|
257
|
+
`docs/Guides/repo-access.md`.
|
|
258
|
+
|
|
259
|
+
## Step 4c — CI trigger, labels, templates, wiki
|
|
260
|
+
|
|
261
|
+
- **Enable workflow triggers** — a freshly-provisioned repo can have GitHub Actions auto-trigger stuck off
|
|
262
|
+
(push/PR never run workflows though dispatch does). Toggle it off→on:
|
|
263
|
+
```bash
|
|
264
|
+
gh api -X PUT repos/$OWNER/$REPO/actions/permissions -F enabled=false
|
|
265
|
+
gh api -X PUT repos/$OWNER/$REPO/actions/permissions -F enabled=true -f allowed_actions=selected
|
|
266
|
+
```
|
|
267
|
+
- **Self-hosted CI is the org default** — the `mmi-automation` runner group is org-wide (all repos), so a
|
|
268
|
+
new repo needs no manual group join. Any CI workflow it adds uses
|
|
269
|
+
`runs-on: [self-hosted, linux, x64, mmi-live]` (never `ubuntu-*`/`windows-*`/`macos-*`, which bill
|
|
270
|
+
GitHub-hosted minutes); jobs needing system packages run in a `container:`. See
|
|
271
|
+
`docs/Guides/gh-runner-runbook.md`.
|
|
272
|
+
- **Product gate + required checks (#1333, stack-aware #1550)** — deployable repos bootstrap-seed
|
|
273
|
+
`.github/workflows/gate.yml` (single `gate` job) and a ruleset reference at
|
|
274
|
+
`.github/rulesets/mmi-product-required-checks.json`. The gate is stack-aware: capture the repo's
|
|
275
|
+
**runtime** (`node` | `python`), its **check command**, and its **working directory** at interview time
|
|
276
|
+
and pass them as `--var GATE_RUNTIME=node|python`, `--var GATE_CMD=...`, `--var GATE_WORKDIR=...` (and
|
|
277
|
+
`--var GATE_CACHE_DEP_PATH=<path/to/package-lock.json>` when the app's Node lockfile is not at the repo
|
|
278
|
+
root). Defaults: `node` runtime, `npm run check` / `npm ci` at the repo root; a Python repo defaults to
|
|
279
|
+
`pytest` / `pip install -e ".[dev]"` with `--var GATE_PY_VERSION=` (3.11 default). The runtime selects
|
|
280
|
+
which setup step (`setup-node` vs `setup-python`) the rendered `if:` fires. After apply,
|
|
281
|
+
master-admin must **activate** that JSON as a repository ruleset (GitHub → Settings → Rules → Rulesets →
|
|
282
|
+
Import/create from the committed reference) so the `gate` context is required on train branches. MMI-Hub
|
|
283
|
+
keeps its own three-job gate (`cli`/`infra`/`docs`) — never apply the product ruleset there.
|
|
284
|
+
- **Standard labels** — type labels only (the issue templates reference them). **Priority is a Project
|
|
285
|
+
field, not a label** (#416): never seed `priority:*` labels; `--priority` writes the board field.
|
|
286
|
+
```bash
|
|
287
|
+
gh label create bug --color d73a4a --description "Something is broken or behaving wrong" -R $OWNER/$REPO
|
|
288
|
+
gh label create feature --color a2eeef --description "New capability or enhancement" -R $OWNER/$REPO
|
|
289
|
+
gh label create task --color 0052cc --description "Task, chore, or improvement" -R $OWNER/$REPO
|
|
290
|
+
```
|
|
291
|
+
- **Board view (Priority chip)** — the Project's board view must **show the Priority field on cards**, not
|
|
292
|
+
the Labels field (GitHub's API can't set view columns): Board view → **Fields** → remove **Labels**, add
|
|
293
|
+
**Priority**. Otherwise cards show label soup and no priority chip. Strip any legacy `priority:*` /
|
|
294
|
+
taxonomy labels with `mmi-cli board prune-priority-labels`.
|
|
295
|
+
- **Org App credentials** — nothing to register per repo (#494). Board moves are central (the Hub webhook
|
|
296
|
+
moves Todo/In Progress/In Review for every repo) and the org App token is minted inside the Hub's own
|
|
297
|
+
central workflows, so `MMI_APP_ID` / `MMI_APP_PRIVATE_KEY` live only on the Hub — a product repo seeds no
|
|
298
|
+
App var/secret.
|
|
299
|
+
- **Issue templates** — seed `.github/ISSUE_TEMPLATE/` (Bug · Feature · Task + `config.yml`).
|
|
300
|
+
- **Merge settings (org canon)** — every repo: auto-merge on, squash on, delete-branch-on-merge on, so a
|
|
301
|
+
green allowlisted PR can land itself and never leaves a dead branch:
|
|
302
|
+
`gh api -X PATCH repos/$OWNER/$REPO -f allow_auto_merge=true -f allow_squash_merge=true -f delete_branch_on_merge=true`
|
|
303
|
+
- **Wiki** — `gh api -X PATCH repos/$OWNER/$REPO -F has_wiki=true`, then **create the wiki's first page once**
|
|
304
|
+
in the UI (an empty page is enough — GitHub blocks programmatic first-page creation). **MMI-Keeper**
|
|
305
|
+
generates and maintains the wiki thereafter (on release + weekly); no further manual edits.
|
|
306
|
+
- **Cursor environment** — commit `.cursor/environment.json` with the repo's dependency `install` command
|
|
307
|
+
(e.g. `npm ci`, `npm --prefix infra ci`, `pip install -r requirements.txt`). Cursor honors repo-level
|
|
308
|
+
config and auto-snapshots after install, so the repo's cloud agents (keepers) get fast cold starts with
|
|
309
|
+
no dashboard step. A repo needing system packages can instead use `build.dockerfile` (a committed
|
|
310
|
+
`.cursor/Dockerfile`, layer-cached). No snapshot-by-ID (that path needs the dashboard wizard).
|
|
311
|
+
|
|
312
|
+
## Step 5 — install the plugin + seed docs
|
|
313
|
+
|
|
314
|
+
- Write the repo's `.claude/settings.json` (marketplace + `enabledPlugins`) so Claude Code prompts the
|
|
315
|
+
developer to install the org plugins: `mmi@mutmutco` (its SessionStart hook keeps the rules current) and
|
|
316
|
+
`superpowers@claude-plugins-official` (Anthropic's skills framework — TDD, debugging, subagent dev). Mirror
|
|
317
|
+
the hub's own `.claude/settings.json` verbatim. Fanout keeps this file current after bootstrap —
|
|
318
|
+
it is org-owned and delivered verbatim like the spine.
|
|
319
|
+
- Seed `README.md` + `architecture.md` from the templates, then **fill them before finishing** — `bootstrap
|
|
320
|
+
verify` now fails on any leftover `(placeholder)` or `{{TOKEN}}` (#1520). Fill the code-local fields from
|
|
321
|
+
what this bootstrap already knows: **Stack / Run locally / Verify** from the Step-4c gate + install commands
|
|
322
|
+
and the repo's actual code; **Gotchas** and the architecture **Overview / Build & deploy** from the confirmed
|
|
323
|
+
Step-0 axes (class, project-type, deploy-model). Do **not** write the release track, board number, or deploy
|
|
324
|
+
coords as a value — the templates point at `mmi-cli project get` (registry SSOT, never copied, so it cannot drift). Write
|
|
325
|
+
the delivered `AGENTS.md` / `CLAUDE.md` verbatim (org-owned, whole-file — identical in every repo; no markers,
|
|
326
|
+
no tail).
|
|
327
|
+
- **Push the mandated fill past the active ruleset (#1807).** Deployable repos activate
|
|
328
|
+
`mmi-product-required-checks` during apply (its `bypass_actors` is empty by design), so the `gate` check is
|
|
329
|
+
required on `development`/`main` before the seeded README + architecture have ever produced a green run. The
|
|
330
|
+
fill above (#1520) then cannot be pushed, and not even `gh pr merge --admin` clears it (GH013 on push /
|
|
331
|
+
GraphQL rule violation on admin-merge). Sanctioned final step: in GitHub Settings > Rules > Rulesets >
|
|
332
|
+
`mmi-product-required-checks`, set **Enforcement** to **Disabled**, push/merge the filled `README.md` +
|
|
333
|
+
`architecture.md`, then set **Enforcement** back to **Active**. Programmatic equivalent: PUT the ruleset
|
|
334
|
+
with `enforcement: disabled` (a PATCH is rejected, #917/#922), push the fill, then PUT it back to
|
|
335
|
+
`active` (or re-run `bootstrap apply`, which re-activates the ruleset idempotently). Never leave enforcement
|
|
336
|
+
disabled.
|
|
337
|
+
- Make sure the target repo's `.gitignore` does **not** ignore `.claude/settings.json`; only
|
|
338
|
+
`.claude/settings.local.json` is local-only.
|
|
339
|
+
- **Reserve the spine filenames.** `AGENTS.md` / `CLAUDE.md` are the org spine — never repo-specific. Seed
|
|
340
|
+
`.cursor/rules/<repo-slug>.mdc` (frontmatter `alwaysApply: true`) with repo-specific agent guidance (what
|
|
341
|
+
the repo is, services/deps, build/test, conventions). Include the saga startup pattern for non-Claude
|
|
342
|
+
agents: `mmi-cli saga health --json`, `mmi-cli saga show`, then explicit `mmi-cli saga note` at handoff or
|
|
343
|
+
meaningful checkpoints. This gives Cursor's setup agent a home so it does not hijack `AGENTS.md`; Cursor
|
|
344
|
+
cloud agents read `.cursor/rules` automatically.
|
|
345
|
+
|
|
346
|
+
## Step 6 — register Hub META
|
|
347
|
+
|
|
348
|
+
Do not seed a product repo `.mmi/config.json`. `mmi-cli` carries the Hub API endpoint and resolves board,
|
|
349
|
+
deploy, secret, and project state from the Hub registry at runtime.
|
|
350
|
+
|
|
351
|
+
Choose the v2 shape explicitly. Use `--project-type web-app --deploy-model tenant-container` for ordinary
|
|
352
|
+
web tenants, `--project-type desktop-game --deploy-model none --clear-web-profile` for a desktop game, and
|
|
353
|
+
`--class content --project-type content --deploy-model content --clear-web-profile` for a content/KB repo.
|
|
354
|
+
Run the apply path with the board variables discovered above, or register the same values with
|
|
355
|
+
`mmi-cli project set` from the Hub or from the target project checkout:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
mmi-cli bootstrap apply "$OWNER/$REPO" --class deployable \
|
|
359
|
+
--project-type web-app --deploy-model tenant-container --execute \
|
|
360
|
+
--var PROJECT_OWNER="$PROJECT_OWNER" \
|
|
361
|
+
--var PROJECT_NUMBER="$PROJECT_NUMBER" \
|
|
362
|
+
--var PROJECT_ID="$PROJECT_ID" \
|
|
363
|
+
--var STATUS_FIELD_ID="$STATUS_FIELD_ID" \
|
|
364
|
+
--var STATUS_TODO="$STATUS_TODO" \
|
|
365
|
+
--var STATUS_IN_PROGRESS="$STATUS_IN_PROGRESS" \
|
|
366
|
+
--var STATUS_IN_REVIEW="$STATUS_IN_REVIEW" \
|
|
367
|
+
--var STATUS_DONE="$STATUS_DONE"
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Tenant-container repos must carry a `docker-compose.yml` and Dockerfile that build from the shipped source
|
|
371
|
+
archive; the train does not ship a prebuilt `dist/`. **Bootstrap seeds both files** for
|
|
372
|
+
`deployModel: tenant-container` from `skills/bootstrap/seeds/` (rendered from
|
|
373
|
+
`docs/Reference/tenant-runtime/docker-compose.yml` and `docs/Reference/tenant-runtime/Dockerfile`). The box
|
|
374
|
+
writes the release `.env` from the registry + vault at deploy time; the compose file carries `env_file: .env`
|
|
375
|
+
and the app reads plain env vars — it must **not** self-load SSM and must **not** ship a committed `.env`.
|
|
376
|
+
|
|
377
|
+
For a `web-app` that declares `oauth` META, print the canonical OAuth surface and provision the client once:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
mmi-cli oauth plan --repo "$OWNER/$REPO" # the exact JS origins + redirect URIs + canonical SSM keys
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Register those JS origins + `/api/auth/callback` redirect URIs on the Console client (master, per
|
|
384
|
+
`docs/Guides/oauth-provision.md`), then store the creds in the canonical keys in one step:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
mmi-cli oauth set-creds --repo "$OWNER/$REPO" < client.json # the Console "Download JSON" file
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The keys are `{dev,rc,main}/GOOGLE_CLIENT_ID|SECRET` — never a `GOOGLE_OAUTH_CLIENT_*` or `prod/` variant; the
|
|
391
|
+
runtime reads only the canonical names.
|
|
392
|
+
|
|
393
|
+
Local `/stage` is optional product-owned configuration. A repo that wants `/stage` may carry a local
|
|
394
|
+
`stage` block, but that file must not contain board, deploy, or secret registry facts.
|
|
395
|
+
|
|
396
|
+
**Stage port block:** run `mmi-cli port-range <Repo>` to assign (idempotently) the repo's local port block
|
|
397
|
+
from the central registry. Use `$STAGE_PORT` in `stage.up` / `healthUrl`; `/stage` then picks a free port
|
|
398
|
+
inside the block so a dev can run several projects/versions locally without collisions.
|
|
399
|
+
|
|
400
|
+
## Step 7 — register for fanout
|
|
401
|
+
|
|
402
|
+
Add the repo to `.github/fanout-targets.json` so future org-spine changes reach it via App-token PRs. Use
|
|
403
|
+
`branch: "development"` for deployable repos and `branch: "main"` for content repos.
|
|
404
|
+
|
|
405
|
+
## Step 8 — report
|
|
406
|
+
|
|
407
|
+
Repo, default branch, ruleset applied, train branches locked (push allowlist), project attached/created
|
|
408
|
+
(+ info seeded, Status lanes and Labels field verified), secrets set (names only), developer access, plugin
|
|
409
|
+
installed, docs seeded, registry META written, issue templates committed, org App credentials registered,
|
|
410
|
+
fanout registered, and the final `mmi-cli bootstrap verify "$OWNER/$REPO" --class ... --json` result.
|
|
411
|
+
|
|
412
|
+
## Retro — one check before you finish
|
|
413
|
+
Before your final report, answer one question honestly: did **this skill's own instructions** misfire
|
|
414
|
+
this run — ambiguous wording, a misleading message, or an environment failure it should have warned
|
|
415
|
+
about? (Process only — never the user's code or task; e.g. an ambiguous seed, registry, or OIDC step, or
|
|
416
|
+
a guard that fired on a healthy repo.) If yes, file **one** lesson and move on; a clean run is silent
|
|
417
|
+
(hard cap: one per run). It lands on the Hub board (deduped) and is fixed only via a reviewed PR — never
|
|
418
|
+
edit the skill live; the retro is advisory, so if the call fails, note it and continue:
|
|
419
|
+
`mmi-cli skill-lesson --skill bootstrap --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Tenant-container reference Dockerfile — seeded at bootstrap (#1593).
|
|
2
|
+
# Adapt package manager and build commands to the project; keep the image building from source.
|
|
3
|
+
FROM node:24-alpine AS deps
|
|
4
|
+
WORKDIR /app
|
|
5
|
+
COPY package.json package-lock.json ./
|
|
6
|
+
# npm workspaces: copy EVERY workspace package.json before `npm ci` so adding a workspace later
|
|
7
|
+
# does not break the image. Add one COPY line per workspace directory (apps/*, packages/*, …).
|
|
8
|
+
# COPY apps/my-app/package.json ./apps/my-app/
|
|
9
|
+
RUN npm ci
|
|
10
|
+
|
|
11
|
+
FROM node:24-alpine AS build
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
14
|
+
COPY . .
|
|
15
|
+
RUN npm run build
|
|
16
|
+
RUN npm prune --omit=dev
|
|
17
|
+
|
|
18
|
+
FROM node:24-alpine AS runtime
|
|
19
|
+
WORKDIR /app
|
|
20
|
+
ENV NODE_ENV=production
|
|
21
|
+
COPY --from=build /app/package*.json ./
|
|
22
|
+
COPY --from=build /app/node_modules ./node_modules
|
|
23
|
+
COPY --from=build /app/dist ./dist
|
|
24
|
+
EXPOSE 3000
|
|
25
|
+
CMD ["node", "dist/index.js"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# {{REPO_NAME}}
|
|
2
|
+
|
|
3
|
+
> One paragraph: what this repo **is** — the product/service and who it's for. (Write fresh — D35: do
|
|
4
|
+
> not carry a legacy README over verbatim; the old docs are archived under `docs/Archive/`.)
|
|
5
|
+
|
|
6
|
+
## What it is
|
|
7
|
+
|
|
8
|
+
(Describe the product/service.)
|
|
9
|
+
|
|
10
|
+
## Agent context
|
|
11
|
+
|
|
12
|
+
Read this section at the start of agent work in this repo.
|
|
13
|
+
|
|
14
|
+
- **Stack:** (languages, frameworks, major services)
|
|
15
|
+
- **Run locally:** (install, dev server, `/stage` if non-obvious)
|
|
16
|
+
- **Verify before done:** (exact commands — test, lint, typecheck, repo gate script)
|
|
17
|
+
- **Release track + coords:** `mmi-cli project get` (registry SSOT for release track, stages, board, and deploy coords; not copied here, so it cannot go stale).
|
|
18
|
+
- **Architecture:** deep build/deploy shape → `architecture.md`
|
|
19
|
+
- **Gotchas:** (ports, env from vault not files, Windows/shell quirks specific to this repo)
|
|
20
|
+
|
|
21
|
+
## Develop
|
|
22
|
+
|
|
23
|
+
(How to run, build, and test locally. How it's *built* lives in `architecture.md`.)
|
|
24
|
+
|
|
25
|
+
## Access
|
|
26
|
+
|
|
27
|
+
Repo access follows the MMI Future three-level model: read for org members, developer as GitHub `write`,
|
|
28
|
+
and project-admin as `write` plus train-branch allowlist (registry `projectAdmins` on this project).
|
|
29
|
+
What each level can **do** is in `AGENTS.md` § Authority and `docs/org-architecture.md` §4 in `MMI-Hub`;
|
|
30
|
+
agents check `mmi-cli access role <owner/repo> --json` before redirecting anyone to the master. Grant/revoke
|
|
31
|
+
mechanics (master-only) are `docs/Guides/repo-access.md` in `MMI-Hub`.
|
|
32
|
+
|
|
33
|
+
## Org
|
|
34
|
+
|
|
35
|
+
Part of **Mutatis Mutandis** · class **{{CLASS}}** · board **{{PROJECT_OWNER}} #{{PROJECT_NUMBER}}**.
|
|
36
|
+
Agent rules: `AGENTS.md` (the org spine). Architecture: `architecture.md`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# {{REPO_NAME}} — Architecture
|
|
2
|
+
|
|
3
|
+
> How this repo is **built** — present truth. Pair with `README.md` (what it *is*). State current truth;
|
|
4
|
+
> no change-comments or version-era labels (history is in git). (Write fresh — D35.)
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
(System shape: components, data flow, deploy model.)
|
|
9
|
+
|
|
10
|
+
## Build & deploy
|
|
11
|
+
|
|
12
|
+
- **Class:** {{CLASS}}
|
|
13
|
+
- **Release track + stages:** `mmi-cli project get` (registry SSOT: full = development/rc/main, direct = development/main, trunk = main; never copied here).
|
|
14
|
+
- **Deploys run centrally** via the Hub (`tenant-deploy.yml`); this repo carries no deploy files.
|
|
15
|
+
- (Build/test commands, CI gate, deploy target.)
|
|
16
|
+
|
|
17
|
+
## Conventions
|
|
18
|
+
|
|
19
|
+
Follows the org spine (`AGENTS.md`). Repo-specific agent guidance: `.cursor/rules/{{REPO_SLUG}}.mdc`.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "radix-nova",
|
|
4
|
+
"rsc": true,
|
|
5
|
+
"tsx": true,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "",
|
|
8
|
+
"css": "app/globals.css",
|
|
9
|
+
"baseColor": "neutral",
|
|
10
|
+
"cssVariables": true,
|
|
11
|
+
"prefix": ""
|
|
12
|
+
},
|
|
13
|
+
"iconLibrary": "lucide",
|
|
14
|
+
"rtl": false,
|
|
15
|
+
"aliases": {
|
|
16
|
+
"components": "@/components",
|
|
17
|
+
"utils": "@/lib/utils",
|
|
18
|
+
"ui": "@/components/ui",
|
|
19
|
+
"lib": "@/lib",
|
|
20
|
+
"hooks": "@/hooks"
|
|
21
|
+
},
|
|
22
|
+
"menuColor": "default",
|
|
23
|
+
"menuAccent": "subtle",
|
|
24
|
+
"registries": {
|
|
25
|
+
"@mutmutco": "https://ui.mutatismutandis.co/r/{name}.json"
|
|
26
|
+
},
|
|
27
|
+
"mmi": {
|
|
28
|
+
"cacheDir": ".mmi/design-system/components",
|
|
29
|
+
"installed": []
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: true
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# {{REPO_NAME}} — agent context
|
|
6
|
+
|
|
7
|
+
Read **`README.md` § Agent context** first (stack, verify commands, gotchas). Deep build truth: `architecture.md`.
|
|
8
|
+
|
|
9
|
+
Org behavior: `AGENTS.md` / `CLAUDE.md` — never edit here. This file is the Cursor always-on pointer + repo-specific notes only.
|
|
10
|
+
|
|
11
|
+
(Saga: plugin hooks call `mmi-cli` automatically; without plugin see `docs/Guides/cursor-saga.md` in MMI-Hub.)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
services:
|
|
2
|
+
app:
|
|
3
|
+
build:
|
|
4
|
+
context: .
|
|
5
|
+
dockerfile: Dockerfile
|
|
6
|
+
restart: unless-stopped
|
|
7
|
+
# The box control document writes registry coords + stage-scoped SSM secret values into the
|
|
8
|
+
# release ./.env before `docker compose up`; env_file is what delivers them into the container.
|
|
9
|
+
env_file: .env
|
|
10
|
+
environment:
|
|
11
|
+
NODE_ENV: production
|
|
12
|
+
MMI_STAGE: ${MMI_STAGE:-dev}
|
|
13
|
+
MMI_PORT: ${MMI_PORT:-3000}
|
|
14
|
+
PORT: ${PORT:-3000}
|
|
15
|
+
MMI_EDGE_DOMAIN: ${MMI_EDGE_DOMAIN:-}
|
|
16
|
+
ports:
|
|
17
|
+
- "${MMI_PORT:-3000}:${PORT:-3000}"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: gate
|
|
2
|
+
# Org-standard green-before-merge gate for product repos (#1333). Runs on PRs, train-branch pushes,
|
|
3
|
+
# and v* tags so /release and /hotfix can discover required contexts on the tagged SHA.
|
|
4
|
+
#
|
|
5
|
+
# Runner: self-hosted mmi-runner (mmi-live) — see docs/Guides/gh-runner-runbook.md in MMI-Hub.
|
|
6
|
+
# Stack-aware (#1550): the runtime is rendered into the setup-step `if:` — both the Node and Python
|
|
7
|
+
# setup steps live in the file but only the one matching GATE_RUNTIME runs. Knobs (override at
|
|
8
|
+
# bootstrap with --var):
|
|
9
|
+
# GATE_RUNTIME — node | python (selects which setup step fires)
|
|
10
|
+
# GATE_CMD — the check command ({{GATE_CMD}})
|
|
11
|
+
# GATE_INSTALL_CMD — the dependency-install command ({{GATE_INSTALL_CMD}})
|
|
12
|
+
# GATE_WORKDIR — app working directory when not the repo root ({{GATE_WORKDIR}})
|
|
13
|
+
# GATE_CACHE_DEP_PATH— npm lockfile path for the setup-node cache ({{GATE_CACHE_DEP_PATH}})
|
|
14
|
+
# GATE_PY_VERSION — Python version for setup-python ({{GATE_PY_VERSION}})
|
|
15
|
+
on:
|
|
16
|
+
pull_request:
|
|
17
|
+
push:
|
|
18
|
+
branches: {{GATE_PUSH_BRANCHES_YAML}}
|
|
19
|
+
tags: ['v*']
|
|
20
|
+
|
|
21
|
+
env:
|
|
22
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
23
|
+
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
gate:
|
|
29
|
+
if: ${{ github.event_name != 'push' || github.ref_name == '{{GATE_FULL_RUN_BRANCH}}' || github.ref_type == 'tag' }}
|
|
30
|
+
runs-on: [self-hosted, linux, x64, mmi-live]
|
|
31
|
+
defaults:
|
|
32
|
+
run: { working-directory: {{GATE_WORKDIR}} }
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
35
|
+
- if: ${{ '{{GATE_RUNTIME}}' == 'node' }}
|
|
36
|
+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
37
|
+
with: { node-version: 24, cache: npm, cache-dependency-path: {{GATE_CACHE_DEP_PATH}} }
|
|
38
|
+
- if: ${{ '{{GATE_RUNTIME}}' == 'python' }}
|
|
39
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
40
|
+
with: { python-version: '{{GATE_PY_VERSION}}' }
|
|
41
|
+
- run: {{GATE_INSTALL_CMD}}
|
|
42
|
+
- run: {{GATE_CMD}}
|