Agents
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.
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#
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):
# 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/**"]}'
{ "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 }
# 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"]}'
{ "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 answer409 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:
{ "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 --pathsreleases 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:
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) |
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 |
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#
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, symbolsfile::Qualified::name. - Failure:
{"error": {"code", "message", "retryable", "error_id"?, …}, "warnings": […]}, exit status 1. weave contract check --strictexits 1 with its document;weave msg waitexits 2 on timeout ({"messages": [], "timed_out": true}).- Commands with nothing to report as JSON (
login,config,mcp,watcher, foregroundserve, …) refuse--jsonwithunsupportedbefore 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.
Retrying retryable errors#
A temporary storage failure on the server answers 503:
{ "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_idand quote it when reporting a problem.internalerrors carry one too. 429 rate_limitedcomes withRetry-After: back off.
weave serve: one fast process per checkout#
Agents that run hundreds of commands should start one daemon per checkout:
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
weavecommands 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-watchwhen other machines or sandboxes change the files (a network filesystem),--watchto 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=1runs one command by itself;WEAVE_DEBUG_SERVE=1says 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 socket0600). Connections from other users are refused by their peer credentials. - It only answers clients that present its key (a random secret in a
0600file 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_URLor 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_TOKENis used, but never sent anywhere else. --socket .weave/sock(andWEAVE_SOCKETfor 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.
# 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
--pathsadds 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-claimskeeps them. Files with parts routed to owners stay claimed.--also-session <session>first takes that session's drafted changes to those paths over, asweave add --adopt, with a decision record naming it.--sessionsseals the whole drafts of the named sessions on this device and sends them in onesubmit_stitchesrequest: 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#
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:
- 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/lockfor whole commands) and can silently take back a clash a 0.4.0 CLI routed. - Register one worker agent per builder and issue each its own
wva_token, withpathScopeincluding.weave/decisions/**. - One checkout:
weave clone <org>/<repo>, thenweave serve --detach. - Each agent runs with its own
WEAVE_AGENT=<name>andWEAVE_TOKEN=<its token>(or--agent), and its own MCP server (weave --agent <name> mcp). - Each agent claims its part with
--feature part:<id>(--partialto take what is free) and stitches with--pathsas soon as the part passes its checks. - Agents read
weave notices(or get them with tool results) andweave msgbetween turns. - At the end:
weave drafts --all-sessions --json, then adopt or stitch orphaned drafts; checkweave sync --jsonforheldbefore recording a head; scheduleweave resolvetasks for open resolution points.
Recommended agent workflow#
- Orient with
outline,owners,searchandcontextinstead of reading whole files. Answer "who has this file?" withownersbefore asking. - Read constraints:
weave decision for <symbols> --format constraints. - Claim your part's scope:
weave claim <targets> --feature part:<id>(--partialif others may hold some). - Edit files on disk.
- Check your work (build, tests), then
weave status --symbolsto review your draft by symbol. - Stitch with an intent and a why:
weave stitch -i "…" -w "…" --paths <your files>. - Handle the outcome:
weaved— done;suggested/routed— not a failure, the owner decides; read the message. - Stay informed:
weave notices,weave msg inbox,weave sync. - Follow up open resolution points as their own task:
weave resolutions, thenweave resolve.
Rules of thumb#
- Use
--jsoneverywhere and parse it, not text. - Retry on
retryable; log everyerror_id. - A routed clash is not a failure. Never treat a
__rp_copy as permanent code. - One agent token per agent; add
.weave/decisions/**to itspathScope. - Stitch each part when it passes its checks; don't batch everything for the end.
- Upgrade every agent sharing a checkout together.
- Never put secrets in code: the server refuses them (
secret_detected). - Repository ids, not
org/name, go in/api/weave/{repoId}URLs.