Files
khosra/docs
bdeshiandClaude Opus 5 64e53f28c8 give a page the assets its own content asked for, and write down the rule
Two decisions and one mechanism. The human wants demos, games and runnable
embeds to carry real CSS and JS while every ordinary page stays scriptless, and
wants adding an asset to be theme work rather than a rebuild.

The mechanism reuses what already had that property. A theme defines
`assets:<name>` beside its other fragments; shortcodes record their own name as
they are opened; after conversion the engine renders each matching fragment once
into Page.Assets. So a gallery calling one shortcode forty times carries its
stylesheet once, and a page that called nothing carries nothing. Frontmatter
`use:` reaches the same fragments without a call.

Considered and rejected: templates/assets.yaml, which reads more declaratively
and buys a parser, a contract shape and a rebuild for conditional markup; and a
table in Go mapping shortcode to files, which would hardcode exactly what was
deliberately made data-driven.

Collection is parse-phase, so no transform counter moves — goldmark's extender
list is already the ordered pipeline for parse work, which state.md's counter
says in its "does not count" column.

Separately, styles/scripts are lifted at last. They sat in content-model.md's
table unread, and the theme contract listed them under "what the engine
provides", which was aspirational rather than true. Both are bundle-relative: a
name with .. or a leading / is dropped and logged, the refusal ::include and a
code block's file= already make. The engine builds the URLs because a theme must
not construct an address.

ADR-0080 writes the antifeature list down, with its single exception inside it.
An antifeature nobody recorded does not bind anything, and each of these dies to
one reasonable-looking request at a time. The exception is author-invoked and
cannot fire by accident.

The reference theme emits the stylesheets and no script element at all. That was
the human's correction to a first attempt which had page.html emitting the tag
and verify.sh narrowed to permit it — narrowing the gate to fit the code was
backwards, and the narrowing was also wrong, passing a probe with a hardcoded src
because it filtered whole lines and every line carries {{define}}. verify.sh is
untouched. examples/demo-site redefines the head block instead, so the JavaScript
half is demonstrated by a site rather than built into the binary, which is a
better demonstration and a stronger property.

Evidence, against the demo site with a freshly built binary: the sandbox page
carries its own css and js at bundle-relative URLs; colophon calls ::tally twice
and carries tally.css once with zero scripts; about calls it never and carries
neither; listings unaffected. Plus a table test for the escape refusal, which
until now had only the running server behind it.

19 files, +355/-86. No counter moves. Demo is 31 bundles.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 19:22:56 +06:00
..

Doc map

Read the one you need. Do not read them all.

Doc Contains Mutability
architecture.md The six primitives, invariants, per-primitive STATUS Only via an ADR
state.md What exists now: inventory, earn-it counters, latent items Every feature
decisions.md ADR log — one entry per load-bearing choice Append-only. One exception: a superseded entry's Status line is annotated in place to name what replaced it, because a reader arriving at the older entry has no other way to learn it was replaced. Never the Decision text — that stands as history
roadmap.md Arcs, earn-triggers, the core freeze point When an arc completes
content-model.md On-disk layout, frontmatter, post types, permalinks — what the parser accepts today, never a plan When the disk format changes
conventions.md Go style floor, package layout, perf and test rules Rarely; via ADR if contested
extensions.md Extension/plugin contract: target shape + earn gates When earned or frozen
toolchain.md Versions and agent-tooling contracts this was built against When you deliberately move a version
theme-contract.md What the engine promises a theme; the only theme-facing obligation When the contract is extended — additively only
context-economy.md How the agent spends context: what to read, in what form, and the floor no saving may cross When a technique or a gate for one changes
surface.md Generated. Every top-level declaration with its line — read before opening source Never by hand; make surface

Sibling folders sit outside docs/ because they are storage, not working material: ../ideas/ (parked ideas, any topic, and exploration.md — the catalog of engine features nobody has asked for yet) and ../reference/ (durable facts from conversation). Write there when asked to park something; open a file only when the human names it. Nothing sweeps them.

Topic ownership — read before you assert

The inverse of the refresh triggers: those say what to update after changing code, this says what to read before writing a rule — including when you are only writing an ADR or a comment about it. Nearly always exactly one doc; if two seem to apply, the single-source rule is already broken and that is the finding to report.

