Multi-developer
One remote box can serve a whole team. Every developer gets their own token, their own isolated checkout, and a fair place in line. The diff still returns to the laptop that asked for it.
This page ties together the four pieces that make that safe: identity, isolation, fairness, and a paper trail.
Identity: one token per developer
The agent keeps a user registry at ~/.patchwire/users.json. It only ever
stores a SHA-256 hash of each token, never the plaintext. The admin manages
users from the remote box:
# create a developer; the token is printed oncepatchwire-agent user add ana# → Token (save this, it will not be shown again): pw_b9f...
patchwire-agent user list # who exists, active/disabled, last seenpatchwire-agent user disable ana # token still resolves, every request 403spatchwire-agent user enable anapatchwire-agent user rotate ana # new token; the old one dies immediatelypatchwire-agent user rm ana # remove entirelyEach developer loads their token on their laptop once:
patchwire setup --token pw_b9f...# → writes PW_TOKEN + PW_USER to ~/.patchwire/envOn every request the agent resolves the bearer token to a username. An unknown
token gets 401; a known-but-disabled user gets 403. That username is the key
for everything below.
Upgrading from v0.1? On first start the agent migrates your single
PW_AGENT_TOKENinto adefaultuser automatically, so existing setups keep working unchanged.
Isolation: a checkout per developer
Project files live under a per-user directory on the remote:
<projects-root>/<user>/<project>/patchwire ask rsyncs your local project into your directory (PW_USER), and
the agent runs the AI against that checkout. Two developers can both have a
project called team-app and never touch each other’s tree. The agent also
refuses any project path that would escape your user directory.
Fairness: a queue nobody has to manage
The agent caps how many AI runs happen at once, so one box does not melt under team load:
| Variable | Default | Meaning |
|---|---|---|
PW_MAX_CONCURRENT_TOTAL | 3 | Global ceiling across everyone. |
PW_MAX_CONCURRENT_PER_USER | 1 | Per-developer ceiling, so nobody hogs all the slots. |
Requests over a cap wait in arrival order (FIFO). Because /ask is a streamed
NDJSON endpoint, you watch your place in line in real time:
{"type":"queued","position":2}{"type":"accepted","queueWaitMs":3400}{"type":"result","diff":"…","files":["…"],"exitCode":0}The CLI surfaces this as Queued — position 2… then Asking Patchwire…. A
read-only GET /queue returns the current snapshot of who is in flight and who
is waiting:
{ "globalCap": 3, "perUserCap": 1, "inFlight": ["ana"], "queued": [{ "user": "ben", "position": 1 }, { "user": "you", "position": 2 }]}Paper trail: the audit log
Every successful /ask and /chat turn appends one JSONL line to
~/.patchwire/agent.log (override with PW_AUDIT_LOG):
ts,user,project,routeprompt_sha256: a hash of the prompt. Plaintext is never written to disk.- For
/ask:files,lines_added,lines_removed,exit_code - For
/chat:uuid,tokens_in,tokens_out duration_ms,queue_wait_ms
The file rotates at 50 MiB (PW_AUDIT_LOG_MAX_BYTES / PW_AUDIT_LOG_MAX_FILES).
Read it with filters:
patchwire-agent log # last 100, prettypatchwire-agent log --user ana --since 24hpatchwire-agent log --project team-app --limit 10patchwire-agent log --json # raw JSONL, pipe into jqWhere to go next
- Running the agent covers install, env vars, and the concurrency and audit sections in full.
- HTTP API documents the streamed
/askevents andGET /queue. - Configuration lists every environment variable.
- Security model explains token handling and the network posture.