@techgoblin/gobstack 0.5.0-beta.8 → 0.6.0-alpha.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +161 -124
  3. package/VERSION +1 -1
  4. package/automations/drift-audit.sh +4 -4
  5. package/bans/layer-check.sh +10 -8
  6. package/bin/goblin +69 -57
  7. package/bin/goblin-audit +11 -13
  8. package/bin/goblin-bans +11 -11
  9. package/bin/goblin-extras +342 -0
  10. package/bin/goblin-init +382 -711
  11. package/bin/goblin-install +160 -114
  12. package/bin/goblin-lib.sh +234 -1
  13. package/bin/goblin-map +226 -21
  14. package/bin/goblin-mcp.js +492 -0
  15. package/bin/goblin-model +4 -4
  16. package/bin/goblin-upgrade +1 -1
  17. package/bin/goblin-verify +159 -145
  18. package/bin/goblin.js +35 -51
  19. package/docs/ADOPTION.md +15 -15
  20. package/docs/CONTRACTS.md +16 -15
  21. package/docs/DESIGN.md +1 -1
  22. package/docs/ENFORCEMENT.md +89 -90
  23. package/docs/FLOWS.md +1 -1
  24. package/docs/GLOSSARY.md +3 -3
  25. package/docs/GUARDRAILS.md +5 -5
  26. package/docs/GUIDE.md +194 -177
  27. package/docs/INTEGRATION.md +1 -1
  28. package/docs/LIMITS.md +25 -0
  29. package/docs/LOOP.md +12 -12
  30. package/docs/RE-PLAYBOOK.md +3 -3
  31. package/docs/ROLES.md +5 -5
  32. package/extras-catalogue/catalogue.tsv +42 -0
  33. package/extras-catalogue/payload/README.md +14 -0
  34. package/extras-catalogue/payload/taste-skill/taste/REFERENCE.md +3 -0
  35. package/extras-catalogue/payload/taste-skill/taste/SKILL.md +9 -0
  36. package/manifest/bans.tsv +8 -8
  37. package/manifest/classes.tsv +3 -3
  38. package/manifest/enforcement.tsv +40 -40
  39. package/manifest/glossary.tsv +3 -3
  40. package/manifest/playbooks.tsv +1 -1
  41. package/package.json +3 -1
  42. package/presets/electron-overlay.yaml +2 -2
  43. package/presets/fleet.yaml +8 -7
  44. package/presets/game.yaml +1 -1
  45. package/presets/research.yaml +1 -1
  46. package/presets/service.yaml +1 -1
  47. package/presets/software.yaml +1 -1
  48. package/skills/goblin-bootstrap/SKILL.md +2 -2
  49. package/templates/AGENTS.md.tmpl +8 -18
  50. package/templates/HANDOFF.md.tmpl +5 -5
  51. package/templates/agents-block.tmpl +45 -0
  52. package/templates/audit-waiver.tsv.tmpl +2 -2
  53. package/templates/boundary-waivers.tmpl +1 -1
  54. package/templates/checks/gate.sh.tmpl +6 -6
  55. package/templates/install-hooks.allowlist.tmpl +1 -1
  56. package/templates/ci/goblin-gate.yml.tmpl +0 -46
  57. package/templates/goblin.yaml.tmpl +0 -146
  58. package/templates/loop/decisions.tsv.tmpl +0 -1
  59. package/templates/loop/predicate.tmpl +0 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techgoblin/gobstack",
3
- "version": "0.5.0-beta.8",
3
+ "version": "0.6.0-alpha.2",
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",
@@ -23,6 +23,8 @@
23
23
  "automations/",
24
24
  "bans/",
25
25
  "docs/",
26
+ "extras-catalogue/catalogue.tsv",
27
+ "extras-catalogue/payload/",
26
28
  "roles.yaml",
27
29
  "VERSION",
28
30
  "CHANGELOG.md"
@@ -2,13 +2,13 @@
2
2
  #
3
3
  # The `desktop` class is gone; F was merged into software because their classes.tsv need
4
4
  # columns are IDENTICAL on all 10 parts (measured). Everything F added beyond software lives in
5
- # plain goblin.yaml config keys, so it is an OVERLAY, not a class: `gob install --class software
5
+ # plain frontmatter config keys, so it is an OVERLAY, not a class: `gob install --class software
6
6
  # --electron` (or the `--class desktop` / `F` alias, which sets --electron) renders the keys
