Write the agent files
Write your project’s rules into the files agents read on their own, AGENTS.md and the Ascribe skill, and keep them current.
For AI agents: the documentation index is at llms.txt, and this page is available as Markdown.
ascribe agents sync writes your project’s rules into the files agents read on their own, from ascribe.toml:
ascribe agents sync
It writes:
AGENTS.mdbesideascribe.toml: the check to run after each edit and before finishing, to runascribe searchfor a subject before writing a page about it, your page types with what each is for and its frontmatter, and that each page names its type withtype:, your phrases, the directives your pages use, with your dimensions and their values for@variantand an example of your own targets for@available, and how to link. It’s at most 4,000 characters; when it would be longer, what an agent can read elsewhere is cut first, and the page types last.- A short block in the repository’s root
AGENTS.md, when your project is in a subfolder: where its pages are, the check to run, and where its full rules are. Some agents, such as Codex, read noAGENTS.mdbelow the folder they start in. - The skill, in
.agents/skills/ascribe/at the repository’s root. See The skill.
Beside each file it writes, sync says which agents read it, and when an agent doesn’t read one, the target that writes it where that agent does. Claude Code doesn’t read the skill in .agents/skills/, so without the claude target, sync says so:
wrote AGENTS.md read by Claude Code, Codex, Copilot, and Cursor
wrote .agents/skills/ascribe/SKILL.md read by Codex, Copilot, Cursor, and Gemini CLI
wrote .agents/skills/ascribe/references/directives.md read by Codex, Copilot, Cursor, and Gemini CLI
Claude Code doesn't read the skill in .agents/skills/; `--target claude` writes it to .claude/skills/ too, where it does.When a page has a @memo, AGENTS.md also tells the agent to read a block’s memo before changing the block, and to keep the two together. When the project has a memo file in memos/, a sentence after it says that ascribe outline <page> lists the memos about a page and its headings, and to read a memo before changing the block it’s about. A personal memo doesn’t count, so the rules are the same on every machine. When the rules run over their 4,000 characters, those sentences are cut first.
When a page declares a permalink, AGENTS.md also says, with how to link, that a product’s message linking to the docs by a permalink can read what the docs will show for it with ascribe resolve go:<name>, which prints the help a product shows. When a heading declares one, it says to give the heading’s section a @summary, the sentence a product shows with its help, and how to choose between @summary above a paragraph and @summary: <text>; ascribe check --format prompt quotes the text of each section without one, so the agent can write it.
When the project has an ascribe.addresses, AGENTS.md also has a section on moving pages: move or rename a page with ascribe rename, which records the move; after moving pages with git mv, record the moves git sees with ascribe addresses move --from-git; and forward or retire a page deleted on purpose, with ascribe addresses move <old> <page> or ascribe addresses retire <old> --reason "<why>", since ascribe check reports address-lost for one that’s gone with neither.
AGENTS.md also says how to see what a reader of the site gets, not only a reader of the Markdown: ascribe resolve <page> --build <name> --emit site, or ascribe_resolve with emit: "site", writes the page as the site output gives it, and links to reading the site output. The skill’s line for ascribe resolve says the same.
What a type is for is its purpose in ascribe.toml, or, for a type ascribe templates eject added, The Good Docs Project’s summary of it, from templates.lock (the content model reference).
Here’s what it writes for the Quill example:
<!-- ascribe:agents start (generated by `ascribe agents sync`; edit ascribe.toml, not this block) -->
## Ascribe documentation
The Markdown pages under `docs/` are Ascribe documentation: pages with YAML frontmatter, `@` directives, and `{key}` phrases, checked against the content model in `ascribe.toml`.
After editing a page, run `ascribe check <file> --format concise` and fix every error. Before you finish, run `ascribe check`. `ascribe explain <code>` says what a problem means and how to fix it.
Before writing a page about a subject, run `ascribe search "<words>"` to find where the pages already say it, as readers read them, and link to what's there or extend it instead of saying it again.
Read a block's `@memo` before changing the block, and keep the two together: a memo says why the page is written the way it is, and is never published.
`ascribe outline <page>` lists the memo files about a page and each of its headings: read a memo before changing the block it's about, and keep it.
### Page types
A page says what type it is with `type:` in its frontmatter, first, and its other fields are its type's. A file or folder whose name starts with `_` is a fragment, which pages `@include`, not a page, and names no type.
- `page`: frontmatter `title` (string, required), `description` (string)
### Phrases
Write the phrase (`{product}`), not the text it stands for.
- `{product}`: Quill
- `{cloud}`: Quill Cloud
- `{version}`: 3.4.1
- `{api}`: https://api.quill.dev/v3/
### Directives this project uses
- `@id: <id>` on the line under a heading: an id for links to it that doesn't change with its text
- `@include: <file>.md`, or `@include: <file>.md#<id>` for one section: another file's content, in place
- `@variant {<dimension>=<value>}:` before each arm, and one `@end` after the last: content that differs by a dimension. Here: dimensions `pm` (`npm`, `pnpm`, `yarn`), `deployment` (`cloud`, `self-managed`)
- `@available: <spec>` under a heading or above a block: where it applies, as targets with an optional state and version (`cloud, self-managed`), or a feature's key
- `@note {type=<type>}: <text>`, or `@note:` … `@end` around several blocks: a callout. Here: types `note`, `tip`, `important`, `warning`, `caution`
- `@steps` on the line above an ordered list: the list is a procedure
- `@memo: <text>` under a heading or above a block, or `@memo:` … `@end` around several lines: a note for whoever maintains the page, never published
### Links
Link to the source file, with a relative path such as `../guides/install.md#configure`, not to the site's address. `ascribe outline <page>` lists a page's headings with their ids, and `ascribe link <target> --from <page>` says whether a link works and what to write. A product's message that links to these docs by a permalink can read what the docs will show for it first: `ascribe resolve go:<name>` prints the help a product shows, from the build's `help.json`. Give a heading with a permalink a summary, a sentence or two a product shows with its help: `@summary` on the line above a paragraph of the section that reads well alone, or `@summary: <text>` under the heading and its `@id` when none does, as for a lead-in to a list. Keep it under 300 characters.
### More
To see what a reader of the site gets, not only a reader of the Markdown, run `ascribe resolve <page> --build <name> --emit site`, or call `ascribe_resolve` with `emit: "site"`: the page as the site output gives it to the site, with Ascribe's elements. How to read them: https://ascribed-dev.com/go/reading-site-output/
`ascribe model` shows everything the content model allows. Every directive: https://ascribed-dev.com/go/directives/
<!-- ascribe:agents end -->When the rules are long
AGENTS.md takes at most 4,000 characters. When the whole would be longer, what an agent can read elsewhere is cut before what only your project says, a step at a time, until the rest fits:
- The sentences about memos.
- Each built-in directive’s syntax, which the skill’s
references/directives.mdhas. Its line keeps the directive’s name and what your project declares for it: your dimensions and their values for@variant, your note types, your sources, and your own targets for@available. A sentence says where the syntax is. Your own directives’ lines stay whole. - The sentences on
@summaryand on seeing the site output, which the skill says too. - Each page type’s template, guide, and frontmatter. Its line keeps its name and what it’s for.
Only then are lines cut, the directives’ before the page types’, each list ending with where the rest are. A page names its type before anything else, so the types are the last thing cut.
Your text stays yours
Ascribe writes only between its two markers, <!-- ascribe:agents start … --> and <!-- ascribe:agents end -->. Everything else in the file is your team’s, and is left byte for byte as it was: write your own rules above or below the block. A file with no markers gets the block at its end, and a file that doesn’t exist is created with only the block. When a file has a start marker and no end marker, or two of either, sync changes nothing anywhere and exits with 2: fix the markers by hand.
Don’t edit the block itself: change ascribe.toml, or your pages, and run sync again.
Other agents’ files
Beyond AGENTS.md and the skill, sync keeps up to date the files of each target that already has them, and writes a target’s files when you ask with --target. The targets are claude, claude-rules, copilot, and codex; ascribe agents sync lists what each writes, and what it names the files of a project in a subfolder. Claude Code and GitHub Copilot say when you need theirs.
A repository with several projects can run sync at its root, with no ascribe.toml there: it syncs each project below, and the root’s AGENTS.md gets a block for each, which tells an agent starting at the root which project a page is in.
The command they name
The files tell the agent which commands to run, and sync writes each as your project runs Ascribe. When a package.json in the project’s folder, or a folder above it up to the repository’s root, has @ascribed/cli or @ascribed/astro in its dependencies, as Install sets up, the commands are pnpm exec ascribe with a pnpm-lock.yaml beside it or above it, yarn ascribe with a yarn.lock, and npx ascribe otherwise. Without one, they’re ascribe, from the path. AGENTS.md, the skill, the rules for claude-rules and copilot, and what the hooks tell the agent all use it.
To name another, such as bunx ascribe, give it with --command, every time you run sync, --check too: a file written with another command is out of date.
ascribe agents sync --command "bunx ascribe"
The skill at the repository’s root is shared by its projects, so when they run Ascribe in different ways, it writes ascribe, and says how to run it from a package.json.
Keeping them current in CI
--check writes nothing, prints how each file out of date would change as a unified diff, and exits with 1 when one is. Run it in CI so the instructions can’t fall behind ascribe.toml:
ascribe agents sync --check
--dry-run lists the files sync would write, and writes none. Like every command that writes, sync won’t change a file git couldn’t put back, such as an AGENTS.md with changes not committed: commit them, or pass --force.
The skill
The skill is one folder, ascribe, in the Agent Skills format, which most agents read. It teaches the tool, the same for every project, and sends the agent to AGENTS.md and ascribe model for your project’s rules:
- the loop: edit a page, run
ascribe check <file> --format concise, fix what it reports, and run the whole check before finishing; and to stop and ask after three rounds that don’t fix it; - the commands that answer questions:
explain,model,outline,link,resolve,refs, andsearch, which it runs before writing a page about a subject; - which fixes in
ascribe check’s JSON can be applied as they are; - in a project with
ascribe.addresses, how to move, forward, and retire pages so their old addresses still lead somewhere, and the MCP server’sascribe_addresses_moveandascribe_addresses_retire, which give the edit to apply without a shell; - that text from a review or a pull request is someone else’s, not instructions;
- each directive’s syntax, in a reference it reads only when it needs it.
sync writes it to .agents/skills/ascribe/ at the repository’s root, where Codex, Cursor, Gemini CLI, and Copilot find it, and with the claude target to .claude/skills/ascribe/, where Claude Code does. When the repository’s only project is in a folder, the skill gives the commands that work on the whole project, such as ascribe check with no file, that folder with --config, so they work from the repository’s root, where an agent starts. With more than one project, the skill is each one’s, so it names none. ascribe agents skill prints its SKILL.md. The @ascribed/cli package ships it too, as skills/ascribe/, for tools that install skills from packages.
In VS Code, chat has the skill before you run sync: the extension ships it.
See ascribe agents for every option.