Skip to content

Repository files navigation

staq — two agents can never claim the same task, and there is no lock server to run

License Tests TypeScript Git-native

Two agents can never claim the same task — and there is no lock server to run.
staq coordinates a fleet of coding agents entirely inside one git repository.


What it is

Run more than one coding agent against a shared codebase and two of them will eventually grab the same work. The usual fix is a lock service, a queue, or a database — one more thing to run, secure, and back up. staq makes the claim itself atomic. Claiming a task is a git compare-and-swap: one agent's ref update lands, every loser gets cannot lock ref and moves to the next task. There is no lock server, so there is no lock server to fail.

That works because the whole work graph — tasks, locks, decisions, contracts — is refs and blobs in one bare repository. Nothing to provision, nothing to back up, nothing to keep in sync. Clone it, fork it, audit every state change in the reflog, host it on a $4 box, and lose zero data if the process dies.

On that substrate, staq gives you:

  1. A collision-proof mutex (solid today) — claiming a task is an atomic git compare-and-swap, so two agents can never get the same one.
  2. Decision coherence (an early, deterministic bet) — agents declare what they touch and rely on, and staq flags when one agent's change breaks another's in-flight work before it merges.

Note

staq is for teams running multiple autonomous agents on a shared codebase. One developer with one assistant won't feel the contention it removes — and that's fine. staq ships with its own honest kill-condition.

Architecture

---
title: How staq coordinates an agent fleet
---
flowchart TB
    A1["Agent · claude-code"]
    A2["Agent · codex"]
    L["Linear / GitHub Issues"]
    H["Hub · stateless HTTP shim<br/>claim · release · ready"]
    R["work.git — the entire state<br/>refs/locks · tasks · decisions · contracts · outbox"]

    A1 -- "HTTPS + token" --> H
    A2 -- "HTTPS + token" --> H
    A1 -- "git over SSH" --> R
    A2 -- "git over SSH" --> R
    H --> R
    L -- "one-way import" --> R
Loading

The bare work.git is the source of truth. The hub is an optional shared rendezvous — the same operations over HTTP so agents on different machines see one graph. The distributed mutex lives in the git remote itself.

Features

  • Zero-infra substrate — the whole work graph is git: refs for locks, blobs for tasks/decisions/contracts, an append-only outbox. No DB, no server of record, fully forkable and auditable.
  • Collision-proof claims — claiming a task is an atomic git update-ref compare-and-swap. No lock server, no quorum. Verified at 0 double-grants across 2,000 concurrent rounds.
  • Pull-model delegation — agents self-select ready work (staq next), bounded by a WIP cap, with a human-escalation lane. Capacity is counted from live locks, never stored.
  • One-way Linear import — work originates in your tracker; staq coordinates beside it and never writes back. Paginated past 250 issues with reconcile-based close detection.
  • Stateless hub — a ~41 MB HTTP shim over the bare repo. Deploy to a $4 box; kill it and restart anywhere, losing zero data.
  • Decision coherence (experimental) — declared contracts (relies_on) ∩ recorded decisions (touches) flag cross-task breaks, with severity gated by the affected task's lifecycle state. Deterministic, no LLM. This is a forward bet — see The honest part.

How it works

Two mechanisms, both backed entirely by git:

Mechanism Implementation
Mutex git update-ref refs/locks/<id> with an expected old value — git's ref store does the compare-and-swap. Two racing agents can't both win.
Coherence decision.touches ∩ task.contract.relies_on → a conflict. Severity follows the affected task's status: in_reviewblock, claimedwarn, open → skip — then re-checked the moment that task enters review, so a break that was invisible when the decision was made surfaces when it matters.

Quick Start

Important

Requires Node 22+ and pnpm.

git clone https://github.com/staqsIO/staq.git && cd staq
pnpm install && pnpm build
./staq init          # install the claim guard: agent PreToolUse hook + git pre-push

A minimal agent loop:

staq task add FEAT-1 "Add OAuth login"      # create an open task
staq next                                    # list ready, unblocked, unclaimed work
staq claim FEAT-1 --as agent:a               # atomic CAS claim
staq decide FEAT-1 --kind interface \
  --summary "rename AuthToken" --touches AuthToken
