chore: bootstrap agent-ready docs and rules

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-23 18:25:46 +02:00
1 parent 10ce858b31
commit 80f6c97127
17 files changed
+486

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
# Architecture
How `epic-the-musical-timeline` is built today. Update in the same commit as any structural change.
## Overview
A Bun server (`Bun.serve`) with HTML-import routes serves an index page and seven mockup pages. Bun's bundler
turns each HTML page and its imported TS/CSS into hashed assets. `bun run build` bundles the server and every
page into `dist/`; the Docker image runs that bundle. All pages read one typed sample dataset and mount one
shared credits snippet.
## Map
| Path | Responsibility |
|---|---|
| `src/server.ts` | `startServer(port)`: routes `/`, `/mockups/NN-slug/` (+ 302 from the no-slash form), 404 otherwise. Runs when `import.meta.main`; `PORT` env, default 3000. |
| `src/index.html`, `src/index.ts`, `src/index.css` | Index page: static cards linking each mockup, then `mountCredits()`. |
| `src/mockups/registry.ts` | `mockups: MockupInfo[]` — slug, number, name, pitch, what to try. |
| `src/mockups/NN-slug/` | One design direction: `index.html` (links `../../shared/credits.css`, has `<footer data-fan-credits>`), `main.ts`, `style.css`. |
| `src/data/types.ts` | `Saga`, `Song`, `Part`, `Motif`, `StoryTime`, `OdysseyRef`, `Video`. |
| `src/data/sample.ts` | `sagas`, `motifs`, `songs`. Placeholder lyrics; unverified fields `// TODO(verify)`. |
| `src/data/query.ts` | `songsWithMotif`, `motifsInSong`, `gapYears`, `sagaOf`. |
| `src/shared/credits.ts` | `FAN_NOTICE`, `mountCredits(target?)`. |
| `src/shared/audio-slot.ts` | `createAudioSlot(song)`: `<audio>` for `song.audio`, else an empty-state slot. |
| `src/shared/video-cards.ts` | `createVideoCards(song)`: YouTube link cards, no embeds. |
| `src/shared/credits.css` | Styles for credits, audio slot, video cards. |
| `tests/` | `data.test.ts` (dataset invariants), `shared.test.ts` (DOM modules under happy-dom), `server.test.ts` (every route 200s, index links every registry slug, each mockup has the credits hook). |
| `Dockerfile` | Two-stage `oven/bun:1.3`: install + build, then copy `dist/` and run from `WORKDIR /app/dist`. |
## Data flow
1. Request hits `Bun.serve`; an HTML-import route returns the bundled page (dev: bundled on demand with HMR
via `bun --hot`; production: prebuilt assets from `dist/`).
2. The page's `main.ts` imports `src/data/*` and `src/shared/*` (bundled in; no runtime API).
3. `main.ts` renders the direction and calls `mountCredits()` into `<footer data-fan-credits>`.
## External dependencies
None at runtime. Fonts (`@fontsource/*`) and three.js are bundled from npm. Outbound links only: YouTube
(video cards) and Project Gutenberg (Odyssey references) — the site works without them.
## Invariants
- Every page renders `FAN_NOTICE` via `mountCredits()`.
- `src/server.ts` routes, `src/mockups/registry.ts` and the cards in `src/index.html` list the same slugs
(`tests/server.test.ts`).
- Every motif id used by a part exists; every motif appears in at least one song (`tests/data.test.ts`).
- No two mockups ship byte-identical `style.css` (the build fails otherwise).
## Known rough edges
- The production bundle only runs with `dist/` as the cwd (`bun run start`, Docker `WORKDIR /app/dist`);
`bun dist/server.js` from the repo root crashes. See `docs/TODO.md`.
- Routes, registry and index cards are three hand-maintained lists. See `docs/TODO.md`.
+50
View File
@@ -0,0 +1,50 @@
# Decisions
Append-only. Never edit or delete an entry — supersede it with a new one that links back.
One entry per decision a future maintainer would otherwise have to reverse-engineer.
No index: `grep -n '^## ' docs/DECISIONS.md` lists every entry (date, title, line number).
## 2026-10-23 — Mockups are committed and served, not throwaway
**Status:** accepted
**Context:** The agent-repo playbook keeps mockups gitignored in `design/mockups/`, never wired into the app.
Spec 001 asks for 7 design-direction mockups that run in the Docker image for the maintainer to compare.
**Decision:** (maintainer decision) Mockups live in `src/mockups/NN-slug/`, are committed, served by the
Bun server and covered by route smoke tests. Mockup agents edit only their own folder.
**Alternatives:** Gitignored `design/mockups/` (can't ship in the image or be reviewed from the remote).
**Consequences:** Mockup code is in the bundle and the history; when a direction is chosen, the unused
mockups need an explicit removal decision (`docs/TODO.md`).
## 2026-10-23 — Production bundle runs from `dist/`
**Status:** accepted
**Context:** With Bun 1.3.14, a `--production` bundle of HTML imports resolves its assets relative to the
current working directory; `bun dist/server.js` from the repo root throws "Bundled file … not found".
**Decision:** `bun run start` is `cd dist && bun server.js`; the Docker runtime stage uses `WORKDIR /app/dist`.
**Alternatives:** Not recorded (e.g. `--asset-naming`/`naming` options were not explored).
**Consequences:** Any new run script or deploy target must set the cwd to `dist/`.
## 2026-10-23 — Bun only, self-contained assets
**Status:** accepted
**Context:** Spec 001 constraints.
**Decision:** Bun's own server, bundler and test runner with HTML imports; no Vite/Next. Fonts and three.js
bundled from npm, no CDN. YouTube as link cards, not embeds. three.js only in the 3D mockups (06, 07).
**Alternatives:** Not recorded.
**Consequences:** The image works offline apart from outbound links.
## 2026-10-23 — Placeholder lyrics, unverified facts marked
**Status:** accepted
**Context:** Lyrics recalled from memory risk inaccuracy, and their copyright question is open.
**Decision:** Sample data uses clearly marked placeholder lyric lines in the real data shape; any fact,
story time or Odyssey reference not confirmed carries `// TODO(verify)`.
**Alternatives:** Real lyrics (deferred by the maintainer).
**Consequences:** Nothing in `src/data/sample.ts` may be presented as fact-checked.
## 2026-10-23 — Adopt AGENTS.md as single source of truth
**Status:** accepted
**Context:** Agents had no durable project context and no consistent workflow between sessions.
**Decision:** `AGENTS.md` is canonical; `CLAUDE.md`/`GEMINI.md` are pointers. Specs are permanent in
`docs/specs/`. Plans live in `docs/plans/` only while work is in progress and are removed before the
merge request. Both override the superpowers default paths.
**Alternatives:** Per-tool rule files (drift, synchronisation debt); no rules file (agents re-explore
the repo every session — measurably slower and more tokens).
**Consequences:** Rule changes happen in one file; pointer files must stay thin. Plans are working
artefacts: kept after merge they go stale and contradict the code, so the spec is the record.
+58
View File
@@ -0,0 +1,58 @@
# Agent permissions
Source of truth for what AI coding agents may run here. Tool files are renderings of this page:
`.claude/settings.json`, `.codex/config.toml`, `.codex/rules/project.rules`, `.gemini/settings.json`.
Change this page and every tool file in the same commit.
## Verified commands
Run 2026-10-23 with Bun 1.3.14, each in a fresh shell. Only `worked` rows may appear in a tier, a tool file,
or `AGENTS.md` Commands.
| Command | Result |
|---|---|
| `bun install --frozen-lockfile` | worked (no changes) |
| `bun test` | worked — 32 pass, 0 fail, 3 files |
| `bun test tests/data.test.ts` | worked — 10 pass |
| `bun test -t "registry has 7"` | worked — 1 pass |
| `bun run typecheck` | worked (`tsc --noEmit`, exit 0) |
| `bun run build` | worked — `dist/server.js` + hashed page assets |
| `bun run dev` (`PORT=3113`) | worked — `/` and all mockup routes 200, no-slash form 302 |
| `bun run start` (`PORT=3112`) | worked — same route results as dev |
| `bun dist/server.js` (from repo root) | failed — `TypeError: Bundled file "./index-….js" not found`; assets resolve from cwd |
| `docker build -t epic-timeline .` | worked |
| `docker run --rm -p 3000:3000 epic-timeline` | worked — `/mockups/06-constellation/` 200 |
| `docker run -e PORT=8080 -p 8099:8080 epic-timeline` | worked — `/` and all 7 mockups 200, credits hook present (host port 8080 was taken on this machine) |
| `google-chrome --headless --window-size=1440,900 --screenshot=… <url>` | worked (no `chromium` binary on this machine) |
| `codex execpolicy check --rules .codex/rules/project.rules -- <cmd>` | worked — deny/ask rules match as intended |
| Lint / format | not run — no linter or formatter configured |
TODO(maintainer): confirm whether a linter/formatter should be added.
## Tiers
| Tier | Commands | Why |
|---|---|---|
| Allow | `git status`, `git diff`, `git log`, `git show`, `git branch --list`, `git rev-parse`, `git add`, `git commit`; `bun install --frozen-lockfile`, `bun test`, `bun run typecheck`, `bun run build`, `bun run dev`, `bun run start` | Inspection and the verified dev loop; no prompt needed. |
| Ask | `git push`, `git merge`, `git rebase`, `git switch`, `git restore`, `git commit --amend`, `rm` (any); `bun add`, `bun remove`, `bun update`, `bun upgrade`, `bunx`, `npx`; `docker` (any) | Leaves the machine, rewrites work, changes dependencies, downloads and runs code, or touches containers — a human decides. |
| Deny | `git push --force` / `-f` / `--force-with-lease`, `git reset --hard`, `git clean`, `git add -f` / `--force`, `git commit --no-verify` / `-n`, `rm -r` / `-R` / `-rf` / `-fr` / `-Rf` / `-fR` / `--recursive`, `sudo`; reading `.env`, `.env.*`, `secrets/**` | Destroys work, skips checks, or exposes secrets. |
`docker build`/`docker run` are verified but stay in Ask because they touch containers.
## Known gaps
- Allowlists save prompts; they are not a security boundary. Use the tool's sandbox for isolation.
- Prefix rules are bypassable: `git -C dir push`, flags placed later (`git push origin main --force`),
`+refspec` pushes. Claude Code's `:*` matches at a word boundary, so each flag cluster must be
listed — which is why `git clean` is denied whole and `rm` always asks.
- Allowed test, typecheck, and build commands run code from the repo; an agent that can edit
`package.json` or the tests can run anything through them (`bun run dev`/`start` run the server).
- Denying reads of `.env` does not stop a script that opens it itself, and
git can print staged or committed secrets (`git show HEAD:.env`). `git add -f` is denied so an agent
cannot stage an ignored secret; keep real secrets out of the working tree.
- Codex: loaded only once the user trusts the project; `approval_policy` here can loosen a stricter user
setting. No `allow` rules (allow = run outside the sandbox). In `workspace-write`, `.git/` is read-only, so
`git add`/`git commit` ask for escalation, and `bun install` needs network and asks too. Codex rules cannot
deny file reads. `--force-with-lease=<ref>`, `+refspec` and later-placed flags only hit the Ask rule.
- Gemini CLI: ignored until the folder is trusted. `tools.exclude` is deprecated but is the only
project-level deny. No Ask tier (anything not allowed asks). Cannot deny file reads.
- Cursor and Copilot: not configured — no sign the team uses them.
+43
View File
@@ -0,0 +1,43 @@
# TODO
Durable backlog. Agents append here instead of leaving `TODO` comments in source.
Small, specific, independently actionable. Remove only when actually done.
## Now
- [ ] Verify every `// TODO(verify)` field in `src/data/sample.ts` (48 at bootstrap: saga names, singers,
story times, Odyssey book/lines, motif descriptions, facts) before any content leaves mockup stage.
## Next
- [ ] After a direction is chosen: decide whether the unused mockups are deleted or kept, and record the
chosen direction in `DESIGN.md`.
- [ ] Add CI under `.gitea/workflows/` (none exists): `bun install --frozen-lockfile`, `bun test`,
`bun run typecheck`, `bun run build`; plus a check that `AGENTS.md`, `CLAUDE.md`, `GEMINI.md` and the
`docs/` paths exist and `AGENTS.md` is under 150 lines. Proposed, not added.
## Someday
- [ ] Make `bun dist/server.js` work from any cwd (Bun 1.3.14 resolves bundled assets relative to cwd;
try `--asset-naming` / `naming`, or re-check on a newer Bun). Today `bun run start` and Docker
work around it.
- [ ] Derive `src/server.ts` routes and `src/index.html` cards from `src/mockups/registry.ts` instead of
three hand-kept lists (tests catch drift today).
- [ ] Decide whether real lyrics may be shown (copyright question, deferred).
## Recurring
- [ ] Maintain `AGENTS.md`:
- **Add a rule only in response to a real failure.** When an agent repeatedly gets something wrong,
that is a gap; add one line, ideally with a code example. Do not pre-empt hypothetical mistakes.
- **Update in the same PR as the convention change.** A stale rules file is worse than none — it
actively misleads.
- **Prune quarterly.** Delete rules whose convention has changed or whose mistake no longer occurs.
- **Optional, cheap validation:** run the same task twice in clean sessions, with and without the
file, and compare steps and token use. This is how the published numbers were produced, and it is
the only way to know your file is helping rather than costing 20% for nothing.
## Known issues
- [ ] `bun dist/server.js` from the repo root crashes: `TypeError: Bundled file "./index-….js" not found`.
Repro: `bun run build && bun dist/server.js`. Workaround: `bun run start`.
- [ ] Two mockups with byte-identical `style.css` fail `bun run build` with "Multiple files share the same
output path" (reproduced by copying `01-editorial/style.css` over `02-vertical-story/style.css`).
Identical `main.ts` files do not trigger it.
- [ ] `docs/plans/001-timeline-mockups.md` tells mockup agents to start `bun dist/server.js`, which hits
the issue above; use `bun run start` instead.
+11
View File
@@ -0,0 +1,11 @@
# Plans
Implementation plans from the superpowers writing-plans workflow. **Transient:** a plan lives only on
its feature branch and is removed with `git rm` before the merge request is opened. This README stays.
- Naming: `NNN-short-slug.md`, matching its spec number.
- Links back to its spec. Bite-sized checkbox tasks with exact file paths, test commands, and
commit checkpoints.
- Written for an engineer with zero context for this codebase — spell out the obvious.
- Tick checkboxes as you go so another agent can resume an interrupted session.
- Front matter: `status: draft | approved | in-progress`. There is no `done` — a finished plan is deleted.
+10
View File
@@ -0,0 +1,10 @@
# Specs
Approved specifications from the superpowers brainstorming workflow. Nothing non-trivial gets
implemented without one.
- Naming: `NNN-short-slug.md`, zero-padded, sequential.
- A spec states **what** and **why**, plus acceptance criteria. Not **how**.
- Front matter: `status: draft | approved | implemented | superseded`. No link to a plan — plans are
removed before merge.
- Never delete an implemented spec; it is the record of intent.