@techgoblin/gobstack 0.6.0-alpha.2 → 0.6.0-alpha.4

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/README.md CHANGED
@@ -87,7 +87,7 @@ is unwired in this alpha: the shim refuses the verb by name and prints the usage
87
87
  | `gob bans` | run the ban list (per-pattern red lines over the source tree) |
88
88
  | `gob extras` | the curated extras catalogue: `list [category]` / `show <id>` / `install <id...> [­-target <dir>] [--platform <id>] [--with-mcp-config]` — init only SUGGESTS; installs come from the catalogue (the allowlist rule), never the web |
89
89
  | `gob mcp` | serve the harness to your coding agent over MCP stdio — three tools (`gob_verify`, `gob_map_status`, `gob_init_status`), local only, no SDK, no network |
90
- | `gob uninstall` | remove everything an install wrote, byte-exactly (`gob install --target <dir> --uninstall` is the same job) |
90
+ | `gob uninstall` | remove everything an install wrote, byte-exactly (the same job as `goblin-install --target <dir> --uninstall` from the checkout/install tree) |
91
91
 
92
92
  `goblin` remains as a legacy alias for every command above — existing scripts keep working, but
93
93
  new commands and docs use `gob`.
@@ -146,6 +146,14 @@ The verdict decides what each row can do: `RECOMMEND` rows are pre-ticked when `
146
146
  suggests, `MAYBE` rows are listed but never pre-ticked, and a `SKIP` row refuses install —
147
147
  it stays visible so the curation history is readable, but the curator declined it.
148
148
 
149
+ **The license gate is hard.** A verdict alone never installs anything: every row carries a
150
+ `license_status` (verified | pending | proprietary-confirmed-ok) and the date it was checked.
151
+ Only `verified` installs. A row whose license is not yet resolved carries verdict
152
+ `LICENSE-PENDING` — it is never pre-ticked at init, and `gob extras install` refuses it with
153
+ `license pending verification` until a curator verifies the license and flips the row's data
154
+ in `catalogue.tsv`. The gate reads the data, not the code: flipping a row installable is a
155
+ catalogue edit (a new `license_status` + `license_check_date`), never an engine change.
156
+
149
157
  **The catalogue is the allowlist.** An id that is not a row in `catalogue.tsv` is refused by
150
158
  name; nothing is ever installed from a URL, a repo name, or a web search. Installs are
151
159
  offline by contract: skill and workflow rows copy from the vendored payload the curator
@@ -246,14 +254,17 @@ capability.
246
254
 
247
255
  gob uninstall --target .
248
256
 
249
- (equivalently `gob install --target . --uninstall` — through the legacy alias, spell it `goblin`
257
+ (the same job as `goblin-install --target . --uninstall` — through the legacy alias, spell it `goblin`
250
258
  instead of `gob`). The uninstall is **byte-exact**: it removes exactly the files
251
259
  `installed.json` records — hash-compared preimages, so a file you edited after install is
252
260
  reported and kept, never clobbered — then every directory that leaves empty, and it strips the
253
261
  `<!-- gob:begin --> … <!-- gob:end -->` block out of `AGENTS.md` (the body prose stays). After
254
262
  it, the repo has zero harness files; only the project's own record (`HANDOFF.md`, `AGENTS.md`'s
255
263
  prose, `reviews/`, the `.gitignore` block) survives, because that is the project's, not the
256
- harness's to delete. And because the engine is vendored, the repo needs no gobstack installed to
264
+ harness's to delete. Two residues are left **by design, and named in the output**: the
265
+ `.gitignore` ignore-rules block stays (removing it could eat a line the project added inside
266
+ it — delete that block by hand if you want it gone), and prose that named `.gob/` paths
267
+ (HANDOFF, the AGENTS.md body, SPECs) now points at removed files. And because the engine is vendored, the repo needs no gobstack installed to
257
268
  run this — it is self-contained until the moment you remove it.
258
269
 
259
270
  The short version, for a full removal from a machine and its repos: (b) in each initialized
@@ -261,7 +272,7 @@ repo, then (a).
261
272
 
262
273
  ## Re-pin the referenced standard
263
274
 
264
- gob install --target <dir> --re-pin
275
+ goblin-install --target <dir> --re-pin # from the gobstack checkout / install tree
265
276
 
266
277
  `practice_sha256:` in the AGENTS.md gob block pins the referenced standard and `IN-02`
267
278
  re-checks it, so editing that standard — a legitimate, intended edit — reds `IN-02` in every
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0-alpha.2
1
+ 0.6.0-alpha.4
package/bin/goblin-audit CHANGED
@@ -23,7 +23,7 @@
23
23
  # because an empty record reads to SC-07 as "clean" and that would be a fabricated pass
24
24
  set -uo pipefail
25
25
 
26
- GOBLIN_AUDIT_VERSION="0.6.0-alpha.1"
26
+ GOBLIN_AUDIT_VERSION="0.6.0-alpha.4"
27
27
 
28
28
  usage() { sed -n '2,/^$/p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; }
29
29
 
package/bin/goblin-bans CHANGED
@@ -28,7 +28,7 @@
28
28
 
29
29
  set -uo pipefail
30
30
 
31
- GOBLIN_BANS_VERSION="0.6.0-alpha.1"
31
+ GOBLIN_BANS_VERSION="0.6.0-alpha.4"
32
32
  SELF_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
33
33
  # shellcheck source=goblin-lib.sh
34
34
  . "$SELF_DIR/goblin-lib.sh"
package/bin/goblin-extras CHANGED
@@ -14,6 +14,11 @@
14
14
  #
15
15
  # Verdicts: RECOMMEND rows install; MAYBE rows install (an explicit choice, never
16
16
  # pre-ticked at init); SKIP rows refuse — the curator's verdict is the contract.
17
+ # THE LICENSE GATE (W-license, hard): verdict RECOMMEND|MAYBE alone is not enough —
18
+ # a row installs only when its catalogue license_status is `verified`. Rows with an
19
+ # unresolved license carry verdict LICENSE-PENDING (never pre-ticked at init) and
20
+ # refuse install with `license pending verification` until the curator flips the
21
+ # DATA (license_status + license_check_date), never this file.
17
22
  #
18
23
  # NO NETWORK. Skill and workflow installs copy from a VENDORED PAYLOAD the curator
19
24
  # maintains under extras-catalogue/payload/<id>/ (payload/README.md is the layout
@@ -49,7 +54,7 @@ usage() { sed -n '2,/^$/p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; }
49
54
  CATALOGUE="${GOB_EXTRAS_CATALOGUE:-$SRC/extras-catalogue/catalogue.tsv}"
50
55
  PAYLOAD="${GOB_EXTRAS_PAYLOAD:-$SRC/extras-catalogue/payload}"
51
56
 
52
- die() { g_err "extras: $*"; exit "${2:-2}"; }
57
+ die() { local msg="$1"; shift; g_err "extras: $msg"; exit "${1:-2}"; }
53
58
 
54
59
  # catalogue_row <id> — the whole data row (tab-separated), empty when absent.
55
60
  catalogue_row() {
@@ -100,15 +105,15 @@ cmd_list() {
100
105
  fi
101
106
  local total
102
107
  total=$(catalogue_ids | wc -l | tr -d ' ')
103
- g_info "gob extras — the curated catalogue ($total rows; RECOMMEND pre-ticks at init, MAYBE is visible but never pre-ticked, SKIP refuses install)"
108
+ g_info "gob extras — the curated catalogue ($total rows; RECOMMEND pre-ticks at init, MAYBE is visible but never pre-ticked, SKIP refuses install; LICENSE-PENDING rows refuse install until their license is verified)"
104
109
  g_info "install: gob extras install <id...> · one row: gob extras show <id>"
105
110
  local cat
106
111
  for cat in $(category_order); do
107
112
  [ -z "$want" ] || [ "$cat" = "$want" ] || continue
108
113
  printf '\n[%s]\n' "$cat"
109
- printf ' %-34s %-8s %-7s %-24s %-10s %s\n' "id" "kind" "stars" "license" "verdict" "matches"
114
+ printf ' %-34s %-8s %-7s %-24s %-10s %-16s %s\n' "id" "kind" "stars" "license" "verdict" "lic-status" "matches"
110
115
  awk -F'\t' -v cat="$cat" 'NR>1 && $2==cat {
111
- printf " %-34s %-8s %-7s %-24s %-10s %s\n", $1, $3, $9, $8, $15, $11
116
+ printf " %-34s %-8s %-7s %-24s %-10s %-16s %s\n", $1, $3, $9, $8, $15, $18, $11
112
117
  }' "$CATALOGUE"
113
118
  done
114
119
  return 0
@@ -124,10 +129,10 @@ cmd_show() {
124
129
  [ -n "$row" ] || die "unknown id '$id' — gob extras list names the catalogue" 2
125
130
  local labels=(id category kind name source_repo path_within_repo has_skill_md license
126
131
  stars last_push matches conflicts requires install_hint verdict
127
- reviewed_by reviewed_date)
132
+ reviewed_by reviewed_date license_status license_check_date)
128
133
  local i
129
- for i in $(seq 1 17); do
130
- printf '%-16s %s\n' "${labels[$((i-1))]}:" "$(catalogue_field "$row" "$i")"
134
+ for i in $(seq 1 19); do
135
+ printf '%-18s %s\n' "${labels[$((i-1))]}:" "$(catalogue_field "$row" "$i")"
131
136
  done
132
137
  return 0
133
138
  }
@@ -162,22 +167,35 @@ parse_install() {
162
167
  fi
163
168
  }
164
169
 
165
- # resolve_one <id> — validates against the ALLOWLIST and the curator's verdicts; prints
166
- # the row. Every install path goes through here: no row, no install. That is the whole
167
- # allowlist rule, in one gate.
170
+ # resolve_one <id> — validates against the ALLOWLIST, the curator's verdicts and the
171
+ # LICENSE GATE; prints the row. Every install path goes through here: no row, no
172
+ # install; no verified license, no install. That is the whole allowlist rule plus the
173
+ # hard gate, in one gate.
168
174
  resolve_one() {
169
- local id="$1" row verdict
175
+ local id="$1" row verdict lic
170
176
  row=$(catalogue_row "$id")
171
177
  # Captured, not piped (pipefail + grep -q early-exit trap — see cmd_list).
172
178
  if [ -n "$row" ]; then
173
179
  verdict=$(catalogue_field "$row" 15)
180
+ lic=$(catalogue_field "$row" 18)
174
181
  else
175
182
  die "unknown id '$id' — nothing outside catalogue.tsv is ever installed (gob extras list names the allowlist)" 2
176
183
  fi
177
184
  case "$verdict" in
178
- RECOMMEND|MAYBE) ;;
185
+ RECOMMEND|MAYBE|LICENSE-PENDING) ;;
179
186
  SKIP) die "id '$id' carries verdict SKIP — the curator declined it; it stays visible in the catalogue but refuses install" 1 ;;
180
- *) die "id '$id' carries verdict '$verdict' — not an installable verdict (RECOMMEND|MAYBE|SKIP)" 2 ;;
187
+ *) die "id '$id' carries verdict '$verdict' — not an installable verdict (RECOMMEND|MAYBE|SKIP|LICENSE-PENDING)" 2 ;;
188
+ esac
189
+ # THE LICENSE GATE (hard, data-driven): a row whose catalogue says its license is
190
+ # not verified never installs — the verdict alone is not consulted. A curator flips
191
+ # a row to installable by fixing the data (license_status=verified + a check date),
192
+ # never by touching this file.
193
+ case "$lic" in
194
+ verified) ;;
195
+ pending|proprietary-confirmed-ok|"")
196
+ die "id '$id' refuses install: license pending verification — see catalogue.tsv license_check_date" 1 ;;
197
+ *)
198
+ die "id '$id' carries license_status '$lic' — not a known status (verified|pending|proprietary-confirmed-ok)" 2 ;;
181
199
  esac
182
200
  printf '%s\n' "$row"
183
201
  }
@@ -232,7 +250,12 @@ install_skill() {
232
250
  [ -d "$d" ] || continue
233
251
  name=$(basename "$d")
234
252
  n=$((n + 1))
235
- g_info "extras: skill $name -> ${dst_root#"$TARGET"/}$name/"
253
+ # QA fix (v2-qa issue 9): the display path must carry exactly one separator between
254
+ # $dst_root and $name — the old single format printed `.gob/extras` + `taste` as
255
+ # `.gob/extrastaste/` (files landed in the right place, only the LOG lied). The
256
+ # platform branch normalizes $dst_root to end in /, the standalone branch does not,
257
+ # so the trailing slashes are stripped at print time and one / is always inserted.
258
+ printf 'extras: skill %s -> %s/%s/\n' "$name" "${dst_root%/}" "$name"
236
259
  copy_tree "$d" "$dst_root/$name"
237
260
  done
238
261
  [ "$n" -gt 0 ] || die "payload for '$id' holds no skill dirs ($src_root/*/ with SKILL.md each) — see extras-catalogue/payload/README.md" 2
package/bin/goblin-init CHANGED
@@ -133,6 +133,10 @@ back one proposal file. Do this now:
133
133
  found in step 1 — react, vue, playwright, godot, unity, node, postgres, …);
134
134
  - RECOMMEND rows are pre-ticked (write `- id` with `[x]`); MAYBE rows are
135
135
  listed but NOT pre-ticked (`[ ]`) — they are visible choices, never defaults;
136
+ - a row with NO vendored payload (no `extras-catalogue/payload/<id>/` directory)
137
+ must NOT be pre-ticked even when RECOMMEND — print it as `[ ]` instead;
138
+ `--write` installs through `gob extras install`, which refuses a
139
+ payload-missing id and fails the whole --write;
136
140
  - a row whose `conflicts:` names an id you also picked: pick at most one of them;
137
141
  - SKIP rows are never suggested and refuse install; leave them out entirely.
138
142
 
@@ -226,13 +230,21 @@ print_heuristic() {
226
230
  # files). The SAME matches column the agent brief reads — the fallback suggests from
227
231
  # the catalogue, never from its own private list. Verdicts are respected: only
228
232
  # RECOMMEND rows pre-tick; MAYBE rows print unticked; SKIP rows never appear.
233
+ # QA fix (v2-qa): a row pre-ticks ONLY when its vendored payload exists —
234
+ # extras-catalogue/payload/<id>/ — because --write installs through
235
+ # `gob extras install`, which refuses a payload-missing row and fails the whole
236
+ # --write after everything else was already written. A RECOMMEND row with no
237
+ # payload prints as a visible, unticked `[ ]` choice instead. (41 researched rows,
238
+ # 1 vendored payload: the old pre-tick turned a day-one init into a guaranteed
239
+ # exit 2 halfway through writing.)
229
240
  if [ -f "$CATALOGUE_TSV" ]; then
230
241
  local scan
231
242
  scan=$(cat "$TARGET/package.json" "$TARGET"/*.lock "$TARGET"/pnpm-lock.yaml \
232
243
  "$TARGET"/vue.config.* "$TARGET"/nuxt.config.* "$TARGET"/godot/project.godot \
233
244
  "$TARGET"/unity/ProjectSettings/ProjectVersion.txt 2>/dev/null | tr 'A-Z' 'a-z')
234
245
  if [ -n "$scan" ]; then
235
- local ticked="" maybe=""
246
+ local ticked="" maybe="" payload_root
247
+ payload_root="${GOB_EXTRAS_PAYLOAD:-$SRC/extras-catalogue/payload}"
236
248
  while IFS=$'\t' read -r cid ccat ckind cname crepo cpath chmd clic cstars cpush \
237
249
  cmatches cconf creq chint cverdict cby cdate; do
238
250
  [ -n "$cid" ] || continue
@@ -242,6 +254,12 @@ print_heuristic() {
242
254
  case "$scan" in *"$tok"*) hit=1; break ;; esac
243
255
  done
244
256
  [ "$hit" -eq 1 ] || continue
257
+ if [ ! -d "$payload_root/$cid" ]; then
258
+ # no vendored payload: the row stays visible but never pre-ticks —
259
+ # a tick --write cannot honour is a refusal waiting to happen
260
+ maybe="$maybe - [ ] $cid # matches this repo, NO VENDORED PAYLOAD yet (gob extras install would refuse — vendor it under extras-catalogue/payload/$cid/ first)"$'\n'
261
+ continue
262
+ fi
245
263
  case "$cverdict" in
246
264
  RECOMMEND) ticked="$ticked - [x] $cid # matches this repo ($cmatches)"$'\n' ;;
247
265
  MAYBE) maybe="$maybe - [ ] $cid # matches, verdict MAYBE (not pre-ticked)"$'\n' ;;
@@ -326,6 +344,37 @@ SYNC_SEL=$(g_agents_list "$PROP" sync_platforms | tr '\n' ' ')
326
344
  # cannot install anything the catalogue does not carry.
327
345
  EXTRAS_SEL=$(sed -n '/catalogue_suggestions:/,/^[^ -]/{s/^[[:space:]]*-[[:space:]]*\[x\][[:space:]]*\([A-Za-z0-9_-]*\).*/\1/p;}' "$PROP" | sort -u | tr '\n' ' ')
328
346
 
347
+ # ---------------------------------------------------------------- pre-flight ---
348
+ # QA fix (v2-qa issue 1b): the TICKED extras are validated BEFORE anything is written.
349
+ # The old order installed the harness first and ran `gob extras install` last, so a
350
+ # missing vendored payload refused AFTER 23 files were already in the tree (the day-one
351
+ # exit 2 with the repo half-initialized). Here every ticked id is resolved through the
352
+ # same allowlist path goblin-extras uses (row exists, verdict installable, license gate,
353
+ # vendored payload present) while the target is still untouched; a refusal names the id
354
+ # and the fix and exits before the first write.
355
+ if [ -n "$EXTRAS_SEL" ] && [ "$DRYRUN" -eq 0 ]; then
356
+ PAYLOAD_ROOT="${GOB_EXTRAS_PAYLOAD:-$SRC/extras-catalogue/payload}"
357
+ for xid in $EXTRAS_SEL; do
358
+ row=$(awk -F'\t' -v id="$xid" 'NR>1 && $1==id { print; exit }' "$CATALOGUE_TSV" 2>/dev/null)
359
+ [ -n "$row" ] || { g_err "pre-flight: catalogue has no row '$xid' — fix the proposal's catalogue_suggestions (gob extras list names the allowlist)"; exit 2; }
360
+ verdict=$(printf '%s' "$row" | awk -F'\t' '{print $15}')
361
+ lic=$(printf '%s' "$row" | awk -F'\t' '{print $18}')
362
+ case "$verdict" in
363
+ RECOMMEND|MAYBE) ;;
364
+ *) g_err "pre-flight: '$xid' carries verdict '$verdict' — untick it in the proposal's catalogue_suggestions"; exit 2 ;;
365
+ esac
366
+ # the same license gate goblin-extras enforces, read before any write
367
+ case "$lic" in
368
+ verified) ;;
369
+ *) g_err "pre-flight: '$xid' refuses install: license pending verification — untick it in the proposal's catalogue_suggestions"; exit 2 ;;
370
+ esac
371
+ [ -d "$PAYLOAD_ROOT/$xid" ] || {
372
+ g_err "pre-flight: no vendored payload for '$xid' at $PAYLOAD_ROOT/$xid — untick it in the proposal's catalogue_suggestions, or vendor the payload there first";
373
+ exit 2;
374
+ }
375
+ done
376
+ fi
377
+
329
378
  if [ "$DRYRUN" -eq 1 ]; then
330
379
  g_info "gob init --write --dry-run: validated OK (class $CLASS, branch $BRANCH, owner $EMAIL, 1+ gate)"
331
380
  g_info " sync: ${SYNC_SEL:-none}"
@@ -1,19 +1,23 @@
1
1
  #!/usr/bin/env bash
2
2
  # goblin-install — drop the harness into a target repo, idempotently.
3
3
  #
4
- # Usage: gob install --target <dir> [options] (script: bin/goblin-install)
4
+ # Usage: bash bin/goblin-install --target <dir> [options] # checkout-only; `gob init --write` is the user surface
5
5
  # --target <dir> required; the repo root to install into
6
6
  # --class <name> required unless --uninstall or --re-pin; one of
7
7
  # software|service|game|research|fleet, or the aliases A-E / app / agent
8
8
  # / desktop (desktop/F => software + --electron); anything else is refused
9
9
  # --electron the electron opt-in overlay over the software class (electron: true):
10
10
  # the app_bundle_bytes ratchet, BN-06..09 bans, the host-gate declaration
11
- # --models <path> model mapping file (default: $GOBLIN_MODELS -> ~/projects/fleet-model.yaml)
12
- # --practice <path> the referenced standard (default: $GOBLIN_PRACTICE -> ~/projects/PROJECT-PRACTICE.md); a named path that is absent is reported, never silently dropped
11
+ # --models <path> model mapping file (default: $GOBLIN_MODELS; unset = rendered as an
12
+ # empty models_file: the repo's machine-specific input, never a path
13
+ # from the machine the installer ran on)
14
+ # --practice <path> the referenced standard (default: $GOBLIN_PRACTICE; unset = empty
15
+ # practice: pin — a named path that is absent is reported, never
16
+ # silently dropped)
13
17
  # --parts <list> comma list to install; default = every part the class requires
14
18
  # --archive mark the project archive: verify requires no HANDOFF and no gates
15
19
  # --skills yes|no install agent skills under .hermes/skills (default no; opt in per
16
- # platform with: gob emit --platform <p>)
20
+ # catalogue row with: gob extras install <id>)
17
21
  # --dry-run print the plan; write nothing
18
22
  # --upgrade re-install at the current version; report created/updated/unchanged/skipped
19
23
  # --opt-out <part> record the part in disabled: so its required checks are skipped
@@ -31,7 +35,7 @@
31
35
 
32
36
  set -uo pipefail
33
37
 
34
- GOBLIN_INSTALL_VERSION="0.6.0-alpha.1"
38
+ GOBLIN_INSTALL_VERSION="0.6.0-alpha.4"
35
39
  SELF_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
36
40
  SRC=$(cd "$SELF_DIR/.." && pwd)
37
41
  # shellcheck source=goblin-lib.sh
@@ -39,8 +43,16 @@ SRC=$(cd "$SELF_DIR/.." && pwd)
39
43
 
40
44
  TARGET=""
41
45
  CLASS=""
42
- MODELS="${GOBLIN_MODELS:-$HOME/projects/fleet-model.yaml}"
43
- PRACTICE="${GOBLIN_PRACTICE:-$HOME/projects/PROJECT-PRACTICE.md}"
46
+ # QA fix (v2-qa issue 4): the old defaults were $HOME/projects/fleet-model.yaml and
47
+ # $HOME/projects/PROJECT-PRACTICE.md - the MAINTAINER's home layout baked into every
48
+ # rendered config on every machine, including a fresh contributor's (their rendered
49
+ # AGENTS.md pointed at a file that does not exist on their machine). The neutral default
50
+ # is EMPTY: no --models / no GOBLIN_MODELS renders an empty models_file: line, and the
51
+ # practice pin stays empty (verify already treats both as the legitimate no-mapping /
52
+ # no-standard state). A machine that HAS a fleet mapping exports GOBLIN_MODELS (or
53
+ # passes --models) and gets the same rendering as before.
54
+ MODELS="${GOBLIN_MODELS:-}"
55
+ PRACTICE="${GOBLIN_PRACTICE:-}"
44
56
  # W5-3: `--practice <path>` naming a file that is not there used to be IGNORED IN SILENCE -
45
57
  # exit 0, `practice: ~`, `practice_sha256: ~`, and not one line about it in the install log.
46
58
  # The empty pin is a legitimate state (a repo may reference no standard, and the default path is
@@ -220,6 +232,15 @@ if [ "$UNINSTALL" -eq 1 ]; then
220
232
  printf '.goblin\n.gob/bin\n.gob/manifest\n.gob/bans\n.hermes\n.hermes/skills\n'
221
233
  } | awk 'NF' | awk -F/ '{print NF " " $0}' | sort -rn | cut -d' ' -f2- | awk '!seen[$0]++')
222
234
  g_info "removed $n file(s) and $nd empty director(y|ies). Left in place: HANDOFF.md, AGENTS.md, ROUND-000-SPEC.md, reviews/, the .gitignore block${KEPT:+, and the decision record(s) you edited:$KEPT}."
235
+ # QA fix (v2-qa issue 10): honesty about what the uninstall leaves UNTOUCHED. Two
236
+ # by-design residues a reader could otherwise read as a clean sweep:
237
+ # - the .gitignore block the install appended stays (removing it could eat a
238
+ # line the project added inside the block; the preimage is untracked text),
239
+ # - prose in kept files (HANDOFF.md, AGENTS.md body, SPECs) may still name
240
+ # now-deleted paths (.gob/bin/goblin-verify, checks/) — those references are
241
+ # dead after this command.
242
+ g_info " note: the .gitignore ignore-rules block stays (by design: it may carry lines the project added; remove it by hand if you want it gone)"
243
+ g_info " note: prose that names .gob/ paths (HANDOFF.md, AGENTS.md body, SPECs) now points at removed files — those references are dead"
223
244
  exit 0
224
245
  fi
225
246
 
@@ -852,7 +873,7 @@ if [ "$DRY_RUN" -eq 0 ]; then
852
873
  if [ "$SKILLS" = "yes" ]; then
853
874
  g_info " 4. hermes skills trust $TARGET # one-time, so the project-tier skills load"
854
875
  else
855
- g_info " 4. agent skills are opt-in: gob emit --platform <p> # run gob doctor for the platform list"
876
+ g_info " 4. agent skills are opt-in: gob extras install <id...> # gob extras list shows the catalogue"
856
877
  fi
857
878
  g_info ""
858
879
  g_info "automations (optional; neither writes outside this repo, and A-02 has no agent in it):"
package/bin/goblin-lib.sh CHANGED
@@ -16,7 +16,7 @@
16
16
  # - name: typecheck four-space-indented second member of a list entry
17
17
  # cmd: npx tsc --noEmit
18
18
 
19
- GOBLIN_LIB_VERSION="0.6.0-alpha.1"
19
+ GOBLIN_LIB_VERSION="0.6.0-alpha.4"
20
20
 
21
21
  # ---------------------------------------------------------------- output -----
22
22
  # g_trunc <width> <text> — fold a long detail to one line at <width> columns, keeping the
@@ -31,6 +31,9 @@ g_trunc() {
31
31
  # <indent> (the cannot-see footer shape). Byte-safe: awk length on bytes approximates
32
32
  # columns for ASCII prose, which is all this text is.
33
33
  g_fold() {
34
+ # QA fix (v2-qa issue 9): the rest-assignment used to inline substr() as sub()'s third
35
+ # parameter — not a changeable lvalue, a hard error on gawk 5.2+ (the helper had never
36
+ # been exercised until the remedy fold called it). A temp variable is portable awk.
34
37
  awk -v w="$1" -v ind="$2" '
35
38
  {
36
39
  line = $0
@@ -39,10 +42,9 @@ g_fold() {
39
42
  while (cut > 1 && substr(line, cut, 1) != " ") cut--
40
43
  if (cut <= 1) cut = w
41
44
  print substr(line, 1, cut)
42
- sub(/^[ ]+/, "", substr(line, cut + 1))
43
- line = substr(line, cut + 1)
44
- sub(/^[ ]+/, "", line)
45
- line = ind line
45
+ rest = substr(line, cut + 1)
46
+ sub(/^[ ]+/, "", rest)
47
+ line = ind rest
46
48
  }
47
49
  print line
48
50
  }'
@@ -71,12 +73,16 @@ g_fail() {
71
73
  case "$rem" in
72
74
  —*) return 0 ;; # an em-dash cell: history and blindness, never a remedy
73
75
  esac
74
- # Whole in verbose/--only mode (the mode that reads, not scans), width-folded otherwise —
75
- # the same contract the row printers keep.
76
- if [ "${GOB_VERIFY_VERBOSE:-0}" -eq 1 ]; then
77
- [ -n "$rem" ] && printf 'remedy: %s\n' "$rem"
78
- else
79
- [ -n "$rem" ] && printf 'remedy: %s\n' "$(g_trunc "${GOB_REPORT_COLS:-100}" "$rem")"
76
+ # QA fix (v2-qa issue 9): a remedy is an instruction, not a detail line — truncating it
77
+ # with a ~ cut the command the operator had to type (measured: 'git -c user.ema~').
78
+ # The remedy is now WORD-FOLDED to continuation lines at the report width in every
79
+ # mode (whole text either way); --verbose keeps the single-line form it always had.
80
+ if [ -n "$rem" ]; then
81
+ if [ "${GOB_VERIFY_VERBOSE:-0}" -eq 1 ]; then
82
+ printf 'remedy: %s\n' "$rem"
83
+ else
84
+ printf 'remedy: %s\n' "$rem" | g_fold "${GOB_REPORT_COLS:-100}" " "
85
+ fi
80
86
  fi
81
87
  }
82
88
  g_remedy() {
package/bin/goblin-map CHANGED
@@ -45,7 +45,7 @@
45
45
  #
46
46
  # Never-clobber contract:
47
47
  # features/ absent (or empty of .md) -> generate README + one file per slug, exit 0
48
- # features/ already a map, no --force -> write NOTHING, name the path and --force, exit 1
48
+ # features/ already a map, no --force -> validate only; the index is kept (never rewritten)
49
49
  # --force -> regenerate ONLY README.md (indexing every existing
50
50
  # feature file too) and add files for NEW slugs;
51
51
  # existing feature files are never touched, exit 0
@@ -129,8 +129,9 @@ Notes:
129
129
  human pass has actually driven the feature once.
130
130
  - entry_paths tokens must be repo-relative paths that EXIST, and should occur in
131
131
  source text (a route literal, an import) so FM-02 can grep for them.
132
- - An existing map is never overwritten without --force (the index only); if a map
133
- already exists, hand-pass the files instead of regenerating them.
132
+ - --write validates and never rewrites: your hand-written README index is KEPT
133
+ (pass --force only if you want the index REGENERATED from the feature files);
134
+ existing feature files are never touched either way.
134
135
 
135
136
  == FEATURE-FILE SCHEMA =========================================================
136
137
 
@@ -201,13 +202,15 @@ if [ -n "$WRITE_DIR" ]; then
201
202
  WDIR=$(cd "$WRITE_DIR" && pwd) || { g_err "cannot enter: $WRITE_DIR"; exit 2; }
202
203
  # A map, for --write purposes, is the README index: --write never writes feature
203
204
  # files (they are its INPUT), so the only thing it could clobber is the index.
205
+ # QA fix (v2-qa issue 5): an existing index used to be a refusal ("pass --force") —
206
+ # but the AGENT BRIEF itself tells the agent to WRITE features/README.md before
207
+ # running --write, so the first --write of the brief's own prescribed flow demanded
208
+ # the scary flag. The coherent contract: --write VALIDATES and never rewrites the
209
+ # index without --force; an existing index is the author's own output and is kept,
210
+ # named in the done line. (The never-clobber promise is unchanged: --write still
211
+ # writes NOTHING without --force — the refusal was protecting an empty write.)
204
212
  HAVE_WMAP=0
205
213
  if [ -f "$WDIR/README.md" ]; then HAVE_WMAP=1; fi
206
- if [ "$HAVE_WMAP" -eq 1 ] && [ "$FORCE" -ne 1 ]; then
207
- g_err "refusing to overwrite an existing feature map: $WDIR"
208
- printf 'error: map: pass --force to regenerate the README index and add NEW files only; existing files are never rewritten\n' >&2
209
- exit 1
210
- fi
211
214
  # Validation: the frontmatter + H2 + verified contract, per file, fail closed.
212
215
  BAD=0; N=0
213
216
  for f in "$WDIR"/*.md; do
@@ -264,7 +267,10 @@ if [ -n "$WRITE_DIR" ]; then
264
267
  for f in "$WDIR"/*.md; do
265
268
  [ -f "$f" ] || continue
266
269
  slug=$(basename "$f"); slug=${slug%.md}
267
- case "$slug" in README.md) continue ;; esac
270
+ # QA fix (v2-qa issue 6): $slug is the STEM (README, not README.md) — the old
271
+ # pattern compared README against README.md, never matched, and the regenerated
272
+ # index listed the index itself as a feature.
273
+ case "$slug" in README) continue ;; esac
268
274
  printf '%s\t%s\n' "$slug" "$(printf '%s' "${f#"$WDIR"/}" | sed 's#^#./#')" >> "$SLUGS_TSV"
269
275
  done
270
276
  TODAY=$(date +%F)
@@ -509,7 +515,9 @@ MID
509
515
  for f in "$FEAT"/*.md; do
510
516
  [ -f "$f" ] || continue
511
517
  slug=$(basename "$f"); slug=${slug%.md}
512
- case "$slug" in README.md) continue ;; esac
518
+ # QA fix (v2-qa issue 6): stem comparison, same bug as the --write index loop —
519
+ # the slug is README after .md is stripped, so the old README.md pattern never fired.
520
+ case "$slug" in README) continue ;; esac
513
521
  awk -F'\t' -v s="$slug" '$1 == s { found=1 } END { exit !found }' "$SLUGS_TSV" && continue
514
522
  title=$(file_title "$f" "$slug")
515
523
  printf '%s\n' "- [${title}](./${slug}.md) covers TODO — existing feature file kept by --force (not re-described)"
package/bin/goblin-mcp.js CHANGED
@@ -211,7 +211,29 @@ function remedyMap(root) {
211
211
  }
212
212
 
213
213
  function toolGobVerify(args) {
214
- const root = process.cwd();
214
+ // QA fix (v2-qa issue 7): the tool honours an explicit `target` — an agent calling from
215
+ // an installed repo with a different repo named as target used to get the CWD's matrix
216
+ // with the bogus target silently dropped (wrong-repo-as-verified). Resolution rules:
217
+ // - target absent/empty -> process.cwd() (the documented default)
218
+ // - target relative -> resolved against process.cwd()
219
+ // - resolved dir carries no .gob/engine and no AGENTS.md gob block -> REFUSAL (the
220
+ // exact resolved path is named), never a silent fall-back to the CWD's matrix
221
+ // The result's first line names the verified path, so the agent sees WHICH repo was judged.
222
+ const cwd = process.cwd();
223
+ let root = cwd;
224
+ const target = args && typeof args.target === "string" ? args.target.trim() : "";
225
+ if (target) {
226
+ root = path.resolve(cwd, target);
227
+ if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) {
228
+ return errText("gob_verify: target is not a directory: " + root);
229
+ }
230
+ const blockText = readBlock(path.join(root, "AGENTS.md"));
231
+ if (!fs.existsSync(path.join(root, ".gob", "bin", "goblin-verify")) && !blockText) {
232
+ return errText(
233
+ "gob_verify: target is not a gobstack repo (no .gob/bin/goblin-verify, no AGENTS.md gob block): " + root
234
+ );
235
+ }
236
+ }
215
237
  const engine = path.join(root, ".gob", "bin", "goblin-verify");
216
238
  if (!fs.existsSync(engine)) {
217
239
  return errText(
@@ -235,7 +257,9 @@ function toolGobVerify(args) {
235
257
  const verdict = parsed.failed === 0 && r.status === 0 ? "PASS" : "FAIL";
236
258
  const lines = [];
237
259
  lines.push(
238
- "gate: " + verdict + " — " + parsed.passed + " passed, " + parsed.failed + " failed, " +
260
+ // the resolved repo is named first: the consumer sees WHICH tree was judged
261
+ "verified: " + root +
262
+ "\ngate: " + verdict + " — " + parsed.passed + " passed, " + parsed.failed + " failed, " +
239
263
  parsed.advisory + " advisory, " + parsed.skipped + " skipped (exit " + r.status + ")"
240
264
  );
241
265
  for (const row of parsed.rows) {
@@ -358,7 +382,9 @@ const TOOLS = [
358
382
  type: "object",
359
383
  properties: {
360
384
  only: { type: "string", description: "optional comma-separated rule ids to run (e.g. FM-01,FM-02)" },
385
+ target: { type: "string", description: "optional repo root to verify (absolute, or relative to the CWD); defaults to the current working directory" },
361
386
  },
387
+ additionalProperties: false,
362
388
  },
363
389
  },
364
390
  {
@@ -30,7 +30,7 @@
30
30
  # `git revert` of this command's own two commits (W3-SPEC §5).
31
31
  set -uo pipefail
32
32
 
33
- GOBLIN_UPGRADE_VERSION="0.6.0-alpha.1"
33
+ GOBLIN_UPGRADE_VERSION="0.6.0-alpha.4"
34
34
 
35
35
  usage() { sed -n '2,/^$/p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; }
36
36
 
package/bin/goblin-verify CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  set -uo pipefail
21
21
 
22
- GOBLIN_VERIFY_VERSION="0.6.0-alpha.1"
22
+ GOBLIN_VERIFY_VERSION="0.6.0-alpha.4"
23
23
  SELF_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
24
24
  # shellcheck source=goblin-lib.sh
25
25
  . "$SELF_DIR/goblin-lib.sh"
@@ -276,9 +276,9 @@ if [ ! -f "$CONFIG" ]; then
276
276
  if [ "$ROOT" != "$PWD" ]; then
277
277
  g_err "not installed: $CONFIG is absent — and $PWD is not the installed repo ($ROOT)."
278
278
  g_err "fix: cd to your project repo, then re-run gob verify."
279
- g_err " (installing here would initialize $PWD: goblin-install --target $PWD --class <software|service|game|research|fleet>)"
279
+ g_err " (installing here would initialize $PWD: npx @techgoblin/gobstack init)"
280
280
  else
281
- g_err "not installed: $CONFIG is absent. Run: goblin-install --target $ROOT --class <software|service|game|research|fleet>"
281
+ g_err "not installed: $CONFIG is absent. Run: npx @techgoblin/gobstack init # or: gob init, inside $ROOT"
282
282
  fi
283
283
  exit 2
284
284
  fi
@@ -484,7 +484,7 @@ check_in_01() {
484
484
  # IN-01 recovery line (review 1, scope 4): the record is corrupt or missing; name the two
485
485
  # restores. The matrix's remedy: line rides under the payload via g_fail.
486
486
  printf 'installed.json is absent or records no version\n'
487
- printf 'recover: gob install --upgrade, or git checkout -- .gob/installed.json\n'
487
+ printf 'recover: git checkout -- .gob/installed.json, or re-run npx @techgoblin/gobstack init --write to re-install\n'
488
488
  return 1
489
489
  }
490
490
 
@@ -609,7 +609,7 @@ check_in_02() {
609
609
  # catch a SILENT edit, so re-pinning is a deliberate act: one explicit command, which
610
610
  # prints the old and new hash (docs/CONTRACTS.md, "An edited standard is not a dead end").
611
611
  printf ' if the edit is yours and intended, re-pin it deliberately:\n'
612
- printf ' goblin-install --target %s --re-pin\n' "$ROOT"
612
+ printf ' goblin-install --target %s --re-pin # from the gobstack checkout/install tree\n' "$ROOT"
613
613
  bad=1; pin=" | practice EDITED"
614
614
  else
615
615
  pin=" | practice pin ok"
@@ -626,7 +626,7 @@ check_in_02() {
626
626
  # naming the drifted file the payload above reported. Sits between the row's own lines and
627
627
  # the summary; g_fail appends the matrix's remedy: line under the whole payload.
628
628
  if [ "$bad" -ne 0 ] && [ -n "$DRIFTED" ]; then
629
- printf 'recover: git checkout -- %s, or gob install --upgrade\n' "$DRIFTED"
629
+ printf 'recover: git checkout -- %s, or re-run npx @techgoblin/gobstack init --write to re-install\n' "$DRIFTED"
630
630
  fi
631
631
  [ "$bad" -eq 0 ]
632
632
  }
package/docs/CONTRACTS.md CHANGED
@@ -13,12 +13,15 @@ same way the fleet's own tool reads it. Everything else is line-oriented shell.
13
13
  software · service · game · research · fleet. The letters A-E and the
14
14
  older names app (software), agent (fleet) and desktop/F (software + the
15
15
  electron opt-in) are read-time aliases.
16
- --models <path> model mapping file (default: $GOBLIN_MODELS -> ~/projects/fleet-model.yaml)
17
- --practice <path> the referenced standard (default: $GOBLIN_PRACTICE -> ~/projects/PROJECT-PRACTICE.md)
16
+ --models <path> model mapping file (default: $GOBLIN_MODELS; unset = an empty
17
+ models_file: the repo's machine-specific input, set per machine)
18
+ --practice <path> the referenced standard (default: $GOBLIN_PRACTICE; unset = no
19
+ practice pin; a named path that is absent is reported, never
20
+ silently dropped)
18
21
  --parts <list> comma list to install; default = every part the class requires
19
22
  --archive mark the project archive: verify requires no HANDOFF and no gates
20
23
  --skills yes|no install agent skills under .hermes/skills (default no — the harness is
21
- neutral; opt in per platform with: gob emit --platform <p>). On a repo whose
24
+ neutral; opt in per catalogue row with: gob extras install <id...>). On a repo whose
22
25
  record already has skills installed, an OMITTED flag keeps them; an explicit
23
26
  --skills no removes them.
24
27
  --dry-run print the plan; write nothing
@@ -31,7 +31,7 @@ Measured shape of this table: **87 rows** - 82 target, 5 source; advisory 10, ga
31
31
  | id | scope | enforced by | rule | check | if it cannot be enforced, why |
32
32
  |---|---|---|---|---|---|
33
33
  | `IN-01` | target | script | The install exists and records its version + every file's hash. | goblin-verify --only IN-01 | — (W1: the check is a builtin so the engine.mode=global clause can run — a global, declaration-only repo has no install record and SKIPs with `global engine mode — no per-repo install record`; the vendored clauses are the old one-liner: the record exists and names its version) |
34
- | `IN-02` | target | script | Every installed file still matches its recorded hash. | goblin-verify --only IN-02 | recover: gob install --upgrade, or git checkout -- .gob/installed.json; for a file it names drifted: git checkout -- <path> (if the edit is yours and intended, re-pin it: gob install --target <dir> --re-pin) |
34
+ | `IN-02` | target | script | Every installed file still matches its recorded hash. | goblin-verify --only IN-02 | recover: git checkout -- .gob/installed.json (or re-run `npx @techgoblin/gobstack init --write` to re-install); for a file it names drifted: git checkout -- <path> (if the edit is yours and intended, re-pin it: `goblin-install --target <dir> --re-pin` from the checkout/install tree) |
35
35
  | `IN-03` | target | script | The verifier's own manifest is complete: every rule has a check or is advisory. | goblin-verify --only IN-03 | — (this row is the reason the matrix cannot rot; the second clause is D6's shape in general: a row that carries no check must be labelled advisory, or it claims verification it does not perform. The third clause is Z1-5: `enforced_by` is documented as a closed enum in docs/ENFORCEMENT.md and was read by NOTHING, so a typo in that cell changed nothing - `script\|lint\|gate\|advisory` plus `test`, the source-scope value whose check is tests/run-tests.sh. W1: the check runs against whichever manifest the engine actually resolved (the chain in bin/goblin-verify), no longer the hardcoded per-repo path — the rule's meaning is untouched, only the path input follows the engine) |
36
36
  | `IN-04` | target | script | No file goblin-stack did not create has been overwritten. | goblin-verify --only IN-04 | Detects a file the installer recorded as pre-existing (a `refused` entry) that has since vanished, or that is listed as installed anyway. The second clause is an internal-consistency guard: with correct code a refused path is never written, so it fires only if the installer regresses. The negative control exercises the vanished branch. |
37
37
  | `HP-01` | target | gate | HANDOFF.md exists at the root. | test -f HANDOFF.md | — |
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.6.0-alpha.1` · Last measured: 2026-10-09 · Every command and every output below was run on a
6
+ Version: `0.6.0-alpha.4` · 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
  ---
