@techgoblin/gobstack 0.5.0-beta.8 → 0.6.0-alpha.1

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +112 -124
  3. package/VERSION +1 -1
  4. package/automations/drift-audit.sh +4 -4
  5. package/bans/layer-check.sh +10 -8
  6. package/bin/goblin +61 -58
  7. package/bin/goblin-audit +11 -13
  8. package/bin/goblin-bans +11 -11
  9. package/bin/goblin-init +275 -713
  10. package/bin/goblin-install +160 -114
  11. package/bin/goblin-lib.sh +234 -1
  12. package/bin/goblin-map +226 -21
  13. package/bin/goblin-mcp.js +492 -0
  14. package/bin/goblin-model +4 -4
  15. package/bin/goblin-upgrade +1 -1
  16. package/bin/goblin-verify +159 -145
  17. package/bin/goblin.js +33 -51
  18. package/docs/ADOPTION.md +15 -15
  19. package/docs/CONTRACTS.md +16 -15
  20. package/docs/DESIGN.md +1 -1
  21. package/docs/ENFORCEMENT.md +89 -90
  22. package/docs/FLOWS.md +1 -1
  23. package/docs/GLOSSARY.md +3 -3
  24. package/docs/GUARDRAILS.md +5 -5
  25. package/docs/GUIDE.md +167 -177
  26. package/docs/INTEGRATION.md +1 -1
  27. package/docs/LIMITS.md +25 -0
  28. package/docs/LOOP.md +12 -12
  29. package/docs/RE-PLAYBOOK.md +3 -3
  30. package/docs/ROLES.md +5 -5
  31. package/manifest/bans.tsv +8 -8
  32. package/manifest/classes.tsv +3 -3
  33. package/manifest/enforcement.tsv +40 -40
  34. package/manifest/glossary.tsv +3 -3
  35. package/manifest/playbooks.tsv +1 -1
  36. package/package.json +1 -1
  37. package/presets/electron-overlay.yaml +2 -2
  38. package/presets/fleet.yaml +8 -7
  39. package/presets/game.yaml +1 -1
  40. package/presets/research.yaml +1 -1
  41. package/presets/service.yaml +1 -1
  42. package/presets/software.yaml +1 -1
  43. package/skills/goblin-bootstrap/SKILL.md +2 -2
  44. package/templates/AGENTS.md.tmpl +8 -18
  45. package/templates/HANDOFF.md.tmpl +5 -5
  46. package/templates/agents-block.tmpl +45 -0
  47. package/templates/audit-waiver.tsv.tmpl +2 -2
  48. package/templates/boundary-waivers.tmpl +1 -1
  49. package/templates/checks/gate.sh.tmpl +6 -6
  50. package/templates/install-hooks.allowlist.tmpl +1 -1
  51. package/templates/ci/goblin-gate.yml.tmpl +0 -46
  52. package/templates/goblin.yaml.tmpl +0 -146
  53. package/templates/loop/decisions.tsv.tmpl +0 -1
  54. package/templates/loop/predicate.tmpl +0 -16
package/docs/GUIDE.md CHANGED
@@ -3,7 +3,7 @@
3
3
  A step-by-step guide for your first week. **Read this before the README.** The README tells you
4
4
  what the pieces are; this tells you what to *do*, in order, and what you should see when it works.
5
5
 
6
- Version: `0.5.0` · Last measured: 2026-10-05 · Every command and every output below was run on a
6
+ Version: `0.6.0-alpha.1` · Last measured: 2026-10-09 · Every command and every output below was run on a
7
7
  real repository while writing this guide.
8
8
 
9
9
  ---
@@ -38,16 +38,16 @@ installed, three things change:
38
38
 
39
39
  - A file called `HANDOFF.md` sits at the root. It is the note from the last session to the next one.
40
40
  Any agent — or you, a month later — reads it first.
41
- - A command called `goblin-verify` exists in that project. Run it and it checks the project against
42
- a table of rules and prints `PASS` / `FAIL` / `SKIP` for each one.
43
- - The rules table is a real file (`.goblin/manifest/enforcement.tsv`). Every row either names a
44
- command that can fail, or is labelled `advisory`. **Nothing in between.** That is what stops the
45
- rules turning into decoration.
41
+ - A command called `goblin-verify` exists in that project (vendored at `.gob/bin/`). Run it and it
42
+ checks the project against a table of rules and prints `PASS` / `FAIL` / `SKIP` for each one.
43
+ - The config and the rules table are real files: the config is the `<!-- gob:begin --> …
44
+ <!-- gob:end -->` block at the top of `AGENTS.md`, and the rules table is
45
+ `.gob/manifest/enforcement.tsv`. Every row either names a command that can fail, or is labelled
46
+ `advisory`. **Nothing in between.** That is what stops the rules turning into decoration.
46
47
 
47
48
  It is not a framework, not a service, and not a runtime. It has no server and no dependencies
48
49
  beyond `bash`, `git`, `awk`, `sed`, `grep` and `python3`. It makes **no network call at verify
49
- time** — the one command in the toolbox that reaches the network is `goblin-audit`, which you run
50
- deliberately, and §8 and §11 say why.
50
+ time** — nothing in the v2 surface touches the network at all.
51
51
 
52
52
  ### The one idea worth holding onto
53
53
 
@@ -60,7 +60,7 @@ ships a file of things it *cannot* check (`docs/LIMITS.md`).
60
60
 
61
61
  **Words this guide uses** — gate, ratchet, class, part, replay and the rest are defined in one
62
62
  sentence each in `docs/GLOSSARY.md` (rendered from the glossary table the install ships:
63
- `.goblin/manifest/glossary.tsv`).
63
+ `.gob/manifest/glossary.tsv`).
64
64
 
65
65
  ---
66
66
 
