@techgoblin/gobstack 0.0.0-stage → 0.4.4-beta.2
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 +351 -0
- package/LICENSE +21 -0
- package/README.md +217 -2
- package/VERSION +1 -0
- package/adapters/_template/adapter.tsv +16 -0
- package/adapters/_template/detect.sh +10 -0
- package/adapters/_template/emit.sh +5 -0
- package/adapters/_template/verify.sh +4 -0
- package/adapters/claude/adapter.tsv +8 -0
- package/adapters/claude/detect.sh +8 -0
- package/adapters/claude/verify.sh +47 -0
- package/adapters/codex/adapter.tsv +12 -0
- package/adapters/codex/detect.sh +9 -0
- package/adapters/codex/verify.sh +45 -0
- package/adapters/copilot/adapter.tsv +10 -0
- package/adapters/copilot/detect.sh +8 -0
- package/adapters/copilot/verify.sh +45 -0
- package/adapters/cursor/adapter.tsv +11 -0
- package/adapters/cursor/detect.sh +10 -0
- package/adapters/cursor/verify.sh +45 -0
- package/adapters/gemini/adapter.tsv +15 -0
- package/adapters/gemini/detect.sh +11 -0
- package/adapters/gemini/verify.sh +49 -0
- package/adapters/hermes/adapter.tsv +9 -0
- package/adapters/hermes/detect.sh +8 -0
- package/adapters/hermes/verify.sh +27 -0
- package/adapters/opencode/adapter.tsv +14 -0
- package/adapters/opencode/detect.sh +9 -0
- package/adapters/opencode/verify.sh +45 -0
- package/automations/README.md +53 -0
- package/automations/bugreporter-intake.sh +145 -0
- package/automations/drift-audit.sh +139 -0
- package/automations/report.schema.tsv +10 -0
- package/bans/README.md +82 -0
- package/bans/grep-ban.sh +84 -0
- package/bans/layer-check.sh +57 -0
- package/bin/goblin +119 -0
- package/bin/goblin-audit +145 -0
- package/bin/goblin-bans +178 -0
- package/bin/goblin-doctor +233 -0
- package/bin/goblin-emit +484 -0
- package/bin/goblin-init +519 -0
- package/bin/goblin-install +720 -0
- package/bin/goblin-lib.sh +289 -0
- package/bin/goblin-model +105 -0
- package/bin/goblin-upgrade +572 -0
- package/bin/goblin-verify +2798 -0
- package/bin/goblin.js +103 -0
- package/docs/ADOPTION.md +168 -0
- package/docs/CI.md +187 -0
- package/docs/CONTRACTS.md +197 -0
- package/docs/DESIGN.md +92 -0
- package/docs/ENFORCEMENT.md +225 -0
- package/docs/FLOWS.md +164 -0
- package/docs/GUARDRAILS.md +126 -0
- package/docs/GUIDE.md +610 -0
- package/docs/INTEGRATION.md +92 -0
- package/docs/LIMITS.md +591 -0
- package/docs/LOOP.md +165 -0
- package/docs/RE-PLAYBOOK.md +183 -0
- package/docs/RISKS.md +70 -0
- package/docs/ROLES.md +105 -0
- package/manifest/bans.tsv +9 -0
- package/manifest/classes.tsv +61 -0
- package/manifest/enforcement.tsv +88 -0
- package/manifest/glossary.tsv +25 -0
- package/manifest/playbooks.tsv +16 -0
- package/package.json +37 -4
- package/presets/A-shipped-software.yaml +48 -0
- package/presets/B-service-config.yaml +40 -0
- package/presets/C-game.yaml +38 -0
- package/presets/D-knowledge.yaml +41 -0
- package/presets/E-fleet-config.yaml +42 -0
- package/presets/F-electron.yaml +67 -0
- package/roles.yaml +54 -0
- package/skills/goblin-bootstrap/SKILL.md +51 -0
- package/skills/goblin-bugfix/SKILL.md +26 -0
- package/skills/goblin-bugreporter/SKILL.md +52 -0
- package/skills/goblin-drift-audit/SKILL.md +43 -0
- package/skills/goblin-eval/SKILL.md +68 -0
- package/skills/goblin-feature/SKILL.md +26 -0
- package/skills/goblin-feature-map/SKILL.md +140 -0
- package/skills/goblin-handoff/SKILL.md +28 -0
- package/skills/goblin-investigation/SKILL.md +26 -0
- package/skills/goblin-judge/SKILL.md +74 -0
- package/skills/goblin-loop/SKILL.md +88 -0
- package/skills/goblin-mode/SKILL.md +70 -0
- package/skills/goblin-overnight/SKILL.md +42 -0
- package/skills/goblin-pr-gate/SKILL.md +42 -0
- package/skills/goblin-re-mobile/SKILL.md +51 -0
- package/skills/goblin-refactor/SKILL.md +23 -0
- package/skills/goblin-sweep/SKILL.md +23 -0
- package/skills/goblin-tdd-repro/SKILL.md +27 -0
- package/skills/goblin-verify-author/SKILL.md +50 -0
- package/skills/practice/SKILL.md +37 -0
- package/templates/AGENTS.md.tmpl +23 -0
- package/templates/HANDOFF.md.tmpl +43 -0
- package/templates/SPEC.md.tmpl +34 -0
- package/templates/audit-waiver.tsv.tmpl +10 -0
- package/templates/boundary-waivers.tmpl +8 -0
- package/templates/checks/assert.mjs.tmpl +60 -0
- package/templates/checks/gate.sh.tmpl +29 -0
- package/templates/ci/goblin-gate.yml.tmpl +46 -0
- package/templates/goblin.yaml.tmpl +138 -0
- package/templates/install-hooks.allowlist.tmpl +9 -0
- package/templates/loop/decisions.tsv.tmpl +1 -0
- package/templates/loop/predicate.tmpl +16 -0
- package/templates/report.yaml.tmpl +16 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
One line per released version. `goblin-install --upgrade` prints the delta between the
|
|
4
|
+
version recorded in a target's `.goblin/installed.json` and the source `VERSION`.
|
|
5
|
+
|
|
6
|
+
## 0.4.4
|
|
7
|
+
|
|
8
|
+
The five findings an independent verification of 0.4.3 left open (AB3). The blocker is the species
|
|
9
|
+
this campaign keeps meeting: a false statement about the artifact's own enforcement, written into the
|
|
10
|
+
guide **while** the wave that fixed five of the same kind was landing. No row was added, moved or
|
|
11
|
+
re-labelled — `advisory` stays at **10 of 10**, and `manifest/enforcement.tsv` and
|
|
12
|
+
`tests/t-verify-red.sh` are untouched, so the census cannot drift.
|
|
13
|
+
|
|
14
|
+
- **`docs/GUIDE.md` §8's rule sentence was false (AB3-1, the BLOCKER).** It said `IN-02` "hashes
|
|
15
|
+
**every file the installer wrote**". Measured on a fresh class-A install: the installer writes
|
|
16
|
+
**50** files and the row's `files` map covers **40** — ten sit outside it, including
|
|
17
|
+
`.goblin/goblin.yaml`, the file §5 step 3 tells the reader to edit. Editing all ten at once still
|
|
18
|
+
printed `PASS IN-02 40 installed files hashed` rc 0, so a reader who followed §5 and then §8 would
|
|
19
|
+
watch REPLAY "confirm" a check that never moved. The sentence now names the 40, the 8 it `owns` and
|
|
20
|
+
`.goblin/installed.json`, and points the exercise at `.goblin/bans/README.md`.
|
|
21
|
+
`tests/t-doc-guide.sh` asserts the count the guide quotes equals the `files`-map length of the
|
|
22
|
+
install it made, and that the universal is gone — both RED at `58a6fe6`.
|
|
23
|
+
- **The 9/10 in `docs/GUIDE.md` §11 was unversioned.** It presented a previous revision's score as
|
|
24
|
+
"the current status" in a file stamped `0.4.3`, so the next pass made it false in silence. The
|
|
25
|
+
sentence now carries the revision it was measured at (`0.4.2`, where AC1 measured 9.0), and
|
|
26
|
+
`t-doc-guide.sh` reads it — RED at `58a6fe6`.
|
|
27
|
+
- **Two more live copies of the stale 9-of-10 advisory arithmetic.** `docs/GUARDRAILS.md`'s third
|
|
28
|
+
design constraint carried the count with no dating at all; `docs/LIMITS.md` #26 said `SK-03`
|
|
29
|
+
"reports that arithmetic **on every run** (`advisory 9 of ceiling 10 (1 free slot)`)" while the run
|
|
30
|
+
prints `advisory 10 of ceiling 10 (0 free slots: the next advisory row FAILs)`. Both now state the
|
|
31
|
+
measured value and date the correction, and `tests/t-doc-sync.sh` reads the two LIVE copies — RED at
|
|
32
|
+
`58a6fe6` — while the dated history (the CHANGELOG entries, `docs/ENFORCEMENT.md`'s chronology,
|
|
33
|
+
`t-verify-red.sh`'s pre-change note) keeps its own tense and is not read.
|
|
34
|
+
- **`CHANGELOG.md`'s 0.4.0 census is annotated, not rewritten.** It claimed "**105** controls and
|
|
35
|
+
**19** `expect_green` — **124**", a figure that matched no tree even when it was written: 0.4.0's
|
|
36
|
+
own tree (`63d62d2`) measures **112** + **22** = **134**, and the tree at 0.4.3 measures **121** +
|
|
37
|
+
**28** = **149**. The released numbers stand and carry a dated correction beside them.
|
|
38
|
+
- **`VERSION` is `0.4.4`** — `VERSION`, the five `bin/` version constants and this entry agree. No
|
|
39
|
+
logic changed in `bin/`, and no id, verdict or matrix cell moved.
|
|
40
|
+
|
|
41
|
+
## 0.4.3
|
|
42
|
+
|
|
43
|
+
Five defects an independent verification of 0.4.2 measured, and all five are the same species: a
|
|
44
|
+
sentence in a reader-facing artifact that a measurement contradicts. Four are prose, one is a row
|
|
45
|
+
that stayed GREEN under its own violation. No row was added, moved or re-labelled — `advisory` stays
|
|
46
|
+
at **10 of 10**.
|
|
47
|
+
|
|
48
|
+
- **`docs/GUIDE.md`'s only hands-on REPLAY exercise was false as written (D1, the BLOCKER).** §7 and
|
|
49
|
+
the appendix both told the reader `git stash && .goblin/bin/goblin-verify --only GT-02 # expect
|
|
50
|
+
FAIL`, and `GT-02` runs the gates the config declares (`commit`, `todo_ceiling`), whose exit status
|
|
51
|
+
a stash cannot change: measured on the shipped class-A configuration, `PASS` rc 0 before, during
|
|
52
|
+
and after — the guide taught the lesson backwards. The exercise REPLAYs `IN-02` now, the row that
|
|
53
|
+
hashes the files the installer wrote: break one, watch the row go `FAIL` rc 1, put the file back,
|
|
54
|
+
watch it go `PASS` rc 0. The restore is path-limited (`git stash push -- <path>`) so it cannot
|
|
55
|
+
swallow the uncommitted `.goblin/goblin.yaml` edit step 3 leaves behind, and both copies carry the
|
|
56
|
+
same block between sentinels.
|
|
57
|
+
- **`docs/GUIDE.md` had no control at all, which is how four false sentences survived in it (D1's
|
|
58
|
+
cause).** `grep -rn GUIDE tests/*.sh` was **0** hits before this release. `tests/t-doc-guide.sh`
|
|
59
|
+
now extracts the guide's own exercise and RUNS it — every `goblin-verify` line must do what its
|
|
60
|
+
`# expect PASS|FAIL` annotation promises, verdict and exit code — and re-measures the guide's own
|
|
61
|
+
numbers on a fresh class-A install (`created 49` against **50** files on disk; the day-one and
|
|
62
|
+
green-path summary lines). RED on `d5424be`.
|
|
63
|
+
- **`GT-03` was GREEN under its own violation (D2).** Its freshness clause compared the gate line
|
|
64
|
+
with `$(git rev-parse --git-dir)/HEAD`, and `.git/HEAD` is rewritten by **branch operations, never
|
|
65
|
+
by a commit**: measured, its mtime was unchanged across a real commit and `--only GT-03` stayed
|
|
66
|
+
`PASS` rc 0 while the round had moved on. The clause reads HEAD's **reflog** (`.git/logs/HEAD`) now,
|
|
67
|
+
which a commit rewrites in an attached *and* a detached worktree and whatever the refs' packing
|
|
68
|
+
state; the row's `—` why-cell became the two limits that remain (a disabled reflog passes
|
|
69
|
+
vacuously, and any HEAD movement counts as staleness). `tests/t-gt03-freshness.sh` controls it in
|
|
70
|
+
both directions: RED on `d5424be`.
|
|
71
|
+
- **"The four rows that do not skip" is two (D3).** `README.md` and `docs/CONTRACTS.md` both said
|
|
72
|
+
four. Measured on the class-A run the paragraph describes: `PG-05` and `PG-06` PASS, and the four
|
|
73
|
+
electron bans named in the same breath (`BN-06`..`BN-09`) **SKIP**. Both copies say **two** now and
|
|
74
|
+
name them, and `docs/ADOPTION.md` and the shipped `skills/goblin-bootstrap/SKILL.md` no longer give
|
|
75
|
+
the bans' reason as "no `src/`" when five of those eight rows skip as *not enabled in `bans:`*.
|
|
76
|
+
- **"`created 49` means it wrote 49 files" was one file short (D4).** The installer writes **50**
|
|
77
|
+
files into an empty repo: the 49 it counts (40 `files` + 8 `owned` + `.gitignore`) plus
|
|
78
|
+
`.goblin/installed.json`, the record it keeps for itself, which it writes and does not count. The
|
|
79
|
+
guide says exactly that now. The counter is unchanged — moving it would have moved every derived
|
|
80
|
+
number in every document that quotes a `created N` line.
|
|
81
|
+
- **"It adds no network calls" was unscoped, and false (D5).** Every other copy of that claim is
|
|
82
|
+
scoped — `docs/GUARDRAILS.md` says "No network at **verify time**", README and `docs/CONTRACTS.md`
|
|
83
|
+
put it under "**Dependencies**", and `bin/goblin-audit`'s own header calls itself "the ONE command
|
|
84
|
+
in the toolchain that touches the network" — as does the guide itself in §8 and §11. §1, the first
|
|
85
|
+
sentence a new reader meets, now says `no network call at verify time`.
|
|
86
|
+
- **`VERSION` is `0.4.3`** — `VERSION`, the five `bin/` version constants and this entry agree. The
|
|
87
|
+
seven dated `0.4.2` statements (this file's own 0.4.2 entry, `docs/LIMITS.md`'s AA1 note,
|
|
88
|
+
`docs/ENFORCEMENT.md`'s and `manifest/enforcement.tsv`'s SC-08 cells, and
|
|
89
|
+
`tests/t-verify-red.sh`'s two "measured at …" notes) describe a past revision and keep their
|
|
90
|
+
version.
|
|
91
|
+
|
|
92
|
+
## 0.4.2
|
|
93
|
+
|
|
94
|
+
- **`SC-08` no longer passes vacuously on a minified lockfile (Z2-2).** `check_sc_08` read
|
|
95
|
+
`package-lock.json` with a line-anchored awk, so a **minified** (one-line) lockfile matched
|
|
96
|
+
nothing and the row printed `0 install hook(s), 0 allowlisted` — **exit 0, a PASS** where the
|
|
97
|
+
pnpm/yarn branch's SKIP is the honest shape. Measured on one tree: the same unlisted hook is
|
|
98
|
+
`FAIL` rc 1 pretty-printed and was `PASS` rc 0 on one line. The text is normalised into the
|
|
99
|
+
pretty shape before the reader sees it (a text transform — no npm, no jq, no parser) and the
|
|
100
|
+
anchor accepts `": {` and `":{`; two controls hold it, and the FAIL half is RED against the
|
|
101
|
+
0.4.1 verifier.
|
|
102
|
+
- **`HS-02` shell-quotes the harness file name it substitutes (Z2-3).** Z1-4 made the row run the
|
|
103
|
+
DECLARED command instead of `node "$f"`, which put a file name from the harness dir into the
|
|
104
|
+
command text `bash -c` parses — the same surface class as the G8-1 injection. Measured with a
|
|
105
|
+
file named `z2;true;#.mjs`: unquoted, two commands ran and the trailing `true` decided the exit
|
|
106
|
+
code (rc 1, "was GREEN on the pre-change tree"); quoted with `printf %q`, `node` receives one
|
|
107
|
+
argument. The control carries that name.
|
|
108
|
+
- **Y1 §7's items 1, 2 and 6 have their direct controls, so the census moves (AA1).** The layer
|
|
109
|
+
probe's `bans_exempt:` path, the engine→probe `GOBLIN_BANS_ID`/`GOBLIN_BANS_EXEMPT` contract,
|
|
110
|
+
and the prefix's segment alignment (including the trailing-slash case) each have one now;
|
|
111
|
+
`grep -c GOBLIN_BANS_EXEMPT tests/` was **0** before, and the five W5-1/W5-2 controls all drive
|
|
112
|
+
`grep-ban.sh`, never `layer-check.sh`. The census is therefore **18 listed · 2 fixed · 2 closed ·
|
|
113
|
+
3 controlled · 11 recorded**: three mechanisms left `LIMITS.md` #41's recorded set, which is the
|
|
114
|
+
only direction that frees headroom, and no advisory row was spent — **10 of 10**.
|
|
115
|
+
- **`tests/t-verify-red.sh`'s census is re-counted, not carried: 121 `expect_red` + 28
|
|
116
|
+
`expect_green` = 149 calls**, 78 distinct ids, 0 phantom, 0 uncovered. Its W5-1/W5-2 comment no
|
|
117
|
+
longer says that all five of those controls are RED on the pre-fix tree — two of the five are
|
|
118
|
+
(Z2-4). Measured on 7fec08f: the two `expect_green` halves fail there (the escape did nothing),
|
|
119
|
+
the three `expect_red` halves report ok; all five name a row that is RED there.
|
|
120
|
+
- **`VERSION` is `0.4.2`** — `VERSION`, the five `bin/` version constants and this entry agree.
|
|
121
|
+
|
|
122
|
+
## 0.4.1
|
|
123
|
+
|
|
124
|
+
- **Y1's remaining defects, landed (Z1).** Eight MINOR/STYLE findings from an independent verification
|
|
125
|
+
of 0.4.0, plus the carried W5 items that survived X1. The load-bearing one is `{{GATE2}}`, which
|
|
126
|
+
leaked an unsubstituted token into **all six classes'** installed `.goblin/goblin.yaml` for two
|
|
127
|
+
waves while `grep -rl '{{GATE2}}' tests docs manifest bin` was **0 files**: nothing rendered it and
|
|
128
|
+
nothing saw it. It is deleted, and it now has the control that would have caught it —
|
|
129
|
+
`tests/t-render-tokens.sh` renders all six classes and scans every installed file for a `{{…}}`
|
|
130
|
+
token (RED on the pre-fix template: 6 leaks, 1 per class).
|
|
131
|
+
- **`replay.cmd` now runs.** `presets/*.yaml` declared `replay_cmd: node checks/{name}.mjs` and `HS-02`
|
|
132
|
+
read it only to assert it was non-empty, then ran `node <file>` itself — so the declared command and
|
|
133
|
+
its `{name}` placeholder were decorative and `replay.cmd: false` changed no verdict. The row
|
|
134
|
+
executes the declared command with `{name}` substituted; measured, `false` now FAILs and the PASS
|
|
135
|
+
line names the command it ran.
|
|
136
|
+
- **Also fixed:** `IN-03` now enforces the `enforced_by` enum it documented as closed (a `bogus` cell
|
|
137
|
+
changed nothing before); `FM-02` refuses an entry path that resolves only to a file git does not
|
|
138
|
+
track (the freshness clause used to skip silently); `SC-03` prints a hit count instead of the
|
|
139
|
+
character count of the matching line (W5-11, a half-done fix); the summary prints the advisory
|
|
140
|
+
arithmetic, so `advisory 10 of ceiling 10` beside 11 `ADV` lines is explained on screen (Z1-7);
|
|
141
|
+
`--practice <path>` that does not resolve is now reported instead of silently dropped (W5-3);
|
|
142
|
+
`CHANGELOG.md`'s own ban-lane claim is corrected to its measurement (two of five RED pre-fix, three
|
|
143
|
+
pinning behaviour that was never broken, which is what X1 §5 reports); `docs/ENFORCEMENT.md` cites
|
|
144
|
+
the right `LIMITS` entry; `tests/run-tests.sh`'s header counts five source rows, not four.
|
|
145
|
+
- **`docs/LIMITS.md` #41** records Y1 §7's census, and the arithmetic is stated separably so a
|
|
146
|
+
reader can check it: Y1 listed **18** documented mechanisms with no control of their own; this
|
|
147
|
+
wave **fixed** two (the unrendered token, `replay.cmd` — items 17 and 18, which by definition
|
|
148
|
+
now HAVE controls and so sit **outside** the "carry no control" set), **closed** two more (the
|
|
149
|
+
ban engine's `exit 2` paths and `--list` — items 4 and 5, three assertions in
|
|
150
|
+
`tests/t-verify-red.sh`), and **recorded the remaining 14** with their reason. **18 listed ·
|
|
151
|
+
2 fixed · 2 closed · 14 recorded.** (This sentence said *sixteen* and counted the two fixed
|
|
152
|
+
mechanisms inside the no-control set, so `2 + 2 + 14` could not be reconciled from it —
|
|
153
|
+
Z2-1; the corrected counts are the ones that add up.) W5-10's exemption (`docs/` is never
|
|
154
|
+
installed) is stated there too. No advisory row was added: **10 of 10**, unchanged.
|
|
155
|
+
- **`VERSION` is `0.4.1`** — `VERSION`, the five `bin/` version constants and this entry agree.
|
|
156
|
+
|
|
157
|
+
## 0.4.0
|
|
158
|
+
|
|
159
|
+
- **W5's regression is closed: the ban lane's two documented escapes now work (X1).** `bans_exempt:`
|
|
160
|
+
was a **permanent RED** after W1's V3-2 fix — the engine filtered the probe's stdout *after* the
|
|
161
|
+
probe had already chosen its exit code, so the filter was decorative and a violation inside an
|
|
162
|
+
exempted path had no remedy (measured `rc 0` at `72490f0` → `rc 1` at `7fec08f`, and
|
|
163
|
+
`grep -rn bans_exempt tests/` was **0 hits**, which is why nothing caught it). The engine now
|
|
164
|
+
exports `GOBLIN_BANS_ID` and `GOBLIN_BANS_EXEMPT` and the shipped probes filter the **file list
|
|
165
|
+
before judging**; the manifest's `escape` column is now true — `// BAN-OK(<id>): <reason>` on the
|
|
166
|
+
offending line clears that line, and a non-empty reason is required. Five controls, both
|
|
167
|
+
directions — **two of the five RED on the pre-fix tree; the other three pin behaviour that was
|
|
168
|
+
never broken** (Y1 measured the ban-lane half at 2, which is what X1 §5 itself reports);
|
|
169
|
+
the residual (a project's own `detect` that ignores the
|
|
170
|
+
variables keeps the old, closed failure) is `docs/LIMITS.md` #36.
|
|
171
|
+
- **W5's four half-instrumentations: closed where closable, recorded where not (X1).** `FM-02` no
|
|
172
|
+
longer resolves a token that occurs only in the harness — `.goblin/`, `.hermes/`, the declared
|
|
173
|
+
`harness_dir` and the map's own directory are skipped, so a stub map that echoes the template
|
|
174
|
+
FAILs (W5-4, `docs/LIMITS.md` #37). `MD-02` now resolves the **judge** lane and compares its model
|
|
175
|
+
with the code lane's, instead of leaving the judge distinct by profile name only; it stays
|
|
176
|
+
advisory, and the measured state is recorded (#38 — on this box the live mapping names **no
|
|
177
|
+
`judge:` profile at all**, so the judge lane reads unresolved, while every profile it does name
|
|
178
|
+
resolves to one model: map a judge and it is the author's family). `LP-02`
|
|
179
|
+
requires a close-and-reopen to archive the predicate **and** the pin it was closed under and to
|
|
180
|
+
name the archived digest on a `previous:` line, so a silent relaxation FAILs while a real re-scope
|
|
181
|
+
costs one line (#39 — whether the new bar is *weaker* is not decidable from a digest). And
|
|
182
|
+
`PG-06`'s why-cell now says plainly that the CI lane's enforcement is the **target repo's**, not
|
|
183
|
+
goblin-stack's (#34), rather than reading as enforcement.
|
|
184
|
+
- **The control census is counted, not carried.** `tests/t-verify-red.sh` now carries **112**
|
|
185
|
+
`expect_red` and **22** `expect_green` — **134** call sites over all 78 target rows, 78 distinct
|
|
186
|
+
ids, 0 uncovered, 0 phantom (W5-9 measured the header sentence one count behind at 105+19).
|
|
187
|
+
- **`VERSION` is `0.4.0`.** It read `0.3.0` at `7fec08f` while the board and four build passes
|
|
188
|
+
called the wave v0.4 — this section is the entry the wave lacked, and the artifact no longer
|
|
189
|
+
calls itself a version its own build passes did not.
|
|
190
|
+
|
|
191
|
+
The wave proper (W1–W4) built on **0.3.0**'s ban list and added:
|
|
192
|
+
|
|
193
|
+
- **V3's four 9/10 blockers closed (W1).** `GT-01` FAILs when a declared gate carries no `cmd:` —
|
|
194
|
+
deleted, blanked or re-indented — instead of silently counting the survivors (G8-3, the third
|
|
195
|
+
condition of G8's own 9/10 sentence); the ban engine and the `bans:` switch are named in the
|
|
196
|
+
installed `AGENTS.md`, so a ban is discoverable while the code is written and not only in the
|
|
197
|
+
post-mortem (V3-1); `bin/goblin-bans` reads a detect's exit 1 as VIOLATED even when stdout is
|
|
198
|
+
empty, so the code matches the exit contract it documents instead of failing open (V3-2); and
|
|
199
|
+
`PF-01` FAILs when `ratchet.ceiling` and `perf.baseline_value` disagree, so a hand-raised
|
|
200
|
+
ceiling no longer passes while printing the contradiction (G8-6b). The verifier's "cannot see"
|
|
201
|
+
footer now names the ban lane's own blind spots (V3-8), and `docs/ROLES.md`'s "exactly two
|
|
202
|
+
scripts" is corrected to the four an install actually writes (V3-6).
|
|
203
|
+
- **The feature map, the P6↔P12 wiring, and the skills evidence (G1, W2).**
|
|
204
|
+
`skills/goblin-feature-map/SKILL.md` is the map's contract — the README index, the four-H2 entry
|
|
205
|
+
contract, the rot table, the upkeep pass — and three **declared** config keys drive it:
|
|
206
|
+
`feature_map:` (the map's README; **empty means both FM rows SKIP with that reason**, so a fresh
|
|
207
|
+
install is not born RED), `source_root:` and `verify_doctor:`. Three new rows: `FM-01` (every
|
|
208
|
+
feature file indexed and linked, `feature:` equal to the filename stem, at least one
|
|
209
|
+
`entry_paths:`, the four H2s in order), `FM-02` (every declared entry path still resolves under
|
|
210
|
+
`source_root:` and none changed after its `verified:` date — a tripwire, never a proof) and
|
|
211
|
+
`VA-01` (the declared doctor exits 0, the executable half of P6's "never executed is a draft").
|
|
212
|
+
`P6` gains step 5 (seed the map) and step 6 (hand the generated skill to `P12`: `verified:` does
|
|
213
|
+
not advance until an eval record exists); `P12` gains the record format (`evals/<slug>/`), the
|
|
214
|
+
eleven-token ban, the cheap-checks-first ladder, the merge rule and the pass condition. The eval
|
|
215
|
+
**runner is not shipped** and no row reads a lane (`docs/LIMITS.md` #31). `docs/LIMITS.md` #15 is
|
|
216
|
+
corrected: the controlled evidence now exists — SkillsBench 1.1 measures curated Skills at
|
|
217
|
+
**+16.6 points (33.9% → 50.5%, 18 model–harness configurations, 87 tasks)**, and its
|
|
218
|
+
**self-generated condition put all three tested configurations BELOW their no-Skills baseline**
|
|
219
|
+
(`docs/RISKS.md` K15) — a warning about this repo's own agent-authored output, not someone
|
|
220
|
+
else's.
|
|
221
|
+
- **The judge role and the loop contract (G2, W3).** `role-judge` in `roles.yaml` — a capability,
|
|
222
|
+
never a model — plus `skills/goblin-judge` (what a judge is, and what it must refuse) and
|
|
223
|
+
`skills/goblin-loop` (the record it leaves). `docs/LOOP.md` is the contract **and** the measured
|
|
224
|
+
reading of Hermes's own `goal_mode`: the judge is called as `judge_goal(goal_text,
|
|
225
|
+
last_response)`, with **no contract, no subgoals and no quality gates**
|
|
226
|
+
(`hermes_cli/goals.py:1660`); it sees the card's goal (2000 chars) and the worker's own most
|
|
227
|
+
recent response (4000) (`:38`, `:901-905`); and the loop has **no progress detector at all** —
|
|
228
|
+
its whole state is `last_response`, `turns_used`, `nudged_to_finalize` (`:1634-1636`). Eight new
|
|
229
|
+
rows. `JG-01`: a `done` verdict may only cite a **handle the repo can resolve** (`sha:` a commit
|
|
230
|
+
in `git rev-list --all`, `file:` a path under the root, `sha256:` a file under `.goblin/loop/`) —
|
|
231
|
+
a `cmd:` token resolves **nothing**, because the command's output is not in the record.
|
|
232
|
+
`JG-02`: the declared judge lane must be **disjoint** from the author's — a FAIL, not a report;
|
|
233
|
+
an unresolved lane is an `ADV` with a one-line remedy, because a repo cannot choose the fleet's
|
|
234
|
+
routing. `JG-03`: a judge lane with no non-`done` verdict is escalated — **counted, never gated**,
|
|
235
|
+
and the advisory slot W2 left free for G2. `LP-01`..`LP-05`: one predicate command, run and
|
|
236
|
+
recorded (`exit=<n> ts=<ISO8601>`) **before iteration 1**; pinned by digest and never relaxed;
|
|
237
|
+
a budget under the new `loop_max_turns_ceiling` (default **20** — the engine's own
|
|
238
|
+
`DEFAULT_MAX_TURNS`, so the two numbers agree); no three consecutive rows on one evidence
|
|
239
|
+
pointer without reaching `predicate:green`; and a `.goblin/loop/stuck.md` naming the predicate
|
|
240
|
+
when the loop ends red. `templates/loop/` ships a copy-ready predicate and record header, and
|
|
241
|
+
**nothing installs them**: a fresh install must not be born with a loop record. `P10`'s role is
|
|
242
|
+
now `code + judge`, `P7` gains the S3+ foreman (`role-judge`, one decision from N lane verdicts),
|
|
243
|
+
and `docs/INTEGRATION.md`'s claim that the auxiliary judge "is the predicate re-check" is
|
|
244
|
+
corrected in place with the measured calls. `docs/LIMITS.md` #32 and #33 and `docs/RISKS.md` K17
|
|
245
|
+
record what the lane cannot see.
|
|
246
|
+
- **The CI lane and the desktop-shell class (G6, W4).** `PG-05` is **re-declared**, not patched: it
|
|
247
|
+
counted "every step is guarded", which passed the shape G8 measured — a single **job-level**
|
|
248
|
+
`if:`, a job with no step, and one *unguarded* step deciding whether the guarded gate step runs —
|
|
249
|
+
all of which reach the end of the job without running the gate while the required check reports
|
|
250
|
+
Success. It now FAILs all four. **`PG-06` is new**: the gate CI runs must be the gate the project
|
|
251
|
+
declares, read from the same `g_yaml_gates` reader `GT-01` uses so a gate cannot vanish from the
|
|
252
|
+
comparison in silence; a workflow satisfies it by running the verifier with no `--only`, or by
|
|
253
|
+
running every declared gate command verbatim, with comments blanked first. A `ci-gate` **part**
|
|
254
|
+
joins `manifest/classes.tsv` (`R` for A/F, `O` for C/E, `-` for B/D) and the installer renders
|
|
255
|
+
`templates/ci/goblin-gate.yml.tmpl` into `.github/workflows/goblin-gate.yml` — one job, no `if:`
|
|
256
|
+
anywhere, one step that runs the repo's own gate set. `CL-01`'s artifact for the part is that
|
|
257
|
+
exact path, never the `.github/` directory, so a repo that forbids `ci-gate` may still carry CI of
|
|
258
|
+
its own. `bin/goblin-install --uninstall` now walks **every** ancestor directory, because that
|
|
259
|
+
workflow empties two levels. **Class F (desktop shell)** is the new preset: five electron bans
|
|
260
|
+
(`BN-06` `nodeIntegration: true`, `BN-07` context isolation/sandbox off, `BN-08` the dangerous
|
|
261
|
+
`webPreferences`, `BN-09` synchronous IPC / `@electron/remote`) and the FPS number as a **host
|
|
262
|
+
gate** — the instrument needs Playwright or Electron plus a display, which no shipped rule may
|
|
263
|
+
depend on, so the ratchet carries the hermetic `app_bundle_bytes` instead. **A stated deviation
|
|
264
|
+
from G6 §B.3**, recorded in `docs/LIMITS.md` #35; a `ratchet.cmd` that cannot run would make a
|
|
265
|
+
fresh install born RED. `docs/CI.md` is the new contract: what makes a workflow a gate (required
|
|
266
|
+
check, no admin bypass, a push identity that is not the sole admin, never conditional), why frame
|
|
267
|
+
time is the wrong metric (measured p50 flat at 16.70 ms while the main thread went 1.8 % → 54.5 %
|
|
268
|
+
busy), and what is deliberately not mechanised. `docs/LIMITS.md` #13 and #34, `docs/RISKS.md` K7
|
|
269
|
+
and the new K18, `docs/DESIGN.md`'s "no CI workflow" invariant (amended as an architecture change)
|
|
270
|
+
and the verifier's "cannot see" footer all carry it.
|
|
271
|
+
- `manifest/enforcement.tsv` is **83 rules** (78 target, 5 source); the advisory count is **10 of
|
|
272
|
+
ceiling 10 — full**, unchanged (both new rows are real commands, so no slot was spent);
|
|
273
|
+
`tests/t-verify-red.sh` carries **105** controls and **19** `expect_green` — **124** over all 78
|
|
274
|
+
target rows, 0 uncovered and 0 phantom. (Superseded 2026-09-25: this line read 78 rules / 73
|
|
275
|
+
target / 93 controls / 14 green before W4's five rows landed. **Corrected 2026-09-25 (AB3):** the
|
|
276
|
+
census above was wrong when it was written — 0.4.0's own tree (`63d62d2`) carries **112**
|
|
277
|
+
`expect_red` + **22** `expect_green` = **134**, not 105 + 19 = 124, and the tree at 0.4.3 measures
|
|
278
|
+
**121** + **28** = **149**. The released numbers stand as written; this is their correction.)
|
|
279
|
+
- A fresh class-A install verifies **`43 passed, 0 failed, 11 advisory, 24 skipped`**, exit 0
|
|
280
|
+
(twenty-four rows skip with a reason: `HS-02`, `AU-02`, `AU-03`, `SC-06`, `SC-07`, `SC-08`,
|
|
281
|
+
`PF-01`, `BN-01`/`BN-02`/`BN-03`/`BN-05` plus `BN-06`..`BN-09` on a repo with no `src/`,
|
|
282
|
+
`FM-01`/`FM-02`/`VA-01` with no map
|
|
283
|
+
and no doctor declared, and `JG-01` + `LP-01`..`LP-05` with no `.goblin/loop/` record); `PG-05`
|
|
284
|
+
and `PG-06` do **not** skip, because this class installs the workflow they read. A fresh
|
|
285
|
+
class-B install (`bans: []`) verifies `37 passed, 0 failed, 10 advisory, 31 skipped`; class-C
|
|
286
|
+
verifies `43 passed, 0 failed, 11 advisory, 24 skipped`; class-E (`bans: [BN-02]`) verifies
|
|
287
|
+
`42 passed, 0 failed, 11 advisory, 25 skipped`; the new **class-F** verifies
|
|
288
|
+
`43 passed, 0 failed, 11 advisory, 24 skipped`; class-A with `--skills no` verifies
|
|
289
|
+
`39 passed, 0 failed, 11 advisory, 28 skipped`. All measured on fresh installs, committed with no
|
|
290
|
+
hand edit. (Superseded 2026-09-25: these lines read 42/0/9/14, 37/0/8/20, 42/0/9/14, 41/0/9/15
|
|
291
|
+
and 38/0/9/18 before G2's eight rows landed, and 42/0/11/20, 37/0/10/26, 42/0/11/20, 41/0/11/21
|
|
292
|
+
and 38/0/11/24 before W4's five.)
|
|
293
|
+
|
|
294
|
+
## 0.3.0
|
|
295
|
+
|
|
296
|
+
- **The ban list (G5).** `manifest/bans.tsv`, `bin/goblin-bans` and `bans/` install as
|
|
297
|
+
`.goblin/manifest/bans.tsv`, `.goblin/bin/goblin-bans` and `.goblin/bans/` — Dune rule 2 made
|
|
298
|
+
a gate: **a ban without a mechanism is a wish.** Four bans ship with a real command each
|
|
299
|
+
(`BN-01` no `any`, `BN-02` no `@ts-ignore`/`@ts-expect-error`, `BN-03` no `fetch` from a
|
|
300
|
+
component, `BN-05` no import across a declared layer boundary), plus `BN-00` (the coherence
|
|
301
|
+
row: every ban has an enforcement row, every row names a replacement, the table is not empty).
|
|
302
|
+
The config gains `bans:` (which bans this project turns on — an unlisted ban SKIPs with a
|
|
303
|
+
reason), `bans_exempt:` (narrow, explicit exceptions) and `layers:` (what `BN-05` reads).
|
|
304
|
+
Class A and C turn on `BN-01 BN-02 BN-05`; E turns on `BN-02`.
|
|
305
|
+
- The ban probes are **text probes** (`grep`, no npm, no AST — `docs/CONTRACTS.md`), so G5's
|
|
306
|
+
`BN-04` (the nine named unnecessary-effect patterns) is **not shipped**: it cannot be
|
|
307
|
+
mechanised without a parser, and a ban that cannot go red is worse than advisory. Recorded in
|
|
308
|
+
`docs/LIMITS.md` #27 rather than spent as the last advisory slot. Advisory stays **9 of 10**.
|
|
309
|
+
- `manifest/enforcement.tsv` is **67 rules** (62 target, 5 source); `tests/t-verify-red.sh`
|
|
310
|
+
carries **68** controls over the 62 target rows.
|
|
311
|
+
- A fresh class-A install verifies **`42 passed, 0 failed, 9 advisory, 11 skipped`**, exit 0
|
|
312
|
+
(eleven rows skip with a reason: `HS-02`, `AU-02`, `AU-03`, `SC-06`, `SC-07`, `SC-08`,
|
|
313
|
+
`PF-01`, and `BN-01`/`BN-02`/`BN-03`/`BN-05` on a repo with no `src/`). A fresh class-B install
|
|
314
|
+
(`bans: []`) verifies `37 passed, 0 failed, 8 advisory, 17 skipped` — the four BN rows SKIP with
|
|
315
|
+
"not enabled in `bans:`"; class-C verifies `42 passed, 0 failed, 9 advisory, 11 skipped`; class-E
|
|
316
|
+
(`bans: [BN-02]`) verifies `41 passed, 0 failed, 9 advisory, 12 skipped`. All measured on fresh
|
|
317
|
+
installs, committed with no hand edit.
|
|
318
|
+
|
|
319
|
+
## 0.2.0
|
|
320
|
+
|
|
321
|
+
- **Automation agents (G3).** `P13 goblin-bugreporter` and `P14 goblin-drift-audit`, plus the
|
|
322
|
+
producer half in `automations/` — `drift-audit.sh` (deterministic, network-free, silent when
|
|
323
|
+
clean, with a kill switch and a run ceiling) and `bugreporter-intake.sh` (the intake gate: a
|
|
324
|
+
missing key is a refusal card with **no assignee**, so it is structurally un-spawnable). The
|
|
325
|
+
files install to `.goblin/automations/`; the fleet steps are printed by `goblin-install` and
|
|
326
|
+
argued in `automations/README.md`. Six new rules: `AU-01`, `AU-02`, `AU-03`, `AU-04`,
|
|
327
|
+
`SK-04` ("every shipped skill says what it cannot see") and the source row `PR-05`
|
|
328
|
+
(`tests/t-automation-silent.sh` — the mutation is the control). Advisory was **8 of 10** after
|
|
329
|
+
G3 and is **9 of 10** once `SC-09` lands with G4.
|
|
330
|
+
- **Guard rails (G4).** `SC-01`..`SC-09` and `PF-01`: secrets and the config surface, input
|
|
331
|
+
boundaries and dependencies, and the performance lane. The perf budget stays `GT-04`/`GT-05`
|
|
332
|
+
(no second mechanism): the class-A preset's metric is now `client_js_bytes` and the TODO count
|
|
333
|
+
moved into a `todo_ceiling` gate. `bin/goblin-audit` installs to `.goblin/bin/` and is the ONE
|
|
334
|
+
tool allowed to touch the network - run deliberately, it writes the record `SC-07` reads
|
|
335
|
+
offline, and it refuses (exit 5) to write an empty record rather than let "nothing parsed" read
|
|
336
|
+
as "clean". A class declares its security surface and perf baseline in `security:` / `perf:`;
|
|
337
|
+
the guard rails are argued in `docs/GUARDRAILS.md`, and `tests/t-audit.sh` exercises the whole
|
|
338
|
+
producer offline against a canned npm-audit report.
|
|
339
|
+
- `manifest/enforcement.tsv` is **62 rules** (57 target, 5 source); playbooks are **14**;
|
|
340
|
+
`tests/t-verify-red.sh` carries **60** controls over the 57 target rows.
|
|
341
|
+
- A fresh class-A install verifies **`41 passed, 0 failed, 9 advisory, 7 skipped`**, exit 0
|
|
342
|
+
(seven rows skip with a reason: `HS-02`, `AU-02`, `AU-03`, `SC-06`, `SC-07`, `SC-08`,
|
|
343
|
+
`PF-01`); a fresh class-E install verifies `40 passed, 0 failed, 9 advisory, 8 skipped`.
|
|
344
|
+
Advisory is **9 of ceiling 10**.
|
|
345
|
+
|
|
346
|
+
## 0.1.0
|
|
347
|
+
|
|
348
|
+
- First version. Ships `bin/goblin-install`, `bin/goblin-verify`, `bin/goblin-model`,
|
|
349
|
+
`bin/goblin-lib.sh`; `manifest/enforcement.tsv` (46 rules); 12 playbooks + `goblin-mode`
|
|
350
|
+
+ `practice` as Hermes project-local skills; 5 class presets; the templates; and
|
|
351
|
+
`tests/run-tests.sh` with the negative control for every target-scope check class.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 goblin-stack contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,218 @@
|
|
|
1
|
-
#
|
|
1
|
+
# gobstack
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**gobstack** (npm: [`@techgoblin/gobstack`](https://www.npmjs.com/package/@techgoblin/gobstack))
|
|
4
|
+
installs an **executable rule manifest**, a set of **project-local skills**, and an
|
|
5
|
+
**installer/verifier pair** into any project — so that an AI coding session never re-improvises,
|
|
6
|
+
and a rule that cannot be checked is counted rather than asserted.
|
|
7
|
+
|
|
8
|
+
Install it from npm — globally; it is a CLI, not a library:
|
|
9
|
+
|
|
10
|
+
npm install -g @techgoblin/gobstack@beta # gives you the `goblin` CLI (and `gob`)
|
|
11
|
+
npx @techgoblin/gobstack@beta init # or the one-shot: run the wizard, install nothing globally
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
**Global, not local.** gobstack is a CLI with zero runtime dependencies. Install it once per
|
|
16
|
+
machine:
|
|
17
|
+
|
|
18
|
+
npm install -g @techgoblin/gobstack@beta
|
|
19
|
+
|
|
20
|
+
or run a single command without installing:
|
|
21
|
+
|
|
22
|
+
npx @techgoblin/gobstack@beta init
|
|
23
|
+
|
|
24
|
+
**Do NOT add it to an app project's `package.json`.** A `npm install @techgoblin/gobstack` (or a
|
|
25
|
+
`package.json` dependency) inside your app pollutes the app's lockfile with a package the app
|
|
26
|
+
never imports, and can fail resolution outright with `ERESOLVE` when the app's own peer
|
|
27
|
+
dependencies disagree with npm's. If you see `ERESOLVE` after a local install, remove the
|
|
28
|
+
dependency from `package.json` and install globally instead.
|
|
29
|
+
|
|
30
|
+
**The two-layer model.** The global install gives you the CLI only. `goblin init` (or
|
|
31
|
+
`goblin install --target <dir> --class A`) then vendors a self-contained engine into the target
|
|
32
|
+
repo under `.goblin/` — verifier, manifest, ban probes, skills, all of it. That second layer is
|
|
33
|
+
why an initialized repo keeps working on machines with **no gobstack installed at all**: the
|
|
34
|
+
engine lives in the repo, not in your `node_modules`, and `bash .goblin/bin/goblin-verify` (or a
|
|
35
|
+
plain `git` + `bash` box) is the only runtime the repo's gate needs.
|
|
36
|
+
|
|
37
|
+
Then, from any project:
|
|
38
|
+
|
|
39
|
+
goblin install --target /path/to/repo --class A
|
|
40
|
+
|
|
41
|
+
The installer writes only paths it records, hash-compares before writing, and prints `no-op` on a
|
|
42
|
+
second run with the same arguments. It never overwrites `HANDOFF.md`, `AGENTS.md`, a `*-SPEC.md`,
|
|
43
|
+
`reviews/`, the `.gitignore` block or `.goblin/goblin.yaml`. Full option list and the three kinds
|
|
44
|
+
of file it manages: `docs/CONTRACTS.md`.
|
|
45
|
+
|
|
46
|
+
A repo that already has its own `HANDOFF.md` exits 1 on the refusal. That is the contract, not a
|
|
47
|
+
failure: reconcile the file rather than forcing over it — `docs/ADOPTION.md`.
|
|
48
|
+
|
|
49
|
+
After installing, in this order:
|
|
50
|
+
|
|
51
|
+
cd <target> && git add -A && git commit # the install is a change like any other
|
|
52
|
+
goblin verify # or .goblin/bin/goblin-verify, inside the target
|
|
53
|
+
hermes skills trust <target> # one-time, Hermes users, so project-tier skills load
|
|
54
|
+
goblin audit # once, deliberately: the ONLY network step (SC-07)
|
|
55
|
+
|
|
56
|
+
**A class-A install verifies green — `43 passed, 0 failed, 11 advisory, 28 skipped`, exit 0 — once
|
|
57
|
+
`HANDOFF.md` names a commit that exists. Before that edit the scaffold's `0000000` placeholder is
|
|
58
|
+
the one expected red: `42 passed, 1 failed`, `HP-05`. Both numbers measured 2026-09-25; the run and
|
|
59
|
+
the fix are step 2 of `docs/GUIDE.md`.**
|
|
60
|
+
Twenty-eight rows skip (`HS-02` has no pinned pre-change commit yet, so the REPLAY is not provable;
|
|
61
|
+
`AU-02` and `AU-03` have no report to audit; `SC-06`, `SC-07` and `SC-08` have no dependency
|
|
62
|
+
manifest, no lockfile and no audit record to read; `PF-01` has no measured perf baseline;
|
|
63
|
+
`BN-01`/`BN-02`/`BN-05` have no `src/` for a ban to read, and `BN-03` plus the four electron bans
|
|
64
|
+
`BN-06`/`BN-07`/`BN-08`/`BN-09` are not in this class's `bans:` list (`bans: [BN-01, BN-02, BN-05]`),
|
|
65
|
+
so they skip as *not enabled* rather than as *unread*; `FM-01`/`FM-02`/`VA-01`
|
|
66
|
+
have no feature map and no declared `verify_doctor:` yet; `RC-01`..`RC-04` have no reference corpus
|
|
67
|
+
declared and no lab `manifests/` to read; and `JG-01` with `LP-01`..`LP-05`
|
|
68
|
+
have no loop record, because no loop has run in this repo yet). **Two** rows do **not** skip: `PG-05`
|
|
69
|
+
and `PG-06`, the CI lane's. This class installs `.github/workflows/goblin-gate.yml`, so the two of
|
|
70
|
+
them read it and pass. Two, not four — the four electron bans named above are among the skips. Two of
|
|
71
|
+
the eleven advisories
|
|
72
|
+
are new with the judge lane: `JG-02` reports that the judge lane resolves to no profile on this
|
|
73
|
+
fleet (it prints the one-line remedy and never fails a repo for a fleet's routing), and `JG-03`
|
|
74
|
+
is the counted row the advisory ceiling had left for it. The parts
|
|
75
|
+
that only a round can produce — a first review note, a gate that is not the shipped floor — pass
|
|
76
|
+
*vacuously* rather than failing, and `P8` (`goblin-bootstrap`) still walks them as work to do.
|
|
77
|
+
The measurement and the vacuous-pass reading are in `docs/CONTRACTS.md`.
|
|
78
|
+
|
|
79
|
+
## The `goblin` CLI
|
|
80
|
+
|
|
81
|
+
| command | what it does |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `goblin verify` | run the rule matrix against the current repo — `PASS`/`FAIL`/`SKIP` per row, exit 0 pass · 1 a check failed · 2 could not run · 3 the manifest is broken |
|
|
84
|
+
| `goblin bans` | run the ban list (per-pattern red lines over the source tree) |
|
|
85
|
+
| `goblin audit` | check recorded dependency claims against live advisory feeds — the only command that touches the network |
|
|
86
|
+
| `goblin install` | install the manifest, skills and verifier into a target repo |
|
|
87
|
+
| `goblin uninstall` | remove everything an install wrote, byte-exactly (`goblin install --target <dir> --uninstall` is the same job) |
|
|
88
|
+
| `goblin upgrade` | migrate a repo to the shared global engine at `~/.goblin/engine` — 8 steps, two commits, one report |
|
|
89
|
+
| `goblin doctor` | one run across the platforms below: DETECTED / NOT-DETECTED / DRIFT per platform |
|
|
90
|
+
| `goblin emit` | write the skills + context block for one platform (`--scope project` or `global`); `--unshadow` removes a hermes project skill whose hash equals the source |
|
|
91
|
+
| `goblin init` | the first-run wizard: detect → class → branch/email → first gate → emit → verify, one screen per question; every question has a flag (`--class app --branch main --email a@b.c --gate 'cmd' --emit hermes`), so CI runs it with zero prompts; `--dry-run` prints the plan and writes nothing |
|
|
92
|
+
|
|
93
|
+
## Platforms
|
|
94
|
+
|
|
95
|
+
`goblin emit` and `goblin doctor` cover seven agent platforms, each detected via its own anchor:
|
|
96
|
+
|
|
97
|
+
| platform | what emit writes there |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `claude` | skills + context block under `~/.claude` (or `--target`'s project scope) |
|
|
100
|
+
| `hermes` | skills + context block under `~/.hermes` |
|
|
101
|
+
| `copilot` | skills + context block under `~/.copilot` |
|
|
102
|
+
| `cursor` | skills + context block under `~/.cursor` |
|
|
103
|
+
| `opencode` | skills + context block under `~/.config/opencode` |
|
|
104
|
+
| `codex` | skills + context block under `~/.codex` (partial: some commands blocked, `docs/LIMITS.md` #47) |
|
|
105
|
+
| `gemini` | skills + context block under `~/.gemini` (partial: some commands blocked, `docs/LIMITS.md` #47) |
|
|
106
|
+
|
|
107
|
+
One run of `goblin emit --platform <p> --scope project` writes the skills and the context block a
|
|
108
|
+
session of that platform reads; `--scope global` writes to the machine-level anchor. `--dry-run`
|
|
109
|
+
prints the full write plan first.
|
|
110
|
+
|
|
111
|
+
## What it is not
|
|
112
|
+
|
|
113
|
+
Not a rules document (every rule carries a runnable check or is explicitly counted as
|
|
114
|
+
advisory). Not a Cursor-plugin port (`subagent_type`, `/loop`, `/goal`, cloud agents and
|
|
115
|
+
vendored plugin paths do not exist here). Not a replacement for a project standard — it
|
|
116
|
+
**references** one by path and pins its hash, and carries none of its text.
|
|
117
|
+
|
|
118
|
+
## Read this on GitHub
|
|
119
|
+
|
|
120
|
+
**New here? Read `docs/GUIDE.md` first.** It is the step-by-step getting-started guide — install,
|
|
121
|
+
the first green run, your first change. This README is the reference you come back to; the table
|
|
122
|
+
below is the reference material the guide points into, so the two do not compete for the first read.
|
|
123
|
+
|
|
124
|
+
| file | what it decides |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `docs/GUIDE.md` | **read this first**: the first week, in order — install, the first verify, the REPLAY habit |
|
|
127
|
+
| `docs/DESIGN.md` | the thesis, the three load-bearing decisions, and every rejected alternative |
|
|
128
|
+
| `docs/FLOWS.md` | the 15 playbooks, with the 11 cuts and a reason for each |
|
|
129
|
+
| `docs/GUARDRAILS.md` | the security and perf rows (`SC-01`..`SC-09`, `PF-01`), the rung ladder, and what they cannot see |
|
|
130
|
+
| `docs/ROLES.md` | roles versus profiles, the model-mapping contract, the fan-out rule |
|
|
131
|
+
| `docs/ENFORCEMENT.md` | the matrix rendered for a human, and how a rule is added |
|
|
132
|
+
| `docs/CONTRACTS.md` | the installer/verifier interface, exit codes, idempotency, uninstall |
|
|
133
|
+
| `docs/INTEGRATION.md` | the board, cron, the skills precedence order, the referenced standard |
|
|
134
|
+
| `docs/RISKS.md` | the risk register, the advisory rows named, the non-goals |
|
|
135
|
+
| `docs/CI.md` | the CI lane: what makes a workflow a gate, the four settings a repository cannot set, and the desktop-shell class |
|
|
136
|
+
| `docs/LOOP.md` | the judge role and the loop contract: what a goal-mode loop actually does, the record, and what neither can see |
|
|
137
|
+
| `docs/ADOPTION.md` | the six classes, the preset matrix, the adoption order |
|
|
138
|
+
| `docs/LIMITS.md` | where this is weaker than its sources, and what is unproven |
|
|
139
|
+
|
|
140
|
+
`manifest/enforcement.tsv` is the source of truth for rules; `manifest/classes.tsv` for what a
|
|
141
|
+
class requires; `manifest/playbooks.tsv` for the flows; `manifest/glossary.tsv` for the
|
|
142
|
+
vocabulary.
|
|
143
|
+
|
|
144
|
+
## Verify
|
|
145
|
+
|
|
146
|
+
goblin verify [--only <id[,id...]>] [--json] [--list] [--source <path>]
|
|
147
|
+
|
|
148
|
+
Exit codes: `0` pass · `1` a check failed · `2` could not
|
|
149
|
+
run · `3` the manifest is broken. Every run prints what it cannot see.
|
|
150
|
+
|
|
151
|
+
## Develop
|
|
152
|
+
|
|
153
|
+
bash tests/run-tests.sh
|
|
154
|
+
|
|
155
|
+
Runs the source-scope rules (PR-01..PR-05) and the test scripts, including `t-verify-red.sh` —
|
|
156
|
+
one control per target-scope row (167 over 82 target rows), each required to go RED and then
|
|
157
|
+
restored, plus `t-audit.sh` for the SC-07 producer. **A verifier that only ever prints GREEN is a
|
|
158
|
+
failure**, so that file is the one that matters most.
|
|
159
|
+
|
|
160
|
+
## Uninstall
|
|
161
|
+
|
|
162
|
+
gobstack lives in three layers. Each is removed by its own command, and removing one never
|
|
163
|
+
touches the others.
|
|
164
|
+
|
|
165
|
+
**(a) The global CLI** — the npm package itself:
|
|
166
|
+
|
|
167
|
+
npm uninstall -g @techgoblin/gobstack
|
|
168
|
+
|
|
169
|
+
This removes the `goblin` and `gob` commands from the machine and nothing else: no project, no
|
|
170
|
+
repo, no `.goblin/` directory anywhere is touched. Repos you already initialized keep working
|
|
171
|
+
fully — the engine is vendored into each repo's `.goblin/`, so the CLI's absence removes no
|
|
172
|
+
capability (you lose the installer/upgrade/emit entry points, not the gate; see layer (c) for
|
|
173
|
+
the machine-level skills the CLI wrote).
|
|
174
|
+
|
|
175
|
+
**(b) A project's harness** — the `.goblin/` tree an install created in one repo:
|
|
176
|
+
|
|
177
|
+
goblin uninstall --target .
|
|
178
|
+
|
|
179
|
+
(equivalently `goblin install --target . --uninstall`; through the short alias:
|
|
180
|
+
`gob uninstall --target .`). The uninstall is **byte-exact**: it removes exactly the files
|
|
181
|
+
`installed.json` records — hash-compared preimages, so a file you edited after install is
|
|
182
|
+
reported and kept, never clobbered — then every directory that leaves empty. After it, the repo
|
|
183
|
+
has zero goblin files; only the project's own record (`HANDOFF.md`, `AGENTS.md`, `reviews/`, the
|
|
184
|
+
`.gitignore` block) survives, because that is the project's, not the harness's to delete. And
|
|
185
|
+
because the engine is vendored, the repo needs no gobstack installed to run this — it is
|
|
186
|
+
self-contained until the moment you remove it.
|
|
187
|
+
|
|
188
|
+
**(c) Global agent skills** — the machine-level skills an `emit --scope global` wrote outside any
|
|
189
|
+
repo:
|
|
190
|
+
|
|
191
|
+
goblin emit --undo --platform <p> --scope global
|
|
192
|
+
|
|
193
|
+
(`--undo` is the same byte-exact reversal as `--uninstall`, under its friendlier name). By hand,
|
|
194
|
+
the same job is deleting the platform's anchor entries: `~/.claude/skills/goblin-*` (and the
|
|
195
|
+
equivalents under `~/.hermes`, `~/.copilot`, `~/.cursor`, `~/.config/opencode`, `~/.codex`,
|
|
196
|
+
`~/.gemini` — `goblin doctor` lists which platforms were detected).
|
|
197
|
+
|
|
198
|
+
The short version, for a full removal from a machine and its repos: (c) first, then (b) in each
|
|
199
|
+
initialized repo, then (a).
|
|
200
|
+
|
|
201
|
+
## Re-pin the referenced standard
|
|
202
|
+
|
|
203
|
+
goblin install --target <dir> --re-pin
|
|
204
|
+
|
|
205
|
+
`practice_sha256:` pins the referenced standard and `IN-02` re-checks it, so editing that standard
|
|
206
|
+
— a legitimate, intended edit — reds `IN-02` in every installed repo. `--re-pin` re-records that
|
|
207
|
+
one line and prints the old and new hash; `IN-02` then reports `practice pin ok`. Nothing re-pins
|
|
208
|
+
automatically, not even `--upgrade`, and the `practice EDITED` failure prints this command. The
|
|
209
|
+
whole contract: `docs/CONTRACTS.md`, "An edited standard is not a dead end".
|
|
210
|
+
|
|
211
|
+
## Dependencies
|
|
212
|
+
|
|
213
|
+
`bash`, `git`, `awk`, `sed`, `grep`, `python3` (the engine); node ≥ 18 for the npm shim only. No
|
|
214
|
+
jq, no yq, no network at verify time.
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT.
|
package/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.4.4
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# adapters/_template/adapter.tsv — W4A-SPEC §2. One row per adapter, tab-separated, header first.
|
|
2
|
+
# Columns:
|
|
3
|
+
# 1 id ^[a-z]+$, matches the directory name and --platform spelling
|
|
4
|
+
# 2 display human name in doctor output
|
|
5
|
+
# 3 detect_any ':'-separated paths (~ ok) and bare binary names; ANY hit => DETECTED
|
|
6
|
+
# 4 skills_path_project project-scope skill path pattern, relative to the repo (<name> slot)
|
|
7
|
+
# 5 skills_path_global global-scope skill path pattern (<name> slot)
|
|
8
|
+
# 6 context_path the context-injection file emit manages with a marker block ("-" = none)
|
|
9
|
+
# 7 docs_url the platform doc page the shapes came from
|
|
10
|
+
# 8 docs_read ISO date the URL was last verified (LIMITS #15 practice; an absent
|
|
11
|
+
# or empty cell is an unfilled PROBE-REQUIRED value => doctor DRIFT)
|
|
12
|
+
# 9-13 cap_skills cap_context_injection cap_command_blocking cap_marketplace cap_post_compaction
|
|
13
|
+
# yes|no|partial — the plan §3.3 capability matrix, as data.
|
|
14
|
+
# A malformed row (wrong column count, bad enum, id != directory, missing docs_read) is DRIFT
|
|
15
|
+
# by definition (R3): a capability table that cannot parse cannot be trusted.
|
|
16
|
+
id display detect_any skills_path_project skills_path_global context_path docs_url docs_read cap_skills cap_context_injection cap_command_blocking cap_marketplace cap_post_compaction
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# adapters/_template/detect.sh — the W5+ detection stub (W4A-SPEC §1).
|
|
3
|
+
#
|
|
4
|
+
# A template that silently
|
|
5
|
+
# exited 0 would make an unbuilt adapter look installed, so it refuses with 2
|
|
6
|
+
# and names the work — the same posture as the W1 doctor/emit placeholders.
|
|
7
|
+
# W4b built cursor/opencode/codex/gemini from copies of this directory; any
|
|
8
|
+
# future name copied from here must be measured before its row is filled.
|
|
9
|
+
printf 'detect: template adapter - not implemented (copy adapters/_template and fill in the anchors)\n' >&2
|
|
10
|
+
exit 2
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# adapters/_template/emit.sh — W5+ stub. Refuses until the adapter is built (the W4a
|
|
3
|
+
# precedent: a template that silently exited 0 would make an unbuilt adapter look real).
|
|
4
|
+
printf 'emit: template adapter - not implemented (copy adapters/_template and fill in the anchors)\n' >&2
|
|
5
|
+
exit 2
|