@@ -267,7 +267,8 @@ Open it. The keys that matter on day one:
267
267
  branch: main # DECLARED, never assumed
268
268
  owner_email: you@example.com # the commit identity this repo expects
269
269
  practice: /path/to/your-standard.md # optional: your own house rules, hash-pinned
270
- models_file: /path/to/fleet-model.yaml # the ONE machine-specific input
270
+ models_file: /path/to/fleet-model.yaml # the ONE machine-specific input (per machine; a
271
+ # fresh install without --models leaves it empty)
271
272
  gate_<name>_cmd: <one command> # YOUR real commands, one line each
272
273
 
273
274
  **The single most valuable edit you will make:** replace the gate line(s) with the commands you
@@ -290,7 +291,7 @@ repos follow an old version.
290
291
 
291
292
  When *you* legitimately edit your own standard:
292
293
 
293
- gob install --target . --re-pin
294
+ goblin-install --target . --re-pin # from the gobstack checkout / install tree
294
295
 
295
296
  It re-records the hash and prints the old and new value. Nothing re-pins automatically — not even
296
297
  a re-install — an edited standard is never a silent no-op.
@@ -528,8 +529,8 @@ same commands are available outside any repo through the npm CLI: `gob init` / `
528
529
 
529
530
  .gob/bin/goblin-verify [--only <id[,id...]>] [--json] [--list]
530
531
  .gob/bin/goblin-bans # run the ban list
531
- gob install --target <dir> --uninstall # the uninstall job
532
- gob install --target <dir> --re-pin # the deliberate re-pin
532
+ gob uninstall --target <dir> # the uninstall job
533
+ goblin-install --target <dir> --re-pin # the deliberate re-pin (from the checkout/install tree)
533
534
  bin/goblin-model <role> # checkout-only; resolve a role to a profile (docs/ROLES.md)
534
535
 
535
536
  ### Register the harness with your agent (MCP)
@@ -586,6 +587,10 @@ The one rule to hold onto: **init suggests, the catalogue allows, you install.**
586
587
 
587
588
  Verdicts: a `RECOMMEND` row is pre-ticked when `gob init` suggests; a `MAYBE` row is listed
588
589
  but never pre-ticked; a `SKIP` row refuses install (visible history, declined candidate).
590
+ The license gate rides on top, hard: a row installs only when its `license_status` is
591
+ `verified` — a `LICENSE-PENDING` row (license unresolved) is never pre-ticked and
592
+ `gob extras install` refuses it with `license pending verification` until the curator flips
593
+ the row's data in `catalogue.tsv`.
589
594
  Nothing installs at init — `gob init --write` honours only the rows your proposal ticks, and
590
595
  it installs them by calling `gob extras install`, so the allowlist is one code path. An id
591
596
  that is not in the catalogue is refused; installs copy from the vendored payload in the
@@ -1,42 +1,42 @@
1
- id category kind name source_repo path_within_repo has_skill_md license stars last_push matches conflicts requires install_hint verdict reviewed_by reviewed_date
2
- taste-skill frontend skill taste-skill Leonxlnx/taste-skill . yes MIT 93730 2026-10-07 react nextjs vue nuxt frontend ui design - none copy-folder RECOMMEND harvey 2026-10-08
3
- vercel-agent-skills frontend skill vercel-labs agent skills (react pack) vercel-labs/agent-skills skills/ skill none (verify per-skill) 32078 2026-08-28 react nextjs frontend ui design - none copy-folder RECOMMEND harvey 2026-10-08
4
- anthropic-frontend-design frontend skill frontend-design (anthropics/skills) anthropics/skills frontend-design yes none (verify per-skill) 180150 2026-10-05 frontend ui react vue design - none copy-folder RECOMMEND harvey 2026-10-08
5
- vuejs-skills frontend skill vuejs-ai skills (vue 3 pack) vuejs-ai/skills skills/ skill MIT 2889 2026-05-30 vue nuxt frontend - none copy-folder RECOMMEND harvey 2026-10-08
6
- ux-ui-agent-skills frontend skill ux-ui agent skills (design tokens, WCAG) plugin87/ux-ui-agent-skills skills/ skill MIT 1551 2026-10-08 frontend ui design accessibility - none copy-folder RECOMMEND harvey 2026-10-08
7
- impeccable frontend skill impeccable (design language) pbakaus/impeccable .dotagent-dir/ skill Apache-2.0 78552 2026-10-07 frontend ui design - none copy-folder RECOMMEND harvey 2026-10-08
8
- playwright-mcp testing mcp Playwright MCP (Microsoft, official) microsoft/playwright-mcp - no Apache-2.0 37929 2026-10-08 playwright e2e testing browser automation - node >= 18 npx @playwright/mcp@latest RECOMMEND harvey 2026-10-08
9
- chrome-devtools-mcp testing mcp Chrome DevTools MCP (official) ChromeDevTools/chrome-devtools-mcp - no Apache-2.0 53117 2026-10-08 browser debugging cdp e2e performance - node >= 18 npx chrome-devtools-mcp@latest RECOMMEND harvey 2026-10-08
10
- playwright-skill testing skill playwright-skill (no MCP registration) lackeyjb/playwright-skill . yes MIT 3180 2026-10-01 playwright e2e testing - playwright installed copy-folder RECOMMEND harvey 2026-10-08
11
- webapp-testing testing skill webapp-testing (anthropics/skills) anthropics/skills webapp-testing yes none (verify per-skill) 180150 2026-10-05 e2e testing browser playwright - playwright installed copy-folder RECOMMEND harvey 2026-10-08
12
- godot-ai game mcp Godot AI (hi-godot) hi-godot/godot-ai - no MIT 2862 2026-10-08 godot game - see repo README see repo README RECOMMEND harvey 2026-10-08
13
- godot-mcp game mcp Godot MCP (community default) Coding-Solo/godot-mcp - no MIT 5976 2026-04-16 godot game godot-ai see repo README see repo README RECOMMEND harvey 2026-10-08
14
- godotprompter game skill GodotPrompter (66 godot skills) jame581/GodotPrompter skills/ skill MIT 798 2026-10-06 godot game - none copy-folder RECOMMEND harvey 2026-10-08
15
- unity-mcp game mcp Unity MCP (CoplayDev) CoplayDev/unity-mcp - no MIT 14767 2026-10-07 unity game - unity editor + see repo README see repo README RECOMMEND harvey 2026-10-08
16
- awesome-gamedev-skills game skill awesome gamedev agent skills (74 skills, harvest source) gamedev-skills/awesome-gamedev-agent-skills skills/ skill Apache-2.0 1365 2026-09-27 game godot unity unreal phaser threejs bevy pygame - none copy-folder RECOMMEND harvey 2026-10-08
17
- supabase-agent-skills node skill Supabase agent skills (official) supabase/agent-skills skills/ skill MIT 2708 2026-10-02 node backend supabase database auth - none copy-folder RECOMMEND harvey 2026-10-08
18
- pg-aiguide node mcp pg-aiguide (Timescale, postgres) timescale/pg-aiguide - no Apache-2.0 1860 2026-10-07 node postgres database backend - see repo README see repo README RECOMMEND harvey 2026-10-08
19
- hono-skills node skill Hono agent skills (official) honojs/skills skills/ skill MIT 13 2026-10-08 node hono backend api - none copy-folder RECOMMEND harvey 2026-10-08
20
- superdesign-skill frontend skill superdesign-skill (design iteration loop) superdesigndev/superdesign-skill . yes MIT 633 2026-08-21 frontend ui design taste-skill vercel-agent-skills none copy-folder MAYBE harvey 2026-10-08
21
- garden-skills frontend skill garden-skills (collection, harvest source) ConardLi/garden-skills skills/ skill MIT 12771 2026-07-12 frontend ui design - none copy-folder MAYBE harvey 2026-10-08
22
- dev-browser testing skill dev-browser (general web browser skill) SawyerHood/dev-browser . yes MIT 6656 2026-09-05 browser e2e testing playwright-mcp none copy-folder MAYBE harvey 2026-10-08
23
- currents-playwright-best-practices testing skill playwright best practices (Currents.dev) currents-dev/playwright-best-practices-skill . yes MIT 393 2026-07-21 playwright e2e testing testdino-playwright-skill none copy-folder MAYBE harvey 2026-10-08
24
- testdino-playwright-skill testing skill playwright best practices (TestDino) testdino-hq/playwright-skill . yes MIT 389 2026-09-06 playwright e2e testing currents-playwright-best-practices none copy-folder MAYBE harvey 2026-10-08
25
- unity-mcp-alt game mcp Unity-MCP (IvanMurzak, skills + CLI) IvanMurzak/Unity-MCP - no Apache-2.0 4400 2026-10-04 unity game unity-mcp unity editor + see repo README see repo README MAYBE harvey 2026-10-08
26
- cc-game-studios game workflow Game-Studios mega-pack (49 agents, 72 skills) Donchitos/Cc-S-B . skill MIT 25900 2026-10-08 game godot unity - none copy-folder MAYBE harvey 2026-10-08
27
- godot-ui-integration game skill godot-ui-integration (design to godot UI) zimo-xiao-zheng/godot-ui-integration . yes MIT 275 2026-08-23 godot game ui - none copy-folder MAYBE harvey 2026-10-08
28
- agent-nestjs-skills node skill NestJS agent skills Kadajett/agent-nestjs-skills skills/ skill none (verify) 289 2026-07-23 node nestjs backend api - none copy-folder MAYBE harvey 2026-10-08
29
- openapi-to-skills node skill openapi-to-skills (spec to skills generator) neutree-ai/openapi-to-skills . skill Apache-2.0 342 2026-06-23 node api openapi - none copy-folder MAYBE harvey 2026-10-08
30
- do-app-platform-skills node skill DigitalOcean App Platform skills digitalocean-labs/do-app-platform-skills skills/ skill MIT 37 2026-10-04 node deployment database - none copy-folder MAYBE harvey 2026-10-08
31
- agent-skills-standard node skill agent-skills-standard (per-framework best practice) HoangNguyen0403/agent-skills-standard skills/ skill MIT 572 2026-10-08 node backend typescript - none copy-folder MAYBE harvey 2026-10-08
32
- frontend-design-toolkit frontend workflow Frontend-Design-Toolkit (list, harvest source) wilwaldon/cc-frontend-design-toolkit . skill none 1176 2026-04-11 frontend ui design - none copy-folder SKIP harvey 2026-10-08
33
- nuxt-skills frontend skill nuxt-skills (vue/nuxt/nuxthub) onmax/nuxt-skills skills/ skill none 719 2026-10-06 vue nuxt frontend - none copy-folder SKIP harvey 2026-10-08
34
- design-audit frontend skill design-audit (UI/UX checklist) wonjyou/design-audit . yes none 8 2026-03-28 frontend ui design - none copy-folder SKIP harvey 2026-10-08
35
- vibe-coded-website-review frontend skill vibe-coded-website-review (YC design review) zuocharles/vibe-coded-website-review . yes none 0 2026-03-29 frontend ui design - none copy-folder SKIP harvey 2026-10-08
36
- qa-skills testing workflow qa-skills (e2e generation pipeline) neonwatty/qa-skills . skill MIT 33 2026-05-03 e2e testing - none copy-folder SKIP harvey 2026-10-08
37
- agentmantis-test-skills testing skill test-skills (playwright e2e pack) agentmantis/test-skills skills/ skill MIT 12 2026-04-08 playwright e2e testing - none copy-folder SKIP harvey 2026-10-08
38
- invisible-playwright-mcp testing mcp invisible_playwright_mcp (anti-detect) feder-cr/invisible_playwright_mcp - no none 2660 2026-10-08 browser e2e playwright - see repo README see repo README SKIP harvey 2026-10-08
39
- mcp-unity game mcp mcp-unity (CoderGamester, superseded) CoderGamester/mcp-unity - no MIT 1922 2026-09-03 unity game unity-mcp unity editor + see repo README see repo README SKIP harvey 2026-10-08
40
- godot-mcp-native game mcp Godot-MCP-Native (duplicate function) yurineko73/Godot-MCP-Native - no MIT 836 2026-08-03 godot game godot-mcp see repo README see repo README SKIP harvey 2026-10-08
41
- fastify-skills node skill fastify-skills (undocumented) TheCodePace/fastify-skills skills/ skill none 12 2026-10-08 node fastify backend - none copy-folder SKIP harvey 2026-10-08
42
- drizzle-orm-skill node skill drizzle-orm-skill (no credible alternative exists) oldirty/drizzle-orm-skill . yes none 0 2026-02-24 node drizzle orm database - none copy-folder SKIP harvey 2026-10-08
1
+ id category kind name source_repo path_within_repo has_skill_md license stars last_push matches conflicts requires install_hint verdict reviewed_by reviewed_date license_status license_check_date
2
+ taste-skill frontend skill taste-skill Leonxlnx/taste-skill . yes MIT 93730 2026-10-07 react nextjs vue nuxt frontend ui design - none copy-folder RECOMMEND harvey 2026-10-08 verified 2026-10-09
3
+ vercel-agent-skills frontend skill vercel-labs agent skills (react pack) vercel-labs/agent-skills skills/ skill none (verify per-skill) 32078 2026-08-28 react nextjs frontend ui design - none copy-folder LICENSE-PENDING harvey 2026-10-08 pending 2026-10-09
4
+ anthropic-frontend-design frontend skill frontend-design (anthropics/skills) anthropics/skills frontend-design yes none (verify per-skill) 180150 2026-10-05 frontend ui react vue design - none copy-folder LICENSE-PENDING harvey 2026-10-08 pending 2026-10-09
5
+ vuejs-skills frontend skill vuejs-ai skills (vue 3 pack) vuejs-ai/skills skills/ skill MIT 2889 2026-05-30 vue nuxt frontend - none copy-folder RECOMMEND harvey 2026-10-08 verified 2026-10-09
6
+ ux-ui-agent-skills frontend skill ux-ui agent skills (design tokens, WCAG) plugin87/ux-ui-agent-skills skills/ skill MIT 1551 2026-10-08 frontend ui design accessibility - none copy-folder RECOMMEND harvey 2026-10-08 verified 2026-10-09
7
+ impeccable frontend skill impeccable (design language) pbakaus/impeccable .dotagent-dir/ skill Apache-2.0 78552 2026-10-07 frontend ui design - none copy-folder RECOMMEND harvey 2026-10-08 verified 2026-10-09
8
+ playwright-mcp testing mcp Playwright MCP (Microsoft, official) microsoft/playwright-mcp - no Apache-2.0 37929 2026-10-08 playwright e2e testing browser automation - node >= 18 npx @playwright/mcp@latest RECOMMEND harvey 2026-10-08 verified 2026-10-09
9
+ chrome-devtools-mcp testing mcp Chrome DevTools MCP (official) ChromeDevTools/chrome-devtools-mcp - no Apache-2.0 53117 2026-10-08 browser debugging cdp e2e performance - node >= 18 npx chrome-devtools-mcp@latest RECOMMEND harvey 2026-10-08 verified 2026-10-09
10
+ playwright-skill testing skill playwright-skill (no MCP registration) lackeyjb/playwright-skill . yes MIT 3180 2026-10-01 playwright e2e testing - playwright installed copy-folder RECOMMEND harvey 2026-10-08 verified 2026-10-09
11
+ webapp-testing testing skill webapp-testing (anthropics/skills) anthropics/skills webapp-testing yes none (verify per-skill) 180150 2026-10-05 e2e testing browser playwright - playwright installed copy-folder LICENSE-PENDING harvey 2026-10-08 pending 2026-10-09
12
+ godot-ai game mcp Godot AI (hi-godot) hi-godot/godot-ai - no MIT 2862 2026-10-08 godot game - see repo README see repo README RECOMMEND harvey 2026-10-08 verified 2026-10-09
13
+ godot-mcp game mcp Godot MCP (community default) Coding-Solo/godot-mcp - no MIT 5976 2026-04-16 godot game godot-ai see repo README see repo README RECOMMEND harvey 2026-10-08 verified 2026-10-09
14
+ godotprompter game skill GodotPrompter (66 godot skills) jame581/GodotPrompter skills/ skill MIT 798 2026-10-06 godot game - none copy-folder RECOMMEND harvey 2026-10-08 verified 2026-10-09
15
+ unity-mcp game mcp Unity MCP (CoplayDev) CoplayDev/unity-mcp - no MIT 14767 2026-10-07 unity game - unity editor + see repo README see repo README RECOMMEND harvey 2026-10-08 verified 2026-10-09
16
+ awesome-gamedev-skills game skill awesome gamedev agent skills (74 skills, harvest source) gamedev-skills/awesome-gamedev-agent-skills skills/ skill Apache-2.0 1365 2026-09-27 game godot unity unreal phaser threejs bevy pygame - none copy-folder RECOMMEND harvey 2026-10-08 verified 2026-10-09
17
+ supabase-agent-skills node skill Supabase agent skills (official) supabase/agent-skills skills/ skill MIT 2708 2026-10-02 node backend supabase database auth - none copy-folder RECOMMEND harvey 2026-10-08 verified 2026-10-09
18
+ pg-aiguide node mcp pg-aiguide (Timescale, postgres) timescale/pg-aiguide - no Apache-2.0 1860 2026-10-07 node postgres database backend - see repo README see repo README RECOMMEND harvey 2026-10-08 verified 2026-10-09
19
+ hono-skills node skill Hono agent skills (official) honojs/skills skills/ skill MIT 13 2026-10-08 node hono backend api - none copy-folder RECOMMEND harvey 2026-10-08 verified 2026-10-09
20
+ superdesign-skill frontend skill superdesign-skill (design iteration loop) superdesigndev/superdesign-skill . yes MIT 633 2026-08-21 frontend ui design taste-skill vercel-agent-skills none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
21
+ garden-skills frontend skill garden-skills (collection, harvest source) ConardLi/garden-skills skills/ skill MIT 12771 2026-07-12 frontend ui design - none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
22
+ dev-browser testing skill dev-browser (general web browser skill) SawyerHood/dev-browser . yes MIT 6656 2026-09-05 browser e2e testing playwright-mcp none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
23
+ currents-playwright-best-practices testing skill playwright best practices (Currents.dev) currents-dev/playwright-best-practices-skill . yes MIT 393 2026-07-21 playwright e2e testing testdino-playwright-skill none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
24
+ testdino-playwright-skill testing skill playwright best practices (TestDino) testdino-hq/playwright-skill . yes MIT 389 2026-09-06 playwright e2e testing currents-playwright-best-practices none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
25
+ unity-mcp-alt game mcp Unity-MCP (IvanMurzak, skills + CLI) IvanMurzak/Unity-MCP - no Apache-2.0 4400 2026-10-04 unity game unity-mcp unity editor + see repo README see repo README MAYBE harvey 2026-10-08 verified 2026-10-09
26
+ cc-game-studios game workflow Game-Studios mega-pack (49 agents, 72 skills) Donchitos/Cc-S-B . skill MIT 25900 2026-10-08 game godot unity - none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
27
+ godot-ui-integration game skill godot-ui-integration (design to godot UI) zimo-xiao-zheng/godot-ui-integration . yes MIT 275 2026-08-23 godot game ui - none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
28
+ agent-nestjs-skills node skill NestJS agent skills Kadajett/agent-nestjs-skills skills/ skill none (verify) 289 2026-07-23 node nestjs backend api - none copy-folder LICENSE-PENDING harvey 2026-10-08 pending 2026-10-09
29
+ openapi-to-skills node skill openapi-to-skills (spec to skills generator) neutree-ai/openapi-to-skills . skill Apache-2.0 342 2026-06-23 node api openapi - none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
30
+ do-app-platform-skills node skill DigitalOcean App Platform skills digitalocean-labs/do-app-platform-skills skills/ skill MIT 37 2026-10-04 node deployment database - none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
31
+ agent-skills-standard node skill agent-skills-standard (per-framework best practice) HoangNguyen0403/agent-skills-standard skills/ skill MIT 572 2026-10-08 node backend typescript - none copy-folder MAYBE harvey 2026-10-08 verified 2026-10-09
32
+ frontend-design-toolkit frontend workflow Frontend-Design-Toolkit (list, harvest source) wilwaldon/cc-frontend-design-toolkit . skill none 1176 2026-04-11 frontend ui design - none copy-folder SKIP harvey 2026-10-08 pending 2026-10-09
33
+ nuxt-skills frontend skill nuxt-skills (vue/nuxt/nuxthub) onmax/nuxt-skills skills/ skill none 719 2026-10-06 vue nuxt frontend - none copy-folder SKIP harvey 2026-10-08 pending 2026-10-09
34
+ design-audit frontend skill design-audit (UI/UX checklist) wonjyou/design-audit . yes none 8 2026-03-28 frontend ui design - none copy-folder SKIP harvey 2026-10-08 pending 2026-10-09
35
+ vibe-coded-website-review frontend skill vibe-coded-website-review (YC design review) zuocharles/vibe-coded-website-review . yes none 0 2026-03-29 frontend ui design - none copy-folder SKIP harvey 2026-10-08 pending 2026-10-09
36
+ qa-skills testing workflow qa-skills (e2e generation pipeline) neonwatty/qa-skills . skill MIT 33 2026-05-03 e2e testing - none copy-folder SKIP harvey 2026-10-08 verified 2026-10-09
37
+ agentmantis-test-skills testing skill test-skills (playwright e2e pack) agentmantis/test-skills skills/ skill MIT 12 2026-04-08 playwright e2e testing - none copy-folder SKIP harvey 2026-10-08 verified 2026-10-09
38
+ invisible-playwright-mcp testing mcp invisible_playwright_mcp (anti-detect) feder-cr/invisible_playwright_mcp - no none 2660 2026-10-08 browser e2e playwright - see repo README see repo README SKIP harvey 2026-10-08 pending 2026-10-09
39
+ mcp-unity game mcp mcp-unity (CoderGamester, superseded) CoderGamester/mcp-unity - no MIT 1922 2026-09-03 unity game unity-mcp unity editor + see repo README see repo README SKIP harvey 2026-10-08 verified 2026-10-09
40
+ godot-mcp-native game mcp Godot-MCP-Native (duplicate function) yurineko73/Godot-MCP-Native - no MIT 836 2026-08-03 godot game godot-mcp see repo README see repo README SKIP harvey 2026-10-08 verified 2026-10-09
41
+ fastify-skills node skill fastify-skills (undocumented) TheCodePace/fastify-skills skills/ skill none 12 2026-10-08 node fastify backend - none copy-folder SKIP harvey 2026-10-08 pending 2026-10-09
42
+ drizzle-orm-skill node skill drizzle-orm-skill (no credible alternative exists) oldirty/drizzle-orm-skill . yes none 0 2026-02-24 node drizzle orm database - none copy-folder SKIP harvey 2026-10-08 pending 2026-10-09
@@ -1,6 +1,6 @@
1
1
  id scope rule enforced_by artifact check if_not_why
2
2
  IN-01 target The install exists and records its version + every file's hash. script .gob/installed.json goblin-verify --only IN-01 — (W1: the check is a builtin so the engine.mode=global clause can run — a global, declaration-only repo has no install record and SKIPs with `global engine mode — no per-repo install record`; the vendored clauses are the old one-liner: the record exists and names its version)
3
- IN-02 target Every installed file still matches its recorded hash. script .gob/installed.json goblin-verify --only IN-02 recover: gob install --upgrade, or git checkout -- .gob/installed.json; for a file it names drifted: git checkout -- <path> (if the edit is yours and intended, re-pin it: gob install --target <dir> --re-pin)
3
+ IN-02 target Every installed file still matches its recorded hash. script .gob/installed.json goblin-verify --only IN-02 recover: git checkout -- .gob/installed.json (or re-run npx @techgoblin/gobstack init --write to re-install); for a file it names drifted: git checkout -- <path> (if the edit is yours and intended, re-pin it: goblin-install --target <dir> --re-pin from the checkout/install tree)
4
4
  IN-03 target The verifier's own manifest is complete: every rule has a check or is advisory. script manifest/enforcement.tsv goblin-verify --only IN-03 — (this row is the reason the matrix cannot rot; the second clause is D6's shape in general: a row that carries no check must be labelled advisory, or it claims verification it does not perform. The third clause is Z1-5: `enforced_by` is documented as a closed enum in docs/ENFORCEMENT.md and was read by NOTHING, so a typo in that cell changed nothing - `script|lint|gate|advisory` plus `test`, the source-scope value whose check is tests/run-tests.sh. W1: the check runs against whichever manifest the engine actually resolved (the chain in bin/goblin-verify), no longer the hardcoded per-repo path — the rule's meaning is untouched, only the path input follows the engine)
5
5
  IN-04 target No file goblin-stack did not create has been overwritten. script .gob/installed.json goblin-verify --only IN-04 Detects a file the installer recorded as pre-existing (a `refused` entry) that has since vanished, or that is listed as installed anyway. The second clause is an internal-consistency guard: with correct code a refused path is never written, so it fires only if the installer regresses. The negative control exercises the vanished branch.
6
6
  HP-01 target HANDOFF.md exists at the root. gate HANDOFF.md test -f HANDOFF.md —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techgoblin/gobstack",
3
- "version": "0.6.0-alpha.2",
3
+ "version": "0.6.0-alpha.4",
4
4
  "description": "Agent-discipline toolkit: one verify command, an enforcement matrix, and LIMITS. bash engine, npm shim.",
5
5
  "bin": {
6
6
  "goblin": "bin/goblin.js",
@@ -13,7 +13,7 @@ Use when adopting goblin-stack in a repo, or starting one.
13
13
  with the electron bans and a host gate, not a sixth class. The letters `A`-`E` and the older
14
14
  names are read-time aliases.
15
15
  2. **`goblin-install --target <dir> --class <x>`** — the default install is a NEUTRAL harness:
16
- no agent skills. Opt in per platform afterwards with `gob emit --platform <p>` (or vendor the
16
+ no agent skills. Opt in per catalogue row afterwards with `gob extras install <id>` (or vendor the
17
17
  Hermes project tier with `--skills yes`).
18
18
  3. **`goblin-verify`** — a default software-class install (no agent skills) verifies green:
19
19
  `37 passed, 0 failed, 11 advisory, 34 skipped`, exit 0, once `HANDOFF.md` names a commit that