7
7
  # below OVER the software preset. An absent key falls through to presets/software.yaml; a key
8
8
  # present here — including an empty one like sec_write_routes: "" — wins.
9
9
  #
10
10
  # The prose F carried (label / done_means / notes) is preserved here for the record; it is not a
11
- # rendered template key, so it never reaches a target's goblin.yaml.
11
+ # rendered template key, so it never reaches a target's gob block.
12
12
  label: Desktop shell
13
13
  done_means: the renderer is isolated from Node, the main process is not busy, and the packaged bundle ships no dev dependency
14
14
  # software's A-only second gate (the TODO ceiling) is NOT applied: F never had it.
@@ -9,16 +9,17 @@ scaffold_checks: no
9
9
  gate_name: commit
10
10
  gate_cmd: git rev-parse --verify --quiet HEAD
11
11
  ratchet_name: todo_markers
12
- # The harness's own vendored directories are excluded: without it, a fresh class-E install
13
- # counts the ratchet command line itself (`.goblin/goblin.yaml` holds the literal TODO|FIXME)
14
- # and goblin-stack's own skill prose (`.hermes/skills/*/SKILL.md`), so its gate was born RED
15
- # against a ceiling measured before those files were written (D8). The fleet's real config —
16
- # `*.yaml`/`*.yml`/`*.sh` at the root and under `profiles/` — is still counted.
17
- ratchet_cmd: grep -rniE '\b(TODO|FIXME)\b' --include='*.sh' --include='*.yaml' --include='*.yml' --include='*.md' --exclude-dir=.goblin --exclude-dir=.hermes . 2>/dev/null | wc -l
12
+ # The harness's own vendored directories are excluded, and so is root AGENTS.md: in v2 the
13
+ # config IS the AGENTS.md gob block, so the ratchet command line itself (the literal
14
+ # TODO|FIXME inside `ratchet_cmd:`) lives in a *.md file at the root — without the exclude a
15
+ # fresh install counts its own gate and is born RED against a ceiling measured before the
16
+ # file was written (D8). The fleet's real config — `*.yaml`/`*.yml`/`*.sh` at the root and
17
+ # under `profiles/` — is still counted.
18
+ ratchet_cmd: grep -rniE '\b(TODO|FIXME)\b' --include='*.sh' --include='*.yaml' --include='*.yml' --include='*.md' --exclude-dir=.gob --exclude-dir=.hermes --exclude=AGENTS.md . 2>/dev/null | wc -l
18
19
  ratchet_ceiling: measure
19
20
  replay_env: GOBLIN_PRE_COMMIT
20
21
  replay_cmd: node checks/{name}.mjs
21
- runtime_data: .goblin/state.json
22
+ runtime_data: .gob/state.json
22
23
  # A fleet config has no client surface; the secret family still matters (a profile file is one
23
24
  # `git add` away from a live token), so SC-01/SC-02 are the rows that bite here.
24
25
  sec_gitignore_family: yes
package/presets/game.yaml CHANGED
@@ -14,7 +14,7 @@ ratchet_cmd: grep -rniE '\b(TODO|FIXME)\b' --include='*.cs' --include='*.ts' --i
14
14
  ratchet_ceiling: measure
15
15
  replay_env: GOBLIN_PRE_COMMIT
16
16
  replay_cmd: node checks/{name}.mjs
17
- runtime_data: .goblin/state.json
17
+ runtime_data: .gob/state.json
18
18
  sec_gitignore_family: yes
19
19
  sec_build_output: Builds Library
20
20
  sec_audit_cmd: ""
@@ -15,7 +15,7 @@ ratchet_cmd: ""
15
15
  ratchet_ceiling: 0
16
16
  replay_env: GOBLIN_PRE_COMMIT
17
17
  replay_cmd: node checks/{name}.mjs
18
- runtime_data: .goblin/state.json
18
+ runtime_data: .gob/state.json
19
19
  # A knowledge repo has no client surface and no dependency manifest, so SC-03's build-output
20
20
  # clause, SC-05..SC-08 skip with a reason. The SECRET FAMILY is not one of those: a note file is
21
21
  # one `git add` away from a pasted token, so SC-02 is required here too and the installer writes
@@ -14,7 +14,7 @@ ratchet_cmd: grep -rniE '\b(TODO|FIXME)\b' --include='*.ts' --include='*.tsx' --
14
14
  ratchet_ceiling: measure
