跳到正文
GitHub·· 6 天前AI 评分60

writ 发布 Rust 并行编码智能体协调层

rmems/writ

AI 导读

rmems/writ 是一个 Rust 编写的、与 provider 无关的并行编码智能体协调层,用同主机 SQLite 存储登记任务、智能体会话、仓库、检出、分支与 head,并通过租约跟踪归属。

正文

A Rust-first, provider-neutral coordination layer for parallel coding agents.

Cursor, Claude Code, Codex, and similar harnesses already spawn workers and give each one an isolated checkout. What they don't share is coordination: who owns which task, branch, and worktree; what paths each worker intends to touch; who is blocked on whom; and how to hand work off without losing WIP. writ supplies that shared coordination layer so parallel workers can see each other, avoid duplicate work, negotiate overlapping edits early, and recover cleanly from pauses, crashes, and timeouts.

What writ does

  • Identity and ownership. Registers tasks, agents/sessions, repositories, checkouts, branches, and heads in a shared SQLite store, and tracks which worker owns what via leases.
  • Visibility. Declared paths and live status let workers see overlap before it becomes a merge conflict — overlap on separate branches is advisory and negotiated, not a fleet-wide freeze.
  • Communication. Intent, dependency, blocker, help-request, and handoff messages so workers coordinate directly instead of through a human relay.
  • Recovery. Pauses, timeouts, and stale leases are handoff events that preserve WIP and branch history — never permission to seize a live worktree or erase changes.
  • Local integration. git merge, rebase, and cherry-pick of peer work into an assigned feature branch are normal collaboration tools.

What writ does not do

  • Does not own worker lifecycles. Harnesses (Cursor, Claude Code, Codex, plain git worktree add) create and isolate checkouts. writ worktree register records them; it never creates, moves, fetches, resets, or deletes a checkout.
  • Does not assign work. Task decomposition and scheduling belong to the manager agent and the tracker.
  • Does not replace GitHub or Linear. Linear is the task tracker for teams that use it. GitHub is the source, PR, review, checks, and protected-branch merge authority.
  • Does not silently allow duplicate ownership. Two live owners of the same task is a detected collision, not a race.
  • Local only. SQLite coordination is same-host. Other transports are out of scope until implemented and tested.

How it fits with Cursor / Claude / Codex

        Cursor / Claude Code / Codex / other harness
        owns worker spawn + checkout/worktree lifecycle
                          │
                          │ register existing checkouts
                          ▼
        ┌──────────────────────────────────────────┐
        │ writ (Rust binary → writ-core)           │
        │ SQLite coordination store, same host     │
        │                                          │
        │  tasks/agents · checkouts/branches/heads │
        │  ownership leases · declared paths       │
        │  intent/dependency/blocker/help/handoff  │
        │  pause/timeout/recovery · status         │
        └──────────────────────────────────────────┘
                          │
                          ▼
                  git / gh / OS primitives
                          │
                          ▼
              GitHub (source, PRs, reviews, checks)
              Linear (task tracking)

Workers keep their harness-native isolation. writ is the shared memory and message bus between them — the part none of the harnesses provide.

One end-to-end example

  1. The harness creates a checkout for a Linear task and registers it:

    git -C /path/to/repo worktree add /path/to/job-42 -b task/RM-42-example origin/main
    writ --json worktree register /path/to/job-42 --job RM-42

    Registration is coordination-state only — any path works, including a standalone clone; a branch ahead of its base registers as-is.

  2. The worker declares its intended paths and picks up a lease. A second worker whose paths overlap sees the collision, identifies the owner, and negotiates a split or a handoff instead of silently diverging.

  3. Work proceeds in the assigned checkout. Compatible peer work can be integrated locally (git merge / cherry-pick into the assigned branch). Commands routed through the safety boundary are checked first:

    writ git-safe --expected-branch task/RM-42-example --repo <worktree> status
    writ gh-safe -R acme/example-org pr view 1
  4. On a pause, crash, or timeout, the lease plus declared state let another worker resume or take over without losing WIP.

  5. The worker opens a PR; GitHub checks and reviews run; Linear tracks the task. Shared status stays truthful for managers and workers throughout.

Status