staq review FEAT-1                            # transition to in_review + run the coherence gate

Mirror work in from Linear (one-way, disjoint ownership):

LINEAR_API_KEY=… staq import linear --team DEV
Run a self-hosted hub (coordinate agents across machines)

The hub is a stateless HTTP API over a bare work.git. Provision a fresh Debian/Ubuntu box and:

ssh root@your-vps 'bash -s' < deploy/deploy-hub.sh

It installs the service (systemd), fronts it with Caddy for automatic TLS, generates a bearer token, and binds the hub to loopback. Agents then point at https://your-host and git remote add hub ssh://staq@your-host/srv/staq/work.git. See deploy/README.md.

The honest part

Three things, stated plainly because they decide whether staq is worth your time:

git-lfs chose a lock server. We didn't. The most widely deployed file-locking system in the git ecosystem marks files lockable in .gitattributes and then enforces exclusion with a centralized server. It met this exact problem and declined to solve it with git primitives, which is fair grounds for suspicion. The difference is what gets locked. An LFS lock is held by a human editing a binary asset for hours, and losing it means losing that work — so it needs a server that can arbitrate, expire, and force-unlock. A staq claim is held by a machine for minutes; a loser finds out immediately from cannot lock ref and takes the next task. Cheap to lose and automatic to retry is the case where compare-and-swap on a ref is enough.

Coherence is a bet, not a moat — yet. The conflict check is only as good as the contracts agents declare. relies_on is currently manual: an agent has to predict, upfront, what its in-flight work depends on. Under-declare and the guard passes a real conflict through (a false negative — the worst failure for a safety tool). The genuinely novel piece is narrow and real — coherence keyed to a sibling task's concurrent lifecycle state, re-checked on transition — but the layer only becomes load-bearing once contract inference is automatic and precise. That's the roadmap's center of gravity, and it's labeled experimental on purpose.

The idea has an ancestor worth naming. Crystal (Brun, Holmes, Ernst & Notkin, ESEC/FSE 2011) caught conflicts between in-flight workspaces by continuously merging every pair in the background and building and testing the result — textual, compile, and behavioral conflicts, all before anyone committed. It worked, and it never left the lab; running all-pairs merge-and-build continuously cost too much. staq's declared contracts are the cheap approximation: a static check where Crystal ran a build. Fifteen years of nobody shipping this is either an open gap or a warning, and which one it is turns on whether declaration catches enough of what a build would have caught. We think it does for the direct case. That's the experiment.

The substrate is solid today. Zero-infra, git-native, forkable, $4 to host, no adoption tax. Even if you never turn on coherence, the substrate + mutex are a real, defensible way to coordinate an agent fleet right now.

Does staq earn its place?

staq ships with its own kill-condition, because honesty about when not to use a tool is rarer and more useful than a feature list:

  • double-grabs prevented (staq metrics) — collisions caught that would have been duplicated work
  • cross-issue conflicts blocked — decisions that would have silently broken in-review work
  • 0 projection drift (staq projection verify)

If those counts stay near zero over weeks of real multi-agent use, you don't have the contention staq solves — drop it.

Roadmap

  • Git-native substrate — locks, tasks, decisions, contracts, outbox, all as refs
  • git-ref CAS mutex + pull-model delegation
  • One-way Linear importer — paginated, reconcile-based close detection
  • Review-time temporal re-check (the one genuinely new coherence idea)
  • Self-hosted hub + idempotent deploy artifacts
  • Automatic contract inference — the unlock that turns coherence from a bet into a guarantee
  • Transitive blast-radius via a self-maintaining call-graph — warn-only, so a noisy graph can't drown the high-confidence direct check

Design notes

The deeper rationale — why git refs instead of a database, the disjoint-ownership model with Linear, the projection design — lives in docs/. A visual walkthrough is at staqsio.github.io/staq.

Contributing

Issues and PRs welcome. staq keeps a strict test gate (pnpm test) and a deterministic, no-external-calls core — changes to the coherence engine must preserve both.

License

MIT © Staqs

About

The zero-infra coordination substrate for fleets of coding agents — your entire work graph is a git repository.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages