@bongos/core 1.19.777 → 1.19.778

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/.bongos-core.json CHANGED
@@ -2,22 +2,22 @@
2
2
  "artifact": "bongos-core",
3
3
  "manifest_schema": 1,
4
4
  "generator": "scripts/gds/package-core.js",
5
- "core_version": "1.19.777",
6
- "core_contract": "1.19.777",
7
- "source_commit": "8c4c3db04491300feb300426c07f7d4bce19f981",
5
+ "core_version": "1.19.778",
6
+ "core_contract": "1.19.778",
7
+ "source_commit": "789aac3a01b8b02183c2dd2b3ebfee12bb25a703",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-16T18:55:13.712Z",
9
+ "built_at": "2026-09-16T19:16:36.821Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 486,
12
+ "docs_redacted": 482,
13
13
  "agent_docs_stubbed": 25,
14
14
  "functional_verbatim": 2153,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2664,
20
- "tree_sha256": "48b4056d95f14a44152bbeafa4b8208f71b3bbb6890cb8fff14b4b5a70f27b10",
19
+ "file_count": 2660,
20
+ "tree_sha256": "0b65b14c44cb8fe069f46bc63b1572cb3471d535843beda4b24ebade6173c4b1",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -49,21 +49,11 @@
49
49
  "mode": "0000644",
50
50
  "sha256": "722cb6ec3054b041e6f39e6ae2f1afa7977153cbcb8b005ef943509962c55d05"
51
51
  },
52
- {
53
- "path": ".claude/skills/builder-box/SKILL.md",
54
- "mode": "0000644",
55
- "sha256": "2c99f7d3dc8bd89a4c3f4f49b32c630b0a18a5acf004d849b1e3564effa00ced"
56
- },
57
52
  {
58
53
  "path": ".claude/skills/builder-claim/SKILL.md",
59
54
  "mode": "0000644",
60
55
  "sha256": "e98c9fc650b38916f81b453d20035259006160043c4170d36505756b314c4ffa"
61
56
  },