@@ -76,10 +76,15 @@ sentence each in `docs/GLOSSARY.md` (rendered from the glossary table the instal
76
76
 
77
77
  You need node ≥ 18 (for the npm shim only), beyond the row above.
78
78
 
79
- **You do *not* need:** network access at verify time, or an agent running.
79
+ **You do *not* need:** network access at verify time, or an agent running — though the `init`
80
+ brief is written for an agent to answer, you can fill the proposal in by hand.
80
81
 
81
82
  **Get gobstack:**
82
83
 
84
+ npx @techgoblin/gobstack init # the one-shot path; installs nothing globally
85
+
86
+ or, if you want the CLI on your PATH:
87
+
83
88
  npm i -g @techgoblin/gobstack
84
89
 
85
90
  This puts **two** commands on your PATH — `gob` and `goblin`, both the same node shim over the
@@ -93,48 +98,55 @@ scripts.
93
98
  **Do not install into a real project yet.** You want to see what it does before it touches
94
99
  something you care about.
95
100
 
96
- The guided path is `gob init` — one screen per question (health check, class,
97
- identity (branch/email), the health check, the CI opt-in, which platforms to sync), every question also
98
- answerable by flag, `--dry-run` to see the plan first:
101
+ The v2 flow is **`init`**: it prints an AGENT BRIEF (what to scan, what to decide) plus the
102
+ schema of the proposal file, the agent (or you) writes the proposal, and `--write` validates it
103
+ and installs:
99
104
 
100
105
  mkdir -p /tmp/gs-try && cd /tmp/gs-try
101
106
  git init -b main
102
107
  git config user.email "you@example.com"
103
108
  git config user.name "you"
104
109
 
105
- gob init --target . --class software --branch main --email "you@example.com" \
106
- --gate "bash tests/run-tests.sh" --yes
110
+ gob init --heuristic # the brief + schema; --heuristic adds scanned hints
111
+
112
+ The brief asks for exactly four decisions — class, branch, owner email, and ONE gate command
113
+ that proves the repo is healthy. Write them into the proposal file (the brief names the schema;
114
+ a hand-written one works fine):
115
+
116
+ <!-- gob:begin (gobstack config — edit in place; the parser reads only this block) -->
117
+ class: software
118
+ branch: main
119
+ owner_email: you@example.com
120
+ gate_check_cmd: bash tests/run-tests.sh
121
+ <!-- gob:end -->
107
122
 
108
- The wizard's ci step asks whether the gate should also run in CI
109
- (`.github/workflows/goblin-gate.yml`). The wizard's default is **no** — nothing lands under `.github/` unless you opt in. (Outside the wizard, `gob install`'s own default is the class decides: a class whose
110
- contract requires or permits the ci-gate part gets the workflow, one that forbids it never does.)
111
- `--ci-gate yes|no` overrides: an explicit `no` is recorded as an opt-out (so verify reports the
112
- opt-out, never a silent absence), and an explicit `yes` is refused for a class that forbids the
113
- part.
123
+ ## gob init summary
114
124
 
115
- or the plain installer this wizard drives, if you prefer the one-shot shape:
125
+ - scan: bare repo, no package.json — the brief was answered by hand
126
+ - chose: class software, branch main, gate `bash tests/run-tests.sh`
116
127
 
117
- gob install --target . --class software
128
+ then install it:
129
+
130
+ gob init --write .gob-init-proposal.md --yes
118
131
 
119
132
  Expected output (this is a real transcript, trimmed):
120
133
 
121
- created 24 · updated 0 · unchanged 0 · skipped 0
122
- recorded opt-out: ci-gate
134
+ created 23 · updated 0 · unchanged 0 · skipped 0
123
135
 
124
136
  next:
125
137
  1. cd /tmp/gs-try && git add -A && git commit # the install is a change like any other
126
- 2. .goblin/bin/goblin-verify # or add .goblin/bin to PATH
127
- 3. edit .goblin/goblin.yaml: replace the default gate with your real commands (P8 step 3)
128
- 4. agent skills are opt-in: gob sync --platform <p> # hermes, claude, copilot, cursor, opencode, codex, gemini
129
-
130
- **`created 24`** is the installer's count of the files it **tracks** — one fewer than the plain
131
- installer's 25, because the wizard's unanswered ci screen defaults to an explicit **no**, which is
132
- recorded as an opt-out and suppresses `.github/workflows/goblin-gate.yml`. It writes **25**: the
133
- 25th is `.goblin/installed.json`, the record it keeps for itself, which it writes but does not
134
- count. It has written nothing outside this directory. The default install ships **no agent
135
- skills** — the harness is neutral, and `gob sync --platform <p>` is the per-platform opt-in
136
- (`gob emit` is the same command under its original name; the old `--skills yes` default is
137
- still there for repos that want the Hermes project tier vendored).
138
+ 2. .gob/bin/goblin-verify # or add .gob/bin to PATH
139
+ 3. edit AGENTS.md: replace the default gate with your real commands (P8 step 3)
140
+ 4. agent skills are opt-in (the per-platform emit surface returns in a later alpha)
141
+
142
+ **`created 23`** is the installer's count of the files it **tracks**. It writes **24**: the 24th
143
+ is `.gob/installed.json`, the record it keeps for itself, which it writes but does not count. It
144
+ has written nothing outside this directory — and nothing under `.github/`: **v2 installs no
145
+ CI, ever.** The default install ships **no agent skills** — the harness is neutral.
146
+
147
+ **The config is the AGENTS.md frontmatter.** There is no separate config file: every key the
148
+ harness reads lives in the `<!-- gob:begin --> … <!-- gob:end -->` marker block at the top of
149
+ `AGENTS.md`. Edit it in place; the parser reads only that block.
138
150
 
139
151
  ### Why `git init -b main` matters
140
152
 
@@ -144,8 +156,8 @@ branch is `master` and the config says `main`, verify fails on the very first ru
144
156
  FAIL PT-02 declared main, actual master
