# For AI agents

> Sessions, registered agents and agent tokens, pathScope, the MCP server and every tool, orientation commands, --json, weave serve, parallel stitching, retries and a recommended workflow.
>
> Source: https://www.weave.directory/docs/agents

Weave treats an AI agent as a first-class author. This page covers everything an agent, or the system that runs agents, needs: identity, tokens, limits, the MCP server, orientation tools, machine-readable output, speed and a recommended workflow.

## Quick start for an agent

```bash
export WEAVE_TOKEN=wva_…          # this agent's own token
export WEAVE_AGENT=builder-1      # this agent's session name
weave clone acme/shop && cd shop
weave serve --detach              # keep one fast process for this checkout
weave --json outline --exports-only --budget 2000
weave --json claim 'app/checkout/**' --feature part:checkout --partial
# ... edit files ...
weave --json stitch -i "Checkout page" -w "part checkout of the build plan" --paths app/checkout
```

## Sessions: --agent

Every command runs as a **session**: `--agent <name>` (or `WEAVE_AGENT`), else you. Each session has its own active workstream, its own private draft (`.weave/drafts/<session>/`) and its own lock, so several agents can work in one folder without sharing a draft or waiting for each other. `--agent-model <model>` (or `WEAVE_AGENT_MODEL`) records the model.

On the hosted service, the **agent** credited on a stitch comes from the token, never from the client. With an agent token, stitches are recorded as that registered agent (with the model the client sends). With a person's token, the stitch is credited to the person, and `--agent` only separates drafts and local records.

## Register agents and issue agent tokens

An agent is registered in an organization. It acts **for the person who issued its token**, under its own id `agent:<agentId>`, and only ever reaches repositories of its own organization.

**In the web UI:** organization → **Settings** → **Agents** (owners and admins). Under **Register an agent** enter a **Name**, a **Kind** (Worker or Verifier) and optionally **Paths it may change**, and click **Register agent**. Then, on the agent's row, choose a **Token lifetime** (15 minutes, 1 hour, 4 hours or 24 hours) and click **Issue token**. Give the token to the agent as `WEAVE_TOKEN`.

**Over the API** (a personal access token; the caller must be an owner or admin of the organization, with 2FA on):

```bash
# register (scope org:admin)
curl -s https://weave.directory/api/v1/orgs/acme/agents \
  -H "Authorization: Bearer $WEAVE_PAT" -H "Content-Type: application/json" \
  -d '{"name": "builder-1", "kind": "worker", "pathScope": ["app/**", "lib/**", ".weave/decisions/**"]}'
```

```json
{ "id": "cm9x2…", "userId": "agent:cm9x2…", "name": "builder-1", "kind": "worker",
  "pathScope": ["app/**", "lib/**", ".weave/decisions/**"], "disabled": false, "disabledAt": null,
  "createdAt": "2026-10-30T12:00:00.000Z", "activeTokens": 0 }
```

```bash
# issue a token (scope tokens:write)
curl -s https://weave.directory/api/v1/agents/cm9x2…/tokens \
  -H "Authorization: Bearer $WEAVE_PAT" -H "Content-Type: application/json" \
  -d '{"ttlMinutes": 1440, "repositoryIds": ["cm3k…"], "scopes": ["repo:read", "repo:write"]}'
```

```json
{ "token": "wva_…", "id": "…", "agentId": "cm9x2…", "expiresAt": "2026-10-31T12:00:00.000Z",
  "scopes": ["repo:read", "repo:write"], "repositoryIds": ["cm3k…"] }
```

| Field | Rules |
| --- | --- |
| `name` | `[A-Za-z0-9][A-Za-z0-9._-]{0,62}`, unique in the organization (duplicate → `409 conflict`). |
| `kind` | `worker` (default) or `verifier`. |
| `pathScope` | Optional glob list (≤ 50). Empty or absent: no path limit for a worker; a verifier gets the default test paths. |
| `ttlMinutes` | Default 60, maximum 1440 (24 hours). Renew before it expires. |
| `repositoryIds` | Optional; must belong to the agent's organization. |
| `scopes` | Only `repo:read` and `repo:write` (both by default). Scopes the issuing token lacks are dropped. |

