agentleFS
nattiini45nattiini45/caotang/AGENTS.md

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.

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
  1. Very specific:

    Run pnpm verify, pnpm build and pnpm test:e2e before opening a PR.

    line 133
  2. Very specific:

    Use pnpm — the workspace uses workspace:* dependencies, which npm and yarn do not resolve the same way.

    line 134
  3. Very specific:

    Add a line to docs/decisions.md when you change a standing rule, and update the matching spec.

    line 136
  4. Very specific:

    Don't add onlyBuiltDependencies to pnpm-workspace.yaml naming a package that is not installed (see the gotcha above).

    line 140
  5. Very specific:

    Don't hand-edit apps/desktop/dist/ — it is build output.

    line 141
  6. Common:

    Don't write a test that needs a provider API key, and don't let one reach a real provider endpoint.

    line 142
  7. Common:

    Don't put a token, a key or a session secret into a project folder, an export or a log line.

    line 143
  8. Distinctive:

    Don't let the agent write to the project outside the command bus.

    line 144
  9. Distinctive:

    Don't push to main — open a pull request.

    line 145

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

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

PartStack
Workspacepnpm 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
LanguageTypeScript ^6.0.3 (strict)
AppReact 19.3, Vite 8.3.2 (rolldown/oxc, not esbuild)
Unit testsVitest 5.0.3 (node environment)
E2EPlaywright 1.63 (Chromium, Firefox and WebKit on pull requests; Firefox and WebKit nightly)
LintESLint 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:5173

A 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 JavaScript

Gotchas that bite:

  • pnpm verify does not run the pure model specs in e2e/unit/ — they are Playwright specs, so they run under pnpm test:e2e.
  • pnpm test:e2e starts its own dev server, and a second preview server on dev port + 1000. Set CAOTANG_E2E_PORT (and CAOTANG_E2E_PREVIEW_PORT) when running a second checkout beside another.
  • Do not add onlyBuiltDependencies to pnpm-workspace.yaml naming a package that is not installed. test/toolchain-floor.test.ts asserts every allowlist entry is actually present, so an orphan entry fails that test. The allowlist belongs in pnpm-workspace.yaml — pnpm 12 reads it from there, not from the pnpm block in package.json, and an entry left in package.json makes pnpm 12 fail the install with ERR_PNPM_IGNORED_BUILDS. Vite 8 bundles with rolldown/oxc, so esbuild no longer resolves anywhere in the tree — that is why the allowlist is empty.
  • pnpm build writes THIRD-PARTY-NOTICES.md into apps/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 decided

Conventions

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/*.md and 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 to docs/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 build and pnpm test:e2e before opening a PR. CI runs pnpm 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 uses workspace:* dependencies, which npm and yarn do not resolve the same way.
  • Regenerate THIRD-PARTY-NOTICES.md when you add or upgrade a dependency.
  • Add a line to docs/decisions.md when you change a standing rule, and update the matching spec.

Don't

  • Don't add onlyBuiltDependencies to pnpm-workspace.yaml naming 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

VariableEffect
CAOTANG_BASEBuild for a sub-path, e.g. CAOTANG_BASE=/app/ pnpm build. Default: asset paths start at /.
CAOTANG_E2E_PORTDev-server port for the Playwright suite (default 5173). Setting it also stops the suite from reusing an existing server.
CAOTANG_E2E_PREVIEW_PORTProduction-preview port (default = dev port + 1000).
CAOTANG_MCP_ALLOW_WRITEStrue allows the MCP server to write to the project folder.
CAOTANG_MCP_TOKENBearer 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.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.