# Working together

> Claims, owners and leases, suggestions, change requests, clashes that never block, resolution points, held edits, sync, drafts, adopt, messages and notices.
>
> Source: https://www.weave.directory/docs/working-together

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.

| Case | How Weave decides | What happens |
| --- | --- | --- |
| **Stale copy** | The symbol's text on disk is exactly what Weave last wrote there | Not an edit. The head's version stays, and `weave add` brings the file on disk up to it. |
| **Real edit that clashes** | You 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 undo** | You put back your own earlier version | Weaves directly. |
| **Intended revert** of someone else's work | `--allow-revert` on `weave add` and `weave stitch` | Weaves 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](https://www.weave.directory/docs/agents#one-token-per-agent)).

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

| Who | May 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 author | `head` only (withdraw) |
| Anyone else | Nothing (`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
```

| Address | Reaches |
| --- | --- |
| `@all` | Everyone 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".
