> For the complete documentation index, see [llms.txt](https://ascribed-dev.com/docs/llms.txt). This documentation describes Ascribe 0.4.4. Anything marked in main, not yet released isn't in that release yet.

# Write the agent files

> How-to · Write your project's rules into the files agents read on their own, AGENTS.md and the Ascribe skill, and keep them current.

`ascribe agents sync` writes your project's rules into the files agents read on their own, from `ascribe.toml`:

```shell
ascribe agents sync
```

It writes:

- **`AGENTS.md`** beside `ascribe.toml`: the check to run after each edit and before finishing, to run `ascribe search` for 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 with `type:`, your phrases, the directives your pages use, with your [dimensions](https://ascribed-dev.com/docs/glossary.md#dimension) and their values for `@variant` and an example of your own targets for `@available`, and how to link. It's at most 4,000 characters; [when it would be longer](https://ascribed-dev.com/docs/agents/instructions.md#when-the-rules-are-long), 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 no `AGENTS.md` below the folder they start in.
- **The skill,** in `.agents/skills/ascribe/` at the repository's root. See [The skill](https://ascribed-dev.com/docs/agents/instructions.md#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:

```text
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.
```

Tested with ascribe 0.4.4 on Linux.

When a page has a [`@memo`](https://ascribed-dev.com/docs/writing/directives.md#memo), `AGENTS.md` also tells the agent to read a block's [memo](https://ascribed-dev.com/docs/glossary.md#memo) before changing the block, and to keep the two together. When the project has a [memo file](https://ascribed-dev.com/docs/writing/memo-files.md) 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](https://ascribed-dev.com/docs/writing/memo-files.md#personal-memos) 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](https://ascribed-dev.com/docs/permalinks.md), `AGENTS.md` also says, with how to link, that a product's message linking to the docs by a [permalink](https://ascribed-dev.com/docs/glossary.md#permalink) can read what the docs will show for it with `ascribe resolve go:<name>`, which prints the help [a product shows](https://ascribed-dev.com/docs/permalinks/in-your-product.md). When a heading declares one, it says to give the heading's section a [`@summary`](https://ascribed-dev.com/docs/writing/directives.md#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`](https://ascribed-dev.com/docs/publishing/redirects.md), `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](https://ascribed-dev.com/docs/command/site-output.md), and links to [reading the site output](https://ascribed-dev.com/docs/command/site-output.md#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`](https://ascribed-dev.com/docs/templates.md) added, The Good Docs Project's summary of it, from `templates.lock` (the [content model reference](https://ascribed-dev.com/docs/content-model.md#41-page-types)).

Here's what it writes for the Quill example:

```markdown
<!-- 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 -->
```

Tested with ascribe 0.4.4 on Linux.

## 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:

1. The sentences about memos.
2. Each built-in directive's syntax, which the skill's `references/directives.md` has. 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.
3. The sentences on `@summary` and on seeing the site output, which the skill says too.
4. 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`](https://ascribed-dev.com/docs/agents/commands.md#ascribe-agents-sync) lists what each writes, and what it names the files of a project in a subfolder. [Claude Code](https://ascribed-dev.com/docs/agents/claude-code.md) and [GitHub Copilot](https://ascribed-dev.com/docs/agents/copilot.md) 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](https://ascribed-dev.com/docs/install.md#in-a-project-with-npm) 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](https://ascribed-dev.com/docs/agents/hooks.md#what-the-agent-hears) 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.

```shell
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`:

```shell
ascribe agents sync --check
```

`--dry-run` lists the files `sync` would write, and writes none. Like [every command that writes](https://ascribed-dev.com/docs/command.md#commands-that-write), `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](https://agentskills.io) 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`, and `search`, 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's `ascribe_addresses_move` and `ascribe_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](https://ascribed-dev.com/docs/editor/agents.md#agents-in-vs-code) ships it.

See [`ascribe agents`](https://ascribed-dev.com/docs/agents/commands.md#ascribe-agents) for every option.
