Use Weave

Working together

Claims, owners and leases, suggestions, change requests, clashes that never block, resolution points, held edits, sync, drafts, adopt, messages and notices.

View as Markdown

Weave lets many people and agents change one codebase at once without merges. Three rules make that work:

  1. Ownership routes work. A change to a symbol someone else owns goes to them as a suggestion; the rest of your stitch weaves.
  2. Clashes never block. A change that would lose someone's newer work goes to them as a suggestion; the rest weaves.
  3. Nobody's work is lost. A rejected clash becomes a resolution point that keeps both versions.

Claims, owners and leases#

Every symbol has at most one owner: the holder of the most specific live claim (a claim on the symbol, else on the enclosing symbol, else on the whole file). Unclaimed symbols can be changed by anyone.

bash
weave claim src/auth.rs::login --feature "MFA login"     # one symbol
weave claim src/auth.rs 'src/session/**/*.rs'            # whole files; globs expanded by the CLI
weave claim 'app/[id]/page.tsx' --feature part:checkout   # [ ] are literal: works before the file exists
weave claims                                             # live claims: target, owner, feature, time left
weave release src/auth.rs::login                         # or: weave release --all
weave watcher                                            # renews your leases while it runs
  • All or nothing. If any target is held by someone else, nothing is claimed and the owners are listed (--json error code claim_conflict with conflicts).
  • Leases. A claim lasts 10 minutes by default (--lease <secs> asks for another length, capped by the server at 4 hours by default). A running weave watcher renews it; otherwise it expires.
  • Claims belong to an identity, not a terminal: you, or the agent whose token you use.
  • Globs. Only *, ? and { make an argument a pattern. [ and ] are literal, so Next.js routes like app/[slug]/page.tsx and api/auth/[...nextauth]/route.ts work as names.
  • JSON keys can be claimed one by one: weave claim package.json::scripts.dev.
  • Claims conflict on the same file (a whole-file claim against anything in it) or on the same, an enclosing or an enclosed symbol (Auth against Auth::login).

Part labels#

A claim made with --feature part:<id> carries a part label. Builders that split an app into parts use it to show which part owns what:

bash
weave claim 'app/checkout/**' lib/cart.ts --feature part:checkout
weave owners app lib/cart.ts

Partial claims#

--partial claims every target that is free and exists in the workstream head, and reports the rest instead of claiming nothing:

bash
weave claim --partial --json app/page.tsx app/cart/page.tsx lib/missing.ts
json
{ "claimed": ["app/page.tsx"],
  "conflicts": [{ "target": "app/cart/page.tsx", "owner": "agent:wk2", "held": "app/cart/page.tsx" }],
  "missing": ["lib/missing.ts"], "lease_secs": 600, "warnings": [] }

held is the claim that blocks it (the same target, the whole file or an enclosing or enclosed symbol). missing lists files not in the head and symbols not in their file.

Who owns what#

bash
weave owners src/auth.rs 'app/[id]/*.tsx'      # owner, part label, lease left, per-key owners in JSON files
weave owners --fresh                           # ask the server now instead of the 15-second local copy

Check owners before asking for a file — you may own it already. weave start "<intent>" asks the server to predict which symbols an intent touches and claims them for you (or reports who owns them).

Suggestions#

When your stitch changes a symbol someone else owns, that part becomes a suggestion to the owner and the rest weaves.

bash
weave suggestions                      # waiting for you, and yours waiting for owners (--all for decided ones)
weave suggestions show <id>            # the change, symbol by symbol, next to the current text
weave suggestions accept <id>          # owner: weave it, credited to its author
weave suggestions reject <id> --reason "keep the old signature until v2"
weave suggestions resubmit <id>        # author: carry a rejected or stale one onto the head and stitch again
  • Your edit stays in your draft and on disk, marked awaiting <owner> in weave status. Later stitches leave it out while it is unchanged.
  • Accepted: the head now has your text; your draft drops it on the next carry forward.
  • Rejected: you see the reason. Drop it (weave draft drop <file::symbol>) or edit it, which makes it part of your next stitch.
  • Stale: the owner changed the symbol since. Carrying your draft forward raises a change request between their version and yours; then resubmit.
  • A change that touches several owners (a rename across their symbols) is a group: it weaves once every owner has accepted, and is rejected if any one rejects.
  • When everything left in your draft is awaiting owners, weave stitch sends nothing and still succeeds (result: "awaiting" with --json).

A repository admin can decide a suggestion for an absent owner over the API with a reason: POST /api/weave/{repoId}/suggestions/{id}/accept with {"as_admin": true, "why": "release blocker: owner is away"}. Agent tokens can't do this.

In the web UI: Suggestions → For symbols I own → Accept / Reject.

Clashes: stale copies and real edits#

Files on disk can be older than the head: copied in from a stale clone, rewritten from an earlier read, or left with an un-added edit when the head moved. Weave tells two cases apart.

CaseHow Weave decidesWhat happens
Stale copyThe symbol's text on disk is exactly what Weave last wrote thereNot an edit. The head's version stays, and weave add brings the file on disk up to it.
Real edit that clashesYou changed a symbol someone else changed after the version you started from (lost_update), or you put back a version, removed a symbol or brought one back against someone's newer weave (reverts_newer_work)Your version goes to the newest such author (or the symbol's owner) as a suggestion with the reason. The head keeps theirs. The rest of your stitch weaves.
Your own undoYou put back your own earlier versionWeaves directly.
Intended revert of someone else's work--allow-revert on weave add and weave stitchWeaves directly. weave revert <stitch> never needs it.

