caotang
AGENTS.md1 starsChanged 7 days agoMITView on GitHub
Caotang is a local-first writing studio for long-form work: novels and other long fiction first, and the scripts and serials a writer makes from them — screenplays, comics, podcasts, narrated video and newsletters. It is a browser app where the manuscript lives on your own machine (a project folder or the browser), an AI agent works in it under your approval, and a compile step exports Word, EPUB, Markdown, Fountain, Ink and storyboards. Pictures, comics, a timeline and interface languages…
- Installs packages
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,700 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repositoryOne other file it gives its agents.
- site/llms.txtllms.txt
The file
We split this AGENTS.md into the rules it gives an agent
9 rules. About 2 are common, 2 are distinctive, and 5 are very specific to this project.
≈2
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 133
Run pnpm verify, pnpm build and pnpm test:e2e before opening a PR.
- Very specific: line 134
Use pnpm — the workspace uses workspace:* dependencies, which npm and yarn do not resolve the same way.
- Very specific: line 136
Add a line to docs/decisions.md when you change a standing rule, and update the matching spec.
- Very specific: line 140
Don't add onlyBuiltDependencies to pnpm-workspace.yaml naming a package that is not installed (see the gotcha above).
- Very specific: line 141
Don't hand-edit apps/desktop/dist/ — it is build output.
- Common: line 142
Don't write a test that needs a provider API key, and don't let one reach a real provider endpoint.
- Common: line 143
Don't put a token, a key or a session secret into a project folder, an export or a log line.
- Distinctive: line 144
Don't let the agent write to the project outside the command bus.
- Distinctive: line 145
Don't push to main — open a pull request.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AGENTS.md — Caotang
Caotang is a local-first writing studio for long-form work: novels and other long fiction first, and the scripts and serials a writer makes from them — screenplays, comics, podcasts, narrated video and newsletters. It is a browser app where the manuscript lives on your own machine (a project folder or the browser), an AI agent works in it under your approval, and a compile step exports Word, EPUB, Markdown, Fountain, Ink and storyboards. Pictures, comics, a timeline and interface languages are built; web publishing is specified and not built, and AV scripts are built only as far as their model and parser; docs/ROADMAP.md says which.
There is no backend server, no account, no telemetry. The app is static files; the model provider is the only network dependency, plus any MCP server you connect yourself.
Stack
| Part | Stack |
| Workspace | pnpm monorepo (pnpm@12.9.1 pinned in the root packageManager field), corepack enable |
| Node | ^22.19.0 || ^24.0.0 || >=26.0.0 — CI tests Node 22.19.0 and 24; Node 26 is allowed but not covered |
| Language | TypeScript ^6.0.3 (strict) |
| App | React 19.3, Vite 8.3.2 (rolldown/oxc, not esbuild) |
| Unit tests | Vitest 5.0.3 (node environment) |
| E2E | Playwright 1.63 (Chromium, Firefox and WebKit on pull requests; Firefox and WebKit nightly) |
| Lint | ESLint 9 + typescript-eslint |
Workspace globs (pnpm-workspace.yaml): apps/*, packages/*, vendor/*, site.
Setup
On Node 22, first run npm install --global corepack@0.34.3; Node 22.12's bundled Corepack 0.29.4 could not verify pnpm 12.9.1's current signing key.
corepack enable # uses the pnpm version pinned in package.json
pnpm install
pnpm dev # the app at http://127.0.0.1:5173A Chromium-based browser (Chrome, Edge, Brave, Arc) is needed for the end-to-end suite and for folder save/access — other browsers only get in-browser projects and .caotang bundles.
Commands
pnpm verify # lint + typecheck + unit tests — the pre-PR gate
pnpm lint # eslint .
pnpm typecheck # pnpm -r typecheck && tsc --noEmit -p tsconfig.json
pnpm test # vitest run
pnpm test:watch # vitest
pnpm test:e2e # playwright test (needs a Chromium install)
pnpm build # → apps/desktop/dist/
pnpm --filter @caotang/desktop preview # serves the built app on :4173
pnpm --filter @caotang/desktop dev # dev server on :5173
pnpm exec playwright install chromium # once per machine
pnpm --filter @caotang/mcp-server build # → packages/mcp-server/dist/caotang-mcp.mjs
pnpm --filter @caotang/mcp-server run pack # → caotang-mcp-0.1.0.mcpb
node tools/third-party-notices.mjs --write # regenerate THIRD-PARTY-NOTICES.md
node tools/build-site.mjs # the landing page → site/dist/
node tools/check-site-size.mjs # the landing page's HTML, CSS and asset caps, and no JavaScriptGotchas that bite:
pnpm verifydoes not run the pure model specs ine2e/unit/— they are Playwright specs, so they run underpnpm test:e2e.pnpm test:e2estarts its own dev server, and a second preview server on dev port + 1000. SetCAOTANG_E2E_PORT(andCAOTANG_E2E_PREVIEW_PORT) when running a second checkout beside another.- Do not add
onlyBuiltDependenciestopnpm-workspace.yamlnaming a package that is not installed.test/toolchain-floor.test.tsasserts every allowlist entry is actually present, so an orphan entry fails that test. The allowlist belongs inpnpm-workspace.yaml— pnpm 12 reads it from there, not from thepnpmblock inpackage.json, and an entry left inpackage.jsonmakes pnpm 12 fail the install withERR_PNPM_IGNORED_BUILDS. Vite 8 bundles with rolldown/oxc, soesbuildno longer resolves anywhere in the tree — that is why the allowlist is empty. pnpm buildwritesTHIRD-PARTY-NOTICES.mdintoapps/desktop/dist/. A test fails when the committed copy drifts from the lockfile — regenerate it with the tool above whenever a dependency changes.
Layout
apps/desktop/ the app (Vite + React + TS) → dist/ is build output, never edited by hand
packages/bus/ the command bus — every change goes through it
packages/codex/ codex entries (characters, places, lore, subplots)
packages/coherence/ findings and coherence checks
packages/context/ context assembly for agent requests
packages/crypto/ key hierarchy, file sealing and rollback marks for the hosted instance (specified, not built; nothing imports it)
packages/dialogue/ branching dialogue (Ink)
packages/editor/ the scene editor
packages/editor-audit/ editor audit trail
packages/exporter/ compile/export (docx, epub, md, txt, fountain, fdx, pdf, ink)
packages/furniture/ binder / corkboard furniture
packages/gateway/ provider gateway (profiles, roles, endpoints)
packages/harness/ the agent harness — its tools and its registry
packages/import-rtf/ the RTF reader every RTF-based import shares (standalone .rtf/.rtfd and Scrivener's content.rtf): bytes → the import block list and its losses; no DOM, no dependencies
packages/ids/ id helpers
packages/import-read/ the readers every import shares: a namespace-aware XML reader (no DOMParser) and a zip/folder reader over fflate's unzipSync with caps; main thread, Worker and Node; and the plain-text reader (any common encoding, to import blocks)
packages/i18n/ interface locale, formatter locale, cached Intl formatters, collation, bidi isolation, MessageRef (no React, no Lingui)
packages/import-core/ the import block model and the pure chapter and scene splitter every document reader shares (no DOM, no dependencies)
packages/mcp-client/ MCP client (Streamable HTTP)
packages/mcp-server/ Caotang as an MCP server (@caotang/mcp-server)
packages/pdf-fonts/ what both PDFs share for their fallback fonts (byte checks, fontkit, CID writer, emoji)
packages/pictures/ the picture registry's pure parts: the record, usesOf, assets/ file names, the import pipeline (GPS strip, hash)
packages/remote-store/ ArtifactFs over an encrypted remote blob store for the hosted instance (specified, not built; nothing imports it)
packages/screenplay/ Fountain screenplay model
packages/script/ the AV script: the linear timed script model, its parser, line ids and runtime totals (pure)
packages/scan/ the deterministic continuity scan as a library, for a writer's own CI (@caotang/scan); the `caotang scan` command is in packages/cli
packages/sdk/ run the agent from Node against a project folder (@caotang/sdk); owns the Node folder session the MCP server shares
packages/skills/ Agent Skills folders: the SKILL.md reader, the caps, the review pin, the model's catalog
packages/store/ the project store and the manifest
packages/storyboard/ shot cards and animatics
packages/tasks/ recurring agent tasks: tasks.json, when a task is due, what a task may do (pure; the run and the history are the app's)
packages/video-prompt-pack/
vendor/noto-sans-cjk/ @caotang/font-noto-cjk
vendor/noto-emoji/ @caotang/font-noto-emoji
vendor/noto-color-emoji/ @caotang/font-noto-color-emoji (the colour emoji, compiled offline to PDF operators)
vendor/noto-sans-arabic/ @caotang/font-noto-arabic
vendor/noto-sans-hebrew/ @caotang/font-noto-hebrew
site/ the landing page; the workspace package `@caotang/site`, built from `site/` into `site/dist/` by `node tools/build-site.mjs`
e2e/ Playwright specs; e2e/unit/ holds the pure model specs
test/ repo-level vitest guards (lockfile, toolchain floor, guide claims, …)
tools/ third-party-notices.mjs
docs/architecture/ one spec per module — the contract
docs/decisions.md standing decisions, one line each, with who decidedConventions
For product context and the incumbent design language, read PRODUCT.md and DESIGN.md; the linked architecture specs remain the source of truth.
These are the project's own rules (see CONTRIBUTING.md and docs/decisions.md); they hold everywhere.
- The specs are the contract.
docs/architecture/*.mdand the code agree. If the code does something the spec does not say, either the code is wrong or the spec is incomplete — fix one of them in the same pull request. Changing behaviour a spec describes means changing the spec deliberately in the same PR and adding a line todocs/decisions.md. - A new command, tool, project-format file or setting starts in its spec.
- Projects stay local. Nothing is sent anywhere except the provider and MCP servers the writer configured.
- Keys and tokens never go into a project, a bundle, an export or a log.
- The agent changes the project only through the command bus, so every change is gated, logged and undoable.
- Project files stay plain text. A project is a folder:
caotang.json(manifest),coherence.json,docs/(one file per scene,.md/.fountain/.ink),codex/,assets/,exports/,sessions.jsonl. - Commits: the subject is a plain sentence saying what is now true (
The export dialog shows a refused compile beside Compile.), not "Fix bug". One logical change per commit. - Pull requests: one change, describable in a sentence or two; say what changed, why, and how you checked it; include tests (a unit test for module behaviour, an e2e test for anything a writer sees); update the writer-facing docs (
README.md,docs/USER-GUIDE.md,CHANGELOG.md) when behaviour changes. - User-facing text is plain words, whole sentences, and names what the writer can do next.
- Tests never need a real provider key. They run against the built-in mock and demo providers.
Do / Don't
Do
- Run
pnpm verify,pnpm buildandpnpm test:e2ebefore opening a PR. CI runspnpm verify, the production build, bundle-size check, MCP pack and CLI build on Node 22.19.0 and 24; Chromium E2E runs on Node 24 in parallel, and a separate workflow gates PRs in Firefox and WebKit. - Use
pnpm— the workspace usesworkspace:*dependencies, which npm and yarn do not resolve the same way. - Regenerate
THIRD-PARTY-NOTICES.mdwhen you add or upgrade a dependency. - Add a line to
docs/decisions.mdwhen you change a standing rule, and update the matching spec.
Don't
- Don't add
onlyBuiltDependenciestopnpm-workspace.yamlnaming a package that is not installed (see the gotcha above). - Don't hand-edit
apps/desktop/dist/— it is build output. - Don't write a test that needs a provider API key, and don't let one reach a real provider endpoint.
- Don't put a token, a key or a session secret into a project folder, an export or a log line.
- Don't let the agent write to the project outside the command bus.
- Don't push to
main— open a pull request.
Environment variables
| Variable | Effect |
CAOTANG_BASE | Build for a sub-path, e.g. CAOTANG_BASE=/app/ pnpm build. Default: asset paths start at /. |
CAOTANG_E2E_PORT | Dev-server port for the Playwright suite (default 5173). Setting it also stops the suite from reusing an existing server. |
CAOTANG_E2E_PREVIEW_PORT | Production-preview port (default = dev port + 1000). |
CAOTANG_MCP_ALLOW_WRITES | true allows the MCP server to write to the project folder. |
CAOTANG_MCP_TOKEN | Bearer token for the MCP server over HTTP (at least 16 characters). |
Deploy
.github/workflows/pages.yml publishes caotang.app: the landing page, built from site/ into site/dist, at the origin root, and the app built with CAOTANG_BASE=/app/ at /app/. CI runs node tools/build-site.mjs and node tools/check-site-size.mjs beside the app build, and the page ships no JavaScript (its CSP keeps script-src 'none'; docs/architecture/landing.md is its spec). The build must be served from the root of its origin unless CAOTANG_BASE is used, and over HTTPS (WebCrypto key sealing and folder access need a secure origin). The CSP travels in the built index.html as a <meta> tag; no _headers file ships in the tree. For hosts that can send headers (Netlify, Cloudflare Pages), the deployer creates one — README.md shows the file to write.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