62
- {
63
- "path": ".claude/skills/builder-connect/SKILL.md",
64
- "mode": "0000644",
65
- "sha256": "5c8f33777f987c6382e7d232c5ceb1883d0a6964365401169cd5941557e93364"
66
- },
67
57
  {
68
58
  "path": ".claude/skills/builder-cost/SKILL.md",
69
59
  "mode": "0000644",
@@ -72,12 +62,12 @@
72
62
  {
73
63
  "path": ".claude/skills/builder-end/SKILL.md",
74
64
  "mode": "0000644",
75
- "sha256": "29f4456636d782f942b1d0765edadb6735c2ba48d1193edf3f490527155efa6b"
65
+ "sha256": "e6d9739aca81fdc54897049d2d5926b0923150a2f8866f5d1f5945f1412014f8"
76
66
  },
77
67
  {
78
68
  "path": ".claude/skills/builder-exit/SKILL.md",
79
69
  "mode": "0000644",
80
- "sha256": "122599d47266260fa79465754a7f975af106a47703987eba46c9e938efde7e3c"
70
+ "sha256": "9679ffdcb10af1858d45aa1d00be1141b798f167ee5daead42e0f6374e4e9fd4"
81
71
  },
82
72
  {
83
73
  "path": ".claude/skills/builder-key/SKILL.md",
@@ -112,28 +102,18 @@
112
102
  {
113
103
  "path": ".claude/skills/builder-ship/SKILL.md",
114
104
  "mode": "0000644",
115
- "sha256": "e4810f288bc5b0a4d33a62c918c76225b16e6b0c2f733a1c95336d6932512060"
105
+ "sha256": "fee2003d2f6b12f404109217c14f7e0e22ad2abaf073322e08e8079549a136b3"
116
106
  },
117
107
  {
118
108
  "path": ".claude/skills/builder-stage/SKILL.md",
119
109
  "mode": "0000644",
120
- "sha256": "f4a6d1569f1a41d42e5c27ec6a1f1717ef937e08cd8b8d771f7b68585d26472d"
110
+ "sha256": "5f3c09420b08538d66dbe0ab858618907c0b92cf82a6aa44fe0eb53004f224c0"
121
111
  },
122
112
  {
123
113
  "path": ".claude/skills/builder-start/SKILL.md",
124
114
  "mode": "0000644",
125
115
  "sha256": "fd023863bf2f53447be736ac8972423477005cb542c203b4e089d948507d8944"
126
116
  },
127
- {
128
- "path": ".claude/skills/builder-sync/SKILL.md",
129
- "mode": "0000644",
130
- "sha256": "ed647c782b56f40792676341344f4b31d1a6f05e24c93d947d921b48c8117159"
131
- },
132
- {
133
- "path": ".claude/skills/close-box/SKILL.md",
134
- "mode": "0000644",
135
- "sha256": "5cac7dffb190e027b9d3f011c35c16924280c07f6c98ecd60f8a44fcb18d2b50"
136
- },
137
117
  {
138
118
  "path": ".claude/skills/design-sync/SKILL.md",
139
119
  "mode": "0000644",
@@ -192,7 +172,7 @@
192
172
  {
193
173
  "path": ".claude/skills/merge-mode/SKILL.md",
194
174
  "mode": "0000644",
195
- "sha256": "272799b69a445188f6d2c558b01b467d62bb696975c79e08d994c04de81ed54a"
175
+ "sha256": "ef2c92c34d047186eaa016a99d4679f09be028120b9d61bc92b1a999bf87bec0"
196
176
  },
197
177
  {
198
178
  "path": ".claude/skills/new-project/SKILL.md",
@@ -2517,7 +2497,7 @@
2517
2497
  {
2518
2498
  "path": "docs/file-map.md",
2519
2499
  "mode": "0000644",
2520
- "sha256": "4f45da7f069720b0f6cd29a9e8946b006bc592830630528a606cc2b252f2ee80"
2500
+ "sha256": "c3130f09be6637d33eb1ccdaf4fdadf6adbebdeae3e264f2f845e668c9fc90fa"
2521
2501
  },
2522
2502
  {
2523
2503
  "path": "docs/handoff-template.md",
@@ -2527,7 +2507,7 @@
2527
2507
  {
2528
2508
  "path": "docs/module-api-changelog.md",
2529
2509
  "mode": "0000644",
2530
- "sha256": "48accd0cc072b560c546805d257d6ac9695ec17a3702aa7434c17b6eb632f819"
2510
+ "sha256": "4c8bb6807afb74e21e64f0b4d673b335eae7873f90563eb2077e49a210dfd85e"
2531
2511
  },
2532
2512
  {
2533
2513
  "path": "docs/modules-contract.md",
@@ -2597,7 +2577,7 @@
2597
2577
  {
2598
2578
  "path": "docs/onboarding/slash-commands.md",
2599
2579
  "mode": "0000644",
2600
- "sha256": "174c90095ed45bf107852c017493fdd0fa3f07bdf8fbe69c09ebf77bc00747f2"
2580
+ "sha256": "748df9bec7434093e32f70915f151b9cc6ac67beebbe226b997d81eba327de31"
2601
2581
  },
2602
2582
  {
2603
2583
  "path": "docs/packs/artist.md",
@@ -7632,12 +7612,12 @@
7632
7612
  {
7633
7613
  "path": "package-lock.json",
7634
7614
  "mode": "0000644",
7635
- "sha256": "620248e6545e156fd98d84b9dc29bdad59a77be39ba3e761a90d62d385255f4d"
7615
+ "sha256": "6352bb5bd1cf9b2b944dd8ae2baef9fa9a719036dacd4acf5c0104d65fa56dc0"
7636
7616
  },
7637
7617
  {
7638
7618
  "path": "package.json",
7639
7619
  "mode": "0000644",
7640
- "sha256": "d4ebe23ce76cdf1091ce8ab656a5199df19fb171768a947ff7cad259f9262dfd"
7620
+ "sha256": "019205fa726bfcf5d7175ff8e5bdc7589e117bff7757b35b4d64168f1dc6c713"
7641
7621
  },
7642
7622
  {
7643
7623
  "path": "public-docs/index.html",
@@ -9497,7 +9477,7 @@
9497
9477
  {
9498
9478
  "path": "src/module-api.js",
9499
9479
  "mode": "0000644",
9500
- "sha256": "3791abffec940edb90c976525b388d122d16ff5613c1ee1a487d6e9f1ad1a1e0"
9480
+ "sha256": "cc914f78fd5bd1fcb6eb795a98519e8a45551fd5e404b22eb3e118369cce35ea"
9501
9481
  },
9502
9482
  {
9503
9483
  "path": "src/module-loader/catalog.js",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: builder-end
3
3
  description: >-
4
- Close out this session: resolve the active claim, confirm the tree is clean, tear down the worktree, and on a dev box offer to shut it down. Own-scoped; /builder-exit offboards a whole builder. Triggers: "/builder-end", "end my session", "sign off", "wrap up and clean up".
4
+ Close out this session: resolve the active claim, confirm the tree is clean, and tear down the worktree. Own-scoped; /builder-exit offboards a whole builder. Triggers: "/builder-end", "end my session", "sign off", "wrap up and clean up".
5
5
  ---
6
6
 
7
7
  You are closing out the current Claude Code **session** safely: resolve the held claim, confirm no work is stranded uncommitted, and clean up the session's git worktree. It is the bookend to `/builder-start` — one command so a session ends in a known-clean state instead of leaving a half-shipped claim and an orphaned worktree behind.
@@ -15,9 +15,8 @@ Composes operations that already exist, in a safe order, with the destructive on
15
15
  1. **Resolve the claim** — `/builder-ship` when there's committed, shippable work; `/builder-release` when there isn't. (It calls the sibling skills; it does not re-implement shipping.)
16
16
  2. **Clean-git verify** — refuse to go further if any *tracked* file is uncommitted. This is the same guard `scripts/gds/ship.js` enforces (`trackedDirty` in [`src/bongos/ship-preflight.js`](../../../src/bongos/ship-preflight.js)): untracked scratch is ignored, but a modified/staged/deleted tracked file means real work isn't committed — stop before anything is lost.
17
17
  3. **Worktree teardown** — from the main checkout, remove this session's linked worktree via `node scripts/gds/worktree.js remove` (junction-aware), `prune`, and delete the now-merged `claude/<name>` branch.
18
- 4. **Box close-out (dev box only)** — if running on a dev box (`/etc/otb/box.env` exists), offer to `close-box` so the box stops billing. Optional and gated on a yes; declining just lets the box idle-park. On a laptop this step is skipped — there's no box to close.
19
18
 
20
- It never pushes to `main`, never `ssh`-es, never runs a deploy — landing is `/builder-ship`'s job (server-mediated). It only ever touches the caller's **own** claim, **own** worktree, and **own** box.
19
+ It never pushes to `main`, never `ssh`-es, never runs a deploy — landing is `/builder-ship`'s job (server-mediated). It only ever touches the caller's **own** claim and **own** worktree.
21
20
 
22
21
  ## How to use
23
22
 
@@ -25,7 +24,6 @@ It never pushes to `main`, never `ssh`-es, never runs a deploy — landing is `/
25
24
 
26
25
  - **Held claim(s):** `node scripts/gds/api.js GET /api/gds/me` → `active_claims`. (A builder can hold parallel claims across sessions; resolve only the one this session worked.)
27
26
  - **Are we in a linked worktree?** `git rev-parse --git-dir` differs from `git rev-parse --git-common-dir` ⇒ yes (`--git-dir` is the per-worktree `<main>/.git/worktrees/<name>`; `--git-common-dir` is the shared `<main>/.git`); they're equal ⇒ main checkout (skip step 3). Test `--git-dir`, **not** `--git-common-dir` — the latter always returns the shared `<main>/.git` even inside a worktree, so checking *it* for `/worktrees/` never matches.
28
- - **Are we on a dev box?** `/etc/otb/box.env` exists ⇒ yes. This is the codebase's canonical "am I on a box?" marker — written by `box.js provision`, the same presence-check `scripts/gds/sandbox-stage.js` (`isDevBox`) uses. On a box the close-out has an extra step: the box keeps billing until it's shut down or idle-parks (step 4). On a laptop there's no box — skip step 4.
29
27
  - **Working-tree state:** `git status --porcelain`.
30
28
  - **Commits ahead of main:** `git rev-list --count main..HEAD` (fall back to `origin/main..HEAD`). Real commits ⇒ likely shippable; zero ⇒ likely a release.
31
29
 
@@ -34,7 +32,7 @@ It never pushes to `main`, never `ssh`-es, never runs a deploy — landing is `/
34
32
  - **Commits ahead AND clean tree ⇒ shippable.** Confirm with the user, then run the **`builder-ship`** skill with honest handoff `--notes` and a one-line non-jargon `--summary`. Don't fabricate the summary — if you can't state the value plainly, it isn't shippable; release instead.
35
33
  - **No commits / no shippable progress ⇒** run the **`builder-release`** skill with a one-phrase reason.
36
34
  - **No active claim ⇒** nothing to resolve; go to step 2.
37
- - **Ship strands at `confirmed`** (merge conflict or a failing check — the box ships, the merge doesn't): **stop here.** The branch still needs to land via `/merge-mode`. Surface that and do NOT tear down the worktree — its branch isn't merged yet (step 3's `git branch -d` would correctly refuse it).
35
+ - **Ship strands at `confirmed`** (merge conflict or a failing check — the ship lands, the merge doesn't): **stop here.** The branch still needs to land via `/merge-mode`. Surface that and do NOT tear down the worktree — its branch isn't merged yet (step 3's `git branch -d` would correctly refuse it).
38
36
 
39
37
  ### 2. Clean-git verify
40
38
 
@@ -52,31 +50,19 @@ git worktree prune
52
50
  git branch -d claude/<worktree-name> # -d (not -D): git refuses an unmerged branch, by design
53
51
  ```
54
52
 
55
- Removing this session's worktree ends its filesystem — do it last, and tell the user the session is closed and they can start fresh from `/builder-start` anytime. **On a dev box, settle step 4 first:** if the builder is going to `close-box`, skip teardown entirely — deprovisioning destroys the whole `/workspace` disk, so removing one worktree first is wasted effort. Only tear the worktree down if they're keeping the box.
53
+ Removing this session's worktree ends its filesystem — do it last, and tell the user the session is closed and they can start fresh from `/builder-start` anytime.
56
54
 
57
- **On the main checkout (not a worktree):** skip the teardown above — there's nothing to remove. On a **laptop** that means resolving the claim + clean-git verify is the whole close-out. On a **dev box** (step 0 found `/etc/otb/box.env`) the box itself is still up — continue to step 4.
58
-
59
- ### 4. Box close-out — dev box only, gated, after the claim is resolved
60
-
61
- Skip this entirely if step 0 found no `/etc/otb/box.env` (a laptop — there's no box to close). On a box, resolving the claim does **not** stop the box billing; only closing it (or the idle-suspend sweep) does. Once the claim is resolved and the tree is clean, ask plainly:
62
-
63
- > *"Close the box down too? `close-box` deprovisions it — anything in `/workspace` you haven't shipped is gone. Or leave it: closing the tab keeps your session, and the box idle-parks on its own (cheap)."*
64
-
65
- - **Yes, shut it down** → run the **`close-box`** skill (`node scripts/gds/api.js POST /api/gds/box/close`). It enqueues a deprovision that runs within ~a minute. This **subsumes** worktree teardown — the whole box disk is going away, so step 3 was moot.
66
- - **No, keep the box** → leave it; it idle-parks automatically. The close-out is complete (claim resolved, worktree torn down in step 3 if applicable). Tell them they can reopen the terminal to resume, or `/builder-box` to check/wake it later.
67
-
68
- `close-box` is **own-scoped** — it only ever deprovisions the caller's own box. Never another builder's.
55
+ **On the main checkout (not a worktree):** skip the teardown above — there's nothing to remove. Resolving the claim + the clean-git verify is then the whole close-out.
69
56
 
70
57
  ## Constraints
71
58
 
72
- - **Own-scoped.** Only this session's claim, this session's worktree, and the caller's own box — never another builder's claim, never another worktree, never `git worktree remove` a path you didn't create, never another builder's box.
59
+ - **Own-scoped.** Only this session's claim and this session's worktree — never another builder's claim, never another worktree, never `git worktree remove` a path you didn't create.
73
60
  - **Never destroy uncommitted work.** The clean-git verify gates teardown; the dirty-tree refusal in `git worktree remove` and `git branch -d` (not `-D`) are the load-bearing safety nets — keep them as written. But note: that refusal does NOT protect a Windows worktree carrying a `node_modules` junction — node_modules is gitignored, so the clean check passes and `git worktree remove` (even without `--force`) follows the junction and deletes the SHARED node_modules (task 1002809). That is why teardown runs through `node scripts/gds/worktree.js remove`, which unlinks the junction first.
74
- - **Box close is opt-in and destructive.** On a box, never `close-box` without an explicit yes — it deprovisions the box and any unshipped `/workspace` work is gone. Declining is always fine; the box idle-parks on its own.
75
- - **Never push / ssh / deploy.** Landing goes through `/builder-ship` (server-mediated); this skill stays local to the builder's machine (its one possible API write is the opt-in own-scoped `close-box`).
76
- - **The destructive steps (teardown, box-close) never run unattended without a clear go.** Ship vs. release can be inferred from state (commits ⇒ ship, none ⇒ release) and proceed; removing the worktree ends the session and closing the box destroys it, so wait for an explicit yes before steps 3 and 4.
61
+ - **Never push / ssh / deploy.** Landing goes through `/builder-ship` (server-mediated); this skill stays local to the builder's machine and makes no API writes of its own.
62
+ - **Teardown never runs unattended without a clear go.** Ship vs. release can be inferred from state (commits ⇒ ship, none ⇒ release) and proceed; removing the worktree ends the session, so wait for an explicit yes before step 3.
77
63
  - **Don't tear down a branch that isn't merged.** A released task or a ship stuck at `confirmed` still has an un-landed `claude/*` branch — `git branch -d` will refuse it; respect that and leave the worktree for `/merge-mode`.
78
64
 
79
65
  ## Files this skill touches
80
66
 
81
- - Reads: `~/.config/otb/gds-session.json`; `/etc/otb/box.env` (presence check only — "am I on a box?")
82
- - Runs: the `builder-ship` / `builder-release` skills (`scripts/gds/ship.js` · `release.js`), `node scripts/gds/api.js GET /api/gds/me`, and local `git worktree` / `git status` / `git branch` commands. On a dev box, if the builder opts in, it runs the `close-box` skill (`POST /api/gds/box/close`) — the one own-scoped API write it can make; otherwise it makes no API writes of its own.
67
+ - Reads: `~/.config/otb/gds-session.json`
68
+ - Runs: the `builder-ship` / `builder-release` skills (`scripts/gds/ship.js` · `release.js`), `node scripts/gds/api.js GET /api/gds/me`, and local `git worktree` / `git status` / `git branch` commands. It makes no API writes of its own.
@@ -12,8 +12,8 @@ You are gracefully offboarding a builder from Bongos, or reactivating one who ha
12
12
 
13
13
  `/builder-exit` is **not** how you end a working session. It permanently **offboards an entire builder** — an Archon deactivating *someone else's* account (releases all their claims, drops them to Xenos, blocks new claims). "Exit" is the natural word for "log me off," so builders reach for this first ([#1448](https://example.com/builders#/task/1448)) — but it's the wrong, and gated, tool for the everyday close-out. Before touching anything, check intent:
14
14
 
15
- - **The caller wants to wrap up their *own* online-terminal / Claude Code session** — no builder id given, the id is their own, or they said "close out / end / sign off / I'm done" → **do not attempt an offboard.** Say plainly: *"`/builder-exit` offboards an entire builder (releases all their claims, drops them to Xenos) and is Archon-only — it isn't the session close-out. To close out your session, run **`/builder-end`**: it resolves your claim (ship or release) and, on a dev box, offers to shut the box down with `close-box`."* Then stop and hand off to `/builder-end`.
16
- - **The caller is not an Archon** (rank below `archon`, or you can't confirm Archon) → same redirect. The endpoint would 403 (`rank_forbidden`) anyway; don't dead-end them on the error — point them at `/builder-end` (+ `close-box` on a box).
15
+ - **The caller wants to wrap up their *own* online-terminal / Claude Code session** — no builder id given, the id is their own, or they said "close out / end / sign off / I'm done" → **do not attempt an offboard.** Say plainly: *"`/builder-exit` offboards an entire builder (releases all their claims, drops them to Xenos) and is Archon-only — it isn't the session close-out. To close out your session, run **`/builder-end`**: it resolves your claim (ship or release) and tears down the session's worktree."* Then stop and hand off to `/builder-end`.
16
+ - **The caller is not an Archon** (rank below `archon`, or you can't confirm Archon) → same redirect. The endpoint would 403 (`rank_forbidden`) anyway; don't dead-end them on the error — point them at `/builder-end`.
17
17
  - **An Archon is deliberately offboarding (or reactivating) *another* builder, by id** → this is the real operation. Proceed with the steps below.
18
18
 
19
19
  Never run the destructive offboard just because someone wanted to log off — the two are different operations.
@@ -25,15 +25,15 @@ The CLI drives a **three-state lifecycle** with a subagent grader between states
25
25
  - **`GRADER UNAVAILABLE`** (`panel_outcome='unavailable'`) — the grading panel could not run (worker infra outage or a pre-spawn bypass). This is **not a quality rejection**: no quality signal was produced, there are no findings to fix, and the task parks at `completed` ungraded (aggregates exclude these rounds as `n_unavailable` — an outage never counts as a zero). Recovery: when the grader is reachable again, re-run just the grade step — `node scripts/gds/ship.js <id> --regrade`.
26
26
  - **A genuine `FAIL`** — the panel ran and returned findings. Fix the real issues, commit on the claim branch (the grader reads committed history, not the working tree), then re-grade with the same command: `node scripts/gds/ship.js <id> --regrade`.
27
27
 
28
- (Dev-box game changes, `--approved`) Persists the builder's sandbox self-approval to `tasks.sandbox_review` — `{ by, at, stamp, url, method }`, with `by`/`at` stamped server-side ([#1048](https://example.com/builders#/task/1048), ADR 0046).
28
+ (Game-surface changes, `--approved`) Persists the builder's sandbox self-approval to `tasks.sandbox_review` — `{ by, at, stamp, url, method }`, with `by`/`at` stamped server-side ([#1048](https://example.com/builders#/task/1048), ADR 0046).
29
29
 
30
30
  ## How to use
31
31
 
32
32
  1. **Confirm the task id** the user is shipping (it must match their currently-active claim).
33
33
 
34
- **On a dev box with game-surface changes, stage first (#927, ADR 0046 + #1048).** If the diff touches the game (`public/`, `src/world/`, `src/rooms/`, `server.js`) and the session is on a dev box, the flow is: stage → the builder reviews the change at `https://sandbox-<login>.example.com` → approve → ship. `ship.js` enforces this before the claim resolves: un-staged game work gets staged to the sandbox and the ship **aborts with a `🔍 REVIEW REQUIRED` block** carrying the URL (claim intact, nothing lost).
34
+ **With game-surface changes, stage first (#927, ADR 0046 + #1048).** If the diff touches the game (`public/`, `src/world/`, `src/rooms/`, `server.js`), the flow is: stage → the builder reviews the change on their local sandbox preview → approve → ship. `ship.js` enforces this before the claim resolves: un-staged game work gets staged and the ship **aborts with a `🔍 REVIEW REQUIRED` block** carrying the URL (claim intact, nothing lost).
35
35
 
36
- **When you see that block, position the sandbox link prominently for the builder.** `ship.js` also emits the deterministic lifecycle card for the `review` stage (an `[otb-card-html] <path>` marker) — if an in-feed visualization tool is available, render that card (its primary action is **Open in sandbox ↗**, the URL); it's the cleanest way to make the link impossible to miss. Either way, surface the URL as its own standalone, clickable line in chat — a clear callout, NOT buried inside a paragraph of command output — and say in one line what to look at. This is the moment the change is ready to review; the link must be impossible to miss. Let the builder open it, review, and suggest changes; iterate if needed. **Only once the builder explicitly approves, re-run with `node scripts/gds/ship.js <id> --approved`** — that records their sign-off as a durable `sandbox_review` fact on the task (who, when, and the content stamp of exactly what was reviewed). Never pass `--approved` yourself without a real human go; the pause + sign-off IS the feature. `--skip-stage` is the escape hatch (use sparingly — the gate exists so unreviewed game changes don't ride straight to prod). Laptop sessions and non-game diffs are unaffected.
36
+ **When you see that block, position the sandbox link prominently for the builder.** `ship.js` also emits the deterministic lifecycle card for the `review` stage (an `[otb-card-html] <path>` marker) — if an in-feed visualization tool is available, render that card (its primary action is **Open in sandbox ↗**, the URL); it's the cleanest way to make the link impossible to miss. Either way, surface the URL as its own standalone, clickable line in chat — a clear callout, NOT buried inside a paragraph of command output — and say in one line what to look at. This is the moment the change is ready to review; the link must be impossible to miss. Let the builder open it, review, and suggest changes; iterate if needed. **Only once the builder explicitly approves, re-run with `node scripts/gds/ship.js <id> --approved`** — that records their sign-off as a durable `sandbox_review` fact on the task (who, when, and the content stamp of exactly what was reviewed). Never pass `--approved` yourself without a real human go; the pause + sign-off IS the feature. `--skip-stage` is the escape hatch (use sparingly — the gate exists so unreviewed game changes don't ride straight to prod). Non-game diffs are unaffected.
37
37
 
38
38
  2. **Compose the handoff notes (`--notes-file`)** following the structure in `docs/handoff-template.md`:
39
39
  - What shipped (with confidence tags: verified-prod | verified-smoke | implemented-not-verified)
@@ -4,28 +4,24 @@ description: >-
4
4
  Stage the working tree on the builder's own live preview to see a change in a browser BEFORE shipping. Own-scoped and machine-local. Triggers: "/builder-stage", "stage my work", "let me see it before shipping", "preview this change".
5
5
  ---
6
6
 
7
- You are staging a builder's in-progress work on **their own** sandbox — the live game preview running on their dev box (ADR 0044) — so they can see the change in a browser, suggest fixes, and only then decide to ship it to the main game (ADR 0046).
7
+ You are staging a builder's in-progress work on **their own** sandbox — the live game preview running on their own machine — so they can see the change in a browser, suggest fixes, and only then decide to ship it to the main game (ADR 0046).
8
8
 
9
9
  ## Background
10
10
 
11
- The script auto-detects where it's running and (re)starts the right preview — both serve the **game-only** entry (`src/preview-server.js`, ADR 0052), degraded-DB (fully playable, no saved state, isolated from prod, no `/api/gds`):
12
-
13
- - **Dev box:** `box-game-preview.service` serves the `/workspace` tree at `https://sandbox-<login>.example.com` (ADR 0044). Staging restarts that service.
14
- - **Local full clone (laptop):** a private detached process serves it at `http://localhost:<port>` (default 3100, `$OTB_PREVIEW_PORT` to override), managed by `scripts/gds/local-preview.js` (task 1056). Staging (re)starts that process. No tunnel, no public URL — it never leaves your machine.
15
-
16
- Either way staging = (re)start the preview, health-check it, and record a marker of exactly what tree state was staged. `/builder-ship` checks that marker: a game-surface diff that wasn't staged at its current state triggers the sandbox review gate before the claim resolves — on a box AND on a local clone.
11
+ Staging (re)starts the preview, which serves the **game-only** entry (`src/preview-server.js`, ADR 0052), degraded-DB (fully playable, no saved state, isolated from prod, no `/api/gds`): a private detached process at `http://localhost:<port>` (default 3100, `$OTB_PREVIEW_PORT` to override), managed by `scripts/gds/local-preview.js` (task 1056). No tunnel, no public URL — it never leaves your machine.
12
+ Staging = (re)start the preview, health-check it, and record a marker of exactly what tree state was staged. `/builder-ship` checks that marker: a game-surface diff that wasn't staged at its current state triggers the sandbox review gate before the claim resolves.
17
13
 
18
14
  ## How to use
19
15
 
20
- 1. **Run the stage command** from the repo root (`/workspace` on a box; your clone root on a laptop):
16
+ 1. **Run the stage command** from your clone root:
21
17
  ```bash
22
18
  node scripts/gds/sandbox-stage.js
23
19
  ```
24
- It (re)starts the preview, waits until the game answers, writes the staged marker, and prints the review URL (the `sandbox-<login>` host on a box, or `http://localhost:<port>` locally).
20
+ It (re)starts the preview, waits until the game answers, writes the staged marker, and prints the review URL (`http://localhost:<port>`).
25
21
 
26
- > **Local setup (laptop):** the preview needs the game's dependencies, so run `npm install` once in your clone. You can also drive the preview directly: `npm run preview` (start), `node scripts/gds/local-preview.js {status|restart|stop|logs}`. Reviewing via the Claude Code preview tools? A `local-sandbox` server is pre-wired in `.claude/launch.json`.
22
+ > **First-time setup:** the preview needs the game's dependencies, so run `npm install` once in your clone. You can also drive the preview directly: `npm run preview` (start), `node scripts/gds/local-preview.js {status|restart|stop|logs}`. Reviewing via the Claude Code preview tools? A `local-sandbox` server is pre-wired in `.claude/launch.json`.
27
23
 
28
- 2. **Hand the builder the URL** and tell them plainly: this is *their* private copy of the game running on *their* box — nothing has shipped. Ask them to open it, walk around, and check the change.
24
+ 2. **Hand the builder the URL** and tell them plainly: this is *their* private copy of the game running on *their own machine* — nothing has shipped. Ask them to open it, walk around, and check the change.
29
25
 
30
26
  > **Generated art?** If the change was a pixel-art tile, the builder can also see it at the **`/art`** path of the same sandbox URL (`…/art`) — the generated-art gallery (#1262), which shows every tile they've made *even when it isn't placed in the game world yet*. Point them there when the work is "I made a tile" rather than "I changed the map."
31
27
 
@@ -39,14 +35,12 @@ Either way staging = (re)start the preview, health-check it, and record a marker
39
35
 
40
36
  ## Constraints
41
37
 
42
- - **Box or local full clone.** A dev box stages to `sandbox-<login>`; a full local clone stages to `http://localhost:<port>`. The ONLY machine with no sandbox is a partial clone that lacks the game (`src/preview-server.js`) — there the script says so and exits.
43
- - **Named tunnel required (box only).** A quick-tunnel box has no sandbox hostname (ADR 0044); the script says so. The fix is operator-side (`BOX_NAMED_TUNNEL=1` + re-provision), not something to debug here. (Local previews have no tunnel and aren't affected.)
44
- - **On a dev box, the preview is the HOSTED `sandbox-<login>` URL — never localhost.** Get it from this skill (`node scripts/gds/sandbox-stage.js`) or `box-preview status`. Do **NOT** preview a box change with the Claude Code preview tools or `npm run preview`/`npm start`: those bind `http://localhost`, which the builder's own browser can't reach when the server is on a remote box — handing them a dead localhost link is the task-1443 footgun. (`sandbox-stage.js` now routes any box to the hosted URL and refuses to emit localhost; a box with no hostname gets a clear re-provision message, not a localhost link.) Localhost is correct ONLY on a laptop full clone.
45
- - **Never present the sandbox as prod.** No credits, no broadcast, nothing shipped — staging is review, `/builder-ship` is the decision. The local preview is private to the builder's own machine (not shareable).
46
- - If the preview won't come up healthy, point the builder at the logs — `box-preview logs` on a box, `node scripts/gds/local-preview.js logs` locally — rather than guessing.
38
+ - **A full local clone.** The ONLY machine with no sandbox is a partial clone that lacks the game (`src/preview-server.js`) — there the script says so and exits.
39
+ - **Never present the sandbox as prod.** No credits, no broadcast, nothing shipped — staging is review, `/builder-ship` is the decision. The preview is private to the builder's own machine (not shareable).
40
+ - If the preview won't come up healthy, point the builder at the logs — `node scripts/gds/local-preview.js logs` — rather than guessing.
47
41
 
48
42
  ## Files this skill touches
49
43
 
50
- - Runs: `scripts/gds/sandbox-stage.js` (resolves box vs local; box → restarts `box-game-preview.service`; local → `scripts/gds/local-preview.js` + `local-preview-lib.js` (re)start `node src/preview-server.js`)
51
- - Reads: `/etc/otb/box.env` (a box's `BOX_PREVIEW_HOSTNAME`); `$OTB_PREVIEW_PORT` (local port, default 3100)
44
+ - Runs: `scripts/gds/sandbox-stage.js`, which drives `scripts/gds/local-preview.js` + `local-preview-lib.js` to (re)start `node src/preview-server.js`
45
+ - Reads: `$OTB_PREVIEW_PORT` (local port, default 3100)
52
46
  - Writes: the staged marker in the OS temp dir (`otb-sandbox-staged.json`); locally, the preview pid/log in the OS temp dir (`otb-local-preview.{pid,log}`)
@@ -29,10 +29,10 @@ If it exits non-zero, **stop**: this machine cannot finish the procedure, and th
29
29
  partial run is the dangerous outcome (it mutates the main worktree). The skill's
30
30
  `requires:` frontmatter is what it checks — `main-checkout`, `push-credential`,
31
31
  `gh`, `droplet-ssh`. This gate exists because the note below was prose only, and
32
- prose cannot refuse: merge-mode was run on a dev box that had none of them, while
33
- `ship.js` separately already knew (`strandNextStep` tells a box "/merge-mode is
34
- NOT available here"). The knowledge existed twice and neither copy stopped the run
35
- (task 1003167).
32
+ prose cannot refuse: merge-mode was run on a machine that had none of them, while
33
+ `ship.js` separately already knew (`strandNextStep` tells such a machine
34
+ "/merge-mode is NOT available here"). The knowledge existed twice and neither copy
35
+ stopped the run (task 1003167).
36
36
 
37
37
  > **Environment note:** merge-mode is an **ops procedure** — it mutates the single
38
38
  > main worktree and deploys to the Linux droplet (owner-gated SSH). The git /
@@ -120,7 +120,7 @@ This mirrors what `ship.js` does automatically; it's here because /merge-mode de
120
120
 
121
121
  > **Deploy mode (#679 / [ADR 0042](../../../docs/adr/0042-builder-self-deploy-ci-auto-merge.md)).** `config/deploy.json` is now `mode: ci` (CI cutover landed 2026-06-13), so the **`ci`** path is current: there is no laptop merge and no SSH at all — landing happens via PR auto-merge and [`.github/workflows/deploy-prod.yml`](../../../.github/workflows/deploy-prod.yml) deploys `main`→prod from Actions. In `ci` mode, do NOT run the `git push origin main` + `ssh … ~/deploy.sh` lines below — instead confirm the PR auto-merged and the `deploy-prod` Actions run went green. The block below is the **legacy `laptop`** deploy mode (the operator's machine pushes `main` and SSHes the droplet) — it is the fallback path and only applies if `config/deploy.json` is reverted to `mode: laptop`. Check the active mode with `node scripts/gds/ship.js --print-deploy-mode`.
122
122
 
123
- > **Do NOT probe `parseDeployMode` directly (task 1003221).** It reads only the env var and `config/deploy.json`, and **defaults to `laptop`** when neither is present — and `config/` is not in the dev-box sparse checkout (`BASE_SPARSE_PATHS`, ADR 0148), so on a box that probe answers `laptop` every time. It sent a builder down the laptop merge path — local merge, `push-main.js`, SSH deploy — on a machine with none of those credentials (2026-08-21, 163 minutes). `effectiveDeployMode` is the credential-aware answer and reroutes to `ci` when the machine cannot push locally; the flag above prints that one.
123
+ > **Do NOT probe `parseDeployMode` directly (task 1003221).** It reads only the env var and `config/deploy.json`, and **defaults to `laptop`** when neither is present — so on any machine whose checkout does not carry `config/`, that probe answers `laptop` every time. It sent a builder down the laptop merge path — local merge, `push-main.js`, SSH deploy — on a machine with none of those credentials (2026-08-21, 163 minutes). `effectiveDeployMode` is the credential-aware answer and reroutes to `ci` when the machine cannot push locally; the flag above prints that one.
124
124
 
125
125
  ```bash
126
126
  node scripts/gds/smoke-gds.js # 16/16 expected (cross-platform; replaces smoke-gds.sh)
package/docs/file-map.md CHANGED
@@ -393,11 +393,9 @@ tests/
393
393
  ├── blocker-solve/SKILL.md ← /blocker-solve N — drive ONE blocker to done: do the doable parts, hand back owner-only steps, verify, auto-resolve (auto-promotes waiters); Metic+
394
394
  ├── bug-triage/SKILL.md ← /bug-triage — daily walk through open kind=bug tasks (batch-cluster near-dups, merge / won't-fix); the idea-triage counterpart built on the new tasks.merge primitive (task 1001478); Metic+
395
395
  ├── builder-backup/SKILL.md ← /builder-backup — check DB backup status or trigger a fresh local dump before risky changes (migrations, destructive SQL); no SSH required
396
- ├── builder-box/SKILL.md ← /builder-box — show the builder their own dev box (state, IP/host, cost, SSH keys) and help them (re)connect
397
396
  ├── builder-claim/SKILL.md ← /builder-claim N — atomic claim; prints the claim-time context pack + discipline playbook routing
398
- ├── builder-connect/SKILL.md ← /builder-connect — one-command connect of the builder's Claude Desktop to their Example dev box (ADR 0031)
399
397
  ├── builder-cost/SKILL.md ← /builder-cost — log a cost-ledger entry (api|compute|infra|domain|art|other)
400
- ├── builder-end/SKILL.md ← /builder-end — safely close out a session: resolve the claim (ship/release) + clean-git verify + worktree teardown + (on a dev box) offer to close the box; the bookend to /builder-start, and the own-scoped session close-out that /builder-exit redirects non-Archons to
398
+ ├── builder-end/SKILL.md ← /builder-end — safely close out a session: resolve the claim (ship/release) + clean-git verify + worktree teardown; the bookend to /builder-start, and the own-scoped session close-out that /builder-exit redirects non-Archons to
401
399
  ├── builder-exit/SKILL.md ← /builder-exit — gracefully offboard (or reactivate) a builder: release claims, seal session logs, drop rank to xenos
402
400
  ├── builder-key/SKILL.md ← /builder-key — list API-key status, render the visual 'key needed' callout for anything missing, drive the UI-first Settings add-flow + re-sync/confirm; never accepts a key pasted in chat (task 1391)
403
401
  ├── builder-reauth/SKILL.md ← /builder-reauth — refresh an expired Bongos CLI session the UI-first way (no terminal Device Flow)
@@ -405,11 +403,9 @@ tests/
405
403
  ├── builder-release/SKILL.md ← /builder-release — abandon a claim (task returns to ready, no credits)
406
404
  ├── builder-sequence/SKILL.md ← /builder-sequence N — walk a whole dependency chain from one kickoff (claim → build → ship → next), one claim at a time; halts and reports on migration/security/protected-path/thin-spec/judgement tasks (scripts/gds/sequence.js, task 1002484)
407
405
  ├── builder-setup/SKILL.md ← /builder-setup — one-time GitHub Device Flow auth (Bongos); multi-builder-on-one-device gate
408
- ├── builder-ship/SKILL.md ← /builder-ship — record + award credits (runs touches[] scanner; warns on drift; sandbox-first review gate on dev boxes, ADR 0046)
409
- ├── builder-stage/SKILL.md ← /builder-stage — stage work on the builder's sandbox (sandbox-<login>) for browser review before shipping (#927, ADR 0046)
406
+ ├── builder-ship/SKILL.md ← /builder-ship — record + award credits (runs touches[] scanner; warns on drift; sandbox-first review gate for game-surface changes, ADR 0046)
407
+ ├── builder-stage/SKILL.md ← /builder-stage — stage work on the builder's own local sandbox preview (http://localhost:<port>) for browser review before shipping (#927, ADR 0046)
410
408
  ├── builder-start/SKILL.md ← /builder-start — list claimable tasks (parallel-safe vs active claims)
411
- ├── builder-sync/SKILL.md ← /builder-sync — 'sync now': re-run the box source-fetch on demand so a freshly-claimed task's code lands within seconds, re-scoped to the active claim (BV1.R96, ADR 0148)
412
- ├── close-box/SKILL.md ← /close-box — tear down the dev box you're working on, from inside the box terminal (POST /box/close)
413
409
  ├── design/SKILL.md ← /design — the UI design session: the operating playbook for ui-discipline work on ANY instance (load the instance's pack + DESIGN.md first, look before you ship, build inside the platform floors, ship the tests with the UI); routed from a `ui` claim via discipline-modes.json; shipped by the ui-design module (task 1003324, ADR 0197)
414
410
  ├── design-sync/SKILL.md ← /design-sync — export repo design tokens + surfaces into Claude Design (token-preview bundle) and land generated UI code back as a Bongos task (ADR 0081)
415
411
  ├── feedback/SKILL.md ← /feedback — pull the latest Bongos feedback bundle (prompt.md + screenshot file paths) into a Claude Code session; backed by scripts/gds/feedback-latest.js (BV1.R13, ADR 0087)
@@ -2028,5 +2028,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2028
2028
  landed since 1.19.775 with no explicit bump. run 35135604764. (task 1002620)
2029
2029
  1.19.777 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2030
2030
  landed since 1.19.776 with no explicit bump. run 35137334438. (task 1002620)
2031
+ 1.19.778 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2032
+ landed since 1.19.777 with no explicit bump. run 35139523999. (task 1002620)
2031
2033
  ---------------------------------------------------------------------------
2032
2034
  ```
@@ -42,8 +42,6 @@ Every one of these talks to the build system. They're grouped by when you'd reac
42
42
  | `/builder-setup` | One-time enrolment — signs you in and registers you |
43
43
  | `/builder-reauth` | Refresh an expired session |
44
44
  | `/builder-key` | Check / set your own API key status |
45
- | `/builder-box` | Your dev box control panel — wake, create, check cost |
46
- | `/builder-connect` · `/builder-sync` · `/close-box` | Connect to, re-sync, and tear down that box |
47
45
  | `/builder-cost` | Log a cost entry against your claim |
48
46
  | `/builder-backup` | Check or trigger a database backup before risky work |
49
47
  | `/builder-exit` | Offboard or reactivate a builder *(Archon only)* |
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.777",
3
+ "version": "1.19.778",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.777",
9
+ "version": "1.19.778",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.777",
3
+ "version": "1.19.778",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
package/src/module-api.js CHANGED
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
71
71
  // there. scripts/gds/bump-version.js still rewrites the literal below; it appends
72
72
  // the entry to that file. Look for a version's history there, not here.
73
73
  // ---------------------------------------------------------------------------
74
- const CORE_VERSION = '1.19.777'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
74
+ const CORE_VERSION = '1.19.778'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
75
75
 
76
76
  // A namespaced logger so a module's log lines are attributable + consistent.
77
77
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -1,59 +0,0 @@
1
- ---
2
- name: builder-box
3
- description: >-
4
- Show the builder their OWN dev box — state, address, cost, keys — and get them back on it. Own-scoped; never parks or destroys a box. Triggers: "/builder-box", "is my box up", "wake my box", "what's my sandbox URL".
5
- ---
6
-
7
- You are showing a builder the status of **their own** dev box and helping them get (back) onto it. This is a read-only, own-scoped helper — it never mutates infrastructure (provision / park / wake / deprovision live on the operator control plane, `node scripts/gds/box.js`, gated by rank).
8
-
9
- ## Background
10
-
11
- The per-builder box lifecycle (ADR 0031 §2) auto-suspends when idle (snapshot-and-park) and recreates on demand, so a builder's box is often `parked` between sessions — that's normal and cheap, not a problem. **The idle sweep parks; it does not destroy** (task 1002726 — it *did* destroy droplet and snapshot for a long stretch, so a builder who remembers losing work that way is remembering something real that is now fixed). Full reclaim happens only after `BOX_DORMANT_DAYS` (14) parked, and **only after a warning was actually delivered** — an unwarned box is deferred, not reclaimed (task 1002727). The read API:
12
- - `GET /api/gds/box/me` → the caller's box: `state`, `scope`, `ip`, `hostname`, cost, activity timestamps.
13
- - `GET /api/gds/box/ssh-key` → the caller's registered SSH keys (fingerprints + labels).
14
- - `GET /api/gds/box/terminal` → the caller's active box's browser-terminal `url` + basic-auth `credential` (the Chromebook/browser on-ramp, ADR 0038), once the box has published them.
15
-
16
- **The hands-off on-ramp (#701).** A builder no longer needs an operator to get or wake a box. `POST /api/gds/box/ensure` is the "make my box ready" button: it **auto-provisions** if they have no box, or **wakes** a parked one — by queuing a request the control plane runs within ~1 min (the web server never touches DigitalOcean directly). For a Chromebook, after `ensure` reports `active`, `GET /box/terminal` returns the terminal `url` + `credential` (ADR 0038) to open in the browser.
17
-
18
- ## How to use
19
-
20
- 1. **Fetch the box + keys + the resolved scope** (own-scoped; uses the builder's session token):
21
- ```bash
22
- node -e 'const{apiCall}=require("./scripts/gds/cli-lib");(async()=>{for(const p of ["/api/gds/box/me","/api/gds/box/ssh-key","/api/gds/box/scope"]){const r=await apiCall("GET",p);console.log(p,r.status,JSON.stringify(r.data));}})()'
23
- ```
24
- (If the script returns "no Bongos session", run `/builder-setup` first.)
25
-
26
- **Always report the scope, not just the state** (task 1002731). `/box/scope` returns `{scope, modules, sparse_paths, task_scope}`, and a too-narrow box is otherwise a *silent* failure — the builder sees a working box that is quietly missing the code they need. Read it out:
27
- - `scope: 'task'` → name the modules: *"your box holds dev-box, hall-ui — and nothing else."*
28
- - `scope: 'base'` → **say plainly that the box has no `modules/` code at all.** With no active claim that is expected; claiming a task and running `/builder-sync` fixes it.
29
- - `scope: 'full'` with `modules: []` → the task-1002729 fallback fired: they hold claims, but those claims' goals declare no `scope_modules`, so the box fell back to their rank. Usable, but task-scoping is not actually doing anything — setting the goal's wall would give a tighter box.
30
- - `scope: 'starter'` → the fixed newcomer slice, not scoped to their claim.
31
-
32
- 2. **Relay it in plain language:**
33
- - **state = `none`** → they have no box yet. On a Mac/Windows: run `/builder-connect` (registers their SSH key + installs the Desktop file). To actually create the box hands-off, `POST /api/gds/box/ensure` queues the auto-provision (no operator CLI needed). *(The old path — ask an operator to `box.js onboard <login>` — still works but is no longer required.)*
34
- - **state = `active`** → box is up at `hostname` (`ip`). They can connect from Claude Desktop → Code → Environment → "Example Dev Box". For a browser/Chromebook (ADR 0038), the terminal comes from the web: `GET /api/gds/box/terminal` returns a `url` + a basic-auth `credential` (username `otb`, password = <redacted>; open the url, enter them, then type `claude` in the terminal. No SSH needed.
35
- - **Live game preview — the sandbox (ADR 0044).** If `/box/terminal` returns a `url` (i.e. the box is on the named tunnel), the builder also has a private live preview of the game running on their own box, at the **same hostname with `term-` swapped for `sandbox-`** — e.g. terminal `https://term-<login>.example.com` → preview `https://sandbox-<login>.example.com`. It serves their working copy of the game (degraded — fully playable, no saved state), so they can review changes in a browser **without shipping to prod**. The loop: edit in the terminal → run **`/builder-stage`** (or `box-preview restart`) → refresh the preview tab. Staging via `/builder-stage` also records the review marker that `/builder-ship`'s sandbox-first gate checks (#927, ADR 0046) — on a dev box, game changes are staged + reviewed on the sandbox before they ship to the main game. `box-preview status` shows whether it's up + the URL; `box-preview logs` tails the server. (No preview on a quick-tunnel box — that path can't carry the game port; it needs the named tunnel.)
36
- - **state = `parked`** → idle-suspended (cheap, expected). It wakes on demand: `POST /api/gds/box/ensure` queues the wake and it's back in ~1 min (no operator needed). Their data IS safe in the snapshot — say so plainly, and mean it: the idle path preserves the filesystem, and the only thing that deletes the snapshot warns them first with days of lead time.
37
- - **state = `destroyed`** → the box is genuinely gone, and so is anything uncommitted on it. This is NOT the idle path — it means they closed it themselves, an operator deprovisioned it, or it sat parked past the dormancy window after being warned. `POST /box/ensure` gives them a **fresh** box, not their old one; don't imply otherwise.
38
- - **state = `provisioning` / `waking`** → in flight; check back in a minute.
39
- - **state = `error`** → flag it to an operator (don't try to fix infra from here).
40
- - **SSH keys** → list the fingerprints + labels. If empty, they haven't connected yet → `/builder-connect`. They can remove a stale key with `DELETE /api/gds/box/ssh-key/:id` (own-scoped).
41
-
42
- 3. **Cost framing (if asked):** a box only bills compute while `active`; parked costs ~$0.30/mo (just the snapshot). The number in `compute_cost_usd` is their box's running total.
43
-
44
- ## Constraints
45
-
46
- - **`POST /box/ensure` is the only mutation a builder may trigger** — and it only *queues* an auto-provision/wake of their **own** box (rank-gated, one open request at a time); the web server never touches DigitalOcean. Never call provision/park/wake/**deprovision** directly — those are operator control-plane commands (`node scripts/gds/box.js`), rank-gated. If the builder wants their box destroyed, that's an operator action.
47
- - **Own resource only.** `/box/me` and `/box/ssh-key` are scoped to the caller. The full roster (`GET /api/gds/boxes`) is Metic+ (`box.fleet.manage`, metic-floored since ADR 0157) — don't try it for a sub-Metic builder.
48
- - **Don't print the SSH private key** — these endpoints only ever return public fingerprints, never private material. Keep it that way.
49
-
50
- ## Quirks on the box (verified from ssh sessions)
51
-
52
- - **`sharp` resolves only from `/workspace`.** Run image-pipeline tooling (art gen, thumbnailing) from `/workspace` — invoking it from another cwd on the box fails to resolve the native binding.
53
- - **Playwright MCP writes screenshots to `.playwright-mcp/` relative to the server's cwd**, not the caller's — look there first when a screenshot path seems to have gone missing.
54
- - **The Bash tool's cwd persists between calls on the box.** A bare `cd x` silently shifts every later command in the session; prefer absolute paths over `cd`-then-relative sequences.
55
-
56
- ## Files this skill touches
57
-
58
- - Calls: `/api/gds/box/me`, `/api/gds/box/ssh-key` (read), `/api/gds/box/terminal` (read), optionally `POST /api/gds/box/ensure` (queue auto-provision/wake) or `DELETE /api/gds/box/ssh-key/:id`
59
- - Reads: `~/.config/otb/gds-session.json` (the session token, via cli-lib)
@@ -1,60 +0,0 @@
1
- ---
2
- name: builder-connect
3
- description: >-
4
- Connect Claude Desktop to the builder's dev box: GitHub sign-in, SSH key, connection file, then restart Desktop. Builder side only. Triggers: "/builder-connect", "connect me to the dev box", "set up my dev box", "onboard me to the box".
5
- ---
6
-
7
- You are guiding a builder through connecting their **own machine's** Claude Desktop to their org dev box. The audience is often non-technical — narrate each step in plain language, and never make them hand-edit files or paste keys around. One command does everything.
8
-
9
- ## Background (the mental model — ADR 0031)
10
-
11
- Claude Code is three pieces: the **screen** (their device — always local), the **worker** (the dev box — where the repo + work live), and the **brain** (Anthropic's servers). This skill wires the screen to the box. The box itself is provisioned by an operator with `node scripts/gds/box.js onboard <login>`; this skill is the builder's half — it registers their SSH key and installs the Desktop connection file so the box shows up as a one-click "Environment".
12
-
13
- What the bootstrap does, in order:
14
- 1. **GitHub sign-in** (device flow against Bongos — it prints a short code + a URL to open).
15
- 2. **Creates an SSH key** at `~/.ssh/otb_builder` if absent (the private half never leaves their machine).
16
- 3. **Registers the public key** with Bongos (`POST /box/ssh-key`). The box pulls it into `authorized_keys` itself — no operator SSH round-trip.
17
- 4. **Downloads + installs** the Claude Desktop connection file (`managed-settings.json`) at the OS path.
18
-
19
- ## How to use
20
-
21
- 1. **Decide which command to run.** Both do the same thing; pick by where you're running:
22
- - **Repo is present locally** (you can see `infra/box-connect.sh`): run the local copy —
23
- ```bash
24
- bash infra/box-connect.sh
25
- ```
26
- - **No repo** (a bare laptop with only Claude Desktop): run the hosted bootstrap —
27
- - macOS / Linux:
28
- ```bash
29
- curl -fsSL https://example.com/api/gds/box/connect.sh | bash
30
- ```
31
- - Windows (PowerShell):
32
- ```powershell
33
- irm https://example.com/api/gds/box/connect.ps1 | iex
34
- ```
35
- (For staging, swap the host — or set `GDS_API_BASE` before the local script.)
36
-
37
- 2. **Relay the GitHub code + URL verbatim.** The script prints a short user code and a `https://github.com/login/device` URL. The builder must open the URL and enter the code. Do not summarize — they need the literal values. The script also tries to pop the URL open automatically.
38
-
39
- 3. **Wait while it polls.** After they approve in the browser, the script registers the key and installs the connection file. On macOS the install step needs **one `sudo` prompt** (the file lives under `/Library/Application Support/ClaudeCode` — the dir Claude Code actually reads managed settings from; `…/Claude/` is silently ignored).
40
-
41
- 4. **Confirm the finish state and give the next steps:**
42
- - Tell their operator they're registered (so the operator runs `box.js onboard <login>` to provision the box, if not already done).
43
- - **Restart Claude Desktop.**
44
- - Open **Code → Environment → "Example Dev Box"** to connect.
45
-
46
- 5. **Once they're on the box**, the first thing to do there is authenticate the Bongos CLI (`/builder-setup` or `node scripts/gds/setup.js`) so the box can pull rank-scoped source and keep their SSH keys in sync.
47
-
48
- ## Constraints
49
-
50
- - **Never print or save the SSH private key or Bongos token anywhere except where the script puts them.** The private key stays at `~/.ssh/otb_builder`; the token is held only in memory on the laptop for the two authenticated calls (it is NOT persisted there — the box gets its own session when they authenticate Claude Code on it).
51
- - **Don't re-generate a key if `~/.ssh/otb_builder` already exists** — the script reuses it. Overwriting would break an existing box connection. (The script handles this; don't override it.)
52
- - **If `auth_not_configured` comes back**, Bongos has no GitHub OAuth app — stop and point them to an Archon (`blockers/blockers.md#github-oauth-app`). Don't loop.
53
- - **Memory + credits are server-side** (ADR 0024) — reassure the builder that nothing about which box they land on affects their history.
54
-
55
- ## Files this skill touches
56
-
57
- - Runs: `infra/box-connect.sh` (or the hosted `GET /api/gds/box/connect.sh` / `.ps1`)
58
- - Reads/creates: `~/.ssh/otb_builder` (+ `.pub`)
59
- - Writes (macOS): `/Library/Application Support/ClaudeCode/managed-settings.json`; (Windows): `%ProgramFiles%\ClaudeCode\managed-settings.json` — the dir Claude Code reads managed settings from. **Not** `…/Claude/` or `%ProgramData%\Claude\`, which the app ignores (the box then never appears in the Environment picker).
60
- - Calls: `/api/gds/auth/device/{start,poll}`, `/api/gds/box/ssh-key`, `/api/gds/box/managed-settings`
@@ -1,42 +0,0 @@
1
- ---
2
- name: builder-sync
3
- description: >-
4
- Re-fetch the dev box's source now instead of waiting for the ~10-min cron. Runs ON the box. Triggers: "/builder-sync", "sync my box", "re-scope my box", "pull my task's code now", or right after "/builder-claim N".
5
- ---
6
-
7
- **Script skill (authoritative).** The core action is `node scripts/gds/box-sync.js`. Run it and relay its output verbatim.
8
-
9
- You are re-running the dev box's source-fetch **on demand** (BV1.R96, goal 1000051 — task-scoped dev box). The box normally re-fetches on a ~10-min cron; this makes it instant.
10
-
11
- ## Why this exists
12
-
13
- A builder's box holds only the code for their **active claim** (ADR 0148 task-scoping): `GET /box/source-access` returns the sparse-checkout set for the modules the claimed task's goal scopes. The box applies that via `infra/box-source-fetch.sh`, on a cron every ~10 min. So right after `/builder-claim N`, the *new* task's code isn't on the box yet — until the next cron tick.
14
-
15
- `box-sync.js` re-runs that fetch **now**. Because the fetch re-reads `/box/source-access`, it **re-scopes the box in place** to whatever the builder currently holds a claim on — seconds after claiming, not ~10 minutes later. The cron stays the backstop.
16
-
17
- ## How to use
18
-
19
- 1. **Run it** (on the box):
20
- ```
21
- node scripts/gds/box-sync.js
22
- ```
23
- Add `--dry-run` to print what it would run without fetching.
24
-
25
- 2. **Relay the output.** On success it prints `sync: done — your box now holds the code for your active claim.` The sparse-checkout is now scoped to the active claim's modules (plus the base instance).
26
-
27
- 3. **Typical flow:** `/builder-claim N` → `/builder-sync` → the box now has task N's module code; open the working folder and start.
28
-
29
- ## Failure modes
30
-
31
- - **`no infra/box-source-fetch.sh found`** — you are **not on a dev box** (off a box your source *is* your local checkout, so there's nothing to sync). This is expected on a laptop; the skill exits non-zero and says so.
32
- - **The fetch itself errors** — the underlying `box-source-fetch.sh` output is passed through verbatim (e.g. a credential/rank issue surfaces there); relay it and, if it's a rank/claim problem, check the active claim with `/builder-start`.
33
-
34
- ## Constraints
35
-
36
- - **Runs on the box only.** It re-runs the box-side fetch; it does not push, claim, or change scope by itself — scope follows the builder's active claim (change scope by claiming a different task, then sync).
37
- - **Idempotent + safe.** Re-running is harmless; the cron does the same thing on its own schedule.
38
-
39
- ## Files this skill touches
40
-
41
- - Runs: `scripts/gds/box-sync.js` → `infra/box-source-fetch.sh` (on the box)
42
- - Reads (indirectly, via the fetch): `GET /box/source-access`
@@ -1,44 +0,0 @@
1
- ---
2
- name: close-box
3
- description: >-
4
- Tear down the dev box you are working on, from inside its terminal. Own-scoped — never another builder's box and never any other infrastructure. Triggers: "/close-box", "close my box", "shut down this box", "I'm done with this box", "tear down my dev box".
5
- ---
6
-
7
- You are closing (deprovisioning) the dev box the builder is currently working on. This is the Claude-side twin of the `close-box` shell command (`infra/close-box.sh`) — same endpoint, for builders who'd rather say "/close-box" inside `claude` than drop to the shell. It is own-scoped and destructive (the box is destroyed), so confirm before firing.
8
-
9
- ## Background
10
-
11
- A per-builder dev box (ADR 0031 §2) is a DigitalOcean droplet. Closing it enqueues a `deprovision` intent that the control-plane runner executes within ~a minute. The box's disk is gone after that — anything in `/workspace` that was not pushed to its remote is lost. The box is cheap to recreate from the builders' hall ("Request dev box" / `/builder-box`), so closing when done is the right cost hygiene; the idle-suspend sweep would otherwise park it automatically after the idle window.
12
-
13
- The endpoint:
14
- - `POST /api/gds/box/close` → enqueues `deprovision` for the **caller's own** box (`auth.requireBuilder`, own resource). Idempotent-ish: if there's no active box it just no-ops.
15
-
16
- ## What this skill does
17
-
18
- Calls `POST /api/gds/box/close` via the cross-platform helper, after confirming with the builder.
19
-
20
- ## How to use
21
-
22
- 1. **Confirm intent.** Ask plainly: "Close (deprovision) your dev box? Any work in `/workspace` you haven't pushed will be lost." Proceed only on a clear yes. If the builder only wants to stop *using* it for now (not destroy it), tell them they can just close the tab — with session persistence (#893) their work survives and the box auto-parks when idle — and do NOT close it.
23
-
24
- 2. **Fire the close:**
25
- ```
26
- node scripts/gds/api.js POST /api/gds/box/close
27
- ```
28
- (The helper resolves the Bongos session token + API base itself; no manual token handling.)
29
-
30
- 3. **Relay the outcome.** On success tell the builder:
31
- - The box is closing now (a few seconds).
32
- - They can close the browser tab — and if the builders'-hall tab is still open in the background, it auto-closes the terminal tab for them when it sees the box shut down (`modules/hall-ui/public/box-panel.js`). This skill cannot close the tab itself (it has no browser control).
33
- - They can provision a fresh box anytime from the hall or with `/builder-box`.
34
-
35
- ## Constraints
36
-
37
- - **Own box only.** This never deprovisions another builder's box. Operator-scoped lifecycle (provision / park / wake / destroy-any) lives in `node scripts/gds/box.js`, gated by rank — not here.
38
- - **Don't auto-close without a yes.** It is destructive.
39
- - **It cannot close the browser tab.** Be honest about that — see the relay step.
40
-
41
- ## Files this skill touches
42
-
43
- - Reads: `~/.config/otb/gds-session.json`
44
- - Calls: `POST /api/gds/box/close`