Use Weave
Workstreams
The main ← preprod ← dev chain, promote and inherit, ownership and inherit settings, protected workstreams, removing and restoring.
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#
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:
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"}}'
{ "type": "workstream", "workstream": {
"slug": "feature/auth", "parent": "dev", "parent_head": "…", "synced_parent_head": "…", "head": "…",
"settings": { "ownership": "repo", "inherit": "auto" },
"created_by": "<userId>", "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#
-
Create the repository with only
preprod(so it doesn't create the defaultdevundermain):bashcurl -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
mainandpreprod(parentmain). -
Create
devunderpreprod, in a checkout or over the API:bashweave 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"}' -
Check:
weave workstream list(orGET /api/weave/{repoId}/workstreams) should showdev → 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).
Promote: move a stitch up#
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 <stitch> / clashes on <symbol>
- 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-depspromotes them together. With--jsonand without--with-depsyou get the error codeneeds_dependencieswith 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": ["<id>"], "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.
weave cr list # open change requests in this workstream (--all for resolved)
weave cr show <id> # both sides
weave integrate <id|workstream> # private integration draft: clean symbols applied, clashes listed
weave cr resolve <id> this # keep this workstream's version
weave cr resolve <id> other # take the incoming version
weave cr resolve <id> 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:
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:
# 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.
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.
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 <date> by <user>)"
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 refreshcatches it up with its parent. weave undoof 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#
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.