- The plain token is returned **once**. Agent tokens start with `wva_`, are stored hashed, and are refused once the agent is disabled.
- An agent's access = the issuer's access ∩ the token's `repositoryIds` ∩ its scopes. It never exceeds the issuer's.
- Agent tokens work on the Weave server and the CLI. They are refused on the platform's `/api/v1` (`403`), except worker agents removing and restoring workstreams.
- List agents: `GET /api/v1/orgs/{slug}/agents`. Disable one (revokes all its tokens): `DELETE /api/v1/orgs/{slug}/agents/{id}`. A disabled agent's new token requests answer `409 agent_disabled`.

### Workers and verifiers

| | Worker | Verifier |
| --- | --- | --- |
| Purpose | Builds features | Writes and runs tests, reviews |
| Default `pathScope` | none (anything) | `**/tests/**`, `**/test/**`, `**/*_test.*`, `**/*.test.*`, `**/*.spec.*`, `**/spec/**`, `**/specs/**` |
| Remove / restore workstreams | Yes (with write access) | Never |

A `pathScope` you give **replaces** the default; it doesn't add to it. To give a verifier decision records too, list the test globs again plus `.weave/decisions/**`.

### pathScope

A `pathScope` is a list of globs (`*` stays within one path segment, `**` crosses segments). Every write is checked against it: stitches, web edits and moves, claims, accepting suggestions, change-request resolutions, reverts, promotions, restores and seeding. A write touching a path outside it is refused:

```json
{ "type": "error", "code": "path_out_of_scope", "message": "…", "paths": ["lib/db.ts"], "pathScope": ["app/**"] }
```

**Add `.weave/decisions/**` to every agent's pathScope.** Decision records are files stitched with the code (`weave stitch -w` drafts one), so an agent without it can't stitch a why.

### One token per agent

Give **each builder agent its own agent token**. Weave tells authors apart by token: user plus verified agent. Agents sharing one person's token look like one author to the server, which means:

