# Weave documentation (all pages) > Generated from https://www.weave.directory/docs. Each page starts with a level-1 heading. Index: https://www.weave.directory/docs/llms.txt # Overview > What Weave is, how it differs from git, and the core concepts — workstream, draft, stitch, weave, owner, suggestion — with a glossary. > > Source: https://www.weave.directory/docs Weave is a version-control system built for many people and AI agents editing one codebase at the same time. It tracks code by **symbol** — a function, method, class, constant or JSON key — not by line. Instead of merging, it keeps everyone in **real-time sync** and gives every symbol an **owner**. Clashes never block anyone, and nobody's work is lost. There are two parts: | Part | Address | What it does | | --- | --- | --- | | The platform | `https://weave.directory` | Accounts, organizations, repositories, people, tokens, agents, webhooks and the web UI. | | The Weave server | `https://api.weave.directory` | Workstreams, heads, the weave check, ownership, suggestions, change requests, resolution points, messages, search and the operation log. | | The CLI | `weave` (and `weave-watcher`) | Runs on your machine or in an agent's sandbox. Install it with `curl -fsSL https://weave-cli.com/install.sh \| sh`. | New here? Go to the [Quickstart](https://www.weave.directory/docs/quickstart). Building with AI agents? Read [For AI agents](https://www.weave.directory/docs/agents). Agents can fetch these docs as plain text: [/docs/llms.txt](https://www.weave.directory/docs/llms.txt) (an index) or [/docs/llms-full.txt](https://www.weave.directory/docs/llms-full.txt) (every page in one file). Every page is also available as Markdown at `/docs/.md`. ## How Weave works in one minute 1. You work in a **workstream** (`main`, `dev`, `feature/auth`). Everyone on a workstream sees the same **head**. 2. You edit files on disk as usual. `weave add` records your edits, by symbol, in your private **draft**. Nobody sees a draft. 3. `weave stitch -i "" -w ""` seals the draft into one **stitch** with what it is for and why. 4. The server runs the **weave check**. If it passes, the stitch is **weaved**: the head moves forward and everyone receives it. 5. If you changed a symbol someone else **owns**, that part goes to them as a **suggestion**. The rest weaves at once. 6. If your change clashes with newer work, it also goes to that person as a suggestion. Nothing fails. If they reject it, a **resolution point** keeps both versions. ```bash weave clone acme/shop && cd shop weave claim src/cart.ts::addToCart --feature "quantity support" # ... edit src/cart.ts ... weave add weave stitch -i "Add quantity to addToCart" -w "the mobile app sends a quantity" ``` ## How Weave differs from git Weave is not git with a different name. Git lets everyone change anything on a private copy and reconciles the copies later, line by line. Weave keeps everyone on the same head in real time and decides, per symbol, who changes what. | | Git | Weave | | --- | --- | --- | | Unit of change | Lines in files | Symbols: functions, classes, constants, JSON keys | | Who may change code | Anyone, on their own copy | Anyone; changes to an **owned** symbol become a **suggestion** to its owner | | Staying in step | Fetch and merge when you choose | Real-time sync; `weave sync` or `weave watcher` follow the head | | Two people change the same thing | Merge conflict; someone resolves markers before continuing | Never blocks: the newer version stays, the other goes to its author as a suggestion; a rejected one becomes a resolution point with both versions | | Two people change different functions in one file | Usually merges, sometimes conflicts | Never clashes: symbols are independent | | A unit of work | Commit message | Stitch with an **intent** and a **why**, plus optional **decision records** | | Lines of work | Branches merged in one step | Workstreams in a chain; stitches **promoted** up one at a time and **inherited** down automatically | | Rewriting history | Rebase, reset, force-push | Never: heads only move forward; revert and undo add new entries | | AI agents | Share a person's identity | First-class authors with their own sessions, tokens, drafts and path limits | ### Coming from git: what to use instead | If you would… | In Weave | | --- | --- | | `git clone` | `weave clone /` | | `git checkout -b feature` | `weave workstream new feature --from main` | | `git checkout main` | `weave checkout main` | | `git add` / `git commit` | `weave add`, then `weave stitch -i "…" -w "…"` | | `git push` | Nothing: a stitch is sent when you stitch (`weave push` only sends stitches sealed while offline) | | `git pull` | `weave sync` (or let `weave watcher` do it) | | Open a pull request and merge | `weave promote --to ` | | Resolve a merge conflict | Usually nothing. For a **change request**: `weave cr resolve this\|other\|edit`. For a **resolution point**: `weave resolve head\|copy\|edit` | | `git log` / `git blame` | `weave timeline`, `weave log`, `weave log --symbol ` | | `git revert` | `weave revert --why "…"` or `weave undo` | | `git stash` | `weave hibernate` / `weave resume` | | `git tag` | Tags on the server API (`POST /api/weave/{repoId}/tags`) | Weave can still talk to git when you need it: the server can **import** a git repository and **mirror** a workstream to a git remote (see the [API reference](https://www.weave.directory/docs/api#git-import-and-mirrors)). ## Core concepts ### Symbols Weave parses every file into symbols, losslessly. Two people changing different functions in the same file never clash. Parsed languages: Rust, TypeScript/JavaScript (TSX/JSX), Python, Go, Java, C#, Swift, PHP, CSS and SCSS/Sass. A JSON file whose top level is an object is split per key (`dependencies.react`, `scripts.build`), so two agents adding different keys to `package.json` never clash. Other files are one whole-file symbol. Files on disk stay ordinary files, so editors, compilers and builds keep working. A symbol is named `file::qualified::name`, for example `src/auth.rs::Auth::login` or `package.json::scripts.dev`. ### Draft → stitch → weave | Stage | Where it lives | Who sees it | | --- | --- | --- | | **Draft** | On your device, per person or agent (`.weave/drafts/`) | Only you. Never sent anywhere. | | **Stitch** | Sealed and sent to the server with an intent and a why | The server checks it | | **Weaved** | Part of the workstream; the head moved | Everyone on the workstream | **Weaved means deployable** for that workstream. Heads only move forward. ### Owners, claims and suggestions Anyone can change an unclaimed symbol. To own something, **claim** it: `weave claim src/auth.rs::login`. A claim lasts for a **lease** (10 minutes by default) that `weave watcher` renews. When someone else changes a symbol you own, their change does not overwrite yours: it arrives as a **suggestion** you accept or reject. Ownership routes work; it never blocks it. ### Clashes never block - A **stale copy** (text exactly as Weave last wrote it) loses quietly to the newer head. - A **real edit** that clashes with newer work by someone else goes to that person as a suggestion. The rest of your stitch weaves. Both of you get a message. - If they reject it, a **resolution point** keeps both versions, side by side, until someone picks one. ### Workstreams and the chain Workstreams form a chain, for example `main ← preprod ← dev`. Stitches move **up** one at a time by **promotion** and come **down** by **inheritance**. When the same symbol changed differently on both sides, Weave opens a **change request** showing both versions with their intent and why. See [Workstreams](https://www.weave.directory/docs/workstreams). ### Decisions A **decision record** says why code is the way it is: a title, the why, rejected alternatives and constraints, anchored to symbols. Records travel with the code through drafts, stitches, promotion and inheritance. See [Decisions & history](https://www.weave.directory/docs/decisions-and-history). ### Agents An AI agent is a first-class author. Each agent has its own **session** (its own draft and active workstream, even in a shared checkout), ideally its own **agent token**, and optionally a **path scope** that limits what it may change. See [For AI agents](https://www.weave.directory/docs/agents). ## Glossary | Term | Meaning | | --- | --- | | **workstream** | A line of work (`main`, `preprod`, `dev`, `feature/x`). Has a parent (except `main`) and settings for ownership and inheritance. | | **head** | The current weaved state of a workstream (a 64-hex state id). | | **draft** | Your private, in-progress changes on this device, by symbol. Never sent. | | **stitch** | A sealed change with an **intent** (what) and an optional **why**. | | **weave / weaved** | The weave check accepted a stitch; the workstream head moved. | | **weave check** | The server's check of a stitch: base, ownership, clashes with newer work, that every operation applies and every file still parses. | | **symbol** | A named definition: function, method, class, variable, import, JSON key. Named `file::qualified::name`. | | **claim** | Taking ownership of files or symbols for a while. | | **owner** | The holder of the most specific live claim on a symbol. Only the owner changes it directly. | | **lease** | How long a claim lasts unless renewed (server default 10 minutes). | | **part label** | A claim's feature text of the form `part:`, shown by `weave owners`. Builders use it to say which part of a build owns a file. | | **suggestion** | A change to a symbol someone else owns, or one that clashes with their newer work; it goes to them to accept or reject. | | **clash** | A change based on a version someone else has replaced since (`lost_update`), or one that puts back what they replaced (`reverts_newer_work`). Routed as a suggestion, never refused. | | **resolution point** | Both versions kept after the owner rejects a clash suggestion: a renamed copy `__rp_` in the code, or the author's text kept on the point. Resolved with `weave resolve`. | | **change request** | Two versions of one symbol side by side (from two workstreams, a promotion or a revert), each with author, intent and why, for someone to choose. | | **promote** | Submit a weaved stitch to another workstream, usually the parent, through its weave check. | | **inherit** | A child workstream receiving its parent's weaves (`auto` at once, `manual` on `weave refresh`). | | **integrate** | Build a private integration draft to resolve change requests, then stitch the result. | | **carry forward** | Move your draft onto a newer head. Automatic, because changes are by symbol. | | **held edit** | An edit on disk you have not added that clashes with a newer version; `weave sync` leaves it on disk and lists it. | | **session** | One person's or agent's identity in a checkout: its own draft, active workstream and lock (`--agent `). | | **decision record** | `.weave/decisions/D-xxxx.toml`: a decision (title, why, constraints, rejected alternatives) anchored to symbols. | | **notice** | A dependency notice: a signature changed, a name now exists or was removed, in code you use. | | **operation log** | The append-only, hash-chained record of every action (`weave log`). | | **agent token** | A short-lived (`wva_…`, ≤ 24 h) token for a registered agent, acting for the person who issued it. | | **path scope** | Glob patterns an agent may write to; writes outside get `403 path_out_of_scope`. | | **lawful purge** | Removing content (a leaked secret, personal data) from all history without breaking any hash. Needs two admins. | --- # Quickstart > Sign up, create an organization and a repository, install the CLI, clone, edit, add, stitch, and see your change on weave.directory. > > Source: https://www.weave.directory/docs/quickstart From a new account to your first weaved stitch, in about ten minutes. You need macOS or Linux (Windows: see [the installer page](https://weave-cli.com/docs/install)). ## 1. Create your account 1. Go to [weave.directory/signup](https://www.weave.directory/signup). Enter **Full Name**, **Email** and **Password** (at least 8 characters), tick the terms box and click **Sign Up**. 2. Open the email from Weave and click the link. On the **Verify your email** page click **Verify email**. You need a verified email to create organizations and access tokens. 3. [Sign in](https://www.weave.directory/login). The first time, pick the role that best describes you (Developer, Team Lead, Reviewer or Manager) and click **Select**. > **Turn on two-factor authentication now** if you will own or administer a team organization: owners and admins of an organization need 2FA to administer it (personal organizations are exempt). Go to your avatar → **Settings** → **Account** → **Set up 2FA**, scan the QR code and enter the 6-digit code. ## 2. Create an organization In the web UI: click **+** in the header → **Organization** (or go to [/orgs/new](https://www.weave.directory/orgs/new)). Enter an **Organization Name** and an **Organization URL** (`weave.directory/`), then click **Create Organization**. Or with the API, using a personal access token with the `org:admin` scope (step 4 shows how to make one): ```bash curl -s https://weave.directory/api/v1/orgs \ -H "Authorization: Bearer $WEAVE_PAT" \ -H "Content-Type: application/json" \ -d '{"name": "Acme", "slug": "acme"}' ``` ```json { "id": "clx…", "slug": "acme", "name": "Acme" } ``` The slug is lower-case letters, digits and hyphens. A taken slug answers `409 conflict`. ## 3. Create a repository In the web UI: on your organization's page click **New Repository** (or **+** → **Repository**). Choose the **Owner**, a **Repository Name**, an optional description, what to **Initialize with** (Default (README), Empty, Next.js / React, Rust / CLI or Python) and the **Visibility**, then click **Create Repository**. You land on `weave.directory//`. The repository has two workstreams, `main` and `dev` (`dev`'s parent is `main`), and the template's files are the first stitch on `main`. Or with the API (scope `org:admin`, and you must be a member of the organization): ```bash curl -s https://weave.directory/api/v1/orgs/acme/repos \ -H "Authorization: Bearer $WEAVE_PAT" \ -H "Content-Type: application/json" \ -d '{"name": "shop", "description": "Our web shop", "private": true}' ``` ```json { "id": "cm3k…", "name": "shop", "org": "acme", "slug": "acme/shop", "private": true, "workstreams": ["main", "dev"], "warnings": [] } ``` - `id` is the **repository id**. The Weave server API (`/api/weave/{repoId}/…`) takes this id, not `org/name`. - `workstreams` defaults to `["dev"]`; every listed workstream is created with `main` as its parent. Want `main ← preprod ← dev` instead? See [Workstreams](https://www.weave.directory/docs/workstreams#set-up-main-preprod-dev). - `template` defaults to `"empty"` over the API. ## 4. Create a personal access token Go to your avatar → **Settings** → **Access Tokens**. Under **Generate New Token** give it a **Name**, an **Expiration** (30, 60 or 90 days, or 1 year), the **Scopes** you need (`repo:read` and `repo:write` are ticked by default) and the **Repository access**, then click **Generate Token**. Copy it now — it is shown once. Personal access tokens start with `weave_`. | Scope | Lets the token | | --- | --- | | `repo:read` | Read repositories | | `repo:write` | Stitch and weave in repositories | | `repo:admin` | Administer and delete repositories | | `org:admin` | Administer organizations (create repositories, agents) | | `tokens:write` | Issue and revoke tokens | ## 5. Install the CLI and sign in ```bash curl -fsSL https://weave-cli.com/install.sh | sh weave --version # weave 0.4.0 weave login # paste the token; it is checked and saved in ~/.weave/config.json ``` `echo "$WEAVE_PAT" | weave login` reads the token from stdin. In CI or an agent sandbox you can skip `weave login`: set `WEAVE_TOKEN` and `weave clone`, `add`, `stitch` and `sync` work without prompts. ## 6. Clone the repository ```bash weave clone acme/shop cd shop weave status ``` `weave clone / [dir] [--workstream main] [--server URL]` downloads the head of the workstream in one request, writes the files, verifies them against the head and sets up `.weave/` connected to `https://api.weave.directory`. `weave status` is clean straight away. With `--json` (values shortened): ```json { "repo": "acme/shop", "dir": "shop", "workstream": "main", "head": "4218fab7…", "files": 3, "bytes": 1840, "server": "https://api.weave.directory", "state_included": true, "warnings": [] } ``` Already have a folder with code? Run `weave init --server https://api.weave.directory` in it instead (name the repository first with `weave remote add origin acme/shop` if your account can reach several). ## 7. Edit, add and stitch Work on `dev`, then promote to `main`: ```bash weave checkout dev ``` Edit a file with your editor, for example add a function to `src/cart.ts`. Then: ```bash weave status # your draft, and edits on disk not added yet weave add # record the edits in your draft, by symbol weave stitch -i "Add a cart total helper" -w "checkout shows the total before tax" ``` - `-i/--intent` (required) says what the change is for. `-w/--why` keeps the rationale with the change and drafts a **decision record** anchored to the symbols you changed; you confirm it (`-y` records it without asking). - The weave check runs at once. When it passes, the stitch is **weaved** and the head of `dev` moves. - If part of it touched a symbol someone else owns, that part goes to them as a suggestion and the rest weaves. `weave status` marks it `awaiting `. `weave stitch --json` prints the outcome: ```json { "result": "weaved", "workstream": "dev", "stitch": "9c1e…", "head": "77ab…", "suggestions": [], "routed": [], "held_back": [], "warnings": [] } ``` ## 8. Promote to main ```bash weave timeline # weaved stitches of dev, newest first, with their ids weave promote 9c1e --to main # a prefix of the stitch id is enough ``` The stitch goes through `main`'s own weave check and keeps its author, intent and why. If it relies on earlier stitches that are not in `main` yet, Weave lists them and asks; `--with-deps` promotes them together. ## 9. See it on the website Open `weave.directory//`: - **Code** shows the files of the selected workstream (pick it with the workstream selector) and a **latest stitch** link. - **Weaved** (`///stitches`) lists the weaved stitches with author, intent and why, with **Promote to {parent}** and **Revert** actions. - **Workstreams**, **Suggestions**, **Change requests** and **Log** show the rest. You can also stitch from the browser: **New** → **New File**, or edit a file, fill in **What is this change for?** and click **Stitch**. ## Next steps - Work with others: [claims, suggestions and clashes](https://www.weave.directory/docs/working-together). - Set up `main ← preprod ← dev`: [Workstreams](https://www.weave.directory/docs/workstreams). - Run AI agents on the repository: [For AI agents](https://www.weave.directory/docs/agents). - Keep a terminal following the head: `weave watcher` renews your claims, keeps files on disk in step and prints messages for you. --- # Workstreams > The main ← preprod ← dev chain, promote and inherit, ownership and inherit settings, protected workstreams, removing and restoring. > > Source: https://www.weave.directory/docs/workstreams A **workstream** is a line of work: `main`, `preprod`, `dev`, `feature/auth`. Everyone on a workstream shares its **head**. Every workstream except `main` has a **parent**, and together they form a chain. Weaved stitches move **up** the chain by promotion and **down** by inheritance. ``` main weaved = deployable to production └─ preprod weaved = deployable to staging └─ dev weaved = the team's integrated work ``` ## Names A workstream name is one or more parts separated by `/`: `main`, `feature/auth`, `dev/section-of-system`. Parts use letters, digits, `-`, `_` and `.`; no empty, `.` or `..` parts; at most 100 characters. `weave workstream new` lower-cases the name and turns spaces into `-`. In a URL path a name is one segment, so encode `/` as `%2F` (`/workstreams/feature%2Fauth/head`). ## Create a workstream ```bash weave workstream new feature/auth --from dev # creates it and switches to it weave workstream new sandbox --from main --ownership workstream --inherit manual weave workstream list # parent, head, ownership, inherit, weaved count weave checkout dev # switch the files on disk to another workstream ``` `--from` (alias `--base`) defaults to the active workstream. Over the server API: ```bash curl -s https://api.weave.directory/api/weave/$REPO_ID/workstreams \ -H "Authorization: Bearer $WEAVE_TOKEN" -H "Content-Type: application/json" \ -d '{"slug": "feature/auth", "parent": "dev", "settings": {"ownership": "repo", "inherit": "auto"}}' ``` ```json { "type": "workstream", "workstream": { "slug": "feature/auth", "parent": "dev", "parent_head": "…", "synced_parent_head": "…", "head": "…", "settings": { "ownership": "repo", "inherit": "auto" }, "created_by": "", "created_at": "2026-10-30T12:00:00Z", "archived_at": null, "archived_by": null } } ``` An existing name answers `409 conflict`. A removed (archived) workstream keeps its name: restore it instead. In the web UI: the repository's **Workstreams** tab → **New workstream**, pick **Created from**, click **Create**. ## Parents can't change later There is no call to change a workstream's parent. **Create the chain in order, top down.** ### Set up main ← preprod ← dev 1. Create the repository with only `preprod` (so it doesn't create the default `dev` under `main`): ```bash curl -s https://weave.directory/api/v1/orgs/acme/repos \ -H "Authorization: Bearer $WEAVE_PAT" -H "Content-Type: application/json" \ -d '{"name": "shop", "workstreams": ["preprod"]}' ``` This gives `main` and `preprod` (parent `main`). 2. Create `dev` under `preprod`, in a checkout or over the API: ```bash weave workstream new dev --from preprod # or curl -s https://api.weave.directory/api/weave/$REPO_ID/workstreams \ -H "Authorization: Bearer $WEAVE_TOKEN" -H "Content-Type: application/json" \ -d '{"slug": "dev", "parent": "preprod"}' ``` 3. Check: `weave workstream list` (or `GET /api/weave/{repoId}/workstreams`) should show `dev → preprod → main`. Seeding from a template? Seed `main` first, then create `preprod` and `dev`, so they start from the seeded head (see [For AI agents](https://www.weave.directory/docs/agents#seed-a-new-app-from-a-template)). ## Promote: move a stitch up ```bash weave timeline # weaved stitches of the active workstream, with ids weave promote 9c1e --to preprod # a stitch id prefix weave promote 9c1e --to preprod --with-deps weave status # per stitch: promotes cleanly / needs / clashes on ``` - Promotion submits the stitch to the target's own weave check and keeps its author, agent, intent and why. - If it relies on earlier stitches that aren't in the target yet, Weave lists them and asks; `--with-deps` promotes them together. With `--json` and without `--with-deps` you get the error code `needs_dependencies` with the list. - A symbol that changed differently in the target opens a **change request** there instead of weaving. - Between two workstreams with `ownership: repo`, ownership is not checked again. API: `POST /api/weave/{repoId}/workstreams/{from}/promote` with `{"to": "preprod", "changesets": [""], "with_dependencies": false}`. In the web UI, the **Weaved** tab has **Promote to {parent}** on each stitch. ## Inherit: receive the parent's weaves When the parent weaves a stitch, each child receives it according to its `inherit` setting: | `inherit` | What happens | | --- | --- | | `auto` (default) | The child receives the stitch at once, for every symbol it hasn't changed itself. | | `manual` | Nothing until you run `weave refresh` (or the **Inherit from parent** button), which inherits each pending parent stitch in order. | Symbols the child changed differently get a **change request** as soon as the clash exists — you know early, not at promotion time. ## Change requests between workstreams A change request shows the base version and both sides, each with author, agent, intent and why. Nobody merges lines. ```bash weave cr list # open change requests in this workstream (--all for resolved) weave cr show # both sides weave integrate # private integration draft: clean symbols applied, clashes listed weave cr resolve this # keep this workstream's version weave cr resolve other # take the incoming version weave cr resolve edit # take the symbol as edited on disk (or --text / --from-file) weave stitch -i "Take dev's token refresh" # build, test, then weave the resolution ``` The integration draft is private until you stitch it, so nobody sees a half-resolved state. ## Settings: ownership and inherit | Setting | Values | Meaning | | --- | --- | --- | | `ownership` | `repo` (default) | One owner per symbol across every `repo` workstream. Approval happens once; promotion between such workstreams never re-asks. | | | `workstream` | The workstream has its own owners (an experimental sandbox). Promoting from it can raise change requests for the target's owners. | | `inherit` | `auto` (default) / `manual` | See above. | Change them later: ```bash curl -s -X PATCH https://api.weave.directory/api/weave/$REPO_ID/workstreams/dev/settings \ -H "Authorization: Bearer $WEAVE_TOKEN" -H "Content-Type: application/json" \ -d '{"inherit": "manual"}' ``` Only a repository admin, or the creator of a non-`main` workstream (with write access), may change settings. Changing `ownership` while someone else holds a live claim in the workstream's scope is refused with `409`, unless an admin sends `"force": true`. In the web UI: the workstream's page → **Settings** → **Save settings**. ## Protected workstreams A protected workstream only changes by **promotion** (and inheritance from its parent). Direct stitches, web edits, restores, accepted suggestions, change-request resolutions and reverts are refused for everyone but repository admins (`403 "workstream main is protected: changes arrive by promotion only"`). You can also require **attestations** — signed statements such as `tests`, `security` or `approval` — on the source head before a promotion is let in: ```bash # repo admin curl -s -X PUT https://api.weave.directory/api/weave/$REPO_ID/workstreams/main/protection \ -H "Authorization: Bearer $WEAVE_TOKEN" -H "Content-Type: application/json" \ -d '{"requireAttestations": ["tests", "approval"]}' # preflight: is preprod's head ready to promote into main? curl -s "https://api.weave.directory/api/weave/$REPO_ID/workstreams/main/protection/check?head=preprod" \ -H "Authorization: Bearer $WEAVE_TOKEN" ``` A promotion without them answers `409 attestations_required` with `required`, `missing` and `invalid`. Admins are not exempt: to release without attestations an admin removes the protection (`DELETE …/protection`), which is logged. How to sign an attestation: [Decisions & history](https://www.weave.directory/docs/decisions-and-history#attestations). ## Remove and restore a workstream Removing a workstream **archives** it: it is hidden from lists, read-only, and its history and head stay readable by name (`weave cat --workstream`, `weave timeline`). Nothing is deleted. ```bash weave workstream remove feature/auth # alias: archive weave workstream remove feature/auth --force # even with weaved stitches not promoted to the parent weave workstream list --archived # removed ones too, "(removed by )" weave workstream restore feature/auth ``` - Refused for `main` (`400`), for the active workstream (switch first), while it has child workstreams that aren't removed (`409`, listed), and while weaved stitches aren't promoted to its parent unless `--force` (`409 unpromoted_stitches`, with the count). - Only its creator or a repository admin may remove or restore it. Path-scoped and verifier agents never may. - On removal, open change requests are closed (keeping its own side), pending suggestions are rejected, claims in its own ownership scope are released and open resolution points are closed. Restoring does not reopen them; `weave refresh` catches it up with its parent. - `weave undo` of a removal restores it. A restore is refused while the parent is removed. API: platform `DELETE /api/v1/repos/{repoId}/workstreams/{ws}?force=true|false` and `POST /api/v1/repos/{repoId}/workstreams/{ws}/restore` (personal tokens and worker agent tokens with `repo:write`), or the server routes `DELETE /api/weave/{repoId}/workstreams/{ws}?force=` and `POST …/restore`. Web UI: **Workstreams** → **Remove workstream** (tick **Remove it anyway.** when asked), and **Show archived** → **Restore**. ## Hibernate: park your draft ```bash weave hibernate # park your draft in this workstream; files on disk show the weaved head weave checkout main # look at something else weave checkout feature/auth && weave resume # bring the draft back, carried onto the current head ``` `weave checkout` refuses while files on disk have edits you haven't added. --- # 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 ` 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:` 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 ""` 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 # the change, symbol by symbol, next to the current text weave suggestions accept # owner: weave it, credited to its author weave suggestions reject --reason "keep the old signature until v2" weave suggestions resubmit # author: carry a rejected or stale one onto the head and stitch again ``` - Your edit stays in your draft and on disk, marked `awaiting ` 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 `) 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 ` 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 `__rp_` (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 ]`), `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 ` 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 ` 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 # the whole conversation, marked read weave msg send --reply -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:` | Everyone working in that workstream | | `@owner:[::]` | Whoever holds a live claim on it when the message is sent (nobody → `404`) | | a user id, or `agent:` | 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 ` 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". --- # Decisions & history > Decision records, the operation log, timeline, blame and symbol history, revert and undo, tags and attestations. > > Source: https://www.weave.directory/docs/decisions-and-history Every change in Weave carries what it was for and why. History only moves forward: revert and undo add new entries, nothing is rewritten. ## Decision records A **decision record** says why code is the way it is: a title (≤ 80 characters), the why (≤ 240), rejected alternatives and constraints, anchored to symbols. Records are files, `.weave/decisions/D-xxxx.toml`, that travel draft → stitch → weaved **with the code**, so they are owned, promoted, inherited and reverted like the code they explain. Agents need `.weave/decisions/**` in their `pathScope` to stitch them. ### Record decisions ```bash # at stitch time: -w drafts a record anchored to the symbols you changed (confirm it, or -y) weave stitch -i "Keep bcrypt" -w "login p99 budget is 250ms" -y # directly weave decision add -t "Keep bcrypt cost at 12" -w "login p99 budget is 250ms" \ --on src/auth.rs::hash_password --alt "argon2id" --constraint "p99 login < 250ms" --comment ``` `--comment` puts a one-line `why: … [D-xxxx]` comment above each anchor. That tag is the strongest anchor: the record follows it through moves and renames. `WEAVE_DECISION_YES=1` records drafted decisions without asking. ### Read decisions (within a token budget) ```bash weave decision for src/auth.rs::login # one short line per decision on it and its neighbours weave decision for src/auth.rs::login --format constraints weave decision search "password hashing" --near src/auth.rs::login weave decision impact src/auth.rs::login --depth 2 # callers and callees with their decision counts weave decision show D-7f3a weave decision list --all # or --status active|needs_review|superseded|stale|retired ``` `--format constraints` prints rules for an agent's starter pack, best decision first: ``` KEEP: Keep bcrypt cost at 12 — login p99 budget is 250ms [D-7f3a] KEEP: p99 login < 250ms [D-7f3a] NEVER: argon2id [D-7f3a] ``` ### Keep decisions current When an anchored symbol changes, its decisions become `needs_review`; when every anchor is lost, `stale`. ```bash weave decision review # follow moved / renamed anchors, mark drift, list the queue (--dry-run) weave decision review D-7f3a --accept # it still holds weave decision supersede D-7f3a -t "Use argon2id" -w "new hardware budget" weave decision retire D-7f3a --reason "auth moved to the identity service" ``` `weave enrich` can find unconfirmed why-candidates with an LLM (your key, on your machine); `weave decision review --candidates` lists them and `weave decision confirm ` turns one into a decision. MCP: `decisions_for`, `decision_search`, `decision_get`, `impact`, `decision_propose`, `decision_review`. Server API: `GET|POST /api/weave/{repoId}/decisions`, `GET …/decisions/{id}`, `POST …/decisions/{id}/supersede`, `POST …/decisions/{id}/retire`, `POST …/decisions/review` (see [API reference](https://www.weave.directory/docs/api#decisions)). Server writes are stitches too, so a write to a record someone else owns becomes a suggestion. ### Threads **Threads** are the lighter companion: short behaviour notes per symbol, written directly to sidecars under `.weave/threads/` without drafts or stitches. ```bash weave thread add src/auth.rs::login "token refresh is lazy" weave thread show login --depth 1 weave thread search "refresh" weave index && weave thread heal # after renames ``` ## Timeline and the operation log ```bash weave timeline # weaved stitches of the active workstream, newest first weave timeline main --limit 20 # author, agent, intent, why, promoted / inherited / revert weave log # the operation log: every action, newest first (default 30) weave log --actor alice --workstream main --limit 50 weave log --by-agent builder-1 weave log --symbol src/auth.rs::login # everything that touched a symbol weave log --verify # check the log's hash chain first ``` The **operation log** records every action — claims, releases, lease expiries, stitches, weaves, rejections, suggestions, change requests, promotions, reverts, undos, workstream removals, tags, attestations, purges — with the person and agent. It is append-only and hash-chained: each entry's id is the BLAKE3 hash of its content and the previous entry's id. In the web UI it is the repository's **Log** tab, with filters for person, agent, workstream and symbol. ## Blame and symbol history Which weave last changed each symbol of a file (server API, read access): ```bash curl -s "https://api.weave.directory/api/weave/$REPO_ID/workstreams/main/blame?path=src/auth.rs" \ -H "Authorization: Bearer $WEAVE_TOKEN" ``` ```json { "type": "blame", "workstream": "main", "path": "src/auth.rs", "head": "…", "total": 3, "next_offset": null, "items": [{ "symbol": "src/auth.rs::login", "kind": "function", "changeset": "…", "label": "stitch", "author": "alice", "agent": null, "at": "…", "intent": "MFA login", "why": "SOC2", "entry_id": "…" }] } ``` - Paged with `offset` and `limit` (default 200, max 1000). A symbol unchanged since its workstream was created is attributed in the parent. - `GET …/workstreams/{ws}/symbol-history?symbol=src/auth.rs::login` lists every weave that changed one symbol. - `GET …/workstreams/{ws}/history` pages weaved stitches newest first (`before`, `limit` ≤ 500) and filters by `kind`, `agent`, `author`, `source` and `symbol`. Items carry `reverted_by` / `reverts` links. - `GET /api/weave/{repoId}/diff?from=&to=&level=file|symbol&path=` diffs two heads, by file or by symbol. ## Revert and undo ```bash weave revert 9c1e --why "broke MFA on mobile" # a new stitch with the inverse operations weave undo # reverse your own most recent action weave undo # or a chosen entry of yours ``` - **Revert** takes back a weaved stitch with a new stitch. Symbols unchanged since are reverted; a symbol changed again since is not overwritten but becomes a change request. `--why` is required. - **Undo** reverses **your own** action: a weaved stitch is reverted, a claim released, a suggestion withdrawn, a rejection reopened, a settings change restored, a removed workstream restored. Someone else's action is taken back with a revert or a suggestion instead. Undo is logged and never deletes entries. - Several stitches as one revert, all or nothing (server API): `POST /api/weave/{repoId}/workstreams/{ws}/revert` with `{"changesets": ["", ""], "why": "…"}`. If a later weave changed one of the symbols, it answers `409 revert_conflict` with the `blocking` symbols and nothing is weaved. - Restore paths or symbols to an older head as a new stitch: `POST /api/weave/{repoId}/restore` with `{"workstream", "head", "paths"?, "symbols"?, "intent"?, "why"?}`. - Web UI: **Weaved** → **Revert** on a stitch; **Log** → undo on your own entries. ## Tags Tags are immutable names for heads (server API): ```bash curl -s https://api.weave.directory/api/weave/$REPO_ID/tags \ -H "Authorization: Bearer $WEAVE_TOKEN" -H "Content-Type: application/json" \ -d '{"name": "v1.2.0", "workstream": "main", "message": "spring release"}' ``` - `workstream` alone tags its current head; or pass `head` (a state of the repository). Write access. - Names: letters, digits, `.`, `_`, `-`, `/`, ≤ 128 characters, no leading `-` `.` `/`, no trailing `/`, no `..` or `//`. - The same name for the same head answers `200 created: false`; for another head, `409`. - `GET …/tags[?head=]` lists them newest first; `GET …/tags/{name}` (encode `/` as `%2F`); `DELETE …/tags/{name}?why=` (repository admin). - Tags aren't accepted as refs by `diff`, `archive` or `restore` yet: pass the tag's `head`. ## Attestations An **attestation** is a signed statement about one exact head — `tests passed`, `security reviewed`, `approved` — that a [protected workstream](https://www.weave.directory/docs/workstreams#protected-workstreams) can require before a promotion. 1. **Register a key** (Ed25519). Repository keys: `POST /api/weave/{repoId}/attestation-keys` `{"publicKey": "", "label"?, "types"?: ["approval"]}` (repository admin). Organization keys, trusted in every repository of the org: `POST https://weave.directory/api/v1/orgs/{slug}/attestation-keys` (scope `org:admin`). A key's id is `wak_` + the first 32 hex of sha256(raw public key). 2. **Sign** this text (UTF-8, `\n` between lines, no trailing newline): ```text weave-attestation/v1 repo: head: type: payload-sha256: ``` A string payload is its UTF-8 text as is. Any other JSON is compact, with object keys sorted, recursively. ```js import crypto from "node:crypto"; const canonical = (v) => typeof v === "string" ? v : Array.isArray(v) ? `[${v.map(canonical).join(",")}]` : v && typeof v === "object" ? `{${Object.keys(v).sort().map((k) => `${JSON.stringify(k)}:${canonical(v[k])}`).join(",")}}` : JSON.stringify(v); function attest(privateKey, repo, head, type, payload) { const text = typeof payload === "string" ? payload : canonical(payload); const digest = crypto.createHash("sha256").update(text, "utf8").digest("hex"); const msg = `weave-attestation/v1\nrepo:${repo}\nhead:${head}\ntype:${type}\npayload-sha256:${digest}`; return crypto.sign(null, Buffer.from(msg, "utf8"), privateKey).toString("base64"); } ``` 3. **Post it**: `POST /api/weave/{repoId}/heads/{head}/attestations` `{"type", "payload", "signature", "keyId"}` (write access; any principal). `head` must be a 64-hex state id, so you attest exactly what was checked. The signature is verified on the way in. 4. **Read** them: `GET …/heads/{head}/attestations` (a workstream name works here). Anyone can fetch a public key without a token: `GET /api/weave/attestation-keys/{keyId}`. A revoked key verifies no attestation recorded after its revocation; ones it signed before stay valid. ## Verified audit trail The server verifies every repository's hash-chained log every hour and writes checkpoints to write-once storage, chained to each other. Read the latest with `GET /api/weave/{repoId}/audit/verification` (read access; `?deep=true` for admins re-checks the stored checkpoint) and export the log with `GET …/audit/export?from=&to=&format=json|ndjson` (admin). `GET …/log/verify` checks the chain on demand. See [Security & access](https://www.weave.directory/docs/security#audit-trail). --- # Search > Semantic code search (weave search, search_code), keyword find, and what is indexed: stitched workstream heads, never drafts. > > Source: https://www.weave.directory/docs/search Find code by what it does, in one call, within a token budget — including what other agents in your checkout are still writing. ## Semantic search: weave search ```bash weave search "where do we handle refunds?" weave search "the function that formats prices for the cart" --limit 5 --budget 600 weave search "rate limiting" --paths src/api/,lib/http weave --json search "refunds" ``` ``` # 3 hit(s) for "where do we handle refunds?" in main (semantic + keyword) src/billing/refunds.ts:2 export async function processRefund(order: Order, cents: number) — Issue a refund through the payment provider. [owner alice] src/billing/refunds.ts:7 function auditRefund(order: Order) src/cart/coupons.ts:3 export function refundCoupon(code: string): void [added-in-draft-of b1] ``` How it works: - The server's **semantic search** over the active workstream's **head** (embeddings of weaved code only) is fused with the `weave find` **keyword** ranking over the files **on disk** (reciprocal-rank fusion), de-duplicated by `file::symbol`. Exported symbols rank slightly first. - Because the keyword half reads disk, symbols other agents in the checkout are still writing are found too. A hit whose file on disk differs from the head is shown as it is on disk and tagged `[changed-in-draft-of ]`, `[added-in-draft-of ]` or `[removed-in-draft-of ]` (`…-on-disk` when no draft holds it); the head's signature follows as `head:`. - `--limit` default 10 (max 50), `--budget` default 800 tokens (snippets go first, then the last hits), `--paths` path prefixes (repeat or comma-separate). - Local mode and servers without semantic search give the keyword hits with a note. `--json` hits carry `target`, `file`, `symbol`, `kind`, `line`, `signature`, `doc`, `exported`, `score`, `found_by` (`semantic`, `keyword`), `similarity`, `snippet`, `owner`, the last `stitch` that changed it and `draft` details; the document also has `semantic`, `head`, `stale` and `indexing`. MCP tool: `search_code` (`query`, `limit`, `budget_tokens`, `paths`, `json`). ## Keyword search: weave find ```bash weave find add to cart # finds addToCart: exact name, then prefix, words in the name, signature, doc weave find refund --limit 50 ``` `weave find` searches the symbols of the files on disk — names, signatures and first doc lines — with no embeddings and no server. Ranked: the exact name (also `add to cart` for `addToCart`), then a name prefix, every word of the query in the name, words in the signature, words in the doc line; exported symbols first among equals. MCP tool: `find_symbols`. ## What is indexed | Indexed | Not indexed | | --- | --- | | Every named definition in source files at each **workstream head** | Drafts, files on disk, anything not weaved | | Path, qualified name, kind, signature, first doc line, member names, body (cut at 2,000 characters) | Imports, statements, JSON keys, `.weave/` records, lock files, minified bundles | | One index per repository and workstream | `node_modules`, `vendor`, `dist`, `target`, files over 2 MiB | - After every weave (stitch, accepted suggestion, promotion, inheritance, resolution, revert, seed) the server indexes the new head in the background; the weave never waits. Only symbols whose text changed are embedded again. - A search of a workstream that is behind waits briefly, then answers from the last indexed head with `stale: true`, or `indexing: true` if nothing is indexed yet. - Search is scoped to **one repository** and one workstream. Nothing on your device is ever sent for indexing: the old `POST /api/index` route answers `410 Gone`. - A lawful purge drops the embeddings of every path it withholds. - Embeddings are computed on the hosted service. ## Search over the API ```bash curl -s "https://api.weave.directory/api/weave/$REPO_ID/search?q=refunds&workstream=main&limit=5" \ -H "Authorization: Bearer $WEAVE_TOKEN" # or curl -s https://api.weave.directory/api/weave/$REPO_ID/search \ -H "Authorization: Bearer $WEAVE_TOKEN" -H "Content-Type: application/json" \ -d '{"query": "where do we handle refunds?", "workstream": "main", "limit": 5, "paths": ["src/billing/"], "kinds": ["function"]}' ``` ```json { "type": "code_search", "workstream": "main", "head": "f38c81a2…", "hits": [ { "target": "src/billing/refunds.ts::processRefund", "file": "src/billing/refunds.ts", "symbol": "processRefund", "kind": "function", "signature": "export async function processRefund(order: Order, cents: number)", "doc": "Issue a refund through the payment provider.", "line": 2, "exported": true, "score": 0.47, "snippet": "await payments.refund(order.id, cents);", "owner": "alice", "stitch": { "changeset": "400dcb80…", "intent": "billing and cart", "author": "alice", "at": "2026-10-30T19:24:04Z" } } ] } ``` - `query` up to 2,000 characters; `limit` 1–50 (default 10); `score` is cosine similarity. Read access is enough. - `GET /api/weave/{repoId}/search/index` shows, per workstream, the indexed head against the head. Admins backfill with `POST …/search/reindex` `{"workstream"?, "full"?, "wait"?}`. - A server without an embedding provider answers `unavailable`. --- # 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 ` (or `WEAVE_AGENT`), else you. Each session has its own active workstream, its own private draft (`.weave/drafts//`) and its own lock, so several agents can work in one folder without sharing a draft or waiting for each other. `--agent-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:`, 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 ]` | | `weave owners [paths\|globs] [--fresh]` | `owners` | Owner of files, symbols and JSON keys, part label, lease left (local copy ≤ 15 s old) | | `weave context [--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 "" [--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 [--limit]` | `find_symbols` | Keyword search over symbol names, signatures and doc lines on disk | | `weave notices [--since ]` | `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 --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 ` (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/.sock`, else `~/.weave/run/.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 ` 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/.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=` 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": "