15
15
  replay_env: GOBLIN_PRE_COMMIT
16
16
  replay_cmd: node checks/{name}.mjs
17
- runtime_data: .goblin/state.json
17
+ runtime_data: .gob/state.json
18
18
  # A service has real inputs and real dependencies, so the security rows bite here.
19
19
  sec_gitignore_family: yes
20
20
  sec_build_output: dist
@@ -24,7 +24,7 @@ ratchet_cmd: find .next/static dist/assets dist -type f -name '*.js' -exec cat {
24
24
  ratchet_ceiling: measure
25
25
  replay_env: GOBLIN_PRE_COMMIT
26
26
  replay_cmd: node checks/{name}.mjs
27
- runtime_data: .goblin/state.json
27
+ runtime_data: .gob/state.json
28
28
  # SC-02 requires the whole secret family to be ignored; SC-03 clause 2 scans `sec_build_output`
29
29
  # for secret-shaped literals; SC-07 runs `sec_audit_cmd` once, deliberately, via goblin-audit.
30
30
  sec_gitignore_family: yes
@@ -16,10 +16,10 @@ Use when adopting goblin-stack in a repo, or starting one.
16
16
  no agent skills. Opt in per platform afterwards with `gob emit --platform <p>` (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
- `38 passed, 0 failed, 11 advisory, 33 skipped`, exit 0, once `HANDOFF.md` names a commit that
19
+ `37 passed, 0 failed, 11 advisory, 34 skipped`, exit 0, once `HANDOFF.md` names a commit that
20
20
  exists; before that edit the
21
21
  scaffold's `0000000` placeholder is `HP-05`'s one expected day-one red (`37 passed, 1 failed`).
22
- Thirty-three rows skip with a reason, and the reason matters: the five skill rows
22
+ Thirty-four rows skip with a reason, and the reason matters: the five skill rows
23
23
  (`SK-01`..`SK-04`, `AU-04`) skip on the `playbooks` opt-out a skills-free install records,
24
24
  then `HS-02`
25
25
  (no pinned pre-change commit yet, so the REPLAY is not provable), `AU-02`/`AU-03` (no report
@@ -3,31 +3,21 @@
3
3
  This repository uses **gobstack** (class `{{CLASS}}`, installed {{DATE}}). It is a pointer,
4
4
  not a rule dump — the rules live in one executable place, and facts beat requirements.
5
5
 
6
- - **Harness entry point:** `.goblin/bin/goblin-verify` — exit 0 pass, 1 a check failed,
6
+ - **Harness entry point:** `.gob/bin/goblin-verify` — exit 0 pass, 1 a check failed,
7
7
  2 could not run, 3 the manifest is broken. Run it before you commit; the gate is the
8
8
  same run.
9
- - **Rules and their checks:** `.goblin/manifest/enforcement.tsv` (one row per rule; every row
9
+ - **Rules and their checks:** `.gob/manifest/enforcement.tsv` (one row per rule; every row
10
10
  carries a runnable check or the literal `advisory`).
11
- - **Forbidden code (the ban list):** `.goblin/bin/goblin-bans` runs the bans named by `bans:` in
12
- `.goblin/goblin.yaml`; each ban's mechanism lives in `.goblin/manifest/bans.tsv`. Run it before
11
+ - **Forbidden code (the ban list):** `.gob/bin/goblin-bans` runs the bans named by `bans:` in
12
+ this file's gob block; each ban's mechanism lives in `.gob/manifest/bans.tsv`. Run it before
13
13
  you write the line, not after — a ban is a gate, and `goblin-verify` only reports it once the
14
14
  code exists.
15
15
  - **Session state:** `HANDOFF.md` at the repo root. Read it before touching anything.
16
- - **Project config:** `.goblin/goblin.yaml` (class, branch, gates, ratchet, runtime data,
17
- replay, opt-outs). Edit it in place; the installer never overwrites it.
18
- - **The referenced standard**, if configured, is named by `practice:` in `.goblin/goblin.yaml`.
16
+ - **Project config:** the `<!-- gob:begin --> … <!-- gob:end -->` block in this file
17
+ (class, branch, gates, ratchet, runtime data, replay, opt-outs). Edit it in place; the
18
+ installer never rewrites the block after the first install and never touches the prose.
19
+ - **The referenced standard**, if configured, is named by `practice:` in the gob block.
19
20
  Read it before starting work; this repo carries no copy of it.
20
21
 
21
- **Agent skills are opt-in, per platform.** A default install ships none — this is a neutral
22
- harness on purpose, so nothing here assumes which coding agent you use. To install the
23
- procedure skills for your tool:
24
-
25
- gob sync --platform <p>
26
-
27
- (`--scope project` writes them inside this repo; `--scope global` writes them for your user.)
28
- Run `gob sync` with no platform to see the list (`gob emit` is the same command under its
29
- original name). If skills were installed here, they live
30
- under the platform's own directory, and `gob verify` hashes them.
31
-
32
22
  Two things this repo does not do: it does not choose models (a role resolves through the
33
23
  mapping file named by `models_file:`), and it does not write outside its own tree.
@@ -7,10 +7,10 @@
7
7
  ## ▶ START HERE (new session)
8
8
 
9
9
  - Working dir: the repo root.
10
- - Gate set: `{{GATE_NAME}}` — `{{GATE_CMD}}`, plus whatever you add in `.goblin/goblin.yaml`.
11
- - Run the gates and the manifest checks: `.goblin/bin/goblin-verify`
12
- - One line of measured numbers for the round: `.goblin/bin/goblin-verify --only GT-02` writes `.goblin/last-gate-line`.
13
- - Read before working: the referenced standard, if `.goblin/goblin.yaml` declares `practice:`.
10
+ - Gate set: `{{GATE_NAME}}` — `{{GATE_CMD}}`, plus whatever you add in `AGENTS.md`.
11
+ - Run the gates and the manifest checks: `.gob/bin/goblin-verify`
12
+ - One line of measured numbers for the round: `.gob/bin/goblin-verify --only GT-02` writes `.gob/last-gate-line`.
13
+ - Read before working: the referenced standard, if `AGENTS.md` declares `practice:`.
14
14
 
15
15
  ## State
16
16
 
@@ -25,7 +25,7 @@
25
25
  Every number here is a measurement with a date, never a copy from a previous round.
26
26
 
27
27
  - `{{GATE_NAME}}` = 0 · measured {{DATE}}
28
- - ratchet — declared in `.goblin/goblin.yaml`; re-measure it, do not copy it.
28
+ {{GATE2_LINE}}
29
29
  - Example of the required form: `typecheck=0 · build=0 · ratchet <n> (ceiling <c>) · <n>/<n> harnesses green · measured {{DATE}}`
30
30
 
31
31
  ## Next steps
@@ -0,0 +1,45 @@
1
+ <!-- gob:begin (gobstack config — edit in place; the parser reads only this block) -->
2
+ class: {{CLASS}}
3
+ electron: {{ELECTRON}}
4
+ branch: {{BRANCH}}
5
+ models_file: {{MODELS_FILE}}
6
+ practice: {{PRACTICE}}
7
+ practice_sha256: {{PRACTICE_SHA}}
8
+ owner_email: {{OWNER_EMAIL}}
9
+ archive: {{ARCHIVE}}
10
+ max_dirty: {{MAX_DIRTY}}
11
+ advisory_ceiling: {{ADVISORY_CEILING}}
12
+ security.gitignore_family: {{SEC_GITIGNORE_FAMILY}}
13
+ security.build_output: {{SEC_BUILD_OUTPUT}}
14
+ security.audit_cmd: {{SEC_AUDIT_CMD}}
15
+ security.audit_max_age_days: {{SEC_AUDIT_MAX_AGE}}
16
+ security.waiver_max_age_days: {{SEC_WAIVER_MAX_AGE}}
17
+ security.write_routes: {{SEC_WRITE_ROUTES}}
18
+ perf.metric: {{PERF_METRIC}}
19
+ perf.cmd: {{PERF_CMD}}
20
+ perf.baseline_commit: {{PERF_BASELINE_COMMIT}}
21
+ perf.baseline_value: {{PERF_BASELINE_VALUE}}
22
+ perf.measured: {{PERF_MEASURED}}
23
+ perf.host_gate: {{PERF_HOST_GATE}}
24
+ harness_dir: {{HARNESS_DIR}}
25
+ scaffold_checks: {{SCAFFOLD_CHECKS}}
26
+ feature_map: {{FEATURE_MAP}}
27
+ source_root: {{SOURCE_ROOT}}
28
+ verify_doctor: {{VERIFY_DOCTOR}}
29
+ reference_manifest: {{REFERENCE_MANIFEST}}
30
+ quarantine_root: {{QUARANTINE_ROOT}}
31
+ loop_max_turns_ceiling: {{LOOP_MAX_TURNS}}
32
+ gate_{{GATE1_NAME}}_cmd: {{GATE1_CMD}}
33
+ gate_{{GATE2_NAME}}_cmd: {{GATE2_CMD}}
34
+ ratchet.name: {{RATCHET_NAME}}
35
+ ratchet.cmd: {{RATCHET_CMD}}
36
+ ratchet.ceiling: {{RATCHET_CEILING}}
37
+ runtime_data: [{{RUNTIME_DATA}}]
38
+ bans: [{{BANS}}]
39
+ bans_exempt:
40
+ layers:
41
+ replay.env: {{REPLAY_ENV}}
42
+ replay.cmd: {{REPLAY_CMD}}
43
+ replay.commit: ""
44
+ disabled: [{{DISABLED}}]
45
+ <!-- gob:end -->
@@ -1,10 +1,10 @@
1
- # .goblin/audit-waiver.tsv — one line per accepted dependency advisory (SC-07).
1
+ # .gob/audit-waiver.tsv — one line per accepted dependency advisory (SC-07).
2
2
  #
3
3
  # package severity id date reason
4
4
  #
5
5
  # The date is the day the decision was taken, and SC-07 refuses a waiver older than
6
6
  # security.waiver_max_age_days: a waiver with no expiry is a permanent blind spot. A
7
- # high|critical line in .goblin/audit.tsv with no matching row here is a RED.
7
+ # high|critical line in .gob/audit.tsv with no matching row here is a RED.
8
8
  #
9
9
  # example:
10
10
  # next high GHSA-xxxx-yyyy-zzzz 2026-09-24 no fixed release yet; the vulnerable path is the dev server only
@@ -1,4 +1,4 @@
1
- # .goblin/boundary-waivers — write routes that deliberately do NOT validate input (SC-05).
1
+ # .gob/boundary-waivers — write routes that deliberately do NOT validate input (SC-05).
2
2
  #
3
3
  # One repo-relative path per line, with the reason after a '#'. A waiver is a DECISION recorded
4
4
  # where the row can read it; it is not a silence. SC-05 prints the waiver count on its gate line
@@ -5,8 +5,8 @@
5
5
  set -uo pipefail
6
6
  ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
7
7
  # shellcheck source=/dev/null
8
- . "$ROOT/.goblin/bin/goblin-lib.sh"
9
- CONFIG="$ROOT/.goblin/goblin.yaml"
8
+ . "$ROOT/.gob/bin/goblin-lib.sh"
9
+ CONFIG="$ROOT/AGENTS.md"
10
10
 
11
11
  line=""
12
12
  bad=0
@@ -16,13 +16,13 @@ while IFS=$'\t' read -r name cmd; do
16
16
  rc=$?
17
17
  line="$line $name=$rc"
18
18
  [ "$rc" -eq 0 ] || bad=1
19
- done < <(g_yaml_gates "$CONFIG")
19
+ done < <(g_agents_gates "$CONFIG")
20
20
 
21
- rname=$(g_yaml_block_scalar "$CONFIG" ratchet name)
22
- rcmd=$(g_yaml_block_scalar "$CONFIG" ratchet cmd)
21
+ rname=$(g_agents_read "$CONFIG" ratchet.name)
22
+ rcmd=$(g_agents_read "$CONFIG" ratchet.cmd)
23
23
  if [ -n "$rname" ] && [ -n "$rcmd" ]; then
24
24
  rval=$( cd "$ROOT" && bash -c "$rcmd" 2>/dev/null | tr -d '[:space:]' )
25
- line="$line · $rname $rval (ceiling $(g_yaml_block_scalar "$CONFIG" ratchet ceiling))"
25
+ line="$line · $rname $rval (ceiling $(g_agents_read "$CONFIG" ratchet.ceiling))"
26
26
  fi
27
27
 
28
28
  printf '%s · measured %s\n' "${line# }" "$(date +%F)"
@@ -1,4 +1,4 @@
1
- # .goblin/install-hooks.allowlist — dependencies whose install-time script is accepted (SC-08).
1
+ # .gob/install-hooks.allowlist — dependencies whose install-time script is accepted (SC-08).
2
2
  #
3
3
  # One package name per line. SC-08 enumerates package-lock.json for "hasInstallScript": true and
4
4
  # requires every one of them to appear here. An install hook is arbitrary code that runs on every
@@ -1,46 +0,0 @@
1
- # .github/workflows/goblin-gate.yml — written once by goblin-stack for class {{CLASS}}.
2
- #
3
- # WHAT THIS IS. One job that runs the gate set this project DECLARES in `.goblin/goblin.yaml`.
4
- # `.goblin/bin/goblin-verify` executes every declared gate (GT-02) and every rule that carries a
5
- # command, so CI and a local verify cannot report two different truths about one SHA (PG-06).
6
- # The job carries NO `if:` at any level, on purpose: GitHub reports a SKIPPED job as Success even
7
- # when it is a required check, so a conditional here would be a green light with no bulb (PG-05).
8
- #
9
- # A WORKFLOW FILE IS NOT A GATE. Four things make it one, and all four are yours to do:
10
- # 1. REQUIRED CHECK — mark the `gate` job required for this branch (Settings -> Branches, or a
11
- # ruleset). Until then the job runs and nothing waits for it.
12
- # 2. NO BYPASS — tick "Do not allow bypassing the above settings". Without it the restriction
13
- # does not apply to admins, and an admin push skips the check entirely.
14
- # 3. A PUSH IDENTITY — a required check binds nobody while the only committer is the repo's
15
- # sole admin. Push from a non-admin account or token, or accept that the gate is advisory
16
- # for your own pushes. This is a forge change, not a file change: that is why PG-04 is the
17
- # row that records it, and why PG-04 is advisory rather than a gate.
18
- # 4. NEVER CONDITIONAL — keep every job and step unconditional (PG-05 enforces it).
19
- #
20
- # WHAT IT CANNOT SEE. It runs on a runner you do not own, from a checkout of your repo. Any gate
21
- # that needs a display, a licence, a GPU or a signed-in session is a HOST gate: declare it in the
22
- # HANDOFF's measured numbers, do not try to run it here. On a private repo the minutes are billed
23
- # to your account, so a long job is not free.
24
- #
25
- # For a zizmor-clean workflow, pin `uses:` to a commit SHA instead of a tag:
26
- # gh api repos/actions/checkout/git/refs/tags/v4 --jq .object.sha
27
- # (left as a tag here so the file is readable; nothing in goblin-stack reads a workflow's SHA).
28
- name: goblin-gate
29
- on:
30
- push:
31
- branches: [{{BRANCH}}]
32
- pull_request:
33
- permissions:
34
- contents: read
35
- concurrency:
36
- group: goblin-gate-{{BRANCH}}
37
- cancel-in-progress: true
38
- jobs:
39
- gate:
40
- name: the declared gate set
41
- runs-on: ubuntu-latest
42
- timeout-minutes: 20
43
- steps:
44
- - uses: actions/checkout@v4
45
- - name: run the declared gate set
46
- run: bash .goblin/bin/goblin-verify
@@ -1,146 +0,0 @@
1
- # .goblin/goblin.yaml — the project config. Generated once by goblin-install, then YOURS.
2
- # It is never overwritten after the first install: edit it in place.
3
- #
4
- # Format: a flat, line-oriented YAML subset, parsed by .goblin/bin/goblin-lib.sh. No YAML
5
- # library, no network, no npm. Keep one key per line and keep comments on their own line.
6
-
7
- # Which class this project is: software | service | game | research | fleet.
8
- # The letters A-E and the older names app/agent/desktop are READ-TIME aliases, so an old
9
- # value keeps verifying; `desktop`/`F` resolve to software. Selects the required parts
10
- # (manifest/classes.tsv).
11
- class: {{CLASS}}
12
-
13
- # Electron opt-in (software class). true turns on the electron ban set (BN-06..09) even if the
14
- # bans: list below omits them, and requires a declared perf.host_gate (PF-01 fails without one).
15
- # The `desktop`/`F` install alias sets this true; a text-editor app leaves it false.
16
- electron: {{ELECTRON}}
17
-
18
- # The default branch, DECLARED, never assumed. A preset that assumes the wrong branch
19
- # silently skips a repo.
20
- branch: {{BRANCH}}
21
-
22
- # The model mapping — the ONE install-time machine input. goblin-stack READS this file and
23
- # never writes it. Absent on another machine: every model-dependent check reports advisory.
24
- models_file: {{MODELS_FILE}}
25
-
26
- # The global engine (optional, W1). Where the ENGINE tier lives on this machine — an
27
- # absolute path or ~/-prefixed. Absent by default: a fresh per-repo install is
28
- # byte-compatible with today, and verify resolves its engine exactly as it always did.
29
- # Declared but unusable (relative path, missing directory, no manifest inside) is
30
- # verify exit 2 with NO fallback — a repo must not be judged by an engine it did not
31
- # declare. Authored by hand (or by `goblin upgrade`, W3); goblin-install never writes it.
32
- # engine_dir: ~/.goblin/engine
33
-
34
- # The referenced standard (optional). goblin-stack carries no copy of it; it pins its hash.
35
- practice: {{PRACTICE}}
36
- practice_sha256: {{PRACTICE_SHA}}
37
-
38
- # The commit identity this repo expects (CM-01).
39
- owner_email: {{OWNER_EMAIL}}
40
-
41
- # archive: true -> verify requires no HANDOFF and no gates, and says so.
42
- archive: {{ARCHIVE}}
43
-
44
- # Uncommitted entries allowed at verify time (CM-03). 0 means commit as you go.
45
- max_dirty: {{MAX_DIRTY}}
46
-
47
- # Unenforceable rules are counted; this is the cap that stops the matrix decaying into prose.
48
- advisory_ceiling: {{ADVISORY_CEILING}}
49
-
50
- # Whether this class requires a client-visible surface to be secret-free (SC-01..SC-09 read the
51
- # `security:` block below). Declared, never inferred: a stack-specific rule guessed from the
52
- # files on disk is how a matrix starts lying.
53
- security:
54
- gitignore_family: {{SEC_GITIGNORE_FAMILY}}
55
- build_output: {{SEC_BUILD_OUTPUT}}
56
- audit_cmd: {{SEC_AUDIT_CMD}}
57
- audit_max_age_days: {{SEC_AUDIT_MAX_AGE}}
58
- waiver_max_age_days: {{SEC_WAIVER_MAX_AGE}}
59
- write_routes: {{SEC_WRITE_ROUTES}}
60
-
61
- # The performance budget (PF-01). The NUMBER lives in `ratchet:` above — this block only names
62
- # the commit it was measured on, so "I raised the ceiling" cannot silently become "I never
63
- # measured again". An empty baseline_commit means "not measured yet" and PF-01 skips with that
64
- # reason; a baseline_commit that does not resolve to an ancestor of HEAD is a RED.
65
- perf:
66
- metric: {{PERF_METRIC}}
67
- cmd: {{PERF_CMD}}
68
- baseline_commit: {{PERF_BASELINE_COMMIT}}
69
- baseline_value: {{PERF_BASELINE_VALUE}}
70
- measured: {{PERF_MEASURED}}
71
- host_gate: {{PERF_HOST_GATE}}
72
-
73
- # Where the asserting harnesses live.
74
- harness_dir: {{HARNESS_DIR}}
75
-
76
- # Whether this class scaffolds that directory. A declared harness_dir that is absent FAILS
77
- # (HS-01) when this is yes; a class that ships no harness dir skips with a reason.
78
- scaffold_checks: {{SCAFFOLD_CHECKS}}
79
-
80
- # The feature map (P6's inventory, authored by skills/goblin-feature-map).
81
- # feature_map: the map's README, relative to this repo. EMPTY means "no map declared yet" and
82
- # makes FM-01/FM-02 SKIP with that reason - a fresh install has no map and must not be born RED.
83
- # source_root: entry paths in the map resolve against this.
84
- # verify_doctor: the command the map's own instructions say to run. EMPTY -> VA-01 SKIPs.
85
- feature_map: {{FEATURE_MAP}}
86
- source_root: {{SOURCE_ROOT}}
87
- verify_doctor: {{VERIFY_DOCTOR}}
88
-
89
- # The reference corpus (P15). `reference_manifest:` names the manifest RC-01/RC-02/RC-04 read: a
90
- # hash-only record of the quarantined corpus, never the corpus itself. EMPTY means "no reference
91
- # corpus is declared" and makes RC-01, RC-02 and RC-04 SKIP with that reason - a repo with no
92
- # corpus must not be born RED. A key that IS set but names a missing or unparseable file is a
93
- # FAIL, never a skip, so losing the manifest cannot read as "no corpus". RC-01 also reads the
94
- # `security: build_output:` list above: a file there whose sha256 appears in an entry fails the
95
- # build.
96
- # `quarantine_root:` is the quarantine directory the procedure extracts into (outside this repo).
97
- # No row reads it; it is declared so the procedure has a machine-readable anchor instead of a path
98
- # in prose.
99
- reference_manifest: {{REFERENCE_MANIFEST}}
100
- quarantine_root: {{QUARANTINE_ROOT}}
101
-
102
- # The loop ceiling (G2, LP-03). The most turns ONE loop record may declare in its budget, so a
103
- # runaway loop cannot buy itself unlimited iterations. 20 is the engine's own default for a
104
- # kanban goal loop, measured; a ceiling that does not match the engine's default is a number
105
- # someone made up. It bounds one loop's turns, never how many loops exist.
106
- loop_max_turns_ceiling: {{LOOP_MAX_TURNS}}
107
-
108
- # The gate set. DECLARED, never inferred from the stack. Replace the default below with the
109
- # real commands for this project; each must exit 0. The whole block is rendered by one
110
- # placeholder (a class may declare a second gate - A's TODO ceiling), so a second, empty
111
- # placeholder line below it leaked an unsubstituted token into every class's installed config
112
- # and nothing rendered it (Z1-3).
113
- gates:
114
- {{GATES}}
115
-
116
- # A count that must not rise, with its ceiling. The ceiling was measured at install time.
117
- ratchet:
118
- name: {{RATCHET_NAME}}
119
- cmd: {{RATCHET_CMD}}
120
- ceiling: {{RATCHET_CEILING}}
121
-
122
- # Paths a probe must never write (DS-01/DS-02 hash them around every gate run).
123
- runtime_data:
124
- {{RUNTIME_DATA}}
125
-
126
- # The ban list (G5). Which bans this project turns on; an unlisted ban SKIPs with a reason.
127
- # A ban's mechanism lives in .goblin/manifest/bans.tsv; the engine is .goblin/bin/goblin-bans.
128
- bans: [{{BANS}}]
129
-
130
- # Narrow, explicit, reviewed exceptions (Dune rule 5): "- <ban id> <path prefix>".
131
- bans_exempt:
132
- {{BANS_EXEMPT}}
133
-
134
- # What BN-05 reads: "<from> <to>" layer pairs. Empty -> BN-05 SKIPs with a reason.
135
- layers:
136
- {{LAYERS}}
137
-
138
- # How a harness proves RED on the pre-change tree (HS-02). Set commit: to the pinned
139
- # pre-change SHA once the round it guards has landed; until then HS-02 is skipped with a reason.
140
- replay:
141
- env: {{REPLAY_ENV}}
142
- cmd: {{REPLAY_CMD}}
143
- commit: ""
144
-
145
- # Parts recorded as opt-out. Their required checks report SKIP (opt-out) rather than passing.
146
- disabled: [{{DISABLED}}]
@@ -1 +0,0 @@
1
- ts phase decision why evidence result
@@ -1,16 +0,0 @@
1
- # .goblin/loop/predicate — the loop's exit condition. Copy this file to that path and edit it.
2
- #
3
- # ONE command. Exits 0 == the loop is finished. Comments are allowed here; the command is the
4
- # single non-blank, non-comment line (LP-01 checks exactly that).
5
- #
6
- # A duration is NOT a finish condition, and neither is a description of one.
7
- # Run it once BEFORE iteration 1 and record the result in .goblin/loop/first-run as
8
- # "exit=<n> ts=<ISO8601>": the run-once rule is how you know the command is runnable and
9
- # currently red, which is what makes a later green mean anything.
10
- # Then pin it: sha256sum .goblin/loop/predicate | cut -d' ' -f1 > .goblin/loop/predicate.sha256
11
- # Never edit the predicate mid-loop — archive it under .goblin/loop/closed-<date>/ together with
12
- # the pin it was closed under, then open a new loop whose predicate.sha256 names the archived
13
- # digest on a `previous: <digest>` line (LP-02: a silent relaxation FAILs; the chain is the record).
14
- #
15
- # Replace the line below with the real condition. Example shape only:
16
- node tools/check-cycles.mjs