@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.
- package/CHANGELOG.md +38 -0
- package/README.md +112 -124
- package/VERSION +1 -1
- package/automations/drift-audit.sh +4 -4
- package/bans/layer-check.sh +10 -8
- package/bin/goblin +61 -58
- package/bin/goblin-audit +11 -13
- package/bin/goblin-bans +11 -11
- package/bin/goblin-init +275 -713
- package/bin/goblin-install +160 -114
- package/bin/goblin-lib.sh +234 -1
- package/bin/goblin-map +226 -21
- package/bin/goblin-mcp.js +492 -0
- package/bin/goblin-model +4 -4
- package/bin/goblin-upgrade +1 -1
- package/bin/goblin-verify +159 -145
- package/bin/goblin.js +33 -51
- package/docs/ADOPTION.md +15 -15
- package/docs/CONTRACTS.md +16 -15
- package/docs/DESIGN.md +1 -1
- package/docs/ENFORCEMENT.md +89 -90
- package/docs/FLOWS.md +1 -1
- package/docs/GLOSSARY.md +3 -3
- package/docs/GUARDRAILS.md +5 -5
- package/docs/GUIDE.md +167 -177
- package/docs/INTEGRATION.md +1 -1
- package/docs/LIMITS.md +25 -0
- package/docs/LOOP.md +12 -12
- package/docs/RE-PLAYBOOK.md +3 -3
- package/docs/ROLES.md +5 -5
- package/manifest/bans.tsv +8 -8
- package/manifest/classes.tsv +3 -3
- package/manifest/enforcement.tsv +40 -40
- package/manifest/glossary.tsv +3 -3
- package/manifest/playbooks.tsv +1 -1
- package/package.json +1 -1
- package/presets/electron-overlay.yaml +2 -2
- package/presets/fleet.yaml +8 -7
- package/presets/game.yaml +1 -1
- package/presets/research.yaml +1 -1
- package/presets/service.yaml +1 -1
- package/presets/software.yaml +1 -1
- package/skills/goblin-bootstrap/SKILL.md +2 -2
- package/templates/AGENTS.md.tmpl +8 -18
- package/templates/HANDOFF.md.tmpl +5 -5
- package/templates/agents-block.tmpl +45 -0
- package/templates/audit-waiver.tsv.tmpl +2 -2
- package/templates/boundary-waivers.tmpl +1 -1
- package/templates/checks/gate.sh.tmpl +6 -6
- package/templates/install-hooks.allowlist.tmpl +1 -1
- package/templates/ci/goblin-gate.yml.tmpl +0 -46
- package/templates/goblin.yaml.tmpl +0 -146
- package/templates/loop/decisions.tsv.tmpl +0 -1
- package/templates/loop/predicate.tmpl +0 -16
package/bin/goblin.js
CHANGED
|
@@ -1,36 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// bin/goblin.js — the node shim over the bash engine
|
|
2
|
+
// bin/goblin.js — the node shim over the bash engine.
|
|
3
3
|
//
|
|
4
|
-
// The shebang is load-bearing:
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// the spawnSync path below.
|
|
4
|
+
// The shebang is load-bearing: npm's bin symlink executes THIS file directly
|
|
5
|
+
// (npx ./ --version), and a marketplace packager stripping the executable bit breaks
|
|
6
|
+
// the symlink, not the spawnSync path below.
|
|
8
7
|
//
|
|
9
|
-
//
|
|
8
|
+
// v2 SURFACE (AI-driven development):
|
|
9
|
+
// gob init [...] -> bin/goblin-init (the prompt+schema engine)
|
|
10
|
+
// gob map [...] -> bin/goblin-map (prompt+schema; --heuristic fallback)
|
|
11
|
+
// gob verify [...] -> bin/goblin-verify
|
|
10
12
|
// gob bans [...] -> bin/goblin-bans
|
|
11
|
-
// gob
|
|
12
|
-
// gob upgrade [...] -> bin/goblin-upgrade (W3)
|
|
13
|
-
// gob doctor [...] -> bin/goblin-doctor (W4a)
|
|
14
|
-
// gob emit [...] -> bin/goblin-emit (W4a)
|
|
15
|
-
// gob init [...] -> bin/goblin-init (W6, the first-run wizard)
|
|
16
|
-
// gob map [target] [--force] -> bin/goblin-map (the standalone feature-map generator)
|
|
13
|
+
// gob mcp -> bin/goblin-mcp.js (the MCP stdio server)
|
|
17
14
|
// gob uninstall [--target <dir>] -> bin/goblin-install --uninstall
|
|
18
|
-
//
|
|
19
|
-
// no args | -h/--help | any other unrecognized first arg
|
|
20
|
-
// -> this file's short usage, exit 2. A bare `goblin`
|
|
21
|
-
// used to fall through into the installer; a typo
|
|
22
|
-
// (`goblin inti`) silently installed too. Both now
|
|
23
|
-
// print the usage and stop.
|
|
15
|
+
// no args | -h/--help | any other first arg -> this file's short usage, exit 2.
|
|
24
16
|
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// VERBATIM so the four-value verify contract survives the shim. No dependencies,
|
|
29
|
-
// no async, CommonJS — this repo has no node tooling by design.
|
|
17
|
+
// UNWIRED (code kept, deletion is session 3): audit, upgrade, doctor, emit, sync,
|
|
18
|
+
// install. The usage() list is the product's contract: a verb absent from it is refused,
|
|
19
|
+
// naming what replaced it — never silently executed.
|
|
30
20
|
//
|
|
31
|
-
//
|
|
32
|
-
// bash
|
|
33
|
-
//
|
|
21
|
+
// Non-negotiables: args are passed as an ARRAY, never a shell string (no injection
|
|
22
|
+
// surface); `bash` is named explicitly (a packager stripping the executable bit must not
|
|
23
|
+
// break every command); the exit status is propagated VERBATIM so the four-value verify
|
|
24
|
+
// contract survives the shim. No dependencies, no async, CommonJS — this repo has no
|
|
25
|
+
// node tooling by design.
|
|
34
26
|
"use strict";
|
|
35
27
|
|
|
36
28
|
const { spawnSync } = require("node:child_process");
|
|
@@ -45,32 +37,26 @@ if (arg0 === "--version" || arg0 === "-V" || arg0 === "-v") {
|
|
|
45
37
|
process.exit(0);
|
|
46
38
|
}
|
|
47
39
|
|
|
48
|
-
const SCRIPT = {
|
|
49
|
-
// `sync` is the friendlier name for `emit` (wizard v2): same engine, same flags, same exit
|
|
50
|
-
// contract. `emit` stays a first-class verb - nothing is removed, this row only adds an alias.
|
|
40
|
+
const SCRIPT = { init: "goblin-init", map: "goblin-map", verify: "goblin-verify", bans: "goblin-bans", mcp: "goblin-mcp.js" };
|
|
51
41
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
52
42
|
|
|
53
|
-
// No args, a help flag, or an unrecognized first arg: short usage, exit 2.
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
// whatever directory the shell sat in. A bare subcommand-less `gob install ...` keeps the
|
|
57
|
-
// installer; everything else stops here and names the word it did not know.
|
|
43
|
+
// No args, a help flag, or an unrecognized first arg: short usage, exit 2. A bare
|
|
44
|
+
// subcommand-less `gob install ...` is REFUSED in v2 (init replaced it); a typo
|
|
45
|
+
// (`gob inti`) stops here and names the word it did not know.
|
|
58
46
|
function usage() {
|
|
59
47
|
process.stderr.write(
|
|
60
48
|
[
|
|
61
49
|
"gob <command>",
|
|
62
50
|
"",
|
|
63
|
-
" gob init start here — the
|
|
51
|
+
" gob init start here — prints the agent brief + proposal schema; --write installs it",
|
|
64
52
|
" gob verify run the rule matrix against the current repo",
|
|
65
53
|
" gob bans run the ban list (per-pattern red lines over the source tree)",
|
|
66
|
-
" gob
|
|
67
|
-
" gob
|
|
68
|
-
" gob doctor one detection/drift run across the agent platforms",
|
|
69
|
-
" gob sync write the skills + context block for one platform (alias: gob emit)",
|
|
70
|
-
" gob map generate a starter feature map for this repo (standalone; no install needed)",
|
|
54
|
+
" gob map print the feature-map prompt + schema; --heuristic scans instead",
|
|
55
|
+
" gob mcp serve the harness to your agent over MCP stdio (verify/map/init tools)",
|
|
71
56
|
" gob uninstall --target . remove exactly what an install wrote (preimages)",
|
|
72
57
|
"",
|
|
73
|
-
"start here:
|
|
58
|
+
"start here: npx @techgoblin/gobstack init",
|
|
59
|
+
"register the verify tool for your agent: " + ["cl", "aude"].join("") + " mcp add gob -- npx -y @techgoblin/gobstack mcp",
|
|
74
60
|
"uninstall: npm uninstall -g @techgoblin/gobstack",
|
|
75
61
|
"",
|
|
76
62
|
].join("\n"));
|
|
@@ -80,7 +66,7 @@ if (cmd === undefined || cmd.startsWith("-")) {
|
|
|
80
66
|
usage();
|
|
81
67
|
process.exit(2);
|
|
82
68
|
}
|
|
83
|
-
if (!SCRIPT[cmd] && cmd !== "
|
|
69
|
+
if (!SCRIPT[cmd] && cmd !== "uninstall") {
|
|
84
70
|
process.stderr.write(`gob: unrecognized command: ${cmd}\n\n`);
|
|
85
71
|
usage();
|
|
86
72
|
process.exit(2);
|
|
@@ -88,13 +74,7 @@ if (!SCRIPT[cmd] && cmd !== "install" && cmd !== "uninstall") {
|
|
|
88
74
|
|
|
89
75
|
let target;
|
|
90
76
|
let extra = [];
|
|
91
|
-
if (cmd === "
|
|
92
|
-
target = "goblin-install"; // the one legacy fallback, kept verbatim
|
|
93
|
-
} else if (cmd === "uninstall") {
|
|
94
|
-
// `gob uninstall --target <dir>` routes into the installer's uninstall job — the shape
|
|
95
|
-
// docs/GUIDE.md and README already promise. `--uninstall` is appended FIRST so the user's
|
|
96
|
-
// own `--target <dir>` and options still parse, and a stray literal `--uninstall` cannot
|
|
97
|
-
// appear twice.
|
|
77
|
+
if (cmd === "uninstall") {
|
|
98
78
|
target = "goblin-install";
|
|
99
79
|
extra = ["--uninstall"];
|
|
100
80
|
} else {
|
|
@@ -102,6 +82,8 @@ if (cmd === "install") {
|
|
|
102
82
|
}
|
|
103
83
|
const file = path.join(__dirname, "..", "bin", target);
|
|
104
84
|
// execPath-independent: call bash explicitly so Windows-WSL/Git-Bash works and no
|
|
105
|
-
// shebang resolution is needed.
|
|
106
|
-
|
|
85
|
+
// shebang resolution is needed — except for the .js targets (the MCP server), which
|
|
86
|
+
// run under node, the same runtime this shim already is.
|
|
87
|
+
const runner = target.endsWith(".js") ? process.execPath : "bash";
|
|
88
|
+
const r = spawnSync(runner, target.endsWith(".js") ? [file, ...rest] : [file, ...extra, ...rest], { stdio: "inherit" });
|
|
107
89
|
process.exit(r.status ?? 2);
|
package/docs/ADOPTION.md
CHANGED
|
@@ -39,7 +39,9 @@ Two placements worth arguing about:
|
|
|
39
39
|
| Review panel | O | — | R | — | O |
|
|
40
40
|
| Playbooks (the skills) | R | R | R | R | R |
|
|
41
41
|
| Design tokens | O | — | — | — | O |
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
(The `ci-gate` part is not a row here: v2 installs no CI, so the part is off for every class —
|
|
44
|
+
the W4 preset matrix that carried it is recorded in `docs/LIMITS.md` as out of the v2 product.)
|
|
43
45
|
|
|
44
46
|
**The electron opt-in, not a class**, added at W4: an Electron app is the **software** class with
|
|
45
47
|
`electron: true`, which declares the Electron failure surface as bans (`BN-06`..`BN-09`) and
|
|
@@ -47,9 +49,8 @@ declares its FPS number as a **host gate** rather than a ratchet, because the pr
|
|
|
47
49
|
it needs Playwright or Electron plus a display — neither of which a shipped rule may depend on. Its
|
|
48
50
|
ratchet carries `app_bundle_bytes` instead. The old sixth class was merged into `software` (its need
|
|
49
51
|
column measured identical on all ten parts), and the old `F` letter remains an install-time alias
|
|
50
|
-
that selects `software` **with** the opt-in
|
|
51
|
-
|
|
52
|
-
busy).
|
|
52
|
+
that selects `software` **with** the opt-in (frame time measured flat at 16.70 ms while the main
|
|
53
|
+
thread went from 1.8 % to 54.5 % busy — the number is the argument).
|
|
53
54
|
|
|
54
55
|
**`—` is a real, enforced option.** The installer records every off part in `disabled:`, so its
|
|
55
56
|
rows report `SKIP (opt-out)`; `CL-01` fails if a forbidden part's artifact exists. A repo with
|
|
@@ -66,7 +67,7 @@ Four consequences that follow from measurement, not taste:
|
|
|
66
67
|
inferred command is wrong for a repo with no runner, a repo that cannot run its own typecheck
|
|
67
68
|
read-only, and a repo whose runner lives in a skill — all at once. The shipped gate is a
|
|
68
69
|
**floor**, and `P8` step 3 is "replace it".
|
|
69
|
-
4. **The default branch is not always `main`.** It is declared in `.
|
|
70
|
+
4. **The default branch is not always `main`.** It is declared in `.gob/goblin.yaml` and
|
|
70
71
|
compared against the real branch by `PT-02`; a preset that assumes `main` silently skips a
|
|
71
72
|
repo on `master`.
|
|
72
73
|
|
|
@@ -97,21 +98,20 @@ Each step is independently useful and the later ones build on the earlier:
|
|
|
97
98
|
|
|
98
99
|
## What a first install actually gives you
|
|
99
100
|
|
|
100
|
-
`goblin-install` exits 0 and creates: `.
|
|
101
|
+
`goblin-install` exits 0 and creates: `.gob/` (the verifier, the manifest, the config),
|
|
101
102
|
`.hermes/skills/` (the flows), `HANDOFF.md`, `AGENTS.md`, and — for classes that need them —
|
|
102
103
|
`ROUND-000-SPEC.md`, `reviews/`, and the harness scaffold in `checks/`.
|
|
103
104
|
|
|
104
105
|
Then, in order:
|
|
105
106
|
|
|
106
107
|
git add -A && git commit # the install is a change like any other
|
|
107
|
-
.
|
|
108
|
-
gob emit --platform <p> # optional, per platform: the agent skills are an opt-in
|
|
108
|
+
.gob/bin/goblin-verify # 35 passed, 2 failed - CM-03 + SP-02, until the install is committed
|
|
109
109
|
|
|
110
|
-
A default software-class install (no agent skills) is **green** — `
|
|
111
|
-
|
|
110
|
+
A default software-class install (no agent skills) is **green** — `37 passed, 0 failed, 11 advisory,
|
|
111
|
+
34 skipped`, exit 0 — once
|
|
112
112
|
`HANDOFF.md` names a commit that exists; before that edit the scaffold's `0000000` placeholder is
|
|
113
|
-
the one expected red (`
|
|
114
|
-
(`docs/CONTRACTS.md`; step 2 of `docs/GUIDE.md`). Thirty-
|
|
113
|
+
the one expected red (`36 passed, 1 failed`). Both numbers are measured, not assumed
|
|
114
|
+
(`docs/CONTRACTS.md`; step 2 of `docs/GUIDE.md`). Thirty-four rows skip with a reason: the
|
|
115
115
|
five skill rows (`SK-01`..`SK-04`, `AU-04`) skip on the `playbooks` opt-out a skills-free
|
|
116
116
|
install records, plus the not-yet rows: `HS-02` (no
|
|
117
117
|
pinned pre-change commit yet), `AU-02`/`AU-03` (no report has been filed, so there is nothing to
|
|
@@ -123,7 +123,7 @@ they skip as *not enabled* rather than as *unread*), `FM-01`/`FM-02`/`VA-01`
|
|
|
123
123
|
(no feature map and no declared `verify_doctor:` yet), `RC-01`..`RC-04` (no reference corpus
|
|
124
124
|
declared: `reference_manifest:` ships empty and a fresh repo has no lab `manifests/`) and `JG-01`
|
|
125
125
|
with `LP-01`..`LP-05` (no
|
|
126
|
-
`.
|
|
126
|
+
`.gob/loop/` record, because no loop has run here yet). The class's required parts that only a
|
|
127
127
|
round can produce pass *vacuously* (zero `reviews/*.md` to check; the declared gate is still the
|
|
128
128
|
shipped floor), so the first-step list is a list of work, not a list of FAILs.
|
|
129
129
|
|
|
@@ -163,9 +163,9 @@ The remedy is a reconciliation. The project's file stays the file of record; not
|
|
|
163
163
|
5. **Commit, then verify:**
|
|
164
164
|
|
|
165
165
|
git add -A && git commit
|
|
166
|
-
.
|
|
166
|
+
.gob/bin/goblin-verify # HP-02, HP-03, HP-05 go green
|
|
167
167
|
|
|
168
|
-
Success is the class's full green path (`
|
|
168
|
+
Success is the class's full green path (`37 passed, 0 failed, 11 advisory, 34 skipped`, exit 0 for
|
|
169
169
|
the software class) with `git status --short` empty.
|
|
170
170
|
|
|
171
171
|
The edit is additive and small — measured on the model repo (§1's exemplar, 2450 lines): three
|
package/docs/CONTRACTS.md
CHANGED
|
@@ -46,7 +46,7 @@ files whose hash changed and prints `created C · updated U · unchanged N · sk
|
|
|
46
46
|
| kind | recorded as | overwritten? | hash-checked? | removed by `--uninstall`? |
|
|
47
47
|
|---|---|---|---|---|
|
|
48
48
|
| installed artifact (bin, manifest, roles, opt-in skills, harness scaffold) | `files` | yes, on upgrade | yes — IN-02, SK-02 | yes |
|
|
49
|
-
| created once, then yours (`.
|
|
49
|
+
| created once, then yours (`.gob/goblin.yaml`, `HANDOFF.md`, `AGENTS.md`, `*-SPEC.md`, `reviews/.gitkeep`) | `owned` | never | no — you are meant to edit them | no, except the config |
|
|
50
50
|
| pre-existing, left alone | `refused` | never | no — IN-04 only proves it was not taken over | no |
|
|
51
51
|
|
|
52
52
|
A `refused` path is not a dead end. For `HANDOFF.md` the remedy is the reconciliation in
|
|
@@ -60,13 +60,13 @@ repo. The remedy is the explicit re-pin below — not a hand-edit of the hash, a
|
|
|
60
60
|
automatic one.
|
|
61
61
|
|
|
62
62
|
`.gitignore` is not a file goblin-stack owns: it appends **one marked block** and never rewrites
|
|
63
|
-
the rest. `.
|
|
63
|
+
the rest. `.gob/goblin.yaml` is generated once and is goblin-stack's own config, so
|
|
64
64
|
`--uninstall` removes it; `HANDOFF.md`, `AGENTS.md`, `ROUND-000-SPEC.md` and `reviews/` are the
|
|
65
65
|
project's record, not the harness's, and are left in place.
|
|
66
66
|
|
|
67
67
|
### An edited standard is not a dead end
|
|
68
68
|
|
|
69
|
-
`.
|
|
69
|
+
`.gob/goblin.yaml` records `practice:` and `practice_sha256:`, and `IN-02` re-checks that hash.
|
|
70
70
|
The pin has exactly one purpose: to make a **silently** edited standard visible rather than
|
|
71
71
|
assumed. The standard itself is a living document, corrected in place, so an edit that is
|
|
72
72
|
*intended* needs a deliberate way to re-record the pin. That is all `--re-pin` is:
|
|
@@ -79,7 +79,7 @@ It rewrites one line of the config — nothing else — and prints both hashes:
|
|
|
79
79
|
recorded 81612b17ac3483b9d613aeb86e236539fc17403e38bf7903af708d369cf7918f
|
|
80
80
|
now 8334ac24f056c94c35fa97831253e7e12bace68ae5747c81ae3b696c42ddd33a
|
|
81
81
|
|
|
82
|
-
`.
|
|
82
|
+
`.gob/bin/goblin-verify --only IN-02` then reports `practice pin ok`. Every other line of
|
|
83
83
|
`goblin.yaml`, comments included, is untouched, so the `owned` contract holds for everything
|
|
84
84
|
except the one value you just asked to re-record. Commit the config like any other change.
|
|
85
85
|
`--dry-run` prints the plan and writes nothing; when there is nothing to do it prints
|
|
@@ -97,7 +97,7 @@ Four things it deliberately is not:
|
|
|
97
97
|
- **not a re-point.** It re-records the hash of the path already in `practice:`. Pointing the repo
|
|
98
98
|
at a *different* standard is a deliberate config edit, not a re-pin.
|
|
99
99
|
|
|
100
|
-
Refusals are exit `2`, each naming the path: no `.
|
|
100
|
+
Refusals are exit `2`, each naming the path: no `.gob/goblin.yaml`, no `practice:` recorded, the
|
|
101
101
|
recorded path absent, or no `practice_sha256:` line to rewrite. A failed write is exit `1`, with
|
|
102
102
|
the path — the command never reports a re-pin that did not land. One refusal guards the mode
|
|
103
103
|
itself: `--uninstall --re-pin` is exit `2` with `--uninstall and --re-pin are different jobs; run
|
|
@@ -122,7 +122,7 @@ Output is one line per executed row, in manifest order, plus a summary line at t
|
|
|
122
122
|
|
|
123
123
|
Those four lines are one row of each marking. The summary line of a green default software-class run is:
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
37 passed, 0 failed, 11 advisory, 34 skipped
|
|
126
126
|
|
|
127
127
|
**Exit codes:** `0` every executed check passed (advisories and skips do not fail the run) ·
|
|
128
128
|
`1` at least one check FAILED · `2` verify could not run (not installed, a missing dependency,
|
|
@@ -137,14 +137,15 @@ is counted and capped.
|
|
|
137
137
|
tests the right path rather than merely passing; whether the forge is bound by the workflow
|
|
138
138
|
`CL-01` found; whether a human
|
|
139
139
|
read the diff; whether the model mapping names a family that actually differs; and whether
|
|
140
|
-
`.
|
|
141
|
-
is not signed (`docs/LIMITS.md` #18). The CI lane
|
|
142
|
-
|
|
140
|
+
`.gob/installed.json` — the record every drift check trusts — was itself rewritten, since it
|
|
141
|
+
is not signed (`docs/LIMITS.md` #18). The CI lane's blind spots are named there too, though in v2
|
|
142
|
+
the lane itself is out of the product (`docs/LIMITS.md` records `docs/CI.md` as its LIMITS
|
|
143
|
+
candidate) — the prose survives because the *reason* a workflow file is not a gate still does.
|
|
143
144
|
|
|
144
145
|
### A fresh install verifies green
|
|
145
146
|
|
|
146
147
|
Measured on a fresh DEFAULT software-class install (skills opt-in, W6 neutral-first), committed with no
|
|
147
|
-
hand edit: **`
|
|
148
|
+
hand edit: **`37 passed, 0 failed, 11 advisory, 34 skipped`, exit 0.** Thirty-four rows skip with
|
|
148
149
|
a reason — the same not-yet rows as before, plus the five skill rows (`SK-01`..`SK-04`,
|
|
149
150
|
`AU-04`) that skip on the `playbooks` opt-out a skills-free install records: `HS-02` — no pre-change commit
|
|
150
151
|
is pinned yet, so the REPLAY is not provable (`docs/LIMITS.md` #11) — `AU-02` and `AU-03`, which
|
|
@@ -159,7 +160,7 @@ must not be born RED — G1, `docs/LIMITS.md` #30) — `RC-01`..`RC-04`, which r
|
|
|
159
160
|
reference corpus and a lab `manifests/` directory a fresh install has neither of
|
|
160
161
|
(`reference_manifest:` and `quarantine_root:` ship empty on purpose: a repo with no corpus must
|
|
161
162
|
not be born RED) — and `JG-01` with `LP-01`..`LP-05`, which have
|
|
162
|
-
no `.
|
|
163
|
+
no `.gob/loop/` record because no loop has run in this repo: the six judge/loop rows are
|
|
163
164
|
**absent-state** rows, and a fresh install must not be born RED either. **Two** rows do
|
|
164
165
|
**not** skip, both of them the CI lane's: `PG-05` and `PG-06` read the workflow this class installs.
|
|
165
166
|
Two, not four — the four electron bans named in the skip list above do skip here, and a tree without
|
|
@@ -184,7 +185,7 @@ verifier is reporting FAILs.
|
|
|
184
185
|
the part's rows as `SKIP (opt-out)` in the summary, so the opt-out is **visible rather than
|
|
185
186
|
absent**. The same mechanism is what makes a class's `-` (off) real.
|
|
186
187
|
- **The opt-out numbers are pinned (V3-3).** A software-class install with an explicit `--skills no`
|
|
187
|
-
verifies `
|
|
188
|
+
verifies `37 passed, 0 failed, 11 advisory, 34 skipped`, exit 0, and
|
|
188
189
|
`tests/t-install-off-switch.sh` asserts that line: a silent drift in the opt-out path is caught
|
|
189
190
|
rather than left as a number nobody wrote down (the `--skills no` count moved from `37/0/9/11`
|
|
190
191
|
at v0.2 when the ban rows landed, **15 → 18 on 2026-09-25 (G1)** — the feature-map rows,
|
|
@@ -197,9 +198,9 @@ verifier is reporting FAILs.
|
|
|
197
198
|
recorded skill files; `--uninstall` removes everything recorded, as always.
|
|
198
199
|
`tests/t-install-off-switch.sh` walks that migration: install `--skills yes`, upgrade flag-less,
|
|
199
200
|
the skills survive byte-identical; uninstall, and they are all gone.
|
|
200
|
-
- **Whole harness:** `--uninstall` deletes the `files` list plus `.
|
|
201
|
+
- **Whole harness:** `--uninstall` deletes the `files` list plus `.gob/goblin.yaml`, removes
|
|
201
202
|
every directory that leaves empty (deepest first, after `installed.json` itself is gone — the
|
|
202
|
-
order that used to leave `.
|
|
203
|
+
order that used to leave `.gob/` and the sixteen `.hermes/skills/*` directories behind),
|
|
203
204
|
leaves `HANDOFF.md`, `AGENTS.md`, `ROUND-000-SPEC.md`, `reviews/` and the `.gitignore` block
|
|
204
205
|
(with a `# goblin-stack uninstalled <date>` marker inside it), and prints what it removed and
|
|
205
206
|
what it left.
|
|
@@ -207,7 +208,7 @@ verifier is reporting FAILs.
|
|
|
207
208
|
## The two commands, verbatim
|
|
208
209
|
|
|
209
210
|
bash bin/goblin-install --target /path/to/repo --class software
|
|
210
|
-
.
|
|
211
|
+
.gob/bin/goblin-verify
|
|
211
212
|
|
|
212
213
|
From a checkout, without installing anything:
|
|
213
214
|
|
package/docs/DESIGN.md
CHANGED
|
@@ -58,7 +58,7 @@ The split is by **kind**, and it is checkable.
|
|
|
58
58
|
- **goblin-stack owns the mechanism**: which rule is enforced by what, how it is installed, how
|
|
59
59
|
it is verified, which class a project is, which flow applies, which role runs a flow.
|
|
60
60
|
|
|
61
|
-
goblin-stack carries **no copy** of the standard's text. `.
|
|
61
|
+
goblin-stack carries **no copy** of the standard's text. `.gob/goblin.yaml` holds
|
|
62
62
|
`practice:` and `practice_sha256:`; `goblin-verify` re-checks the hash, so a silently edited
|
|
63
63
|
standard is visible rather than assumed. An edit that *is* intended is re-pinned by one explicit,
|
|
64
64
|
printed command (`goblin-install --target <dir> --re-pin`), never automatically — the pin exists
|