@babylonjs-toolkit/agent 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +344 -0
- package/bin/bt-agent.js +266 -0
- package/lib/doctor.js +59 -0
- package/lib/install.js +145 -0
- package/lib/manifest.js +46 -0
- package/lib/paths.js +66 -0
- package/lib/payload.js +56 -0
- package/lib/persona.js +177 -0
- package/lib/targets.js +105 -0
- package/package.json +43 -0
- package/persona.md +5 -0
- package/scripts/postinstall.js +49 -0
- package/skills/bt-atlas/SKILL.md +192 -0
- package/skills/bt-atlas/scripts/composite_skin.py +58 -0
- package/skills/bt-atlas/scripts/preview.py +70 -0
- package/skills/bt-atlas/scripts/requirements.txt +2 -0
- package/skills/bt-atlas/scripts/uv_island_mask.py +87 -0
- package/skills/bt-convert/SKILL.md +32 -0
- package/skills/bt-copycat/SKILL.md +184 -0
- package/skills/bt-design/SKILL.md +187 -0
- package/skills/bt-design/references/3d-hero-docs.md +976 -0
- package/skills/bt-design/references/3d-hero-scroll.md +269 -0
- package/skills/bt-design/templates/3d-hero-scroll/HeroScroll.tsx +167 -0
- package/skills/bt-design/templates/3d-hero-scroll/hero-scroll.css +268 -0
- package/skills/bt-design/templates/3d-hero-scroll/hero-scroll.d.ts +67 -0
- package/skills/bt-design/templates/3d-hero-scroll/hero-scroll.html +78 -0
- package/skills/bt-design/templates/3d-hero-scroll/hero-scroll.js +559 -0
- package/skills/bt-execute/SKILL.md +130 -0
- package/skills/bt-gauntlet/SKILL.md +335 -0
- package/skills/bt-hero/SKILL.md +158 -0
- package/skills/bt-landing/SKILL.md +126 -0
- package/skills/bt-plan/SKILL.md +172 -0
- package/skills/bt-prototype/SKILL.md +161 -0
- package/skills/bt-spec/SKILL.md +328 -0
package/README.md
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# Babylon Toolkit Agent Skills (1.0.0)
|
|
2
|
+
|
|
3
|
+
Universal [Agent Skills](https://agentskills.io) for the `Babylon Toolkit` web game development framework.
|
|
4
|
+
Each `SKILL.md` follows the open standard, so the **same file works unchanged** in Claude Code, Codex CLI, and GitHub Copilot.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install -g @babylonjs-toolkit/agent
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
or, without installing anything globally:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @babylonjs-toolkit/agent install
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
That installs **every skill** into every skills directory and the **Agent Persona** into every
|
|
19
|
+
global instruction file, on macOS, Linux and Windows. Then restart your agent session — skills
|
|
20
|
+
and instruction files are only read at session start.
|
|
21
|
+
|
|
22
|
+
### Commands
|
|
23
|
+
|
|
24
|
+
| Command | What it does |
|
|
25
|
+
|---------|--------------|
|
|
26
|
+
| `bt-agent install` | Install skills + persona into every target (the default) |
|
|
27
|
+
| `bt-agent update` | Reinstall, and remove skills this package no longer ships |
|
|
28
|
+
| `bt-agent uninstall` | Remove what it installed — and nothing else |
|
|
29
|
+
| `bt-agent doctor` | Verify the install; prints `INSTALL OK` or lists what is missing |
|
|
30
|
+
| `bt-agent targets` | Show every target and the paths it writes to |
|
|
31
|
+
|
|
32
|
+
| Option | Effect |
|
|
33
|
+
|--------|--------|
|
|
34
|
+
| `--project` | Install into the current directory instead of your home directory |
|
|
35
|
+
| `--targets claude,agents` | Restrict to specific targets |
|
|
36
|
+
| `--legacy-codex` | Also write `~/.codex/skills` for pre-`.agents` Codex builds |
|
|
37
|
+
| `--no-persona` | Install skills only; leave instruction files alone |
|
|
38
|
+
| `--persona-only` | Install/refresh the Agent Persona only; do not copy skills |
|
|
39
|
+
| `--dry-run` | Print what would happen and change nothing |
|
|
40
|
+
| `--json` | Machine-readable output |
|
|
41
|
+
|
|
42
|
+
### What it writes
|
|
43
|
+
|
|
44
|
+
| Target | Skills | Agent Persona |
|
|
45
|
+
|--------|--------|---------------|
|
|
46
|
+
| Claude Code | `~/.claude/skills/` | `~/.claude/CLAUDE.md` |
|
|
47
|
+
| Codex / Copilot / Antigravity | `~/.agents/skills/` | `~/.agents/AGENTS.md` |
|
|
48
|
+
| Codex chat clients | — | `~/.codex/AGENTS.md` |
|
|
49
|
+
| Gemini CLI | — | `~/.gemini/GEMINI.md` |
|
|
50
|
+
| Legacy Codex CLI (`--legacy-codex`) | `~/.codex/skills/` | — |
|
|
51
|
+
|
|
52
|
+
Gemini CLI is a separate entry on purpose: it reads `GEMINI.md`, **not** `AGENTS.md`, so
|
|
53
|
+
`~/.agents/AGENTS.md` alone never reaches it.
|
|
54
|
+
|
|
55
|
+
Your instruction files are never truncated. The persona goes in as a managed block:
|
|
56
|
+
|
|
57
|
+
```markdown
|
|
58
|
+
<!-- BEGIN BABYLON TOOLKIT PERSONA v1 -->
|
|
59
|
+
...
|
|
60
|
+
<!-- END BABYLON TOOLKIT PERSONA -->
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Re-running rewrites only what is between those markers, so the persona can be revised in a
|
|
64
|
+
later release while everything else in the file is left exactly as you wrote it. An older
|
|
65
|
+
unmarked persona is converted to a managed block automatically; a persona you have reworded
|
|
66
|
+
yourself is detected and left alone. Every modified file is backed up to `<file>.bak` first.
|
|
67
|
+
|
|
68
|
+
Skill folders are tracked in `~/.babylon-toolkit/install-manifest.json`, so `update` and
|
|
69
|
+
`uninstall` only ever touch folders this package installed — a skill you wrote yourself that
|
|
70
|
+
happens to be named `bt-something` is safe.
|
|
71
|
+
|
|
72
|
+
## Skills
|
|
73
|
+
|
|
74
|
+
| Skill | Command | What it does |
|
|
75
|
+
|-------|---------|--------------|
|
|
76
|
+
| [`bt-spec`](skills/bt-spec/SKILL.md) | `/bt-spec` | Turn a short idea into a feature spec file on a new git branch. |
|
|
77
|
+
| [`bt-plan`](skills/bt-plan/SKILL.md) | `/bt-plan` | Produce a detailed, task-checklist technical plan from a spec. |
|
|
78
|
+
| [`bt-execute`](skills/bt-execute/SKILL.md) | `/bt-execute` | Implement one task (or all remaining tasks) from a plan/spec. |
|
|
79
|
+
| [`bt-convert`](skills/bt-convert/SKILL.md) | `/bt-convert` | Convert source code to Babylon Toolkit TypeScript. |
|
|
80
|
+
| [`bt-copycat`](skills/bt-copycat/SKILL.md) | `/bt-copycat` | Re-create the specified website adapted to specified genre. |
|
|
81
|
+
| [`bt-landing`](skills/bt-landing/SKILL.md) | `/bt-landing` | Re-design the landing page, splash screen, preloader and custom overlays. |
|
|
82
|
+
| [`bt-gauntlet`](skills/bt-gauntlet/SKILL.md) | `/bt-gauntlet` | Agent based gauntlet loop engineering. ([usage guide](gauntletusage.md)) |
|
|
83
|
+
| [`bt-prototype`](skills/bt-prototype/SKILL.md) | `/bt-prototype` | Create any number of award winning frontend prototypes. |
|
|
84
|
+
| [`bt-design`](skills/bt-design/SKILL.md) | `/bt-design` | Implement high quality frontend and in-game designs. |
|
|
85
|
+
| [`bt-hero`](skills/bt-hero/SKILL.md) | `/bt-hero` | Create smooth cinematic 3D scrolling hero sections. |
|
|
86
|
+
| [`bt-atlas`](skills/bt-atlas/SKILL.md) | `/bt-atlas` | Generate texture atlas skin variations. |
|
|
87
|
+
|
|
88
|
+
Every tool derives the slash-command from the **folder name** (`bt-spec/` → `/bt-spec`) and reads
|
|
89
|
+
the frontmatter `name` + `description` to decide when the skill applies. The `allowed-tools`
|
|
90
|
+
line is honored by Claude Code (auto-approves those tools) and safely ignored by Codex and
|
|
91
|
+
Copilot.
|
|
92
|
+
|
|
93
|
+
## Universal Installations
|
|
94
|
+
|
|
95
|
+
Where each tool looks for GLOBAL skills (**Default Installation** — `~` = your home directory):
|
|
96
|
+
|
|
97
|
+
| Tool | macOS / Linux | Windows |
|
|
98
|
+
|------|---------------|---------|
|
|
99
|
+
| Claude Code | `~/.claude/skills/` | `%USERPROFILE%\.claude\skills\` |
|
|
100
|
+
| OpenAI Codex | `~/.agents/skills/` | `%USERPROFILE%\.agents\skills\` |
|
|
101
|
+
| GitHub Copilot | `~/.agents/skills/` | `%USERPROFILE%\.agents\skills\` |
|
|
102
|
+
| Gemini CLI / Antigravity | `~/.agents/skills/` | `%USERPROFILE%\.agents\skills\` |
|
|
103
|
+
|
|
104
|
+
> On macOS `~` expands to `/Users/<user>/`, on Linux to `/home/<user>/`,
|
|
105
|
+
> and on Windows `%USERPROFILE%` expands to `C:\Users\<user>\`.
|
|
106
|
+
|
|
107
|
+
Where each tool looks for PROJECT-LOCAL skills (only when the user explicitly requests a project install):
|
|
108
|
+
|
|
109
|
+
| Tool | Project skills directory |
|
|
110
|
+
|------|--------------------------|
|
|
111
|
+
| Claude Code | `.claude/skills/` |
|
|
112
|
+
| OpenAI Codex | `.agents/skills/` |
|
|
113
|
+
| GitHub Copilot | `.agents/skills/` |
|
|
114
|
+
| Gemini CLI / Antigravity | `.agents/skills/` |
|
|
115
|
+
|
|
116
|
+
> **Note:** Install skills into **BOTH** the `.claude/skills/` and `.agents/skills/`
|
|
117
|
+
> locations for maximum coverage — `.claude/skills/` for Claude Code, `.agents/skills/`
|
|
118
|
+
> for everything else (Codex, Copilot, Gemini CLI, Antigravity). By default use the
|
|
119
|
+
> GLOBAL (per-user home) locations; use the project-local locations only when the user
|
|
120
|
+
> explicitly asks for a project install. Copy **whole folders** into each — the
|
|
121
|
+
> `bt-atlas/scripts/` assets must be present in every location.
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# Babylon Toolkit Loop Engineering (Gauntlet Loop)
|
|
125
|
+
|
|
126
|
+
**What it is in one line:** you give it a game brief and a quality bar; it interviews you, writes a loop card, then runs rounds of *build → capture real browser evidence → fresh harsh critic vs your reference (blind A/B) → record* until the success condition passes or a boundary fires — building with **BabylonJS + the Babylon Toolkit, never Three.js**. All state lives in `_gauntlet/<name>/`, so you can stop any time and resume days or weeks later.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 1. Start a new gauntlet (the normal way)
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
/bt-gauntlet I want you to build a first-person shooter at the level of the most
|
|
134
|
+
recent Call of Duty games. It should be utterly perfect, visually beautiful, with
|
|
135
|
+
every single thing done at AAA quality—from textures to physics to anything you
|
|
136
|
+
could think of.
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
What happens:
|
|
140
|
+
|
|
141
|
+
1. It derives a job name from the brief (e.g. `cod-fps`) and runs the **interview** — deliverable, objective, reference/benchmark media (attach screenshots!), success condition, boundaries, Babylon-specific game questions, loop mechanics.
|
|
142
|
+
2. It shows you the filled **loop card** and waits for your confirmation.
|
|
143
|
+
3. It runs up to **5 rounds** (the default session cap), then parks with a status report and the exact resume command.
|
|
144
|
+
|
|
145
|
+
Name it yourself and pick the template explicitly:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
/bt-gauntlet --name:cod-fps --template:gauntlet I want you to build a first-person shooter ...
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Attach reference screenshots/clips with the message — they become the critics' benchmark in `_gauntlet/cod-fps/reference/`.
|
|
152
|
+
|
|
153
|
+
## 2. Choose a template
|
|
154
|
+
|
|
155
|
+
| | `--template:gauntlet` (default) | `--template:bounded` |
|
|
156
|
+
| --- | --- | --- |
|
|
157
|
+
| Style | Full Shumer-style: decompose into parts, fan out builders, fresh harsh critic per part, blind A/B vs reference | Single-track loop card: one coherent improvement per round against an objective/metric/boundary checklist |
|
|
158
|
+
| Best for | One ambitious visual artifact chasing a reference bar ("CoD-level FPS") | Reliability- and cost-sensitive work with objective verifiers ("60 FPS, zero console errors, all checks green") |
|
|
159
|
+
| Cost profile | Heavier (builder + critic subagents per part) | Lighter (one improvement, one verifier per round) |
|
|
160
|
+
|
|
161
|
+
Both templates live verbatim in the SKILL.md, so you can edit their wording there.
|
|
162
|
+
|
|
163
|
+
## 3. Control how much one session does
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
/bt-gauntlet --rounds:20 --name:cod-fps <brief> # a long night: up to 20 rounds
|
|
167
|
+
/bt-gauntlet --rounds:1 --resume cod-fps # one careful round, then park
|
|
168
|
+
/bt-gauntlet --resume cod-fps # default: up to 5 rounds
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`--rounds:N` caps THIS invocation only. State is persisted after **every** round regardless, so even a hard cutoff (usage limit, closed laptop) loses at most the round in flight.
|
|
172
|
+
|
|
173
|
+
## 4. Stop, check things out, come back later (the resume cycle)
|
|
174
|
+
|
|
175
|
+
This is the core workflow the skill was built for:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
# Tuesday night — start, run 5 rounds, it parks itself
|
|
179
|
+
/bt-gauntlet --name:cod-fps I want you to build a first-person shooter ...
|
|
180
|
+
|
|
181
|
+
# (any time) — peek without running anything
|
|
182
|
+
/bt-gauntlet --status cod-fps
|
|
183
|
+
|
|
184
|
+
# ...daily limit resets, or a week later, brand-new session, zero memory of the chat:
|
|
185
|
+
/bt-gauntlet --resume cod-fps
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`--resume` works because nothing lives in the conversation: the fresh session re-reads the Agent Reference, then `loop-card.md` → `progress.md` → the last round journals, sanity-checks them against the real project, reports "resuming from round N", and executes the recorded `NEXT ACTION`. Budgets count in **rounds/attempts (cumulative across sessions)**, never wall-clock, so a two-week gap changes nothing.
|
|
189
|
+
|
|
190
|
+
Park a job deliberately mid-session:
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
/bt-gauntlet --stop cod-fps
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
You can also just interrupt at any time — parking is only the polite version.
|
|
197
|
+
|
|
198
|
+
## 5. Run several gauntlets side by side
|
|
199
|
+
|
|
200
|
+
Each job owns its own `_gauntlet/<name>/` folder — as many as you like, fully independent budgets, rounds, references, and evidence:
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
/bt-gauntlet --name:cod-fps <FPS brief>
|
|
204
|
+
/bt-gauntlet --name:racing-demo <racing brief>
|
|
205
|
+
|
|
206
|
+
/bt-gauntlet --status # index of ALL jobs, one line each
|
|
207
|
+
/bt-gauntlet --resume racing-demo # continue just that one
|
|
208
|
+
/bt-gauntlet --resume # only ONE job exists → resumes it;
|
|
209
|
+
# several exist → lists them and asks
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
A new gauntlet whose name collides with an existing job is an error — it will offer `--resume <name>` or a different name, never overwrite.
|
|
213
|
+
|
|
214
|
+
## 6. Read the workspace while it's parked
|
|
215
|
+
|
|
216
|
+
Everything is plain markdown/media under `_gauntlet/<name>/` — inspect it in your editor between sessions:
|
|
217
|
+
|
|
218
|
+
| File | What you'll find |
|
|
219
|
+
| --- | --- |
|
|
220
|
+
| `loop-card.md` | The confirmed template: objective, benchmark, success condition, boundaries. The loop never edits it. |
|
|
221
|
+
| `brief.md` | Your full interview answers. |
|
|
222
|
+
| `progress.md` | **The resume brain**: part checklist (`- [ ]` / `- [~]` / `- [x]`), attempt counts, failed-approaches log, budgets spent, and the one-line `NEXT ACTION`. |
|
|
223
|
+
| `rounds/round-NN.md` | Per-round journal: what was built, the critic's verdict and the largest gap it named, evidence links. |
|
|
224
|
+
| `reference/` | Your benchmark screenshots/clips — what critics compare against, blind. |
|
|
225
|
+
| `evidence/` | Captured browser screenshots + perf numbers from our side of the A/B. |
|
|
226
|
+
|
|
227
|
+
Want to redirect the loop? Edit `progress.md`'s `NEXT ACTION` (or part priorities) before resuming — the loop trusts the files.
|
|
228
|
+
|
|
229
|
+
## 7. Skip the interview (`--card:` — non-interactive start)
|
|
230
|
+
|
|
231
|
+
Hand it a **pre-filled loop card** (either template with every slot answered, including `<NAME>`) and it starts immediately, no questions:
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
/bt-gauntlet --card:_specs/racing-game_gauntlet-card.md --rounds:10
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
If any slot is unfilled or vague it STOPS and tells you which — it never guesses. This is the entry point used by the spec workflow below, and handy any time you want to author the card by hand.
|
|
238
|
+
|
|
239
|
+
## 8. Use it with the spec workflow (bt-spec / bt-plan / bt-execute)
|
|
240
|
+
|
|
241
|
+
**The gauntlet contains its own plan — never run bt-plan on gauntlet work.** Its loop card is the spec, its part checklist in `progress.md` is the plan, its rounds are the execution.
|
|
242
|
+
|
|
243
|
+
Rule of thumb:
|
|
244
|
+
|
|
245
|
+
- Acceptance criteria you can enumerate up front, each done in one pass → **bt-spec → bt-plan → bt-execute**.
|
|
246
|
+
- "As good as *that reference*", unknown number of iterations → **bt-gauntlet**.
|
|
247
|
+
|
|
248
|
+
Typical two-phase sequence for a real game:
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
# Phase 1 — foundation (checklist-shaped work: scaffold, controller, physics, HUD)
|
|
252
|
+
/bt-spec <feature brief>
|
|
253
|
+
/bt-plan @_specs/<feature>_spec.md
|
|
254
|
+
/bt-execute @_specs/<feature>_plan.md ALL
|
|
255
|
+
|
|
256
|
+
# Phase 2 — quality (reference-bar work on top of what now exists)
|
|
257
|
+
/bt-gauntlet --name:aaa-polish <polish brief + reference media>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Or fold the gauntlet INTO a spec run by naming it in the brief:
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
/bt-spec Build the racing game, then polish it to Gran Turismo quality using bt-gauntlet
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
In that flow, bt-spec runs the gauntlet interview at spec time and writes the pre-filled card (`_specs/<feature>_gauntlet-card.md`); bt-plan makes the gauntlet the final task invoking `--card:`; bt-execute re-enters a parked job via `--resume <name>` on each `NEXT` and flips the task's checkbox only when the job genuinely reports DONE.
|
|
267
|
+
|
|
268
|
+
## 9. Which method should I use for making games? (recommendation)
|
|
269
|
+
|
|
270
|
+
**Recommendation: the two-phase hybrid — spec/plan/execute for the foundation, then a gauntlet job for the quality bar.** One-shot gauntlet looping is the demo; the hybrid is how you'd actually ship.
|
|
271
|
+
|
|
272
|
+
Here's the reasoning:
|
|
273
|
+
|
|
274
|
+
**Why not one-shot gauntlet from a cold start** (the pure Claude-of-Duty move): it makes the loop do work loops are bad at. Scaffolding, the player controller, physics wiring, input, level loading — these have *crisp, enumerable acceptance* ("Havok is initialized, capsule controller walks the test level at 60 FPS"). Running builder-vs-critic rounds on that is paying five critics to confirm a checkbox. It's also where the loop's weaknesses bite: the decomposition emerges mid-run instead of being engineered, coupled foundation systems tempt bad fan-out, and — worth remembering — even Shumer's original run *never won a single blind A/B against real CoD*. The honest lesson of that experiment is that the demanding reference kept the agent improving; not that one prompt replaces engineering.
|
|
275
|
+
|
|
276
|
+
**Why not spec/plan/execute alone:** it terminates at "acceptance met," which for visuals means "good for AI." There's no mechanism that keeps pushing after the box is checked — no reference comparison, no fresh critic naming the largest gap, no "go again." That's precisely the gap the gauntlet fills.
|
|
277
|
+
|
|
278
|
+
**So the playbook for a real game:**
|
|
279
|
+
|
|
280
|
+
```
|
|
281
|
+
# Phase 1 — foundation (cheap, deterministic, checkbox-resumable)
|
|
282
|
+
/bt-spec <game systems brief>
|
|
283
|
+
/bt-plan @_specs/<feature>_spec.md
|
|
284
|
+
/bt-execute @_specs/<feature>_plan.md ALL
|
|
285
|
+
|
|
286
|
+
# Phase 2 — quality (reference-chasing, critic-judged, round-resumable)
|
|
287
|
+
/bt-gauntlet --name:aaa-polish <polish brief + reference screenshots>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Two refinements on top:
|
|
291
|
+
|
|
292
|
+
1. **Scope each gauntlet job tightly.** Rather than one giant `aaa-polish` job, consider a couple of focused jobs — e.g. `visuals` (lighting, materials, post-processing vs reference frames) and `game-feel` (movement, weapon feedback, hit reactions). Focused jobs give critics sharper rubrics, keep parts genuinely independent for fan-out, and let you park/resume/abandon them separately.
|
|
293
|
+
2. **Reserve true one-shot gauntlet** (`/bt-gauntlet <ambitious brief>` on an empty folder) for what it's genuinely great at: prototypes, jams, and "show me what's possible" experiments where you *want* the decomposition to emerge and the ride is the point. That's the mode the Call-of-Duty example lives in, and it works — it's just not the cost-efficient path to a shippable game.
|
|
294
|
+
|
|
295
|
+
The interplay is already wired for this: phase 2's interview can point its reference media and priorities at exactly what phase 1 built, and if you want it fully hands-off you can fold phase 2 into the spec run itself (`/bt-spec … then polish to <reference> quality using bt-gauntlet`), which pre-fills the loop card and drives it via `--card:` — per section 8 above.
|
|
296
|
+
|
|
297
|
+
## 10. Unattended runs (optional native loop drivers)
|
|
298
|
+
|
|
299
|
+
The gauntlet needs **no** native loop tool — the round protocol is the loop, and `--resume` is the continuation. But because state persists after every round, you can safely layer a host's re-invocation driver *on top* for hands-off runs:
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
# Claude Code — keep re-invoking resume rounds while you sleep
|
|
303
|
+
/loop /bt-gauntlet --resume cod-fps
|
|
304
|
+
|
|
305
|
+
# Hosts with a persistent goal feature (e.g. /goal) — same idea:
|
|
306
|
+
# keep "/bt-gauntlet --resume cod-fps until the job reports DONE" alive across turns
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Why this is safe: whenever the native driver dies — daily/weekly limit, session end, closed laptop — the job is simply *parked*, exactly as if you had stopped it yourself. Nothing is lost beyond the round in flight, and `/bt-gauntlet --resume cod-fps` in a fresh session continues where it left off.
|
|
310
|
+
|
|
311
|
+
Keep the layering straight:
|
|
312
|
+
|
|
313
|
+
| | The native driver (`/loop`, `/goal`) | The gauntlet |
|
|
314
|
+
| --- | --- | --- |
|
|
315
|
+
| Job | *When* to re-poke the agent | *What* a round is: build → evidence → fresh critic → record |
|
|
316
|
+
| Survives session end / limits | No | Yes — `_gauntlet/<name>/` + `--resume` |
|
|
317
|
+
| Portable across hosts | Each host different; some have nothing | Identical everywhere |
|
|
318
|
+
|
|
319
|
+
This is an operator convenience you apply from the outside. The SKILL.md deliberately never references any native loop tool, so the skill stays fully portable — on a host with no such feature, you just re-invoke `--resume` yourself.
|
|
320
|
+
|
|
321
|
+
## 11. How a gauntlet ends
|
|
322
|
+
|
|
323
|
+
In order of precedence, a round's gate check ends things when:
|
|
324
|
+
|
|
325
|
+
1. **Success condition met** → one final fresh **integration critic** inspects the whole game for seams and consistency → report DONE with the evidence summary.
|
|
326
|
+
2. **A loop-card boundary fires** (total rounds exhausted, attempts-per-part hit without a new strategy, repeated blocker, permission needed) → park + escalate to you with specifics.
|
|
327
|
+
3. **The `--rounds` session cap is reached** → park cleanly and print `/bt-gauntlet --resume <name>`.
|
|
328
|
+
|
|
329
|
+
Deploy, spending, credentials, deletion, and messaging are always behind your explicit approval, no matter what the brief says.
|
|
330
|
+
|
|
331
|
+
## Quick reference
|
|
332
|
+
|
|
333
|
+
| Command | Effect |
|
|
334
|
+
| --- | --- |
|
|
335
|
+
| `/bt-gauntlet <brief>` | New gauntlet: interview → confirm card → loop (≤5 rounds) → park |
|
|
336
|
+
| `/bt-gauntlet --name:x --template:bounded --rounds:10 <brief>` | New named job, bounded template, 10-round session |
|
|
337
|
+
| `/bt-gauntlet --card:<file> [--rounds:N]` | New job from a pre-filled card, zero questions |
|
|
338
|
+
| `/bt-gauntlet --resume [x]` | Continue a job in any (brand-new) session |
|
|
339
|
+
| `/bt-gauntlet --status [x]` | Read-only: one job's detail, or the index of all jobs |
|
|
340
|
+
| `/bt-gauntlet --stop [x]` | Park a job deliberately, print its resume command |
|
|
341
|
+
|
|
342
|
+
# Babylon Toolkit Agent Persona (@babylonjs-toolkit/agent)
|
|
343
|
+
|
|
344
|
+
Simply ask your agent to install the `Babylon Toolkit Agent` for you.
|
package/bin/bt-agent.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { install, uninstall } = require('../lib/install');
|
|
5
|
+
const { doctor } = require('../lib/doctor');
|
|
6
|
+
const { TARGETS, targetIds } = require('../lib/targets');
|
|
7
|
+
const { prettyPath } = require('../lib/paths');
|
|
8
|
+
const { version } = require('../package.json');
|
|
9
|
+
|
|
10
|
+
const USAGE = `
|
|
11
|
+
@babylonjs-toolkit/agent ${version}
|
|
12
|
+
|
|
13
|
+
Installs the Babylon Toolkit agent skills and Agent Persona for every
|
|
14
|
+
supported AI client, on macOS, Linux and Windows.
|
|
15
|
+
|
|
16
|
+
Usage
|
|
17
|
+
bt-agent [command] [options]
|
|
18
|
+
|
|
19
|
+
Commands
|
|
20
|
+
install Install skills + persona into every target (default)
|
|
21
|
+
update Same as install, and remove skills no longer shipped
|
|
22
|
+
uninstall Remove what this tool installed, and nothing else
|
|
23
|
+
doctor Verify the install; prints INSTALL OK or INSTALL FAILED
|
|
24
|
+
targets List the available targets and their paths
|
|
25
|
+
|
|
26
|
+
Options
|
|
27
|
+
--project Install into the current directory instead of $HOME
|
|
28
|
+
--targets a,b Only these targets (default: ${TARGETS.filter((t) => t.default).map((t) => t.id).join(',')})
|
|
29
|
+
--legacy-codex Also install into ~/.codex/skills for old Codex builds
|
|
30
|
+
--no-persona Install skills only; do not touch instruction files
|
|
31
|
+
--persona-only Install/refresh the Agent Persona only; do not copy skills
|
|
32
|
+
--no-migrate Leave a legacy unmarked persona in place, do not convert it
|
|
33
|
+
--dry-run Print what would happen; change nothing
|
|
34
|
+
--json Machine-readable output
|
|
35
|
+
-h, --help Show this help
|
|
36
|
+
-v, --version Print the version
|
|
37
|
+
|
|
38
|
+
Examples
|
|
39
|
+
npx @babylonjs-toolkit/agent install
|
|
40
|
+
bt-agent install --legacy-codex
|
|
41
|
+
bt-agent install --project
|
|
42
|
+
bt-agent doctor
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
function parseArgs(argv) {
|
|
46
|
+
const opts = {
|
|
47
|
+
command: null,
|
|
48
|
+
mode: 'global',
|
|
49
|
+
ids: null,
|
|
50
|
+
legacyCodex: false,
|
|
51
|
+
persona: true,
|
|
52
|
+
skills: true,
|
|
53
|
+
migrate: true,
|
|
54
|
+
dryRun: false,
|
|
55
|
+
json: false,
|
|
56
|
+
help: false,
|
|
57
|
+
version: false,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
61
|
+
const arg = argv[i];
|
|
62
|
+
switch (arg) {
|
|
63
|
+
case '-h':
|
|
64
|
+
case '--help':
|
|
65
|
+
opts.help = true;
|
|
66
|
+
break;
|
|
67
|
+
case '-v':
|
|
68
|
+
case '--version':
|
|
69
|
+
opts.version = true;
|
|
70
|
+
break;
|
|
71
|
+
case '--project':
|
|
72
|
+
opts.mode = 'project';
|
|
73
|
+
break;
|
|
74
|
+
case '--legacy-codex':
|
|
75
|
+
opts.legacyCodex = true;
|
|
76
|
+
break;
|
|
77
|
+
case '--no-persona':
|
|
78
|
+
opts.persona = false;
|
|
79
|
+
break;
|
|
80
|
+
case '--persona-only':
|
|
81
|
+
opts.skills = false;
|
|
82
|
+
break;
|
|
83
|
+
case '--no-migrate':
|
|
84
|
+
opts.migrate = false;
|
|
85
|
+
break;
|
|
86
|
+
case '--dry-run':
|
|
87
|
+
opts.dryRun = true;
|
|
88
|
+
break;
|
|
89
|
+
case '--json':
|
|
90
|
+
opts.json = true;
|
|
91
|
+
break;
|
|
92
|
+
case '--targets':
|
|
93
|
+
opts.ids = String(argv[++i] || '').split(',').map((s) => s.trim()).filter(Boolean);
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
if (arg.startsWith('--targets=')) {
|
|
97
|
+
opts.ids = arg.slice('--targets='.length).split(',').map((s) => s.trim()).filter(Boolean);
|
|
98
|
+
} else if (arg.startsWith('-')) {
|
|
99
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
100
|
+
} else if (!opts.command) {
|
|
101
|
+
opts.command = arg;
|
|
102
|
+
} else {
|
|
103
|
+
throw new Error(`Unexpected argument: ${arg}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
opts.command = opts.command || 'install';
|
|
109
|
+
return opts;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const ACTION_LABEL = {
|
|
113
|
+
created: 'created',
|
|
114
|
+
updated: 'updated',
|
|
115
|
+
unchanged: 'already current',
|
|
116
|
+
migrated: 'migrated to managed block',
|
|
117
|
+
prepended: 'persona prepended',
|
|
118
|
+
'legacy-unrecognized': 'SKIPPED — reworded persona, left untouched',
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
function printInstall(report) {
|
|
122
|
+
const what = report.dryRun ? 'Would install' : 'Installed';
|
|
123
|
+
|
|
124
|
+
if (report.skillsInstalled === false) {
|
|
125
|
+
console.log(`\n${what} the Agent Persona only (v${report.version}) — skills untouched.`);
|
|
126
|
+
} else {
|
|
127
|
+
console.log(`\n${what} ${report.skills.length} skills (v${report.version})\n`);
|
|
128
|
+
for (const entry of report.skillDirs) {
|
|
129
|
+
console.log(` skills ${prettyPath(entry.dir)} [${entry.targets.join(', ')}]`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (report.pruned.length) {
|
|
134
|
+
console.log('');
|
|
135
|
+
for (const p of report.pruned) console.log(` pruned ${prettyPath(p)} (no longer shipped)`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (report.persona.length) {
|
|
139
|
+
console.log('');
|
|
140
|
+
for (const p of report.persona) {
|
|
141
|
+
const label = ACTION_LABEL[p.action] || p.action;
|
|
142
|
+
console.log(` persona ${prettyPath(p.file)} — ${label}`);
|
|
143
|
+
if (p.note) console.log(` ${p.note}`);
|
|
144
|
+
if (p.backup) console.log(` backup: ${prettyPath(p.backup)}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function printDoctor(result) {
|
|
150
|
+
const { checked } = result;
|
|
151
|
+
console.log(
|
|
152
|
+
`\nChecked ${checked.skills} skills / ${checked.files} files across ` +
|
|
153
|
+
`${checked.skillDirs.length} skill dir(s) and ${checked.instructionFiles.length} instruction file(s).\n`
|
|
154
|
+
);
|
|
155
|
+
if (result.ok) {
|
|
156
|
+
console.log('INSTALL OK');
|
|
157
|
+
} else {
|
|
158
|
+
console.log('INSTALL FAILED — missing:');
|
|
159
|
+
for (const m of result.missing) console.log(` ${prettyPath(m)}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function printTargets(mode) {
|
|
164
|
+
console.log('');
|
|
165
|
+
for (const t of TARGETS) {
|
|
166
|
+
const spec = mode === 'project' ? t.project : t.global;
|
|
167
|
+
const flag = t.default ? 'default' : 'opt-in ';
|
|
168
|
+
console.log(` [${flag}] ${t.id.padEnd(13)} ${t.label}`);
|
|
169
|
+
if (spec.skills) console.log(` skills: ${spec.skills}`);
|
|
170
|
+
if (spec.instructions) console.log(` instructions: ${spec.instructions}`);
|
|
171
|
+
}
|
|
172
|
+
console.log('');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function main() {
|
|
176
|
+
let opts;
|
|
177
|
+
try {
|
|
178
|
+
opts = parseArgs(process.argv.slice(2));
|
|
179
|
+
} catch (err) {
|
|
180
|
+
console.error(`${err.message}\n\nRun \`bt-agent --help\` for usage.`);
|
|
181
|
+
process.exit(2);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (opts.help) return void console.log(USAGE);
|
|
185
|
+
if (opts.version) return void console.log(version);
|
|
186
|
+
|
|
187
|
+
const common = {
|
|
188
|
+
mode: opts.mode,
|
|
189
|
+
projectRoot: process.cwd(),
|
|
190
|
+
ids: opts.ids,
|
|
191
|
+
legacyCodex: opts.legacyCodex,
|
|
192
|
+
persona: opts.persona,
|
|
193
|
+
skills: opts.skills,
|
|
194
|
+
migrate: opts.migrate,
|
|
195
|
+
dryRun: opts.dryRun,
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
switch (opts.command) {
|
|
200
|
+
case 'install':
|
|
201
|
+
case 'update': {
|
|
202
|
+
const report = install(common);
|
|
203
|
+
const check = doctor(common);
|
|
204
|
+
|
|
205
|
+
if (opts.json) {
|
|
206
|
+
console.log(JSON.stringify({ ...report, doctor: check }, null, 2));
|
|
207
|
+
} else {
|
|
208
|
+
printInstall(report);
|
|
209
|
+
if (!opts.dryRun) {
|
|
210
|
+
console.log('');
|
|
211
|
+
if (check.ok) {
|
|
212
|
+
console.log('INSTALL OK');
|
|
213
|
+
console.log('\nRestart your agent session (Claude Code, Codex, Copilot, Gemini CLI)');
|
|
214
|
+
console.log('so the skills and persona are picked up.\n');
|
|
215
|
+
} else {
|
|
216
|
+
printDoctor(check);
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
console.log('\nDry run — nothing was written.\n');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
process.exit(opts.dryRun || check.ok ? 0 : 1);
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
case 'uninstall': {
|
|
227
|
+
const report = uninstall(common);
|
|
228
|
+
if (opts.json) {
|
|
229
|
+
console.log(JSON.stringify(report, null, 2));
|
|
230
|
+
} else if (!report.manifestFound) {
|
|
231
|
+
console.log('\nNothing to uninstall — no install manifest found.\n');
|
|
232
|
+
} else {
|
|
233
|
+
console.log(`\n${opts.dryRun ? 'Would remove' : 'Removed'} ${report.removed.length} skill folder(s).`);
|
|
234
|
+
for (const p of report.persona) console.log(` persona ${prettyPath(p.file)} — ${p.action}`);
|
|
235
|
+
console.log('');
|
|
236
|
+
}
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
case 'doctor': {
|
|
241
|
+
const result = doctor(common);
|
|
242
|
+
if (opts.json) console.log(JSON.stringify(result, null, 2));
|
|
243
|
+
else printDoctor(result);
|
|
244
|
+
process.exit(result.ok ? 0 : 1);
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
case 'targets':
|
|
249
|
+
printTargets(opts.mode);
|
|
250
|
+
break;
|
|
251
|
+
|
|
252
|
+
case 'help':
|
|
253
|
+
console.log(USAGE);
|
|
254
|
+
break;
|
|
255
|
+
|
|
256
|
+
default:
|
|
257
|
+
console.error(`Unknown command: ${opts.command}\n\nRun \`bt-agent --help\` for usage.`);
|
|
258
|
+
process.exit(2);
|
|
259
|
+
}
|
|
260
|
+
} catch (err) {
|
|
261
|
+
console.error(`\nbt-agent: ${err.message}\n`);
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
main();
|
package/lib/doctor.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const { resolveTargets } = require('./targets');
|
|
7
|
+
const { listSkills } = require('./payload');
|
|
8
|
+
const { hasPersona } = require('./persona');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Verify an install.
|
|
12
|
+
*
|
|
13
|
+
* Payload-driven on purpose: it checks every file of every skill this package
|
|
14
|
+
* ships, in every target directory. A hardcoded skill list silently stops
|
|
15
|
+
* verifying skills added later — that is exactly how `bt-gauntlet` shipped
|
|
16
|
+
* unverified while the checker still reported success.
|
|
17
|
+
*/
|
|
18
|
+
function doctor(opts = {}) {
|
|
19
|
+
const {
|
|
20
|
+
mode = 'global',
|
|
21
|
+
projectRoot = process.cwd(),
|
|
22
|
+
ids = null,
|
|
23
|
+
legacyCodex = false,
|
|
24
|
+
persona = true,
|
|
25
|
+
skills: checkSkills = true,
|
|
26
|
+
} = opts;
|
|
27
|
+
|
|
28
|
+
const resolved = resolveTargets({ mode, projectRoot, ids, legacyCodex });
|
|
29
|
+
const skills = checkSkills ? listSkills() : [];
|
|
30
|
+
const missing = [];
|
|
31
|
+
|
|
32
|
+
for (const { dir } of checkSkills ? resolved.skillDirs : []) {
|
|
33
|
+
for (const skill of skills) {
|
|
34
|
+
for (const rel of skill.files) {
|
|
35
|
+
const target = path.join(dir, skill.name, ...rel.split('/'));
|
|
36
|
+
if (!fs.existsSync(target)) missing.push(target);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (persona) {
|
|
42
|
+
for (const { file } of resolved.instructionFiles) {
|
|
43
|
+
if (!hasPersona(file)) missing.push(`${file} (persona)`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
ok: missing.length === 0,
|
|
49
|
+
missing,
|
|
50
|
+
checked: {
|
|
51
|
+
skills: skills.length,
|
|
52
|
+
files: skills.reduce((n, s) => n + s.files.length, 0),
|
|
53
|
+
skillDirs: checkSkills ? resolved.skillDirs.map((d) => d.dir) : [],
|
|
54
|
+
instructionFiles: resolved.instructionFiles.map((f) => f.file),
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = { doctor };
|