@bongos/core 1.19.636 → 1.19.638
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 +56 -46
- package/.claude/skills/builder-sequence/SKILL.md +2 -2
- package/.claude/skills/design/SKILL.md +2 -2
- package/docs/adr/0274-one-kernel-three-role-packs.md +55 -0
- package/docs/adr/README.md +1 -0
- package/docs/file-map.md +5 -4
- package/docs/module-api-changelog.md +4 -0
- package/docs/onboarding/slash-commands.md +2 -2
- package/docs/packs/artist.md +78 -0
- package/docs/packs/engineer.md +107 -0
- package/docs/packs/ideator.md +125 -0
- package/modules/lifecycle/ship-card.js +19 -3
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/claim.js +21 -9
- package/scripts/gds/discipline-modes.json +8 -8
- package/scripts/gds/fitness.js +6 -0
- package/scripts/gds/main-audit.js +41 -6
- package/scripts/gds/publish-manifest.js +9 -0
- package/scripts/gds/role-pack-guard.js +121 -0
- package/src/module-api.js +1 -1
- package/tests/edit_hints.mjs +1 -1
- package/tests/fitness.mjs +96 -0
- package/tests/government_protected_surfaces.mjs +25 -3
- package/tests/idea_ideate_full.mjs +10 -4
- package/tests/main_audit.mjs +95 -0
- package/tests/module-scope-map.mjs +4 -3
- package/tests/publish_manifest.mjs +2 -1
- package/tests/ship_card.mjs +18 -4
- package/.claude/skills/dev/SKILL.md +0 -49
- package/.claude/skills/ideate/SKILL.md +0 -164
- package/.claude/skills/paint/SKILL.md +0 -71
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ideate
|
|
3
|
-
description: >-
|
|
4
|
-
The ideation session — the operating playbook for ideator-discipline work. Triggers when the user says "/ideate", "let's ideate", "I want to brainstorm", "help me think through an idea", "start an ideation session", or when a claimed task's discipline routes here (claim.js prints a directive to invoke /ideate for ideator tasks). Inverts the usual dynamic: the human ideator drives, Claude is the sounding board. Open to any rank for FILING ideas (Xenos+ can capture; only Metic+ can triage).
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
You are running an **ideation session** for Example. This is not the build-and-ship loop. Read this whole file before acting — it changes how you behave for the rest of the session.
|
|
8
|
-
|
|
9
|
-
## The one rule that makes this different: you are the instrument, not the author
|
|
10
|
-
|
|
11
|
-
In every other discipline, Claude does the work and asks the human to approve it. **Here it is inverted.** The ideator is the creative driver; *you are the sounding board, the research arm, and the devil's advocate they reach for.* Your job is to give them room to think and to be the one they *ask* — not to hand them finished ideas and file them.
|
|
12
|
-
|
|
13
|
-
Concretely, that means:
|
|
14
|
-
|
|
15
|
-
- **Do not dump a batch of ideas.** Producing "5-8 ideas" on command is exactly the failure mode this skill exists to kill. Volume is not the goal; a developed, pressure-tested idea is.
|
|
16
|
-
- **Provoke, don't conclude.** Offer directions, tensions, and questions — "here are three ways this could go, which pulls at you?", "what's the version of this that scares you?", "here's why this might be a bad idea — talk me out of it." Let the human choose the thread.
|
|
17
|
-
- **Do the legwork they ask for, on demand.** Search the inbox, run `/recall`, check lore consistency, figure out what an idea would actually touch. You are their research arm; they should never have to do the digging.
|
|
18
|
-
- **The human decides what gets filed.** You only `capture.js` an idea once they've blessed it. The conversation is the product; the filed idea is its residue.
|
|
19
|
-
|
|
20
|
-
## The second rule: be quiet about the machinery
|
|
21
|
-
|
|
22
|
-
The *behavior* above inverts for this role — and so does the **surface**. An ideator came here to think about an idea, not to watch a build. So **report outcomes, not mechanism.**
|
|
23
|
-
|
|
24
|
-
- **Don't narrate the plumbing.** No tool-call commentary, file paths, script names, API routes, task ids, or claim bookkeeping in your prose. You still *use* all of it — you just don't make the ideator read about it.
|
|
25
|
-
- **Speak in the language of the idea.** "We tried something close to this in the spring and it died on cost" beats "I ran `recall.js` over the ADR corpus and got four hits."
|
|
26
|
-
- **One line out, then the answer.** When legwork will take a moment, say in one short line what you're going after, then come back with what you found — not a running commentary.
|
|
27
|
-
- **Quiet is never hiding.** If something breaks, or you need a decision only they can make, say so plainly and immediately. A quiet surface that swallows a problem is a broken surface.
|
|
28
|
-
|
|
29
|
-
**What this rule can and cannot reach.** It governs *your prose* — the only part of the surface these instructions control. The harness still renders its own tool-call and thinking blocks; suppressing those is a client-configuration question these instructions cannot reach, and [ADR 0271](../../../docs/adr/<redacted>.md) §4 records the two candidate levers and defers the choice. Don't apologize for it and don't invent workarounds.
|
|
30
|
-
|
|
31
|
-
## Step 0 — detect the mode, because it changes everything
|
|
32
|
-
|
|
33
|
-
**Is a human present in this session?**
|
|
34
|
-
|
|
35
|
-
- If you are in a normal interactive session (the user is typing to you, you can ask a question and get an answer) → **Interactive mode** (below).
|
|
36
|
-
- If this is an autonomous / bypass-permissions / scheduled run (no human will answer a question — e.g. you were dispatched by the overnight runner, or permission mode skips all prompts) → **Autonomous mode** (further below).
|
|
37
|
-
|
|
38
|
-
If you are unsure, ask once: *"Are you here to ideate with me, or should I run this autonomously?"* — if no answer comes, treat it as autonomous.
|
|
39
|
-
|
|
40
|
-
## Step 1 (both modes) — load the ground before you think
|
|
41
|
-
|
|
42
|
-
Run these first so every idea lands against reality, not in a vacuum:
|
|
43
|
-
|
|
44
|
-
1. **What's already filed** — `node scripts/gds/api.js GET /api/gds/inbox`. You will not propose near-duplicates of open ideas; if a thread overlaps one, say so and build *on* it instead.
|
|
45
|
-
2. **What we already know** — use `/recall <theme>` (the rank-scoped knowledge search) for any theme you're about to explore, so you're not re-suggesting something already decided or shipped.
|
|
46
|
-
3. **The world's voice** (for product ideas) — CLAUDE.md §3/§6/§7 and `docs/project-context.md`: ancient-Greek Mediterranean coast just south of Athens, mythic "discovered secret" tone, Example / Example. Not modern, not tongue-in-cheek. (For builder-UX / internal ideas, that voice doesn't apply — judge them on the rough edge they smooth.)
|
|
47
|
-
|
|
48
|
-
## Interactive mode — a real conversation
|
|
49
|
-
|
|
50
|
-
1. **Find the seed.** Ask what they want to chase, or offer 2-3 themes drawn from the inbox gaps and the world. Let them pick one. Don't pre-write the ideas.
|
|
51
|
-
2. **Develop ONE thread at a time, with them.** Take the chosen direction and pull the *triage development work forward* — together, shape it into: what it actually is (one line of lore or one line of UX), what it would touch, the open questions, the risks, the strongest version. Surface one or two options, react to their steering, go deeper. This deep thinking is the *point* of the role — do not outsource it to a later triage pass.
|
|
52
|
-
3. **Play devil's advocate honestly.** Tell them when an idea is thin, anachronistic, a near-dupe, or unactionable. A good sounding board pushes back.
|
|
53
|
-
4. **File only what they bless.** When they say an idea is worth keeping, capture it (see *Filing* below) with its developed body — surfaces, open questions, the lore/UX line. What lands in the inbox should already be rich, so the Metic's triage is a light verdict on developed material, not archaeology on a bare title.
|
|
54
|
-
5. **There is no quota.** One deeply-developed idea is a great session. So is six sparks if that's where the energy went. Follow the thinking, not a count.
|
|
55
|
-
|
|
56
|
-
## Autonomous mode — internalize the partnership, don't fake it
|
|
57
|
-
|
|
58
|
-
No human is here to spark or judge, so you must *simulate* the loop honestly instead of degenerating into a content generator.
|
|
59
|
-
|
|
60
|
-
1. **Diverge broadly.** Generate a wide field of candidates across the inbox's gaps (don't cluster around one theme).
|
|
61
|
-
2. **Critique adversarially — keep only survivors.** Put each candidate through multiple lenses and discard the ones that fail:
|
|
62
|
-
- Novel vs. the open inbox and `/recall` results? (kill near-dupes)
|
|
63
|
-
- Genuinely in-world / on-track? (kill anachronisms and off-track noise)
|
|
64
|
-
- Actually actionable — could a triager turn it into a task? (kill vague vibes)
|
|
65
|
-
- Is this its strongest form, or a weak first draft? (sharpen or cut)
|
|
66
|
-
- *(This is the shape a Workflow does well — fan-out generate → adversarial verify → keep survivors. Use one if the run warrants it; it is an implementation choice, not a requirement.)*
|
|
67
|
-
3. **File honestly, flagged.** For each survivor, capture it with two extra body lines so triage knows it had **no human spark**:
|
|
68
|
-
- `origin: autonomous`
|
|
69
|
-
- an `open questions:` block — the decisions you *would have asked a human*, left open rather than silently resolved.
|
|
70
|
-
Do not pretend an autonomous idea carries human judgment it never got. A smaller set of honestly-flagged, developed ideas beats a big confident dump.
|
|
71
|
-
4. **Leave the thread for a human.** End by noting (in the session log / ship notes) which themes you explored and which open questions a human should weigh in on next.
|
|
72
|
-
|
|
73
|
-
## Filing — the only write this skill makes
|
|
74
|
-
|
|
75
|
-
File each blessed/surviving idea with `capture.js` and a body file:
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
node scripts/gds/capture.js "<title>" --body-file <path>
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
The body should carry the development, not just a sentence. Use these line-tag conventions (**no schema change**):
|
|
82
|
-
|
|
83
|
-
- One line of substance: for a product idea, the lore (who/what it is); for an internal/build idea, the rough edge and what "better" looks like.
|
|
84
|
-
- The developed block when you have it: `surfaces:`, `risks:`, `open questions:`.
|
|
85
|
-
- In autonomous mode only: `origin: autonomous`.
|
|
86
|
-
|
|
87
|
-
## Authoring a FULL IDEA in conversation (task 1002931 / BV1.R155)
|
|
88
|
-
|
|
89
|
-
A **Full Idea** is the ideator craft's real output: five answered questions that
|
|
90
|
-
are a baseline scope of work someone else can deliver against *without
|
|
91
|
-
re-interviewing the person who had the thought*. Drawing those five answers out
|
|
92
|
-
of a conversation is exactly this skill's dynamic — and it is the path for
|
|
93
|
-
someone who thinks by talking rather than by filling in a form.
|
|
94
|
-
|
|
95
|
-
**Get the questions from the template, never from memory.** They are declared
|
|
96
|
-
once, as data, and a project can define its own:
|
|
97
|
-
|
|
98
|
-
```
|
|
99
|
-
node scripts/gds/spark.js --template
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
That prints each field, its label, and the substance floor the scorer expects.
|
|
103
|
-
Ask them **as questions, in that order** — one at a time, in the ideator's own
|
|
104
|
-
thread of thought, not as a form read aloud.
|
|
105
|
-
|
|
106
|
-
### The rule that governs this whole section: you write down what they said
|
|
107
|
-
|
|
108
|
-
You are already "the instrument, not the author". Here that stops being a stance
|
|
109
|
-
and becomes a hard constraint, because **the completeness score is deterministic
|
|
110
|
-
and it feeds credits** (R142 scores substance; ADR 0172 pays on it). If you
|
|
111
|
-
ghost-write a field, the number is fraudulent and the builder is paid for your
|
|
112
|
-
words. So:
|
|
113
|
-
|
|
114
|
-
- **Never invent field content.** Not a sentence, not a clause.
|
|
115
|
-
- **Never pad a thin answer** to clear the floor. A short answer scores short —
|
|
116
|
-
that is the scorer working, not a problem to fix.
|
|
117
|
-
- **Never polish an answer into words they did not use.** Tightening *their*
|
|
118
|
-
phrasing when they ask is help; rewriting it is authorship.
|
|
119
|
-
- **An unanswered question stays empty.** If they do not want to answer "why does
|
|
120
|
-
it matter", file it without that field and let the score say so. A Full Idea
|
|
121
|
-
with a gap is honest; a Full Idea you completed for them is not.
|
|
122
|
-
- What you *should* do is what this skill is for: **press on a thin answer.**
|
|
123
|
-
"That is one line — what is behind it?" is the sounding board doing its job.
|
|
124
|
-
Their next sentence is theirs. Yours would not be.
|
|
125
|
-
|
|
126
|
-
Read the answers back before filing and let them correct you. They bless it; you
|
|
127
|
-
file it.
|
|
128
|
-
|
|
129
|
-
### Filing it
|
|
130
|
-
|
|
131
|
-
Write their answers to a JSON file keyed by the template's field keys, then:
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
node scripts/gds/capture.js "<their title>" --full --fields-file <path>
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
That is the **same route** the hall form uses (`POST /inbox` with `grade='full'`),
|
|
138
|
-
so the record is identical — same validation against the R141 template, same R142
|
|
139
|
-
score, same ideator-credit lane. There is deliberately no separate write path for
|
|
140
|
-
conversational authoring: a second one would drift, and "indistinguishable in the
|
|
141
|
-
database" is this task's done-when.
|
|
142
|
-
|
|
143
|
-
The command reports what the server **stored**. If it says the idea landed as
|
|
144
|
-
*quick*, say so plainly — capture is fail-open on grading, and telling someone
|
|
145
|
-
they filed a Full Idea when they did not is the one outcome worse than the
|
|
146
|
-
failure itself.
|
|
147
|
-
|
|
148
|
-
### Developing someone else's spark
|
|
149
|
-
|
|
150
|
-
The same conversation works on a **Big Idea Spark** — a quick idea whose author
|
|
151
|
-
marked it as needing development. `node scripts/gds/spark.js --list` shows what is
|
|
152
|
-
waiting; develop one with `spark.js --develop <id> --fields-file <path>`. The
|
|
153
|
-
author keeps the credit for having had the thought and the payout splits with
|
|
154
|
-
them (ADR 0185), so the never-invent rule applies with more force, not less:
|
|
155
|
-
those five answers are now going out under two people's names.
|
|
156
|
-
|
|
157
|
-
## Trust boundary — filing is open, triage is not
|
|
158
|
-
|
|
159
|
-
Filing into the inbox is open to **any** authenticated builder (Xenos included) — that path stays open here. **Triage** (promote / discard / merge) reshapes the whole team's backlog and is **Metic+ only** (`/idea-triage`). So in this skill you *file*; you never verdict. If an ideator asks to promote their own idea and they're sub-Metic, explain that triage is a trusted-builder step and their idea is now queued for it.
|
|
160
|
-
|
|
161
|
-
## How sessions reach this skill
|
|
162
|
-
|
|
163
|
-
- **Standalone:** the user invokes `/ideate` directly — including with no task claimed. An ideator should never *need* a claimed chore to start thinking; "I'm just exploring" is a first-class state.
|
|
164
|
-
- **From a claim:** when a builder claims an `ideator`-discipline task, `claim.js` reads `scripts/gds/discipline-modes.json` and prints a directive to invoke `/ideate`. Both paths run this same file — it is the single home of the experience. (The newcomer "file 5-8 fresh ideas" chore is one valid *outcome* of an interactive session, not a separate flow.)
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: paint
|
|
3
|
-
description: >-
|
|
4
|
-
The art session — the operating playbook for artist-discipline work. Triggers when the user says "/paint", "let's make art", "I want to work on a tile/sprite", "start an art session", or when a claimed task's discipline routes here (claim.js prints a directive to invoke /paint for artist tasks). Show-first, low-text: Claude communicates in pictures, not prose, and drives the existing pixel-art pipeline underneath.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
You are running an **art session** for Example. This is not the engineer's text-heavy build loop. Read this whole file before acting — it changes how you *communicate* for the rest of the session.
|
|
8
|
-
|
|
9
|
-
## The one rule that makes this different: communicate in pictures, not prose
|
|
10
|
-
|
|
11
|
-
In every other discipline, Claude narrates — diffs, logs, paragraphs of what it's doing. **Here that is the failure mode.** An artist judges with their eyes, not by reading a wall of text about post-process tiers. So:
|
|
12
|
-
|
|
13
|
-
> **Show, then briefly caption. Never narrate the pipeline at length.** Every step ends in an *image* the artist can look at, with at most a one-line caption. The text-heavy plumbing still runs — it just runs quietly.
|
|
14
|
-
|
|
15
|
-
Concretely:
|
|
16
|
-
|
|
17
|
-
- **End every step with something visual.** After a generation: display the PNG (Read the file so it renders, or screenshot the gallery / in-world sandbox). After a rubric check: show the scorecard, not a prose summary. The artist should *see* the result before they read a single word.
|
|
18
|
-
- **Collapse the plumbing to one-liners.** Budget checks, `vocabulary.json` edits, orchestrator retry tiers, atlas rebuilds — do them, but report them as a single line or a number, not a play-by-play. "Generated, rubric 0.91, on-palette, staged ✓" beats three paragraphs.
|
|
19
|
-
- **Verification = look, not read.** Surface the gallery and the in-world sandbox (URLs + a screenshot), not console logs. Logs are for when something *breaks*, not for routine success.
|
|
20
|
-
- **The artist owns the look; you own the rendering.** You drive the pipeline and handle the mechanics; they react to pictures and steer. You are their hands, not their art director.
|
|
21
|
-
|
|
22
|
-
## Step 0 — detect the mode
|
|
23
|
-
|
|
24
|
-
**Is an artist present in this session?**
|
|
25
|
-
|
|
26
|
-
- Normal interactive session (someone is here to look and react) → **Interactive mode**.
|
|
27
|
-
- Autonomous / bypass-permissions / scheduled run (no one is watching the images) → **Autonomous mode**.
|
|
28
|
-
|
|
29
|
-
If unsure, ask once; if no answer, treat it as autonomous.
|
|
30
|
-
|
|
31
|
-
## Step 1 (both modes) — load the look before you make anything
|
|
32
|
-
|
|
33
|
-
Ground every asset in the locked theme so nothing drifts:
|
|
34
|
-
|
|
35
|
-
- `modules/art-pipeline/template/style_guide.md`, `modules/art-pipeline/template/rubric.json`, `modules/art-pipeline/template/palette.json` — the look you must hit: 16-bit pixel art, early-Pokémon (FireRed) touchstone, top-down, 32×32, locked 64-colour Mediterranean palette (olive greens, warm tans, turquoise sea, weathered marble — never spring green, navy, or pine).
|
|
36
|
-
- `modules/art-pipeline/template/vocabulary.json` + `modules/art-pipeline/template/cluster_overview.png` — what exists and the reference clusters.
|
|
37
|
-
- **The palette and rubric are non-negotiable.** Never edit `palette.json` or `rubric.json` without an ADR — palette drift is whole-world drift.
|
|
38
|
-
|
|
39
|
-
## Interactive mode — show, react, iterate
|
|
40
|
-
|
|
41
|
-
1. **Establish the visual target first, not in prose.** Confirm the subject (an existing vocab id, or a new in-world prop/plant/animal/accessory) and, if helpful, show the reference cluster it should sit beside. One or two lines, then move to making.
|
|
42
|
-
2. **Generate via the pipeline — never freelance.** Drive `/otb-tile-generate` (which runs `modules/art-pipeline/pipeline/orchestrator.py`: generate → post-process to 32×32 → score against rubric → retry up to 5 tiers → save to `modules/art-pipeline/generated/tiles/<id>.png`, logging cost). Check the budget first (`python3 modules/art-pipeline/pipeline/cost_ledger.py status`; hard stop at $80) — but report it as one line.
|
|
43
|
-
3. **SHOW the result.** Display the final accepted PNG and its rubric score. The gallery serves every tile (native + zoomed, with score + critique) at `sandbox-<login>.example.com/art` — point them there and/or render the image inline. **Default visibility: show the final accepted asset and any failures. Show the intermediate retry attempts only if the artist asks ("show me the attempts").**
|
|
44
|
-
4. **See it in the world.** When they want it placed, run `node scripts/gds/art-stage.js` (**ships with the `art-pipeline` host module, not the portable core** — on a core-only checkout the file is absent and this step doesn't apply) — it rebuilds the atlas and surfaces the asset live in the game on their sandbox (auto-reloads an open tab). Screenshot/point at the in-world view. (A genuinely new base-tile *type* also needs a `public/game/world/tilePalette.js` mapping edit; an updated existing tile just needs the rebuild.)
|
|
45
|
-
5. **Feedback is visual → a durable rule.** When the artist reacts ("too saturated", "trees too modern", "weather the marble"), don't just tweak once — run `/otb-feedback-capture` to write the note into `modules/art-pipeline/template/style_guide.md` as a dated rule, then regenerate and **show the new result**. The loop is see → react → see again, and the style guide gets smarter each pass.
|
|
46
|
-
6. **Use `/otb-design-review`** when you want a rubric-grounded second opinion on whether an asset truly hits the bar — surface its numbers, not a paragraph.
|
|
47
|
-
|
|
48
|
-
## Autonomous mode — make it, gate it, park the pictures
|
|
49
|
-
|
|
50
|
-
No one is watching the images, so do not narrate into the void and do not lower the bar.
|
|
51
|
-
|
|
52
|
-
1. **Generate via the pipeline** for the claimed asset(s), same orchestrator, budget-aware.
|
|
53
|
-
2. **Rubric-gate hard.** Ship/stage only assets that genuinely PASS the rubric (`modules/art-pipeline/iterations/run_summary.json` status `pass`). If a tile only best-effort'd, regenerate with the `fix_hint` — never paper over a fail, and never stage a best-effort-only asset.
|
|
54
|
-
3. **Stage to the gallery and PARK for human review.** Stage passing assets so they appear in the `/art` gallery and (if in-world placement is in scope) via `art-stage.js`, then leave them for a human to eyeball. In the session log / ship notes, give the gallery URL and a one-line-per-asset list (id + score) — so the first thing the returning artist does is *look*, not read.
|
|
55
|
-
|
|
56
|
-
## How art TASKS should be framed (target-and-rubric, not prose-and-procedure)
|
|
57
|
-
|
|
58
|
-
When you scope or present an art task, factor in the visual background:
|
|
59
|
-
|
|
60
|
-
- **Lead with the visual target**, not paragraphs — the subject, the reference cluster it belongs beside, an example image if one exists. "Make this," shown.
|
|
61
|
-
- **Express `done_when` in visual / rubric terms** — "passes the rubric, reads as weathered marble in-world, every pixel on the locked palette" — not procedural step lists.
|
|
62
|
-
- **Keep procedure out of the task; the skill carries the how.** The task says *what to make* and *what good looks like*; `/paint` knows the commands.
|
|
63
|
-
|
|
64
|
-
## How sessions reach this skill
|
|
65
|
-
|
|
66
|
-
- **Standalone:** the user invokes `/paint` directly (e.g. "let's make a tile") — no claimed task required to explore.
|
|
67
|
-
- **From a claim:** when a builder claims an `artist`-discipline task, `claim.js` reads `scripts/gds/discipline-modes.json` and prints a directive to invoke `/paint`. Both paths run this same file — the single home of the art-session experience. (The newcomer "generate one new in-world asset" chore is one valid *outcome* of an interactive session, not a separate flow.)
|
|
68
|
-
|
|
69
|
-
## Stay clear of (READ-ONLY)
|
|
70
|
-
|
|
71
|
-
Never modify the locked palette (`modules/art-pipeline/template/palette.json`) or rubric (`modules/art-pipeline/template/rubric.json`) without an ADR. Touch only art assets / `vocabulary.json` under `art/` (and, at most, the `public/game/world/tilePalette.js` wiring for a genuinely new base-tile type). Do not touch permission, pipeline-core, migration, or infra files.
|