chore: bootstrap agent-ready docs and rules
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
10ce858b31
commit
80f6c97127
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(git status:*)", "Bash(git diff:*)", "Bash(git log:*)", "Bash(git show:*)",
|
||||
"Bash(git branch --list:*)", "Bash(git rev-parse:*)", "Bash(git add:*)", "Bash(git commit:*)",
|
||||
"Bash(bun install --frozen-lockfile:*)", "Bash(bun test:*)", "Bash(bun run typecheck:*)",
|
||||
"Bash(bun run build:*)", "Bash(bun run dev:*)", "Bash(bun run start:*)"
|
||||
],
|
||||
"ask": [
|
||||
"Bash(git push:*)", "Bash(git merge:*)", "Bash(git rebase:*)", "Bash(git switch:*)",
|
||||
"Bash(git restore:*)", "Bash(git commit --amend:*)", "Bash(rm:*)",
|
||||
"Bash(bun add:*)", "Bash(bun remove:*)", "Bash(bun update:*)", "Bash(bun upgrade:*)",
|
||||
"Bash(bunx:*)", "Bash(npx:*)", "Bash(docker:*)"
|
||||
],
|
||||
"deny": [
|
||||
"Bash(git push --force:*)", "Bash(git push -f:*)", "Bash(git push --force-with-lease:*)",
|
||||
"Bash(git reset --hard:*)", "Bash(git clean:*)", "Bash(git add -f:*)", "Bash(git add --force:*)",
|
||||
"Bash(git commit --no-verify:*)", "Bash(git commit -n:*)",
|
||||
"Bash(rm -r:*)", "Bash(rm -R:*)", "Bash(rm -rf:*)", "Bash(rm -fr:*)", "Bash(rm -Rf:*)",
|
||||
"Bash(rm -fR:*)", "Bash(rm --recursive:*)", "Bash(sudo:*)",
|
||||
"Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
sandbox_mode = "workspace-write"
|
||||
approval_policy = "on-request"
|
||||
@@ -0,0 +1,20 @@
|
||||
# Rendered from docs/PERMISSIONS.md. No allow rules: in Codex, allow means "run outside the sandbox".
|
||||
# Deny
|
||||
prefix_rule(pattern = ["git", "push", ["--force", "-f", "--force-with-lease"]], decision = "forbidden",
|
||||
justification = "Force-push rewrites shared history.")
|
||||
prefix_rule(pattern = ["git", "reset", "--hard"], decision = "forbidden", justification = "Discards work.")
|
||||
prefix_rule(pattern = ["git", "clean"], decision = "forbidden", justification = "Deletes untracked files.")
|
||||
prefix_rule(pattern = ["git", "add", ["-f", "--force"]], decision = "forbidden",
|
||||
justification = "Stages ignored files, e.g. secrets.")
|
||||
prefix_rule(pattern = ["git", "commit", ["--no-verify", "-n"]], decision = "forbidden", justification = "Skips hooks.")
|
||||
prefix_rule(pattern = ["rm", ["-r", "-R", "-rf", "-fr", "-Rf", "-fR", "--recursive"]], decision = "forbidden",
|
||||
justification = "Recursive delete.")
|
||||
prefix_rule(pattern = ["sudo"], decision = "forbidden", justification = "No privilege escalation.")
|
||||
# Ask
|
||||
prefix_rule(pattern = ["git", ["push", "merge", "rebase", "switch", "restore"]], decision = "prompt")
|
||||
prefix_rule(pattern = ["git", "commit", "--amend"], decision = "prompt")
|
||||
prefix_rule(pattern = ["rm"], decision = "prompt")
|
||||
prefix_rule(pattern = ["bun", ["add", "remove", "update", "upgrade"]], decision = "prompt")
|
||||
prefix_rule(pattern = ["bunx"], decision = "prompt")
|
||||
prefix_rule(pattern = ["npx"], decision = "prompt")
|
||||
prefix_rule(pattern = ["docker"], decision = "prompt")
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"tools": {
|
||||
"allowed": [
|
||||
"run_shell_command(git status)", "run_shell_command(git diff)", "run_shell_command(git log)",
|
||||
"run_shell_command(git show)", "run_shell_command(git branch --list)", "run_shell_command(git rev-parse)",
|
||||
"run_shell_command(git add)", "run_shell_command(git commit)",
|
||||
"run_shell_command(bun install --frozen-lockfile)", "run_shell_command(bun test)",
|
||||
"run_shell_command(bun run typecheck)", "run_shell_command(bun run build)",
|
||||
"run_shell_command(bun run dev)", "run_shell_command(bun run start)"
|
||||
],
|
||||
"exclude": [
|
||||
"run_shell_command(git push --force)", "run_shell_command(git push -f)",
|
||||
"run_shell_command(git push --force-with-lease)", "run_shell_command(git reset --hard)",
|
||||
"run_shell_command(git clean)", "run_shell_command(git add -f)", "run_shell_command(git add --force)",
|
||||
"run_shell_command(git commit --no-verify)", "run_shell_command(git commit -n)",
|
||||
"run_shell_command(rm -r)", "run_shell_command(rm -R)", "run_shell_command(rm -rf)",
|
||||
"run_shell_command(rm -fr)", "run_shell_command(rm -Rf)", "run_shell_command(rm -fR)",
|
||||
"run_shell_command(rm --recursive)", "run_shell_command(sudo)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -4,3 +4,5 @@ dist/
|
||||
CLAUDE.local.md
|
||||
.worktrees/
|
||||
screenshots/
|
||||
.superpowers/
|
||||
.claude/settings.local.json
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# EPIC: The Musical Timeline
|
||||
|
||||
Unofficial fan site: an interactive timeline of *EPIC: The Musical* songs. Currently 7 design-direction
|
||||
mockups. Bun 1.3.14 (server, bundler, test runner), TypeScript, three.js (mockups 06/07 only), Docker.
|
||||
|
||||
`AGENTS.md` is the single source of truth for agents here. `CLAUDE.md` and `GEMINI.md` only point here.
|
||||
Deeper context on demand: `docs/ARCHITECTURE.md`, `docs/DECISIONS.md`, `docs/TODO.md`.
|
||||
|
||||
## Commands
|
||||
|
||||
Install: `bun install --frozen-lockfile`
|
||||
Dev: `bun run dev` (`PORT` env, default 3000)
|
||||
Test: `bun test` | Single file: `bun test tests/data.test.ts` | Single case: `bun test -t "registry has 7"`
|
||||
Typecheck: `bun run typecheck`
|
||||
Build: `bun run build` | Run the build: `bun run start`
|
||||
Docker: `docker build -t epic-timeline .` then `docker run --rm -p 3000:3000 epic-timeline`
|
||||
|
||||
Run the production bundle **from inside `dist/`**. Bun resolves bundled assets relative to the cwd:
|
||||
```sh
|
||||
bun run start # right: cd dist && bun server.js
|
||||
bun dist/server.js # wrong: crashes with 'Bundled file "./index-….js" not found'
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
- Every page shows the fan notice and the Jorge Rivera-Herrans credit: keep `<footer data-fan-credits>`
|
||||
and the `../../shared/credits.css` link in the page's HTML, and call `mountCredits()` from
|
||||
`src/shared/credits.ts`. Never write your own notice text.
|
||||
- Mockup agents edit only their own `src/mockups/NN-slug/` folder. `src/data/`, `src/shared/`,
|
||||
`src/server.ts`, `src/index.html` and `src/mockups/registry.ts` are the shared contract; change them
|
||||
only when the plan says so.
|
||||
- No two mockups may have byte-identical `style.css` — the build fails with
|
||||
"Multiple files share the same output path". Give each one its own styles from the start.
|
||||
- Sample data (`src/data/sample.ts`): lyrics are placeholders, never real lyrics. Any fact, story time
|
||||
or Odyssey reference you can't confirm gets `// TODO(verify)`.
|
||||
- Assets are bundled, never loaded from a CDN: fonts from `@fontsource/*`, three.js from npm.
|
||||
YouTube videos are link cards (`createVideoCards`), not embeds.
|
||||
- Adding a mockup route means editing `src/server.ts`, `src/mockups/registry.ts` and the cards in
|
||||
`src/index.html` together; `tests/server.test.ts` checks they agree.
|
||||
|
||||
## Workflow
|
||||
|
||||
Required skills: `superpowers`, `impeccable`. Check at session start; install if missing.
|
||||
Specs → `docs/specs/NNN-slug.md` (permanent). Plans → `docs/plans/NNN-slug.md` while in progress;
|
||||
`git rm` them before opening a merge request — the spec is the record.
|
||||
(Overrides the superpowers default paths.)
|
||||
|
||||
Anything beyond a trivial fix: brainstorm → spec (sign-off) → plan (sign-off) → TDD → review.
|
||||
Tick plan checkboxes as you go so an interrupted session is resumable.
|
||||
Trivial changes (typo, version bump, one-line config): say "trivial, skipping spec" and proceed.
|
||||
|
||||
Use impeccable for user-facing UI — `craft` for new, `audit`/`polish` on existing, `harden` before
|
||||
shipping. Design context: `PRODUCT.md`, `DESIGN.md`. No visual direction is chosen yet (see `DESIGN.md`).
|
||||
|
||||
Mockup rounds — any UI change beyond a trivial tweak, while brainstorming and before the spec:
|
||||
- Round 1: about three genuinely different alternatives, each a clickable mockup with realistic
|
||||
content, plus an index page giving each a one-line pitch and what to try.
|
||||
- Then diverge (about three options on one open question) or converge (one combined mockup); small
|
||||
choices can be toggles inside one mockup. Repeat until the user approves one mockup.
|
||||
- Once `DESIGN.md` has a chosen direction, options vary structure, flow and behaviour within it —
|
||||
never a new palette or font family.
|
||||
- **This repo deviates from the usual throwaway setup:** mockups live in `src/mockups/NN-slug/`, are
|
||||
committed, served by the app and smoke-tested.
|
||||
- On approval, write `docs/design/NNN-slug.md` (the spec's number): each chosen idea, buildable without
|
||||
the mockup, and what was deselected and why. The spec links it.
|
||||
|
||||
## Architecture
|
||||
|
||||
`src/server.ts` -> `Bun.serve` with HTML-import routes: `/` and `/mockups/NN-slug/`
|
||||
`src/data/` -> `types.ts` (shapes), `sample.ts` (shared sample data), `query.ts` (helpers)
|
||||
`src/shared/` -> credits, audio slot (direct MP3, empty state), YouTube link cards
|
||||
`src/mockups/NN-slug/` -> one design direction each: `index.html`, `main.ts`, `style.css`
|
||||
`tests/` -> data invariants, shared DOM modules (happy-dom), route smoke tests
|
||||
|
||||
Full picture: `docs/ARCHITECTURE.md` — read it before your first change in a session.
|
||||
|
||||
## Boundaries
|
||||
|
||||
Never touch: `dist/`, `node_modules/`.
|
||||
Never commit `.env`, secrets, or credentials.
|
||||
Never force-push or rewrite pushed history.
|
||||
|
||||
Ask first: new runtime dependencies · changes to `src/data/types.ts` or the shared modules ·
|
||||
the Dockerfile · work the approved plan does not cover.
|
||||
|
||||
If the task turns out much larger than the plan assumed: stop, report, re-plan.
|
||||
|
||||
## Docs duties
|
||||
|
||||
Same commit as the code, not "later":
|
||||
- `docs/ARCHITECTURE.md` — when a module, boundary, or data flow changes.
|
||||
- `docs/DECISIONS.md` — append-only; any choice a future maintainer would reverse-engineer.
|
||||
- `docs/TODO.md` — anything noticed and deliberately not fixed. No `TODO` comments in source
|
||||
(`// TODO(verify)` in sample data is the exception).
|
||||
- `docs/PERMISSIONS.md` — together with every tool permission file (`.claude/settings.json`,
|
||||
`.codex/`, `.gemini/settings.json`), in one commit.
|
||||
|
||||
## Git
|
||||
|
||||
Remote `origin` is Gitea, not GitHub: `gh` does not apply. Commits: Conventional Commits (`feat:`,
|
||||
`docs:`, `chore:`, `feat(mockups):`).
|
||||
Branches: TODO(maintainer): confirm whether work goes on branches (suggest `feat|fix|chore/<slug>`) or straight to `main` as so far.
|
||||
|
||||
## Done means verified
|
||||
|
||||
Do not report success on work you have not run. Before saying done:
|
||||
`bun test` and `bun run typecheck` run *in this session* and seen passing · `bun run build` succeeds ·
|
||||
matches the approved spec · docs duties complete · `git status` clean and the diff is only what you intended.
|
||||
UI work, in the app or a mockup: with `bun run start` running, take headless screenshots at 1440×900
|
||||
(`google-chrome --headless --window-size=1440,900 --screenshot=screenshots/x.png <url>`, or Playwright)
|
||||
of each screen you changed into `screenshots/` (gitignored) and look at them before saying done.
|
||||
"It should work" is not verification.
|
||||
@@ -0,0 +1,9 @@
|
||||
# CLAUDE.md
|
||||
|
||||
**`AGENTS.md` is the single source of truth for this repository.** Read it now and follow it exactly.
|
||||
|
||||
@AGENTS.md
|
||||
|
||||
This file exists only so Claude Code finds the rules, and for Claude-specific configuration that
|
||||
AGENTS.md cannot express. It contains no project rules of its own — add those to `AGENTS.md`.
|
||||
If anything here ever conflicts with `AGENTS.md`, `AGENTS.md` wins.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Design
|
||||
|
||||
## Status: visual direction open
|
||||
No design system, palette or type scale is chosen yet. Seven mockups under `src/mockups/` each commit fully
|
||||
to a different direction; the maintainer will pick one, or combine several, and this file then records the
|
||||
chosen direction as tokens and rules. Until then, do not treat any single mockup's palette or fonts as the
|
||||
house style.
|
||||
|
||||
## The candidate directions
|
||||
| # | Folder | Direction |
|
||||
|---|---|---|
|
||||
| 1 | `01-editorial` | Editorial scroll: horizontal line, parchment and serif, motifs as thin threads |
|
||||
| 2 | `02-vertical-story` | Vertical story: downward scroll with a sticky detail panel |
|
||||
| 3 | `03-transit-map` | Transit map: motifs as metro lines, songs as stations |
|
||||
| 4 | `04-greek-frieze` | Greek frieze: an unrolled black-figure vase frieze |
|
||||
| 5 | `05-score` | Score / waveform: staff or waveform, parts as segments |
|
||||
| 6 | `06-constellation` | Constellation (3D, three.js): songs as stars |
|
||||
| 7 | `07-sea-voyage` | Sea voyage (3D, three.js): ship, sea, saga islands |
|
||||
|
||||
Details per direction: `docs/specs/001-timeline-mockups.md`.
|
||||
|
||||
## Constraints that hold for every direction
|
||||
- Fonts are self-hosted from `@fontsource/*` (installed: Cormorant Garamond, Inter); nothing from a CDN.
|
||||
- three.js only where a direction is 3D.
|
||||
- Motif colours come from the data (`Motif.color` in `src/data/sample.ts`), so threads match across views.
|
||||
- The fan-credits footer (`src/shared/credits.css`) is present on every page; a direction may restyle it
|
||||
but not remove or hide it.
|
||||
- Avoid generic, templated "AI-looking" UI; a direction that is just another layout in different colours
|
||||
has failed.
|
||||
@@ -0,0 +1,7 @@
|
||||
# GEMINI.md
|
||||
|
||||
**`AGENTS.md` is the single source of truth for this repository.** Read `./AGENTS.md` before doing
|
||||
anything else and follow it exactly.
|
||||
|
||||
This file exists only so Gemini CLI finds the rules. It contains no project rules of its own — add
|
||||
those to `AGENTS.md`. If anything here ever conflicts with `AGENTS.md`, `AGENTS.md` wins.
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Product
|
||||
|
||||
## What it is
|
||||
An interactive, **unofficial fan website** for *EPIC: The Musical* by **Jorge Rivera-Herrans**. Its core is
|
||||
one long timeline of the songs. Recurring musical motifs and character themes are drawn as threads between
|
||||
the songs where they appear, and the gaps between songs show how much in-story time passes.
|
||||
|
||||
Opening a song shows: its place in Homer's *Odyssey* (with a link to a public-domain translation), its
|
||||
in-story time, its lyrics split into the song's parts with the singer of each part, the motifs in each part,
|
||||
fun facts, related YouTube videos, and an audio player for a direct MP3 when one exists.
|
||||
|
||||
## Who it is for
|
||||
TODO(maintainer): confirm. Working assumption from the spec: fans of EPIC who want to explore how motifs
|
||||
recur across the songs and how the story maps onto the *Odyssey*. Desktop first (about 1440×900).
|
||||
|
||||
## Non-negotiables
|
||||
- **Fan notice and credit on every page:** the site is unofficial, not affiliated with or endorsed by the
|
||||
creator, and thanks Jorge Rivera-Herrans as the creator of EPIC. One shared snippet
|
||||
(`src/shared/credits.ts`), never retyped.
|
||||
- **Accuracy is visible:** content that isn't verified is marked as such (`// TODO(verify)` in data) and never
|
||||
presented as fact-checked.
|
||||
- **Lyrics:** mockups use placeholder lyric lines only. Whether and how real lyrics are shown is an open
|
||||
copyright question, deferred by the maintainer.
|
||||
- **Media:** videos are YouTube link cards (no embedded player); audio supports direct MP3 URLs. The app
|
||||
works offline apart from following those links.
|
||||
|
||||
## Tone
|
||||
Polished and smooth; may use 3D (three.js). It should feel like a crafted piece made by a fan, not a generic
|
||||
template — see `DESIGN.md`.
|
||||
|
||||
## Current stage
|
||||
Spec `docs/specs/001-timeline-mockups.md`: 7 design-direction mockups over shared sample data (Troy and
|
||||
Cyclops sagas plus later callback songs). The maintainer picks or combines a direction; the real app gets
|
||||
its own spec after that.
|
||||
@@ -0,0 +1,6 @@
|
||||
# EPIC: The Musical Timeline
|
||||
|
||||
An unofficial fan project: an interactive timeline of *EPIC: The Musical*. Not affiliated with or endorsed by
|
||||
its creator, Jorge Rivera-Herrans. See `PRODUCT.md` for what it is.
|
||||
|
||||
Working on this repo (human or agent): start with [`AGENTS.md`](AGENTS.md) — commands, rules and workflow.
|
||||
@@ -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`.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user