145
157
 
146
158
  That is not a bug — it is the harness refusing to guess, which is the same reason it fails instead
147
- of silently skipping a repo whose branch it got wrong. **Fix it in step 3, not by renaming your
148
- branch** (unless you want to).
159
+ of silently skipping a repo whose branch it got wrong. **Fix it in the AGENTS.md block, not by
160
+ renaming your branch** (unless you want to).
149
161
 
150
162
  ---
151
163
 
@@ -153,20 +165,19 @@ branch** (unless you want to).
153
165
 
154
166
  cd /tmp/gs-try
155
167
  git add -A && git commit -m "chore: install gobstack"
156
- .goblin/bin/goblin-verify
168
+ .gob/bin/goblin-verify
157
169
 
158
170
  You will see one line per rule. The shape:
159
171
 
160
172
  PASS IN-01 the install record exists and names its version
161
173
  PASS IN-02 15 installed files hashed
162
174
  FAIL HP-05 HANDOFF.md names no commit that exists in this repo
163
- FAIL GT-02 gate commit: bash tests/run-tests.sh -> exit 127
164
175
  SKIP HS-02 no pinned pre-change commit yet - the REPLAY is not provable
165
176
  ADV HP-04 A stale sentence is corrected in place... (advisory)
166
177
 
167
178
  and a summary line at the bottom:
168
179
 
169
- 35 passed, 2 failed, 11 advisory, 34 skipped # HP-05 and GT-02, below
180
+ 36 passed, 1 failed, 11 advisory, 34 skipped # HP-05, below
170
181
 
171
182
  ### How to read that output
172
183
 
@@ -178,28 +189,28 @@ and a summary line at the bottom:
178
189
  | `ADV` | advisory — a rule with no runnable check, **counted** | nothing, but know it is not enforced |
179
190
 
180
191
  **`SKIP` is not success and not failure.** It is the harness telling you the truth: "this rule has
181
- nothing to read yet." On a brand-new install, two dozen rows skip — because there is no `src/` for a
192
+ nothing to read yet." On a brand-new install, three dozen rows skip — because there is no `src/` for a
182
193
  ban to scan, no feature map, no loop record, no pinned pre-change commit. That is correct on day
183
194
  one. The list of what is still skipping *is* your onboarding checklist.
184
195
 
185
196
  ### Feature maps: generate with `gob map`, then opt in
186
197
 
187
- The feature-map rows (`FM-01`, `FM-02`) are opt-in by declaration: while `feature_map:` in
188
- `.goblin/goblin.yaml` is empty, both rows SKIP. When you are ready to keep a map honest, the flow
198
+ The feature-map rows (`FM-01`, `FM-02`) are opt-in by declaration: while `feature_map:` in the
199
+ AGENTS.md gob block is empty, both rows SKIP. When you are ready to keep a map honest, the flow
189
200
  is:
190
201
 