You are told in the command output, in weave notices, and by a Weave message; so are they. With --json, routed changes are in routed and the warning code routed:

json
{ "result": "weaved", "stitch": "…", "head": "…",
  "routed": [{ "id": "1a2b3c4d…", "owner": "agent:wk3", "targets": ["lib/x.ts::f"],
    "clash": { "code": "lost_update",
      "reason": "lib/x.ts::f: changed by builder-3 (bob) in 5e6f7a8b after the version this change was based on",
      "authors": ["builder-3 (bob)"], "stitches": ["5e6f7a8b…"] } }],
  "warnings": [{ "code": "routed", "message": "lib/x.ts::f went to builder-3 as suggestion 1a2b3c4d …", "paths": ["lib/x.ts"] }] }

A routed clash is not a failure. Read the message or weave notices and decide whether to adjust. If a stitch is overtaken by another one between seal and submit, the server routes the overlap the same way instead of refusing it.

Authors are told apart by user and agent. Agents that share one person's token count as one author, so the check can't protect them from each other — give each agent its own token (see For AI agents).

Resolution points#

When the owner rejects a suggestion that went to them because of a clash, Weave keeps the author's version instead of dropping it. One resolution point is opened per symbol.

Copy in the code (safe shapes)#

For shapes proven safe, the author's version is woven right after the owner's as <name>__rp_<tag> (for example addToCart__rp_1a2b3c4d) under a marker comment:

ts
export function addToCart(id: string, qty: number) { /* the owner's version */ }
// weave: resolution point 1a2b3c4d: bob's version of addToCart, kept beside it. 'weave resolve 1a2b3c4d' keeps one.
function addToCart__rp_1a2b3c4d(id: string) { /* bob's version */ }

