Project context. Read first in every new chat. Written in English to save context; all chat prose, UI text, commits, changelog and PR reviews stay Russian.
- Cost scales with turns, not words: batch independent reads/searches/edits into one message; run long commands in the background instead of polling.
- Show diffs or changed fragments, never reprint a file. Don't re-read what is already in context. Don't re-run a check that passed until code changed.
- Unknown path →
Grep, not a question. Ask only when the answer changes the whole approach. - Big files (
spells.js,data.js,character-builds.js,build-notes-data.js,index.html) —GrepplusReadwithoffset/limit, never whole. One full read of those stays in context for the rest of the session and is billed on every later request. - Session cap: 150 model requests or 200k context. At the cap —
/carry, then/clear, even mid-task. Measured on this repo: sessions over 300 requests burned 72% of all tokens ever spent; context grows ~0.7k per request, so one 600-request session costs four 150-request ones. TheStophook warns at 120 requests / 150k. - Never read the same file twice in one session — measured 32% of all read volume was re-reads (
style.cssalone: 266). What was read is still in context; scroll back instead. If a file changed since, read only the changed range. - Before touching
style.css,index.htmlor a big JS module:Read docs/map.mdlimit 20 (its TOC), then a ranged read of the section you need, then the ranged read of the file itself. Regenerate withnode tools/gen-map.jsafter large structural edits. - Any UI/CSS/preview check goes to the
verifiersubagent, always — screenshots and browser dumps must never land in the main context (measured 459 images and ~130M carried tokens). - Subagents only for wide repo search, browser verification (
verifier) or mechanical routine on a cheap model. Never spawn one for a single command — it starts cold and re-reads everything. - Routine (boilerplate, renames, small fixes) — no extended reasoning.
- Report: what changed / what to check. No task restatement, no unrequested docs or refactors. Task closed → 2-line handoff summary, then suggest
/clear.
- Vanilla JS + HTML + CSS, no bundler, no npm runtime deps (npm is for tools only).
- PWA:
sw.js(CACHE_NAMEshapeddnd-sheet-vN+FILES_TO_CACHE) +manifest.json. - Vendored:
vendor/dice-box/(3D dice, WebGL),vendor/jspdf/(PDF).
Full structure, key functions, character schema and migrations — docs/ARCHITECTURE.md.
Line-level map for ranged reads (CSS sections, markup blocks, function and data-constant indexes) — docs/map.md, generated by node tools/gen-map.js.
index.html— the only page: markup, script order, lazy loader.- Core:
rules.js(pure rules math, no DOM — AC, saves, slots, rest, concentration),app-core.js(state, navigation, characters) +app-migrate.js,app-builds.js,app-io.js. - Tabs:
app-combat.js+app-conditions.js/app-cast-effects.js/app-proficiencies.js,app-hp.js,app-inventory.js,app-spells.js,app-party.js,app-notes.js,app-ui.js+app-dice.js/app-settings.js/app-asi.js,app-desktop.js,app-help.js,history-stack.js,app-backup.js,app-log.js,app-pdf.js,app-home.js. - Data:
data.js(classes/races/feats +APP_VERSION/APP_VERSION_DATE/APP_CHANGELOG),data-2024.js,spells.js,spell-effects.js,character-builds.js+build-notes-data.js,class-choices.js+subclass-choices-data.js,magic-items.js,gear-catalog.js,glossary-data.js,monsters-srd.js+npc-srd.js. - Misc:
icons.js,bg-space.js+dice-arena-bg.js,dev-verify-builds.js(verifyAllBuilds()). tools/— version, changelog and check scripts +phb-search.py(search local rulebook PDFs) +gen-map.js(regeneratesdocs/map.md).tests/—headless-node.js,runner.html+headless.js,fixtures.js,rules-cases.js. CI —.github/workflows/:tests.yml(tests + invariant + themes),pages.yml(deploy),claude-code-review.yml(PR review in Russian, review only).
- Modules are plain
<script src>at the bottom ofindex.htmlin a hard order:app-log→icons→ backgrounds → data →app-core→ tabs →app-ui/app-notes/app-desktop/app-help. The onlytype="module"is the dice-box wrapper. - Everything is exchanged through globals: top-level
function f(), no exports.index.htmlholds ~460 inline handlers (onclick=,oninput=) calling them by name — wrapping such a file in an IIFE breaks the tab. IIFE only in the self-containedapp-log.js/icons.js/history-stack.js/bg-space.js/dice-arena-bg.js, which publish viawindow.X. - ES5 style:
var, almost no arrows or template strings. Match the surrounding code. - Heavy files load lazily via
loadScript()at the bottom ofindex.html:app-pdf+vendor/jspdf,build-notes-data,monsters-srd+npc-srd,magic-items,gear-catalog,data-2024. Their?v=tokens live there too. - New js/css file → wire it in
index.html(<script src>orloadScript) +?v=token + a line inFILES_TO_CACHE(sw.js). All three are enforced bytools/check-invariant.jsin CI; missing any one turns thetestsjob red. - UI and terminology are Russian, canon is the 5e 2014 books; the 2024 edition lives behind
char.edition(EDITION_DATA/edData).
- Preview — the
dnd-appconfig in.claude/launch.json(preview_start, port 3017), or any static server from the repo root; the PWA needshttpsorlocalhost. Browser verification goes through theverifiersubagent (skillverify-ui). /test(=node tests/headless-node.js) — logic;tests/runner.html— same in a browser;tests.htmlin the root —rules.jscases only;verifyAllBuilds()in the DevTools console — builds, currently 36/36 fullPass.
Release invariant — five values change together in one command:
APP_VERSION ↔ APP_CHANGELOG[0].version ↔ CACHE_NAME (dnd-sheet-vN) ↔ every ?v=vN token in index.html ↔ CHANGELOG.md
/bump <patch|minor|major> "<changelog>" [--type chore|feat|fix] edits them, then /preflight. Mechanics and failure modes — skill release.
/ship runs the whole cycle: it reads the diff, decides whether a bump is needed (changes only under .claude/, tools/, docs/ go as a plain commit without a version), writes the level and changelog text, then the releaser subagent does tests → bump → invariant → commit → push → CI wait, and relpost returns the announcement. Commit and push happen only on this command.
Releases are described on three levels, all generated from APP_CHANGELOG + git: short — CHANGELOG.md and the in-app history window; detailed — docs/RELEASES.md; full patch — the GitHub compare/ link. Both generators run from /bump; /relpost builds the announcement.
PostToolUse on Edit|Write|MultiEdit — five. Blocking (exit 2): sw.js edited without a CACHE_NAME bump; APP_VERSION ↔ APP_CHANGELOG[0].version mismatch; node --check on any *.js outside vendor/. Warning only: tests on *.js edits, check-theme.js --hook on style.css. Stop — two, both warning only: uncommitted changes and session size (check-session-size-hook.js, warns at 120 requests / 150k context, hard at 150 / 200k). Mute both with DND_NO_STOP_HINT=1.
- Slash commands —
.claude/commands/*.md, skills —.claude/skills/*/SKILL.md. Read the skill before the task, not after. Content work (class, spell, build, magic item, feat, weapon) — skilladd-content, which also covers files andschemaVersionmigrations. - Plans: phases live in
~/.claude/projects/.../memory/project_*_plan.md, index inMEMORY.md; a new chat starts with «начать фазу X-N», a closed phase is marked**done**. - Rules math changed (
rules.js, AC/saves/slots/rest/concentration,data.jstables) → subagentdnd-rules: checks against the Player's Handbook via local PDFs (tools/phb-search.py), returns a verdict, edits nothing. Manual call —/rules [function|file]. - Delegate mechanical routine to cheaper models:
releaser(sonnet),relpost(haiku),content(sonnet),verifier(sonnet), repo search viaExplorewithmodel: "sonnet". Planning, architecture, bug analysis and content decisions stay in the main chat.
тип(scope): описание in Russian, types feat / fix / chore, releases prefixed vX.Y.Z:. Create commits only when the user asks.
- No bundler, no npm runtime dependencies — everything stays vanilla.
- No changes to
assets/or static files without bumpingCACHE_NAMEinsw.js. - No commits without an explicit request.