Area Today Next
writ CLI (git-safe, gh-safe, worktree, supervisor, status, attribution) Implemented Envelope-compatible additions only
Checkout registration (worktree register/unregister/inspect/list) Implemented Managed lifecycle (create/remove/prune) is deprecated
Claude Code hook dispatcher / writ install Implemented Live burn-in outstanding (#124)
SQLite lease store, agent registry, crash consistency Implemented Additional lease policies remain additive
Same-host claims / messages Implemented Additional transports are out of scope
Declared paths / overlap visibility, handoff protocol Implemented Reuses the lease store — no second database
Path-scoped admission, lease budgets Planned #167
Owner-allowlist enforcement Enforced in writ-core #146

Canonical command names live in SKILL.md and writ --help. This README summarizes them.

Install

Install the binary for coordination and process helpers. The skill is optional portable agent guidance; ordinary contribution does not require installing either helper.

Prerequisites

  • Git
  • GitHub CLI authenticated (gh auth status)
  • Stable Rust from rustup. The workspace MSRV is Rust 1.97.1 (pinned in rust-toolchain.toml)
  • An agent host that loads skills from ~/.agents/skills (or another skill root — see Other agent hosts)

Binary

git clone https://github.com/rmems/writ.git "$HOME/src/writ"
cd "$HOME/src/writ"
cargo build --workspace
cargo install --path crates/writ
writ --help

Override the binary later with WRIT_BIN if it is not on PATH.

Skill (symlink, preferred)

Agents load SKILL.md from a skill root. Symlink the clone so edits stay in one tree:

mkdir -p "$HOME/.agents/skills"
ln -s "$HOME/src/writ" "$HOME/.agents/skills/writ"

Copy is the fallback when a symlink is awkward (some Windows setups):

mkdir -p "$HOME/.agents/skills"
cp -R "$HOME/src/writ" "$HOME/.agents/skills/writ"

A copied tree will drift from upstream; prefer the symlink when you can. Publishing via a skills CLI is not required for local use; packaging and hook-install narrative are #18.

Older docs used ~/.agents/skills/worktrees-hives. Use writ as the skill directory name now.

Verify

ls "$HOME/.agents/skills/writ/SKILL.md"
writ --help

Then confirm the agent host lists a writ skill (the exact UI depends on the host: skill list, /skills, or equivalent). If the file is present but the host does not show the skill, the host is not reading ~/.agents/skills.

Other agent hosts

Skill directories are not standardized. Common roots include ~/.agents/skills, ~/.claude/skills, and a project-local skills folder. Cursor, Cline, Codex, and Claude Code each resolve skills differently. This README documents the ~/.agents/skills/writ primary path only. Point a copy or symlink of this repository at whichever root your host actually scans. A full install matrix is out of scope here (#18).

Quick start

Use the host's authorized native tools, or opt into writ helpers for shared ownership visibility, local integrity checks and bounded execution. Local integration is routine. Remote PR readiness, updates and merges follow GitHub permissions and operator authorization (AGENTS.md).

  1. Install the binary when using these coordination helpers; the skill is optional.

  2. The harness creates the isolated checkout (native worktree support, or plain git):

    git -C /path/to/repo fetch origin
    git -C /path/to/repo worktree add /path/to/job-42 -b hive/issue-42-example origin/main

    Then register it for coordination — any path works, including a standalone clone:

    writ --json worktree register /path/to/job-42 --job job-42

    Registration is coordination-state only: no creation, relocation, rename, fetch, or reset. A branch ahead of its base registers as-is.

  3. If using the optional command helpers:

    writ git-safe --expected-branch hive/issue-42-example --repo <worktree> status
    writ gh-safe -R acme/example-org pr view 1
  4. Inspect collaboration status from the shared lease store:

    writ --json status

Do not expect a discover → add → check-all → list hive loop. Those were scaffold-era skill stubs and were removed with the Python orchestrator. Current operator flow is: the harness isolates a worktree, writ worktree register joins it to the coordination store, the worker integrates compatible peer work locally when needed, implements in that tree, opens a PR, optionally hands it to babysit-pr, and reports readiness. A remote merge requires operator authorization and GitHub permission.

Architecture

Two layers, one binary.

Layer Owns Does not own
Local integrity helpers Checkout/branch identity, WIP preservation, force-with-lease-only pushes, explicit repository targeting, process containment Task assignment, harness checkout placement, remote merge permissions
Coordination state (same host) Agents, leases, declared paths, overlaps, messages, and handoffs in one SQLite store Cross-host transport, task decomposition, or scheduling
git, gh, OS Version-control, GitHub, and process primitives, invoked through allowlists Policy

Leases are the join: coordination state that the enforcement layer checks at write time. Phase 1 ships SQLite (leases.db, WRIT_LEASE_PATH) with a prepare/inspect/reconcile protocol so a crash between checkout registration and the lease row can be classified without adopting unproven ownership. Budget columns are reserved; fix_cycles is the only accumulated counter and uses the same prepare/commit journal. Enforcement of budgets is #167.

                    ┌─────────────────────────┐
                    │  Agent host             │
                    │  loads SKILL.md         │
                    └───────────┬─────────────┘
                                │
                    ┌───────────▼─────────────┐
                    │ Orchestrator session    │
                    │ (host agent + writ CLI) │
                    └───────────┬─────────────┘
               ┌────────────────┼────────────────┐
               ▼                ▼                ▼
          Worktree A       Worktree B       Worktree C
          Worker subagent  Worker subagent  Worker subagent
          issue → PR       babysit          …
               │                │                │
               └────────────────┼────────────────┘
                                ▼
                     Durable coordination state
                     SQLite leases.db (status/list/register)

Call-outs:

  • Isolation: workers must not share a dirty worktree. One writable worker per assigned worktree and branch.
  • Babysit: success means merge-ready (CI green, mergeable, reviews clean, threads resolved). Readiness does not itself authorize a merge.
  • Stacks: handle from the bottom of the stack upward. Do not run parallel writers on one stack.
  • State location: collaboration status reads the SQLite lease store (WRIT_LEASE_PATH, else platform user-data writ/leases.db). watched.json (WRIT_STATE_PATH) is a leftover reader only and is not the status authority.

Why hooks

Enforcement runs as Claude Code hooks: writ install writes the hook block into .claude/settings.json, and writ hook dispatches the JSON payloads. The checked-in .claude/settings.json has no startup hooks or tracker dependency. Writ hooks are opt-in; validate them in a throwaway repository before installing into shared settings.

  • PreToolUse — "Exit 2 means a blocking error… exit 2 blocks whether or not you print JSON: even a JSON permissionDecision of allow can't override it."
  • SubagentStart/SubagentStop — agent registry.

WorktreeCreate/WorktreeRemove are deliberately not installed: worktree lifecycle is harness-owned. If an older settings file still routes them to writ hook, the dispatcher treats them as coordination-only (register/release records, never filesystem mutation).

Register with writ install. Matcher scope starts at Bash(git *) and Bash(gh *) only.

Glossary

Term Meaning
Orchestrator The host agent session that loads SKILL.md, calls writ, and spawns workers. It is not a writ subcommand.
Worker A subagent bound to one assigned worktree and branch. Workers integrate peer work locally and perform remote actions only within operator authorization.
Worktree An isolated git checkout created by the harness (or plain git worktree add), registered with writ worktree register. Any path; no writ-specific root required.

| Watchlist / hive | Legacy name. Live visibility is writ status / writ worktree list over the SQLite lease store. | | Merge-ready | CI green, conflict-free, required checks successful, review threads resolved. Report it; merge only when authorized. | | Lease | SQLite coordination row for a registered checkout (WRITER_LOCKED / UNASSIGNED today). |

Commands

Implemented writ surface (writ --help is authoritative):

Command Status Operator meaning
writ status / writ jobs Implemented (read-only) Collaboration snapshot from the SQLite lease store. See docs/status-schema.md.
writ ci classify Implemented Classify gh pr checks / statusCheckRollup JSON. Emits residual codes plus a compact collaboration view for status consumers. Does not write state.
writ git-safe … Implemented Run a git command after the allowlist and, for mutations, expected-branch checks.
writ gh-safe … Implemented Run a gh command with configured repository-target and local-checkout checks. GitHub decides remote permissions.
writ supervisor run --timeout <secs> … Implemented Spawn a child with wall-clock, idle, and grace recovery (--idle/--stall, --grace, --progress-secs, env WRIT_SUPERVISOR_*; see docs/timeout-policy.md). Timeout is a handoff residual: Unix SIGTERM-then-SIGKILL on the process group; Windows kills only the direct child (grandchildren may survive). Never deletes a harness checkout.
writ watchlist list|check|check-all Implemented (view) Collaboration status over leases.db plus optional live GitHub overlay. Does not persist a watchlist file.
writ worktree register|unregister|inspect|list Implemented Coordination records for harness-owned checkouts. Register/unregister never touch files or branches.
writ lease inspect|reconcile Implemented Read-only identity report and crash recovery for interrupted registration. Never deletes unproven checkouts.
writ coord announce|show|list|inbox|send|ack|pause|handoff Implemented Same-host claims/messages on leases.db. Path overlap is advisory; pause does not seize WIP.
writ worktree create|remove|prune Deprecated Managed lifecycle kept for caller compatibility during the transition. create requires --schema-version 2 and --start-point.
writ attribution format Implemented Render review and collaboration replies with real agent/task/branch/session identity. Include a SHA only when one exists; never invent one.
writ --json Implemented Envelope-producing commands emit versioned JSON on stdout (generic v1; status/jobs v2); diagnostics on stderr. Exceptions: hook --json has no envelope; git-safe/gh-safe validation failures and install failures emit stderr only. See the CLI contract and fixtures.
writ install / hook dispatcher Implemented Registers writ hook into .claude/settings.json; burn-in outstanding (#124).

JSON envelopes look like:

{"ok":true,"schema_version":1,"command":"cli.bootstrap","data":{},"error":null}

Policy rejections print to stderr and exit 2 (they do not wrap a JSON envelope):

$ writ --json git-safe push --force
writ: policy violation [BARE_FORCE_PUSH]: bare --force/-f is not allowed; use --force-with-lease only

Coordination model

Identity

A lease row joins a task, an agent/session, and a checkout path — the "who owns what" record. writ worktree register creates it for an existing checkout; unregister releases it while keeping identity so a verified reclaim can prove ownership. TTL expiry marks a lease stale; it never erases the checkout's WIP.

Overlap and handoff

Declared-path claims provide early overlap visibility through the existing lease store. Overlap on separate branches is advisory: the colliding worker identifies the owner and negotiates a split, a sequence, or a handoff. Duplicate live ownership of one task is a detected collision, not silent divergence. A stale lease is a recovery/handoff event — not permission to kill a worker or discard its changes.

Communication

Same-host coordination records intent, dependency, blocker, overlap, help, handoff, and acknowledgement messages in the existing store, with owner generations to distinguish stale handoffs from live state. A manager can split scope or pick one integration owner without turning every message into a human approval gate. Cross-host transport remains out of scope.

Local integration

git merge, git rebase, and git cherry-pick of peer branches into the assigned branch are routine; conflict repair is expected. Resolve the contended files, validate the combined result, and publish the resulting head/dependencies for other workers. A merge that would overwrite uncommitted WIP must be refused first — commit, stash, or abort. GitHub controls remote protected-branch integration; a local branch name is not a separate permission gate.

GitHub vs Linear

Tool Role
Linear Optional task tracker: task identity, status, planning, when the operator uses it.
GitHub Source of truth for code, PRs, reviews, checks, and protected-branch merges.
writ Same-host coordination state only. No task-tracker clone, no merge authority.

Use the task context already supplied; no tracker account, issue twin or mirror is required.

Safety invariants

Rust helpers enforce their own local integrity checks:

  • Force pushes may use only --force-with-lease; bare --force and -f are forbidden.
  • Each job edits only its assigned branch and isolated checkout; direct supervised git mutations verify the expected branch. The harness chooses checkout placement.
  • One writable worker per assigned worktree and branch; stacked PRs are handled bottom-up.
  • Unbounded fix loops are a named failure class (F2); lease budgets are planned in #167.

Helpers and hooks are opt-in. Supervision accepts host scripts and interpreters; it does not recursively inspect their subprocesses or opaque API payloads. Harness permissions and GitHub authorization remain authoritative. Deprecated managed-create commands retain their own path sandbox.

Owner allowlist

Writ's GitHub helpers check supported explicit target selectors against a configured owner allowlist. GitHub permissions authorize remote access.

  • Set WRIT_ALLOWED_OWNERS=acme,example-org (comma-separated), or pass --allowed-owners / explicit owners at the API boundary.
  • An empty allowlist denies owner-taking operations (writ worktree create and gh commands that select a repository via -R / --repo in any pflag spelling, or via GH_REPO) rather than permitting them.
  • gh api checks literal owners in repos/OWNER/REPO/..., orgs/OWNER/repos, and users/OWNER/repos, including api.github.com URLs. Other API endpoint families and owners hidden in placeholder expansion, GraphQL node IDs or opaque request bodies are outside that inference; configured explicit repository selectors remain checked.
  • HTTP(S) URL scheme and DNS hostname matching are case-insensitive. Numeric ports, userinfo and a trailing DNS dot do not hide the target host. REST URL inference matches api.github.com exactly; PR/issue URLs retain owner checks on valid public and enterprise DNS hosts. Extracting an owner does not authorize the host. Malformed HTTP authorities are rejected.
  • Comparison uses the same host/case normalization as github_repo_slugs_match, so Acme/Repo and github.com/acme/repo cannot diverge.

Examples use generic owners such as acme and example-org.

Related skills

Skill Role
writ (SKILL.md) Fleet procedure: register checkouts, coordinate workers, local integration, issue → PR.
babysit-pr (installed companion) Single-PR interactive monitoring in the current checkout: CI, reviews, threads, merge-ready report.

Build and gates

Run focused checks while working. Use these native gates and appropriate independent review before claiming readiness; checkpoints report their narrower evidence. External findings need actionable evidence:

cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

Install the agent skill

SKILL.md is the portable procedure (not a security boundary). Clone once, then symlink that directory into a skill root so <root>/writ/SKILL.md resolves. Shared hub:

git clone https://github.com/rmems/writ.git "$HOME/src/writ"
"$HOME/src/writ/scripts/install-skill.sh"
test -f "$HOME/.agents/skills/writ/SKILL.md" && echo OK

./scripts/install-skill.sh --root all also links Grok, Cline, Claude Code, and Cursor roots. The installer is idempotent, creates parent directories, and refuses to clobber a non-symlink without --force. Restart the agent (or start a new session) and list skills, or run /skills writ.

Full root table, uninstall, verification, and WSL notes: docs/install.md.

This is not writ install, which writes the writ hook block into .claude/settings.json (implemented; do not run it against a shared settings file until the #124 burn-in completes).

Runtime paths

Purpose Default Override
Deprecated managed-worktree root (not a supervisor constraint) platform user-data writ/worktrees WRIT_WORKTREE_BASE, else WH_WORKTREE_BASE
Job worktree {worktree root}/{owner}/{repo}/{job_id} Deprecated managed lifecycle only; register accepts any path
Lease store platform user-data writ/leases.db WRIT_LEASE_PATH
Watched state (legacy reader) platform user-data writ/watched.json WRIT_STATE_PATH, else WH_STATE_PATH
Rust binary writ on PATH WRIT_BIN

If the new writ data root is absent and a pre-rename worktrees-hives root still exists, the path resolver keeps using the legacy root so an upgrade does not hide existing state. That is a read/fallback, not an automatic directory move.

Troubleshooting

Symptom What to check
Agent does not see the writ skill ls "$HOME/.agents/skills/writ/SKILL.md"; confirm the host's actual skill root; recreate the symlink.
writ: command not found cargo install --path crates/writ from the clone, or set WRIT_BIN.

| writ status / writ jobs is empty | Expected until a checkout is registered. Register with writ worktree register. See docs/status-schema.md; for the live GitHub overlay use writ watchlist (docs/watchlist-schema.md). | | policy violation [BARE_FORCE_PUSH] or [MERGE_BLOCKED] | Exit 2 is the safety boundary working. Use --force-with-lease only when allowed. MERGE_BLOCKED covers local checkout/WIP protections, not GitHub merge authorization. Preserve WIP before local integration. | | Owner allowlist did not block another org | Confirm WRIT_ALLOWED_OWNERS / --allowed-owners is set. Empty lists deny. The gate covers worktree create and gh repo selectors, not host MCP calls. |

Issue labels and templates

Canonical product labels (use these; do not invent new names unless the epic expands the taxonomy). Prefer docs over GitHub's default documentation. Keep GitHub label descriptions identical to this table (commands in CONTRIBUTING.md):

Label Description
epic Multi-issue umbrella / milestone grouping
core Coordination primitives (registration, leases, messages, handoff, status)
orchestrator Multi-subagent scheduling, caps, join/report
docs README, SKILL.md, templates, operator docs
platform Install paths, multi-agent-host packaging, validation on second host
safety Force-with-lease, fix caps, owner allowlist, WIP preservation

Optional GitHub issue forms live in .github/ISSUE_TEMPLATE/: Feature (new capability), Bug (unexpected failure), Chore (hygiene, packaging, docs-only). Each asks for Summary, Problem / context, Acceptance criteria checkboxes, and the Linear footer documented in CONTRIBUTING.md.

Roadmap and tracking

  • Product direction and task tracking for this repo: Linear (writ / RM tickets). Using Linear is a convention of this repository's maintainers, not a product requirement.
  • GitHub issues mirror actionable work items; they are optional, not a required workflow.
  • Open coordination work: crash-consistent lease/ownership records and the same-host claim/overlap/message/handoff layer build on the existing SQLite lease store.
  • Lease budgets (fix-loop bound): #167
  • Hook burn-in: #124 · Install narrative: #18 · Owner allowlist: #146

Project documentation

License

Licensed under the Apache License 2.0.

来源:GitHub · github.com