The author's dependents from the same stitch (symbols that stitch changed and that use the name, in the same file) call the copy, so the author's flow keeps working; everyone else keeps the owner's version. Safe shapes:

  • TypeScript / JavaScript: a top-level function, or a single const / let / var declaration (never export default).
  • Rust: a free fn, const or static (with #[allow(…)] for the temporary name).
  • Python: a def without decorators, or a single assignment.

The copy is only made when the author's CLI is 0.4.0 or newer.

Fallback: kept on the point#

Everything else keeps the owner's version in the code and the author's text on the point, and also opens a change request with both versions, assigned to the owner. Resolving either one resolves the other. Fallbacks include other languages (JSON keys, CSS, Markdown), Next.js route files (app/**/page|layout|route…, pages/**, middleware), methods and nested functions, classes and types, overloads and shared names, removals and moves, dependents in other files, and authors on older CLIs.

See and resolve them#

bash
weave resolutions                      # open points: tag, symbol, both versions or "kept on the point"
weave resolutions list --all           # resolved ones too
weave resolutions show 1a2b3c4d        # both versions, who wrote each and why, the reason, the callers
weave resolve 1a2b3c4d head            # keep the owner's version
weave resolve 1a2b3c4d copy            # keep the author's (renamed back, marker dropped)
weave resolve 1a2b3c4d edit            # keep the symbol as you edited it on disk
weave resolve 1a2b3c4d edit --from-file combined.ts --why "kept qty, restored the guard"

The copy is removed and every caller points back at the symbol, in one stitch; files on disk follow.

WhoMay choose
The symbol's owner when the point opened, the current claim holder, or a repository admin (a person)head, copy or edit
The copy's authorhead only (withdraw)
Anyone elseNothing (403)

Points also show in weave status, weave notices, weave outline ([temporary copy: resolution point <tag>]), weave context, the watcher, the Change requests page of the web UI and webhooks (resolution_point.opened, resolution_point.resolved). Treat them as short-lived duplicated code: schedule weave resolve as its own task, and never build on a __rp_ name. Removing (archiving) a workstream closes its open points. Local mode has no resolution points (clashes are change requests).

API: GET /api/weave/{repoId}/resolution-points?workstream=&state=open|resolved&involving=&suggestion=, GET …/resolution-points/{id}, POST …/resolution-points/{id}/resolve with {"choice": "head"|"copy"|"edited", "text"?, "why"?}. MCP tool: resolutions.

Sync and held edits#

bash
weave sync               # fetch what was weaved since your last sync; update files on disk
weave sync --json        # what arrived, files written, held edits, your routed suggestions
weave watcher            # keep doing it in the background, renew leases, print messages and notices

weave sync brings every symbol up to the head and carries your draft forward. It never overwrites edits you haven't added. An un-added edit that clashes with a newer version stays on disk as held (the rest of the file follows the head). weave status and sync --json list held edits; when you add and stitch one, it is routed to whoever changed it.

json
{ "workstream": "dev", "head": "…", "arrived": 3, "already": 0, "written": 2, "removed": 0, "carried": 1,
  "held": [{ "path": "lib/cart.ts", "target": "lib/cart.ts::total", "since": "…" }],
  "routed": [], "warnings": [{ "code": "held_on_disk", "message": "…", "paths": ["lib/cart.ts"] }] }

If the server is unreachable when you stitch, the stitch is queued; weave push submits it later (listed in weave status).

Drafts across sessions#

Every person and agent in a checkout has its own session with its own draft (--agent <name> or WEAVE_AGENT). A file in another session's draft is left out of your weave add (warning left_out_foreign), so agents don't stitch each other's half-done work.

bash
weave drafts --all-sessions            # who holds which files, how many symbols, how old, behind the head?
weave add --adopt lib/cart.ts          # take a file over from another session's draft
weave draft drop src/auth.rs::login    # take a change out of your own draft
weave status --symbols                 # your draft by symbol, with signatures before / after

weave add --adopt <path> moves the other session's drafted changes to those files into your draft (with their un-added edits in those files), leaves the rest of their draft alone, and adds a decision record naming the previous holder. A file nobody stitches never reaches Weave, so at the end of a run adopt or stitch orphaned drafts.

Messages#

People and agents of a repository can message each other. Ask an owner instead of editing around their claim. Messages are kept 30 days.

bash
weave msg send @owner:src/auth.rs::login -m "May I change login's return type?" --about src/auth.rs::login
weave msg send @all -m "Freezing main for the release at 17:00"
weave msg send @ws:dev -m "dev is red, looking at it"
weave msg send agent:cm9x2… -m "Your part is ready to review"
weave msg inbox                        # unread messages (--all, --sent, --limit)
weave msg show <id>                    # the whole conversation, marked read
weave msg send --reply <id> -m "Yes, go ahead"
weave msg read --all
weave msg wait --timeout 600           # block until one arrives; exit code 2 on timeout
AddressReaches
@allEveryone with access to the repository
@ws:<workstream>Everyone working in that workstream
@owner:<file>[::<symbol>]Whoever holds a live claim on it when the message is sent (nobody → 404)
a user id, or agent:<id>That person or agent

-m - reads the text from stdin. weave status shows the unread count, and a running watcher prints each message. Clash routing and resolution points send messages to both sides automatically. Webhook message.sent sees every message. API: POST /api/weave/{repoId}/messages {to, body, about?, reply_to?}, GET …/messages, POST …/messages/read. MCP: send_message, read_messages, mark_messages_read, wait_for_message.

Notices#

weave notices tells you what other drafts in this checkout changed that your code uses, before anyone stitches:

bash
weave --agent page notices
# signature changed: lib/cart.ts::addToCart (in draft of commerce)
#   was: export function addToCart(id: string): void
#   now: export function addToCart(id: string, qty: number): void
#   used by your app/page.tsx::Page
# now exists: lib/products.ts::listProducts (in draft of catalog)
  • Kinds: signature changed (with was: / now:), now exists (a name your code uses is now defined), removed (with where the name is still defined).
  • It covers the symbols in the files your draft changes and in your live claims; changes in your own files are never reported.
  • In server mode it also lists the server's dependency notices for stitches weaved since (a signature you call changed), and your routed clashes and resolution points.
  • Each call prints the next cursor and remembers it; --since <cursor> replays.

When a weave changes a symbol's signature, owners of its callers are also told by the server: weave status lists "Signature changes affecting your code".