About to assert something about… Read first
plugins, extensions, features-as-packages, stage phases extensions.md
a primitive, an invariant, or what is "earned" architecture.md + counters in state.md
URL paths, permalinks, frontmatter, on-disk layout, post types content-model.md (+ ADR-0008)
Go style, package layout, file/function size, test shape conventions.md + scripts/budgets.env
a dependency scripts/allowed-deps.txt + ADR-0007
a budget or a gate scripts/budgets.env + scripts/verify.sh
the untrusted boundary, comments, webmentions, form input ADR-0003 + extensions.md
language, translation, fallback ADR-0004 + ADR-0009
deploy, containers, external services ADR-0010
whether a future feature is worth building ideas/exploration.md + roadmap.md
what to build next the harness first (CLAUDE.md §1 read order) and git log for what landed, then .scratch/continue.md for the continuation point and roadmap.md for the arc. The handoff is temporary and ungated: check anything it calls pending with git log -- <the path it names> before planning from it
how the harness works — a gate, counter, budget, the loop HARNESS.md + scripts/verify.sh + CLAUDE.md
what one commit contains, and when one happens conventions.md "Git" (shape) + CLAUDE.md §4 (cadence, ADR-0052)
how to read, search, or report without wasting context context-economy.md (+ ADR-0053)
a tool version, or why agent tooling stopped working toolchain.md
templates, layout, presentation, what a theme can rely on theme-contract.md (+ ADR-0019, ADR-0023)

Single-source rule

Each fact lives in exactly one doc. Need it elsewhere? Link. This binds ADRs too: an ADR restating a rule an owning doc already carries is a duplicate, not a decision — delete it and amend the owner.

Values that have drifted before, and their one home. Everywhere else names the concept and points here; nothing else may state the value:

Fact Sole home
Earn-it thresholds (transforms, routes, views, extensions) the counters table in state.md
LOC ceilings, size warnings, dependency cap, the CLAUDE.md ceiling scripts/budgets.env
The permalink path shape content-model.md (decision recorded in ADR-0008)
Which language is at the root, and the prefix form ADR-0009
The leaf/trunk definition architecture.md invariant 7
The sovereignty test roadmap.md Governors
Package layout and the forbidden package names conventions.md
What exists in the code right now state.md inventory

A value restated in two places is not redundancy for safety; it is a future contradiction waiting for whichever copy gets edited alone.

state.md is the only doc describing the present; the rest describe rules, shapes, or intentions. When code and state.md disagree, the code wins and state.md is wrong.

Refresh triggers

Update in the Document step of the change that caused them. Not later.

Change Update
Any code change at all state.md inventory — in the same commit, which is what verify.sh compares (ADR-0057)
New transform, route, view, extension, or dependency the counters table in state.md
A choice expensive to reverse new ADR in decisions.md
A primitive becomes real (earned) STATUS line in architecture.md + counters
New frontmatter field, post type, or path shape content-model.md
New dependency approved scripts/allowed-deps.txt + ADR
Budget raised scripts/budgets.env + ADR — once the first feature has shipped. While the harness is still being tuned, edit in place.
A latent item fixed remove from the Latent list in state.md
A planned item completed after the commit lands, delete it from .scratch/continue.md and note anything learned that changes a later one. Never during Document: a handoff written mid-change describes the plan, and an amend moves the commit under it — which is how one was written at 01:06 saying a trim awaited a yes that the 01:12 commit had already done
Arc finished roadmap.md + a retro line in state.md
Catalog item accepted or rejected verdict line in ideas/exploration.md
CLAUDE.md, scripts/ or .claude/ changed HARNESS.md, same change. Enforced by verify.sh.
A tool version deliberately moved, or a new external contract relied on toolchain.md
The theme contract extended, or embedded templates changed theme-contract.md, same change. Enforced by verify.sh.
A request spans engine and theme contract extension here + a written note of the theme's part; never the theme itself
A new gate, counter, or budget added HARNESS.md "Why the pieces exist" + a row in one of these tables
A top-level declaration added, renamed or moved nothing by hand — make surface, which verify.sh then compares
A rule, value, name or path changed grep the repo for the old form; every doc naming the concept, same change
The disk contract changed content-model.md + testdata/ fixtures + a written migration step for the site root, which the engine repo cannot touch
A doc or ADR mandates what a change made optional supersede the ADR; do not reword it in place
A request reversed a recorded decision new ADR, or supersede the old one — the request does not win by being newer
A request exceeded a convention on purpose note the deviation where the convention lives
An idea floated, not built now a file in ../ideas/ + its index line. Adopted later: Status: adopted → <where>
A fact worth keeping surfaced in conversation a file in ../reference/ + its index line, stating how it was established

Staleness

/refresh-docs reconciles docs against code and reports drift. Run it after a burst of work, before a new arc, and any time a doc surprises you.

House style

Present tense. Terse. Written for a reader who has forgotten everything, including their own reasoning. No changelog prose, no "recently we…", no preamble. Delete a line before rewriting it. A doc needing a table of contents is too long.

Compression contract

Shortening a harness doc removes words, never instructions. Same rules, gates, thresholds, triggers and table rows before and after; the agent must act identically. Redundancy between CLAUDE.md and SKILL.md is deliberate — the constitution is always loaded, the skill is not — and is not duplication to be collapsed.

Deleting a rule, adding one, or narrowing one is a rule change: it needs its own decision and its own reason, and it never rides along in a compression pass.

Verify before reporting a saving: table rows, headings, list items and checklist boxes must match the pre-pass file (git diff --stat, or a snapshot if the change is uncommitted). Report word count, not lines — reflowing prose shrinks lines without saving anything.