191
- 1. **Generate a starter.** `gob map` works in any git repo — no `.goblin/` install, no goblin.yaml.
192
- It scans the repo (Next.js app/pages router, Nuxt, route files, or top-level `src/`/`lib/`
202
+ 1. **Generate a starter.** `gob map --heuristic` works in any git repo — no install needed. It
203
+ scans the repo (Next.js app/pages router, Nuxt, route files, or top-level `src/`/`lib/`
193
204
  module dirs as TODO placeholders) and writes `features/README.md` plus one file per detected
194
205
  feature. It never clobbers: an existing `features/` refuses until `--force`, which regenerates
195
206
  only the index and adds new slugs — your hand-edited feature files are never rewritten.
196
207
  2. **Hand-pass every file.** The generated files say so themselves: a `verified: never-driven
197
208
  (generated <date>)` line is not a drive claim. Edit each one into a real feature description
198
209
  with concrete entry paths and driving steps.
199
- 3. **Then, optionally, declare it.** Set `feature_map: features/README.md` in `.goblin/goblin.yaml`
200
- and `FM-01`/`FM-02` start reading it on every verify — that declaration is the CI/verify opt-in,
201
- never forced. A repo that wants the generator but not the rows can run `gob map` and never
202
- declare anything.
210
+ 3. **Then, optionally, declare it.** Set `feature_map: features/README.md` in the AGENTS.md gob
211
+ block and `FM-01`/`FM-02` start reading it on every verify — that declaration is the
212
+ verify opt-in, never forced. A repo that wants the generator but not the rows can run
213
+ `gob map` and never declare anything.
203
214
 
204
215
  **Read the failure messages.** They are written to be actionable, not decorative. `HP-05` above is
205
216
  telling you the HANDOFF does not yet name a commit — fix it by naming your HEAD in the `State`
@@ -209,17 +220,16 @@ section.
209
220
 
210
221
  | Step | Command | Verify prints | The FAILs |
211
222
  |---|---|---|---|
212
- | 1. the wizard ran | `gob init ... --yes` | `31 passed, 6 failed, 11 advisory, 34 skipped` | the install is uncommitted (`CM-03`), `HP-05`, `GT-02` exit 127, and the identity/branch rows if you skipped the flags |
213
- | 2. the first commit | `git add -A && git commit` | `35 passed, 2 failed, 11 advisory, 34 skipped` | `HP-05` (the placeholder) and `GT-02` |
214
- | 3. name a real HEAD — and **commit that too** | edit `HANDOFF.md`, then `git add -A && git commit` | `36 passed, 1 failed, 11 advisory, 34 skipped` | `GT-02` only |
215
- | 4. your real gate | edit `gates:` in `.goblin/goblin.yaml` (§5) | `36 passed, 0 failed, ...` | none — green |
223
+ | 1. the install ran | `gob init --write ... --yes` | `35 passed, 2 failed, 11 advisory, 34 skipped` | the install is uncommitted (`CM-03`) and the shipped SPEC is untracked (`SP-02`) |
224
+ | 2. the first commit | `git add -A && git commit` | `36 passed, 1 failed, 11 advisory, 34 skipped` | `HP-05` (the placeholder) — plus `GT-02` if your gate names a script the repo does not have |
225
+ | 3. name a real HEAD — and **commit that too** | edit `HANDOFF.md`, then `git add -A && git commit` | `37 passed, 0 failed, 11 advisory, 34 skipped` | none — green |
216
226
 
217
- Two of those deserve their name spelled out:
227
+ One of those deserves its name spelled out:
218
228
 
219
- - **`GT-02` exit 127 is the guide's own teaching point, not a defect.** The default gate is
220
- `bash tests/run-tests.sh`, and a throwaway repo has no `tests/` — the shell's own
221
- *command not found*. It stays red until §5's most valuable edit (your real `gates:`) replaces
222
- it. The failure line tells you this: `gate commit: bash tests/run-tests.sh -> exit 127`.
229
+ - **`GT-02` exit 127 is the guide's own teaching point, not a defect.** The gate you wrote in the
230
+ proposal (`bash tests/run-tests.sh`) does not exist in a throwaway repo — the shell's own
231
+ *command not found*. Replace it with a command that can run (or create the script). The failure
232
+ line tells you this: `gate check: bash tests/run-tests.sh -> exit 127`.
223
233
  - **Step 3 is two steps on purpose.** Naming a real HEAD in `HANDOFF.md` without committing it
224
234
  re-reds `CM-03` (`1 dirty entr(y|ies)`) — commit-as-you-go starts on minute one. Edit, commit,
225
235
  then verify.
@@ -230,8 +240,8 @@ If you ran step 1 without `-b main`, or with the wrong git identity, you will se
230
240
 
231
241
  | FAIL | Cause | Fix |
232
242
  |---|---|---|
233
- | `PT-02 declared main, actual master` | branch name mismatch | set `branch:` in `.goblin/goblin.yaml` |
234
- | `CM-01` (commit identity) | the repo's commit email ≠ the declared `owner_email:` | set `owner_email:` in the config |
243
+ | `PT-02 declared main, actual master` | branch name mismatch | set `branch:` in the AGENTS.md gob block |
244
+ | `CM-01` (commit identity) | the repo's commit email ≠ the declared `owner_email:` | set `owner_email:` in the gob block |
235
245
  | `HP-05` | `HANDOFF.md` still names the scaffold placeholder `` `0000000` `` | replace it with your real short HEAD |
236
246
 
237
247
  **All three are configuration, not defects.** The harness is reporting your repo's actual state
@@ -240,33 +250,27 @@ against a declared expectation. That is exactly what you want it to do.
240
250
  `HP-05` deserves one sentence more, because it surprises people: the scaffold ships
241
251
  `HEAD when this file was written: `0000000``, and `HP-05` **rejects that placeholder on purpose**.
242
252
  A file that names a commit which does not exist is worse than one that names none — it looks like a
243
- record. Commit first, then write the real short SHA in. Measured on this walk: with the placeholder
244
- left in, verify reports `35 passed, 2 failed`; with the real SHA (and the edit committed),
245
- `36 passed, 1 failed` — the one FAIL being the `GT-02` exit 127 above.
253
+ record. Commit first, then write the real short SHA in.
246
254
 
247
255
  ---
248
256
 
249
- ## 5. Step 3 — Make it yours: the one config file
257
+ ## 5. Step 3 — Make it yours: the one config block
250
258
 
251
- Everything you configure lives in **one file**, created once and then never overwritten:
259
+ Everything you configure lives in **one place**, created once and then never overwritten
260
+ by the installer:
252
261
 
253
- .goblin/goblin.yaml
262
+ AGENTS.md — the `<!-- gob:begin --> ... <!-- gob:end -->` block
254
263
 
255
264
  Open it. The keys that matter on day one:
256
265
 
257
- class: software # software|service|game|research|fleet (A-E are aliases) - what kind of project this is (step 6)
266
+ class: software # software|service|game|research|fleet (A-E are aliases)
258
267
  branch: main # DECLARED, never assumed
259
268
  owner_email: you@example.com # the commit identity this repo expects
260
269
  practice: /path/to/your-standard.md # optional: your own house rules, hash-pinned
261
270
  models_file: /path/to/fleet-model.yaml # the ONE machine-specific input
271
+ gate_<name>_cmd: <one command> # YOUR real commands, one line each
262
272
 
263
- gates: # <- replace these with YOUR real commands
264
- - name: commit
265
- cmd: git rev-parse --verify --quiet HEAD
266
- - name: todo_ceiling
267
- cmd: test "$(grep -rniE '\b(TODO|FIXME)\b' --include='*.ts' . | wc -l)" -le 160
268
-
269
- **The single most valuable edit you will make:** replace the default `gates:` with the commands you
273
+ **The single most valuable edit you will make:** replace the gate line(s) with the commands you
270
274
  actually run to know your project is healthy. `tsc --noEmit`, `npm run build`, your test command —
271
275
  whichever three or four you would run before saying "this is fine."
272
276
 
@@ -278,7 +282,7 @@ without you remembering to. And the gate numbers are recorded with a date, so a
278
282
 
279
283
  If you already have a house standard — a `CONTRIBUTING.md`, a `PROJECT-PRACTICE.md`, anything
280
284
  written down — point `practice:` at it. gobstack does **not** copy its text. It records a
281
- **hash** of the file and re-checks that hash on every verify.
285
+ **hash** of the file (`practice_sha256:`) and re-checks that hash on every verify.
282
286
 
283
287
  That buys you one specific, valuable thing: **if someone edits your standard, every project that
284
288
  pins it goes red.** You find out immediately instead of discovering six months later that half your
@@ -288,8 +292,8 @@ When *you* legitimately edit your own standard:
288
292
 
289
293
  gob install --target . --re-pin
290
294
 
291
- It re-records the hash and prints the old and new value. Nothing re-pins automatically — an
292
- edited standard is never a silent no-op.
295
+ It re-records the hash and prints the old and new value. Nothing re-pins automatically — not even
296
+ a re-install — an edited standard is never a silent no-op.
293
297
 
294
298
  ---
295
299
 
@@ -313,10 +317,10 @@ gate, not a sixth class. The old `F` letter still resolves there as an install a
313
317
 
314
318
  - A repo that holds *output* while the code lives elsewhere → **research**, not **software**. Gating
315
319
  it like an application gates the wrong artifact.
316
- - A plain input directory that is not a build target → **research** with `--archive`, which tells
320
+ - A plain input directory that is not a build target → **research** with `archive: true`, which tells
317
321
  verify to expect no HANDOFF and no gates, and to say so.
318
322
 
319
- Switch class later by editing `class:` in the config and re-running install. The parts you no longer
323
+ Switch class later by editing `class:` in the gob block and re-running install. The parts you no longer
320
324
  need are recorded as **disabled** and will report `SKIP (opt-out)` rather than failing.
321
325
 
322
326
  ---
@@ -343,7 +347,7 @@ Step by step:
343
347
  # 2. make your change, committing in small steps
344
348
 
345
349
  # 3. run the gate
346
- .goblin/bin/goblin-verify
350
+ .gob/bin/goblin-verify
347
351
 
348
352
  # 4. write the handoff: state / gates / next steps / NOT verified
349
353
 
@@ -364,16 +368,16 @@ honest entry, and the harness treats it as one.
364
368
  > **Prove it was broken first.**
365
369
 
366
370
  Before you trust a check, break the thing it checks and watch it go red — then put it back and watch
367
- it go green. Break it on a row this walkthrough can actually break: `IN-02` hashes the **16 files it
368
- tracks** — not the 8 it `owns` (including `.goblin/goblin.yaml`, which §5 has you editing) and not
369
- `.goblin/installed.json`; edit one of the 16 — the exercise below uses `.goblin/bans/README.md`.
371
+ it go green. Break it on a row this walkthrough can actually break: `IN-02` hashes the 15 files it
372
+ tracks — not the ones it `owns` (including `AGENTS.md`, whose gob block §5 has you editing) and not
373
+ `.gob/installed.json`; edit one of the tracked — the exercise below uses `.gob/bans/README.md`.
370
374
 
371
375
  # REPLAY-BEGIN (this exact block is run by tests/t-doc-guide.sh - keep the two copies identical)
372
- .goblin/bin/goblin-verify --only IN-02 # expect PASS
373
- printf '\n<!-- a deliberate edit -->\n' >> .goblin/bans/README.md
374
- .goblin/bin/goblin-verify --only IN-02 # expect FAIL
375
- git stash push -- .goblin/bans/README.md # path-limited: your own edits stay put
376
- .goblin/bin/goblin-verify --only IN-02 # expect PASS
376
+ .gob/bin/goblin-verify --only IN-02 # expect PASS
377
+ printf '\n<!-- a deliberate edit -->\n' >> .gob/bans/README.md
378
+ .gob/bin/goblin-verify --only IN-02 # expect FAIL
379
+ git stash push -- .gob/bans/README.md # path-limited: your own edits stay put
380
+ .gob/bin/goblin-verify --only IN-02 # expect PASS
377
381
  git stash drop # the break was deliberate: discard it
378
382
  # REPLAY-END
379
383
 
@@ -382,10 +386,10 @@ That is the whole habit — the change you *undo* is a deliberate break, not a f
382
386
  measures the shipped files rather than your work.
383
387
 
384
388
  `GT-02` is the row most readers reach for first, and it will **not** work as a REPLAY demo on the
385
- shipped configuration: it runs the gates you declared (`commit`, `todo_ceiling`), and stashing a
389
+ shipped configuration: it runs the gates you declared, and stashing a
386
390
  local change does not change either command's exit status — so it prints `PASS` before and after,
387
391
  which is exactly the "green on both trees" result this rule exists to kill. REPLAY a gate of your
388
- own the same way, once that gate is real: declare it in `.goblin/goblin.yaml` and stash a change it
392
+ own the same way, once that gate is real: declare it in the gob block and stash a change it
389
393
  can see.
390
394
 
391
395
  A check that is green on **both** the broken and the fixed tree proves nothing — it would have been
@@ -396,7 +400,7 @@ caught every real regression in this repository's own development history.
396
400
 
397
401
  ## 8. Step 6 — The daily loop, once you are settled
398
402
 
399
- Day to day, the harness should fade into four habits:
403
+ Day to day, the harness should fade into three habits:
400
404
 
401
405
  **Starting work** — read `HANDOFF.md` first. It tells you the state, the gates, what is next, and —
402
406
  most importantly — **what is *not* verified**. Never trust a claim in it without running the
@@ -407,15 +411,7 @@ the harness nudges you to land things as they work rather than in one heroic com
407
411
 
408
412
  **Finishing** — update `HANDOFF.md`, then:
409
413
 
410
- .goblin/bin/goblin-verify && git add -A && git commit -m "..."
411
-
412
- **Every so often** — audit your own claims against the artifact:
413
-
414
- .goblin/bin/goblin-audit
415
-
416
- This is the *only* step that touches the network (rule `SC-07`), and it is deliberate: it is how a
417
- recorded claim ("this dependency is fine") gets checked against reality ("this dependency has a
418
- known advisory").
414
+ .gob/bin/goblin-verify && git add -A && git commit -m "..."
419
415
 
420
416
  ### Keeping `HANDOFF.md` honest
421
417
 
@@ -449,18 +445,18 @@ the next session.
449
445
 
450
446
  ## 9. What to expect on day one (so you do not misread it)
451
447
 
452
- A software-class install through the wizard lands on a specific shape. Two of the first reds are
453
- the scaffold teaching on purpose — `HP-05`, the `0000000` placeholder in `HANDOFF.md` (§4), and
454
- `GT-02`, the default gate pointing at a test script a throwaway repo does not have. The walk in §4
455
- measured, step by step:
448
+ A software-class install lands on a specific shape. The first reds are
449
+ the scaffold teaching on purpose — `HP-05`, the `0000000` placeholder in `HANDOFF.md` (§4). The
450
+ walk in §4 measured, step by step:
456
451
 
457
- 31 passed, 6 failed, 11 advisory, 34 skipped # straight after the wizard, nothing committed
458
- 35 passed, 2 failed, 11 advisory, 34 skipped # first commit: HP-05 and GT-02 left
459
- 36 passed, 1 failed, 11 advisory, 34 skipped # real HEAD named and committed: GT-02 left
452
+ 35 passed, 2 failed, 11 advisory, 34 skipped # straight after the install (CM-03 + SP-02)
453
+ 36 passed, 1 failed, 11 advisory, 34 skipped # first commit: HP-05 left (and GT-02 too if the gate cannot run)
454
+ 37 passed, 0 failed, 11 advisory, 34 skipped # real HEAD named and committed: green
460
455
 
461
- Name a real commit in `HANDOFF.md`, commit, and give `gates:` real commands (§5), and it is green:
456
+ Name a real commit in `HANDOFF.md`, commit, and give the gate lines real commands (§5), and it is
457
+ green:
462
458
 
463
- 36 passed, 0 failed, 11 advisory, 34 skipped (on a real project; your numbers will differ)
459
+ 37 passed, 0 failed, 11 advisory, 34 skipped (on a real project; your numbers will differ)
464
460
 
465
461
  **Thirty-four rows skipping is correct**, and each skip prints its reason. In plain terms: the
466
462
  harness is telling you which of its rules have nothing to read yet. It is a checklist, not a
@@ -486,9 +482,9 @@ Two readings that are easy to get wrong:
486
482
  | Symptom | What it means | What to do |
487
483
  |---|---|---|
488
484
  | `refused to overwrite: HANDOFF.md`, exit 1 | your repo already had a HANDOFF | **do not `--force`** — reconcile it (below) |
489
- | `PT-02 declared main, actual master` | branch mismatch | set `branch:` in the config |
485
+ | `PT-02 declared main, actual master` | branch mismatch | set `branch:` in the gob block |
490
486
  | `IN-02 ... practice EDITED` | someone changed the pinned standard | re-pin deliberately: `--re-pin` |
491
- | `gob install: unknown subcommand` (exit 2) | you ran a bare `gob install` without the npm package installed | install the npm package first: `npm i -g @techgoblin/gobstack`, then `gob install` |
487
+ | `gob: unrecognized command: <verb>` (exit 2) | you ran a verb outside the v2 surface (`audit`, `doctor`, `emit`, `sync`, `upgrade`, `install`) | use the five wired verbs: `init`, `map`, `verify`, `bans`, `uninstall` — the unwired surface returns in a later alpha |
492
488
  | `IN-03` fails, "manifest is broken" | a row has a broken check column | fix the row; this is a source defect, not yours |
493
489
  | a `FAIL` you believe is wrong | the check may be weak, or your belief may be | run `--only <id>` and read the command it prints |
494
490
  | a changelog or matrix note says `W6` or `Z1-4` | that is a revision wave code | `docs/RECORD-NOTES.md` is the legend, one line per code |
@@ -498,37 +494,15 @@ replaces your project's own record with a blank scaffold — the exact act the r
498
494
  prevent. Reconcile instead: keep your file, and add the five sections it is missing. The measured
499
495
  cost of that edit, on a real 2450-line handoff, was **15 lines added, none removed**.
500
496
 
501
- **One engine, many repos:** the rule table does not have to live in every repo. A repo can
502
- point at a shared engine with one line in `.goblin/goblin.yaml`:
503
-
504
- engine_dir: ~/.goblin/engine # absolute or ~/-prefixed; absent = per-repo engine
505
-
506
- Declared but unusable (relative path, missing directory, no manifest inside) is verify **exit 2
507
- with no fallback** — a repo is never judged by an engine it did not declare. A repo whose record
508
- says `mode=global` keeps hashing whatever files it still holds; the engine's own identity prints in
509
- every run's footer (`engine: mode=… cli_sha256=… enforcement_tsv_sha256=…`). The same commands are
510
- available outside any repo through the npm CLI: `gob verify` / `gob bans` / `gob audit` /
511
- `gob doctor` / `gob sync` / `gob upgrade` / `gob --version`.
512
-
513
- **Migrating a repo to the global engine:**
514
-
515
- gob upgrade # 8 steps, two commits, one report
516
-
517
- It refuses on a dirty tree, a detached HEAD, a red repo, or a global engine holding different
518
- bytes — each refusal names the fix. What it does: verifies every recorded hash, lands the engine
519
- at `~/.goblin/engine` (or `--engine-dir <dir>`) from this repo's own verified bytes, commits the
520
- declaration + record rewrite + `checks/gate.sh` + CI re-point (commit A), proves the repo green
521
- with both engines present, then `git rm`s exactly the 18 engine files (commit B) and proves green
522
- again. Nothing is deleted before the engine is safely landed and the tree is green mid-sequence.
523
-
524
- **Rolling back a migration** — the two commits are pure git operations:
525
-
526
- git revert <commit-A-sha> <commit-B-sha>
527
-
528
- reverses byte-for-byte: the vendored payload returns, the record drops its `engine:` block, and
529
- `gob verify` is the 43-green it was before. A second `gob upgrade` on a migrated repo is a
530
- no-op; `goblin-install` onto one refuses with the revert remedy (re-installing would re-shadow the
531
- engine and silently de-migrate the record).
497
+ **One engine, many repos (declared, not wired in this alpha):** the rule table can live outside
498
+ the repo — a declared `engine_dir:` line in the gob block names a shared engine. In v2 the
499
+ **vendored engine wins by design**: a repo carrying both `.gob/` and an `engine_dir:` judges
500
+ itself with the vendored manifest, because that is the manifest its install record hashes
501
+ (`docs/LIMITS.md` #54). A declared but unusable `engine_dir:` is verify **exit 2 with no
502
+ fallback** — a repo is never judged by an engine it did not declare. The engine's own identity
503
+ prints in every run's footer (`engine: mode=vendored cli_sha256=… enforcement_tsv_sha256=…`). The
504
+ same commands are available outside any repo through the npm CLI: `gob init` / `gob map` /
505
+ `gob verify` / `gob bans` / `gob --version`.
532
506
 
533
507
  **Two exit-code contracts worth knowing:**
534
508
 
@@ -536,8 +510,7 @@ engine and silently de-migrate the record).
536
510
  |---|---|
537
511
  | `goblin-install` | `0` ok · `1` a refusal (with the path and the fix) · `2` bad input |
538
512
  | `goblin-verify` | `0` all checks passed · `1` a check failed · `2` could not run · `3` the manifest itself is broken |
539
- | `goblin` (npm CLI) | propagates the subcommand's codes verbatim — `verify`/`bans`/`audit`/`--version`; `install`/`uninstall`/`re-pin`/`upgrade` route into `goblin-install` (`upgrade` migrates to the global engine: `0` ok · `1` refusal · `2` bad input); `doctor`/`emit` carry the same contract: `doctor` exits `0` every probed platform DETECTED and clean · `1` any DRIFT · `2` nothing to probe, and `emit` exits `0` ok or no-op · `1` refusal (with the path and the fix) · `2` bad input or unknown platform; `sync` is the same verb renamed and propagates identically |
540
- | platforms (W4b) | `emit`/`doctor` cover seven: `claude`, `hermes`, `copilot`, `cursor`, `opencode`, `codex`, `gemini` — each detected via its own anchor (`~/.claude`, `~/.hermes`, `~/.copilot`, `~/.cursor`, `~/.config/opencode`, `~/.codex`, `~/.gemini`); codex and gemini carry `partial` command-blocking (see LIMITS #47) |
513
+ | `gob` (npm CLI) | propagates the subcommand's codes verbatim; a verb outside the surface (`audit`/`doctor`/`emit`/`sync`/`upgrade`/`install`) is refused with exit 2 and the usage |
541
514
 
542
515
  `3` is the one to notice: it means gobstack's own rule table is malformed, not your project.
543
516
 
@@ -547,16 +520,34 @@ engine and silently de-migrate the record).
547
520
 
548
521
  ### Commands
549
522
 
550
- gob install --target <dir> --class <software|service|game|research|fleet> [options]
551
- gob install --target <dir> --uninstall
552
- gob install --target <dir> --re-pin
553
- gob install --target <dir> --upgrade
523
+ gob init [--heuristic] [--write <proposal>] [--target <dir>] [--dry-run] [--yes]
524
+ [--with-mcp-config]
525
+ gob map [--heuristic [target]] [--write <dir>] [--force]
526
+ gob mcp # the MCP stdio server (three tools, local only)
554
527
 
555
- .goblin/bin/goblin-verify [--only <id[,id...]>] [--json] [--list]
556
- .goblin/bin/goblin-audit # the only network step
557
- .goblin/bin/goblin-bans # run the ban list
528
+ .gob/bin/goblin-verify [--only <id[,id...]>] [--json] [--list]
529
+ .gob/bin/goblin-bans # run the ban list
530
+ gob install --target <dir> --uninstall # the uninstall job
531
+ gob install --target <dir> --re-pin # the deliberate re-pin
558
532
  bin/goblin-model <role> # checkout-only; resolve a role to a profile (docs/ROLES.md)
559
533
 
534
+ ### Register the harness with your agent (MCP)
535
+
536
+ Your agent can call the discipline gate itself instead of you pasting verify output into the
537
+ chat. `gob mcp` is a local tool server (JSON-RPC over stdin/stdout — the Model Context
538
+ Protocol shape); it exposes `gob_verify` (the gate, with the remedy line under every FAIL),
539
+ `gob_map_status` (the feature map, read-only) and `gob_init_status` (is this repo under the
540
+ harness). It calls no API and opens no socket.
541
+
542
+ The one-liner, per user account:
543
+
544
+ claude mcp add gob -- npx -y @techgoblin/gobstack mcp
545
+
546
+ or, committed with the repo so every teammate's agent picks it up (Claude Code and Cursor
547
+ auto-detect it):
548
+
549
+ gob init --with-mcp-config # writes .mcp.json; never overwrites one you customized
550
+
560
551
  ### The 15 playbooks
561
552
 
562
553
  Named procedures, installed as project-local skills. Each has a measurable verification step.
@@ -584,7 +575,7 @@ Named procedures, installed as project-local skills. Each has a measurable verif
584
575
  | File | Read it for |
585
576
  |---|---|
586
577
  | `docs/DESIGN.md` | the thesis and every rejected alternative |
587
- | `docs/GLOSSARY.md` | every term of art in one table (rendered from `.goblin/manifest/glossary.tsv`) |
578
+ | `docs/GLOSSARY.md` | every term of art in one table (rendered from `.gob/manifest/glossary.tsv`) |
588
579
  | `docs/RECORD-NOTES.md` | the wave codes the changelog uses, one line each |
589
580
  | `docs/FLOWS.md` | the playbooks in full, with reasons |
590
581
  | `docs/ENFORCEMENT.md` | the rule matrix, rendered for a human |
@@ -592,7 +583,7 @@ Named procedures, installed as project-local skills. Each has a measurable verif
592
583
  | `docs/RISKS.md` | the risk register and non-goals |
593
584
  | `docs/CONTRACTS.md` | exact interface, exit codes, uninstall |
594
585
  | `docs/ADOPTION.md` | classes, presets, adoption order |
595
- | `docs/CI.md`, `docs/LOOP.md`, `docs/GUARDRAILS.md` | the newer lanes |
586
+ | `docs/LOOP.md`, `docs/GUARDRAILS.md` | the newer lanes |
596
587
 
597
588
  ---
598
589
 
@@ -611,64 +602,63 @@ Stated plainly, because a guide that oversells its tool is worse than no guide:
611
602
  - **It is not a product.** It is a repository of files, installed into other repositories.
612
603
  No service, no daemon, no support contract.
613
604
 
614
- The current status, if you want the honest number: a separate review pass verified the artifact at
615
- **9/10** (that was 0.4.2), and the point it withheld was not a missing feature — it was sentences
616
- in the record that a measurement contradicted. `docs/LIMITS.md` is the list of what the harness
617
- cannot see.
618
-
619
605
  ---
620
606
 
621
607
  ## 13. Where to go next
622
608
 
623
- **If you only do one thing:** install into your most active repo today, set your real `gates:`, and
624
- run `goblin-verify` once a day for a week. The habit, not the tool, is what produces the result.
609
+ **If you only do one thing:** install into your most active repo today, set your real gate
610
+ commands, and run `goblin-verify` once a day for a week. The habit, not the tool, is what produces
611
+ the result.
625
612
 
626
613
  **Then, in order:**
627
614
 
628
615
  1. Point `practice:` at your existing house standard and pin it.
629
616
  2. Write one `AC:` item that a script could check, and make it pass.
630
617
  3. Add a ban for the one pattern you are tired of seeing in agent-written code
631
- (`.goblin/manifest/bans.tsv` — a ban without a mechanism is a wish, so give it one).
618
+ (`.gob/manifest/bans.tsv` — a ban without a mechanism is a wish, so give it one).
632
619
  4. When you have a bug that a test could catch, walk P5 (`goblin-tdd-repro`) end to end once.
633
620
 
634
- **If you are sharing this with a team:** the parts that matter are `HANDOFF.md`, the `gates:` you
635
- declare, and the REPLAY habit. The rest is optional machinery you can switch off per class. Lead
636
- with *"prove it was broken first"* — it is the one practice that survives contact with a deadline.
621
+ **If you are sharing this with a team:** the parts that matter are `HANDOFF.md`, the gate commands
622
+ you declare, and the REPLAY habit. The rest is optional machinery you can switch off per class.
623
+ Lead with *"prove it was broken first"* — it is the one practice that survives contact with a
624
+ deadline.
637
625
 
638
626
  ---
639
627
 
640
628
  ## Appendix — a 45-minute first run, on one page
641
629
 
642
630
  # 0. get it
643
- npm i -g @techgoblin/gobstack
631
+ npx @techgoblin/gobstack init # or: npm i -g @techgoblin/gobstack
644
632
 
645
633
  # 1. try it somewhere disposable
646
634
  mkdir -p /tmp/gs-try && cd /tmp/gs-try
647
635
  git init -b main
648
- gob install --target . --class software # expect: created 25 (no skills — those are gob sync)
636
+ gob init --heuristic # the brief + schema; answer it in a proposal file
637
+ gob init --write .gob-init-proposal.md --yes
638
+ # expect: created 23 (no skills — those are opt-in)
649
639
 
650
640
  # 2. commit and check
651
641
  git add -A && git commit -m "chore: install gobstack"
652
- .goblin/bin/goblin-verify # expect: mostly PASS, some SKIP
642
+ .gob/bin/goblin-verify # expect: mostly PASS, some SKIP
653
643
 
654
644
  # 3. make it yours
655
- $EDITOR .goblin/goblin.yaml # branch, owner_email, and YOUR real gates:
645
+ $EDITOR AGENTS.md # branch, owner_email, and YOUR real gate commands (the gob block)
656
646
 
657
647
  # 4. prove a check can fail (the habit that matters) - the same block §7 runs
658
648
  # REPLAY-BEGIN (this exact block is run by tests/t-doc-guide.sh - keep the two copies identical)
659
- .goblin/bin/goblin-verify --only IN-02 # expect PASS
660
- printf '\n<!-- a deliberate edit -->\n' >> .goblin/bans/README.md
661
- .goblin/bin/goblin-verify --only IN-02 # expect FAIL
662
- git stash push -- .goblin/bans/README.md # path-limited: your own edits stay put
663
- .goblin/bin/goblin-verify --only IN-02 # expect PASS
649
+ .gob/bin/goblin-verify --only IN-02 # expect PASS
650
+ printf '\n<!-- a deliberate edit -->\n' >> .gob/bans/README.md
651
+ .gob/bin/goblin-verify --only IN-02 # expect FAIL
652
+ git stash push -- .gob/bans/README.md # path-limited: your own edits stay put
653
+ .gob/bin/goblin-verify --only IN-02 # expect PASS
664
654
  git stash drop # the break was deliberate: discard it
665
655
  # REPLAY-END
666
656
 
667
657
  # 5. do it for real, in a repo you care about
668
658
  cd ~/projects/your-project
669
- gob install --target . --class software
659
+ gob init --write .gob-init-proposal.md --yes
670
660
  git add -A && git commit -m "chore: adopt gobstack"
671
- .goblin/bin/goblin-verify
661
+ .gob/bin/goblin-verify
672
662
  $EDITOR HANDOFF.md # state / gates (dated!) / next / NOT verified
673
663
 
674
664
  ---