- the clash check can't protect them from each other (one agent can silently take back another's work as "its own undo");
- claims are shared (`stitch --paths` releases that person's claims on those files);
- notices count "my claims" across all of them;
- batch stitches and credit go to that person.

## The MCP server

`weave mcp` is an MCP server over stdio. Its instructions explain the workflow to the agent. Run it per agent so tools act as that session:

```bash
claude mcp add weave -- weave --agent builder-1 mcp     # Claude Code
weave install-claude                                    # adds a Weave pointer to ./CLAUDE.md
```

`weave init` (interactive) can also wire Claude Code, Gemini CLI, Cursor and Codex. `WEAVE_MCP_LOG` (`warn`, `debug`, …) sets its stderr log level.

### Every MCP tool

| Tool | Parameters (`?` optional) | Does |
| --- | --- | --- |
| `outline` | `paths[]`, `exports_only?`, `budget_tokens?` (4000), `json?` | As `weave outline`: signatures per file, owner, whose draft changed it. |
| `owners` | `paths[]`, `fresh?` | As `weave owners --json`: owner, part label, lease of files, symbols and JSON keys. |
| `symbol_context` | `target`, `budget_tokens?` (600), `json?` | As `weave context`: one card about a symbol. |
| `find_symbols` | `query`, `limit?` (20), `json?` | As `weave find`: keyword search over symbols on disk. |
| `search_code` | `query`, `limit?` (10, max 50), `budget_tokens?` (800), `paths[]`, `json?` | As `weave search`: semantic + keyword search. |
| `notices` | `since?`, `json?` | As `weave notices` for this MCP server's session. |
| `resolutions` | `point?`, `all?` | Open resolution points (or one, by tag), as JSON. |
| `decisions_for` | `symbols[]` or `file`, `radius?` (1), `budget_tokens?` (800), `include_hidden?`, `format?` (`summary` \| `constraints`) | Decisions on symbols and their neighbours; `constraints` gives KEEP/NEVER lines. |
| `decision_search` | `query`, `near[]`, `budget_tokens?` (600), `include_hidden?` | Ranked search over decisions. |
| `decision_get` | `ids[]` | Full decision records. |
| `impact` | `symbol`, `depth?` (1), `budget_tokens?` (500) | Callers and callees with their decision counts. |
| `decision_propose` | `anchors[]`, `title`, `why`, `alternatives[]`, `constraints[]`, `supersedes?`, `comment?` | Record a decision; it joins the draft and is sealed with the next stitch. |
| `decision_review` | `status_filter?` (`needs_review`), `budget_tokens?` (600) | Decisions whose code changed since they were made. |
| `send_message` | `to[]`, `body`, `about_path?`, `about_symbol?`, `reply_to?` | Send a Weave message. |
| `read_messages` | `unread_only?` (true), `thread?`, `limit?` (20) | Read messages (does not mark them read). |
| `mark_messages_read` | `ids[]` or `all?` | Mark messages read. |
| `wait_for_message` | `timeout_secs?` (120, max 600) | Block until a message arrives; marks what it returns read. |
| `thread_show`, `thread_add`, `thread_add_many`, `thread_list`, `thread_search`, `symbol_list` | — | Short behaviour notes per symbol (threads) and the symbol list. |

Message tools need a connected checkout.

## Orientation: know the code without reading it all

These read the files **on disk**, so they see every agent's in-progress work in the checkout, not only what is weaved.

| Command | MCP tool | Gives |
| --- | --- | --- |
| `weave outline [paths\|globs] [--exports-only] [--budget N]` | `outline` | Per file: each symbol's signature, `+` exported / `-` local, owner and part label, `[changed-in-draft-of <agent>]` |
| `weave owners [paths\|globs] [--fresh]` | `owners` | Owner of files, symbols and JSON keys, part label, lease left (local copy ≤ 15 s old) |
| `weave context <file::symbol> [--budget 600]` | `symbol_context` | Signature, doc line, owner, whether it is in someone's draft, callers and callees, decisions, last stitch's intent and why |
| `weave search "<question>" [--limit] [--budget] [--paths a,b]` | `search_code` | Semantic search on the head combined with keyword hits on disk ([Search](https://www.weave.directory/docs/search)) |
| `weave find <words> [--limit]` | `find_symbols` | Keyword search over symbol names, signatures and doc lines on disk |
| `weave notices [--since <cursor>]` | `notices` | What other drafts changed that your code uses; routed clashes; server notices |
| `weave status --symbols` | — | Your draft by symbol, signatures before / after (for fix rounds) |
| `weave drafts --all-sessions` | — | Which session holds which files |
| `weave decision for <targets> --format constraints` | `decisions_for` | `KEEP:` / `NEVER:` lines for a starter pack |
| `weave contract declare\|check\|remove` | — | Planned interfaces between parts, checked against disk |

```bash
weave outline lib --exports-only --budget 1500
# lib/cart.ts  [owner builder-2 part checkout 8m] [changed-in-draft-of builder-2]
#   + export function addToCart(id: string, qty: number): void
#   + export function cartTotal(items: Item[]): number
weave context lib/cart.ts::addToCart
weave decision for lib/cart.ts::addToCart --format constraints
# KEEP: Prices are integers in cents — floats lost pennies in totals [D-7f3a]
# NEVER: store prices as floats [D-7f3a]
```

`--budget` cuts output to about that many tokens (4 characters each), keeping exported symbols first and saying what was cut. Callers, callees and notices resolve references **by name**, so very common names can over-report.

### Contracts between parts

```bash
weave contract declare lib/cart.ts::addToCart \
  --signature "export function addToCart(id: string, qty: number): void" --owner part:commerce
weave contract check --strict          # ok / MISMATCH / MISSING; exit 1 when one is not ok
weave contract remove lib/cart.ts::addToCart
```

Contracts live in `.weave/contracts.toml`, local to the checkout (not stitched). They compare normalised signature text (whitespace, `export`, `pub` ignored), not types. Write signatures as `weave outline` prints them.

## --json: one document per command

Add `--json` (before or after the command) to any command an agent runs. stdout then carries exactly one JSON document; text goes to stderr.

- **Success:** the command's fields plus `warnings`, exit status 0. Hashes are full 64-hex, times RFC 3339, symbols `file::Qualified::name`.
- **Failure:** `{"error": {"code", "message", "retryable", "error_id"?, …}, "warnings": […]}`, exit status 1.
- `weave contract check --strict` exits 1 with its document; `weave msg wait` exits 2 on timeout (`{"messages": [], "timed_out": true}`).
- Commands with nothing to report as JSON (`login`, `config`, `mcp`, `watcher`, foreground `serve`, …) refuse `--json` with `unsupported` before doing anything.

### Error codes

| `error.code` | Meaning | Retry? |
| --- | --- | --- |
| `unavailable` | A temporary server storage failure (`retryable: true`, with `error_id`) | Yes, the same command |
| `unreachable` | The server could not be reached; a stitch is queued for `weave push` | Yes |
| `busy` | Another weave command holds the lock | Yes |
| `rejected` | The weave check refused a stitch (`reject_code`, `authors`, `stitches`, `symbols`) | After fixing |
| `claim_conflict` | A claim target is held (`conflicts`) | Use `--partial` or ask the owner |
| `needs_dependencies` | `weave promote` without `--with-deps` (`dependencies`) | With `--with-deps` |
| `needs_newer_server` | The server doesn't support this request | Upgrade the server |
| `bad_request`, `unauthenticated`, `forbidden`, `not_found`, `conflict`, `internal` | The server's own error code | No (`internal` carries an `error_id`) |
| `push_failed`, `not_a_repository`, `not_running`, `unsupported`, `error` | Local failures | No |

### Warning codes

`warnings` is in every document, maybe empty, as `{"code", "message", "paths"}`:

| Code | Means |
| --- | --- |
| `routed` | A change went to someone as a suggestion because it clashes with their newer work |
| `held_on_disk` | An un-added edit was kept on disk because it clashes with the new version |
| `left_out_foreign` | Edits on disk in another agent's draft were left out of `weave add` |
| `held_back` | Changes awaiting their owners were left out of a stitch |
| `resolution_point` | Your rejected change was kept beside theirs |
| `adopted` | Files were taken over from another session's draft |
| `draft_keeps_yours`, `carried_on_disk`, `carried_forward` | Your draft kept your version / was carried onto a newer head |
| `change_requests_opened`, `clash_change_request` | Change requests were opened (the latter in local mode) |
| `decision_recorded`, `no_decision` | A decision record was or wasn't drafted from `--why` |
| `left_ignored`, `all_or_nothing` | Paths ignored by `.weaveignore`; `--partial` fell back to all-or-nothing on an older server |

`weave stitch --json` includes `result` (`weaved`, `suggested`, `resolved` or `awaiting`), `stitch`, `head`, `suggestions`, `routed`, `held_back` and `files` (`written`, `removed`, `carried`, `held`). Shapes of every command: [CLI reference](https://www.weave.directory/docs/cli#json-output).

## Retrying retryable errors

A temporary storage failure on the server answers `503`:

```json
{ "type": "error", "code": "unavailable", "message": "…", "retryable": true, "error_id": "3f9a1c2b7d40" }
```

- The CLI already resends the **same sealed stitch** up to 3 times (backoff 2 s, 4 s) and prints each attempt with the error id. The server recognises a stitch it already weaved (`duplicate: true`), so a resend never weaves twice. If every attempt fails, your draft is kept.
- When you call the API yourself: resend reads, `submit_stitch` / `submit_stitches` (the **same** changeset or batch), change-request resolutions with a stitch, blob uploads, claims, releases and lease renewals as they are. Other writes (`submit_edit`, revert, undo, promote, create workstream, messages) may have been applied: check first, for example the workstream's history.
- Always log the `error_id` and quote it when reporting a problem. `internal` errors carry one too.
- `429 rate_limited` comes with `Retry-After`: back off.

## weave serve: one fast process per checkout

Agents that run hundreds of commands should start one daemon per checkout:

```bash
weave serve --detach         # background; log in .weave/serve.log; stops after 30 idle minutes
weave status                 # now answered by it: same output, exit status and identity
weave serve --status         # pid, version, uptime, commands served and running, connections, files watched
weave serve --stop
```

- Later `weave` commands in the checkout forward their arguments, working directory and environment to it and print what comes back. Each command keeps its **own identity** (`--agent` / `WEAVE_AGENT`, `WEAVE_TOKEN`, `WEAVE_USER`, `HOME`) and takes the same locks; commands run concurrently. One daemon serves every agent and login in the checkout, with one kept server connection per token.
- It keeps the server connection, loaded states and (with the watcher, on by default on Linux) the walk and stat of files on disk. Use `--no-watch` when other machines or sandboxes change the files (a network filesystem), `--watch` to force it elsewhere.
- If no daemon answers within a second, it is another build of `weave`, or anything goes wrong before it starts the command, the command runs by itself — never twice. Commands that read stdin, would prompt, run for long or set things up (`init`, `clone`, `login`, `msg wait`, `mcp`, …) always run by themselves.
- `--idle-timeout <secs>` (default 1800; 0 = never). `WEAVE_NO_DAEMON=1` runs one command by itself; `WEAVE_DEBUG_SERVE=1` says on stderr why a command didn't use the daemon.
- In a test with the server 100 ms away, `weave add .` went from about 540 ms to 220 ms. Unix only (not Windows).

### Security model

- The socket lives **outside** the checkout: `$XDG_RUNTIME_DIR/weave/<checkout hash>.sock`, else `~/.weave/run/<checkout hash>.sock`, in a folder only you can open (`0700`; the socket `0600`). Connections from other users are refused by their peer credentials.
- It only answers clients that present its **key** (a random secret in a `0600` file in the same folder), so another sandbox that shares the checkout but not your home can't use it.
- A command whose `HOME`, `USERPROFILE`, `XDG_RUNTIME_DIR`, `WEAVE_SERVER_URL`, `WEAVE_PLATFORM_URL` or umask differ from the daemon's — or that runs after the checkout's server configuration changed — runs by itself.
- The daemon only connects to the server and platform it was started for. A token in a client's `WEAVE_TOKEN` is used, but never sent anywhere else.
- `--socket .weave/sock` (and `WEAVE_SOCKET` for clients) puts the socket in the checkout instead, as an explicit choice.

## Stitching in parallel

Stitch each part **as soon as it passes its own checks**. Don't save everything for the end.

```bash
# a worker finishing its part: add + stitch + release claims, in one command
weave --agent builder-1 stitch -i "Checkout page" --paths app/checkout lib/cart.ts

# take a sub-agent's drafted changes to those paths along
weave --agent builder-1 stitch -i "Checkout page" --paths app/checkout --also-session builder-1-tests

# seal several sessions' drafts and weave them in one request
weave stitch -i "part {session}" --sessions builder-1,builder-2,builder-3
```

- `--paths` adds those files or folders from disk, stitches only them (the rest of the draft stays drafted) and, once they weaved, releases the claims your identity holds on them. `--keep-claims` keeps them. Files with parts routed to owners stay claimed.
- `--also-session <session>` first takes that session's drafted changes to those paths over, as `weave add --adopt`, with a decision record naming it.
- `--sessions` seals the whole drafts of the named sessions on this device and sends them in one `submit_stitches` request: woven in order under one workstream lock, one head update, an outcome per stitch. `{session}` in the intent becomes each session's name. One failing session leaves the others alone (the command then exits non-zero). The server credits every stitch of the batch to the token's identity, so builders that must be credited separately should stitch their own parts with their own tokens (in parallel).
- Measured with 6 sessions and 60 ms added latency: 0.44 s all at once against 2 s one after another.

### Locks

Each command holds its **session's lock** (`.weave/locks/sessions/<session>.lock`) for its whole run, so two commands of one agent run one after the other while other agents run alongside. The checkout-wide `.weave/lock` is held only while a command reads or writes files on disk (about 20 ms), never while it talks to the server. A command waits up to 30 s for a lock (`busy`). `WEAVE_LOCK_LOG=<file>` writes one JSON line per lock released.

## Seed a new app from a template

```bash
weave init --server https://api.weave.directory        # in a new, empty repository's folder
weave seed --from acme/starter                         # its main head
weave seed --from acme/starter --workstream dev        # or another workstream's head
weave seed --from acme/starter --state <64-hex>        # or an exact state
```

The server copies the template's files itself, in one stitch by you — nothing is uploaded. The target workstream must be empty (`409` otherwise). You need write on the target and read on the template (a token limited to `repositoryIds` must include the template). Files a lawful purge removed are left out and listed; the seeded repository's own secret check runs on every file. Seed `main` first, then create `dev` and other workstreams so they start from the seeded head. API: `POST /api/weave/{repoId}/workstreams/{ws}/seed` with `{"fromRepo": "<template repo id>"}` (plus `state` or `fromWorkstream`).

## Many agents, one checkout

A tested setup for a builder running many agents in one sandbox:

1. **Upgrade the server first**, then give every agent in the checkout the **same CLI version**. An older CLI in the same checkout is safe but slow (it holds `.weave/lock` for whole commands) and can silently take back a clash a 0.4.0 CLI routed.
2. Register one **worker agent per builder** and issue each its own `wva_` token, with `pathScope` including `.weave/decisions/**`.
3. One checkout: `weave clone <org>/<repo>`, then `weave serve --detach`.
4. Each agent runs with its own `WEAVE_AGENT=<name>` and `WEAVE_TOKEN=<its token>` (or `--agent`), and its own MCP server (`weave --agent <name> mcp`).
5. Each agent claims its part with `--feature part:<id>` (`--partial` to take what is free) and stitches with `--paths` as soon as the part passes its checks.
6. Agents read `weave notices` (or get them with tool results) and `weave msg` between turns.
7. At the end: `weave drafts --all-sessions --json`, then adopt or stitch orphaned drafts; check `weave sync --json` for `held` before recording a head; schedule `weave resolve` tasks for open resolution points.

## Recommended agent workflow

1. **Orient** with `outline`, `owners`, `search` and `context` instead of reading whole files. Answer "who has this file?" with `owners` before asking.
2. **Read constraints**: `weave decision for <symbols> --format constraints`.
3. **Claim** your part's scope: `weave claim <targets> --feature part:<id>` (`--partial` if others may hold some).
4. **Edit** files on disk.
5. **Check** your work (build, tests), then `weave status --symbols` to review your draft by symbol.
6. **Stitch** with an intent and a why: `weave stitch -i "…" -w "…" --paths <your files>`.
7. **Handle the outcome**: `weaved` — done; `suggested` / `routed` — not a failure, the owner decides; read the message.
8. **Stay informed**: `weave notices`, `weave msg inbox`, `weave sync`.
9. **Follow up** open resolution points as their own task: `weave resolutions`, then `weave resolve`.

### Rules of thumb

1. Use `--json` everywhere and parse it, not text.
2. Retry on `retryable`; log every `error_id`.
3. A routed clash is not a failure. Never treat a `__rp_` copy as permanent code.
4. One agent token per agent; add `.weave/decisions/**` to its `pathScope`.
5. Stitch each part when it passes its checks; don't batch everything for the end.
6. Upgrade every agent sharing a checkout together.
7. Never put secrets in code: the server refuses them (`secret_detected`).
8. Repository ids, not `org/name`, go in `/api/weave/{repoId}` URLs.
