@outpacelabs/central
v0.9.13
Published
CLI + worker for Central — the multi-repo agent task board. Claim tasks for a project (a GitHub repo), run each in its own git worktree, open a PR, mark done.
Readme
@outpacelabs/central
CLI + MCP server for Central, one task board for coordinating coding agents across every repo you work in. Your agent claims tasks and does the work in the repo it's in — nothing is installed into your repos. Access is a personal token, scoped to your projects.
Central is a user-level tool, never a repo dependency. Set it up once for your account and it works everywhere.
Setup
1. Get invited + sign in at https://central.outpacestudios.com (email code, no password). 2. Mint a token: dashboard → Tokens → Generate.
3. Connect your agent (MCP) — register once at user scope; the tools are then in every repo you open:
claude mcp add central --scope user \
--env CENTRAL_TOKEN=central_sk_… -- npx -y @outpacelabs/central@latest mcpClaude desktop app — claude_desktop_config.json:
{ "mcpServers": { "central": {
"command": "npx", "args": ["-y", "@outpacelabs/central@latest", "mcp"],
"env": { "CENTRAL_TOKEN": "central_sk_…" }
} } }4. Register a project (from the dashboard's Manage panel, or via the agent):
create_project(slug: "acme", repo: "acme-inc/web")
add_task(project: "acme", title: "Fix the header")Then open your agent in the repo and say "Work the Central board." It loops
claim_next → get_task → do the work → complete_task until the queue is empty.
MCP tools
whoami · list_projects · create_project · grant_access · invite ·
list_tasks · get_task · add_task · update_task · claim_next · progress ·
complete_task · fail_task · set_status · set_lock · add_comment ·
attach_image · list_documents · get_document · add_canvas · add_page ·
update_document
add_canvas(project, title, body?) makes a canvas in the board's Documents tab.
update_document(id, title?, body?) renames a document or replaces a page's or a canvas's body.
A canvas body is .central JSON (see docs/central-canvas-format.md in the Central repo).
It must parse, and it must hold no colour values. A refusal lists each fault with its path.
update_task(id, body?, title?, priority?, track?, crossBoard?) edits a task.
Read it with get_task before writing. body replaces the whole body, including human edits.
To append, read the current body and send the combined text. An empty string clears the body.
Omitted fields stay unchanged. The tool refuses another board unless you pass crossBoard: true.
Locks
A task can name something only one agent may hold at a time — the Figma file, a fixed port, a device, a login:
add_task(project: "acme", title: "Draw the Inspector page", lock: "figma")
set_lock(id: "CEN-621", lock: "figma")Two tasks with the same lock never run at the same time, on either door onto the
board: claim_next skips one whose lock a run holds, and the desktop runner is
not offered it. A task with no lock is unconstrained, which is nearly all of
them. Use it when the work writes to a shared thing that does not error when
two agents write at once — Figma interleaves the two streams and the page comes
out with pieces of both.
Task ids
Anywhere a tool takes id, three forms work:
CEN-176— the id the board shows, and the one quoted in task descriptions. Reach for this one.176— a bare number, when it names exactly one task across the projects you can see. If two boards both have a 176, the call tells you which ids it matched instead of guessing.kh7be5t66kcbjq5vp2tpspw4mh8bkdsw— the raw Convex document id.
An id that doesn't resolve comes back as a plain no such task: …. A task on a
project you can't see reads the same as one that doesn't exist.
CLI (terminal / CI)
npm i -g @outpacelabs/central # or: npx @outpacelabs/central <cmd>
central login central_sk_… # or set CENTRAL_TOKEN (stored in ~/.central)
central project add --slug acme --repo acme-inc/web
central add --project acme "Fix the header" --priority 1 [--image shot.png]
central list --project acme
central access add --project acme --user [email protected]
central invite add --email [email protected] [--project acme]
central work --project acme --root ~/core/acme \
--executor 'claude -p "$(cat .central-task.md)" --permission-mode acceptEdits'central work drains the queue unattended — each task in its own git worktree,
one PR each. The task is written to .central-task.md and exposed as
$TASK_TITLE / $TASK_BODY. The executor and every tool it launches inherit
CARGO_BUILD_JOBS=1, so concurrent workers do not each give Cargo every CPU.
On macOS, Cargo targets live in Central's managed per-worktree cache and expire
after a week of inactivity. If sccache is installed Central uses it across
worktrees on every platform; explicit CARGO_TARGET_DIR or RUSTC_WRAPPER
values keep custom cache setups.
One-task local supervisor
These commands are included in the repository's CLI v0.9.9 and generated desktop
bundle. npm publication is pending; @latest is not yet evidence of availability.
With the repository dependencies already present, run
pnpm --filter @outpacelabs/central build. From the repository root, replace
central in the commands below with node client/dist/cli.js to use that build.
The Central v0.1.183 desktop release includes the generated bundle.
central runner --task CEN-123 claims one available Claude dev task, clones its
base branch into a fresh directory under ~/central/runs, streams readable
transcript lines to Central, and opens a PR when the turn finishes. It requires
Node.js 22+, macOS or Linux, and existing git, gh, and Claude CLI logins. It
does not install dependencies or merge the PR. Use --root /path to choose the
parent directory; the checkout and private raw transcript remain there.
A launcher can prepare a run separately, then start
central runner --run <id> with CENTRAL_RUN_TOKEN in the environment. This
short-lived credential belongs to one task attempt and one supervisor. Avoid
putting it in command history. It expires after 24 hours and stops authorizing
work when project access or the task claim changes. Central stores its hash.
A second supervisor cannot take over an existing connection. After recovering a
failed or stopped run, use central runner --task CEN-123 --retry to create a
fresh checkout and task attempt. Retry requires that your own supervisor still
owns that blocked task; it preserves the previous failure in task history. It
cannot reopen completed work or take another worker’s claim.
Send directions with central runner-send --run <id> --text "…", and stop with
central runner-stop --run <id>, using the owner's normal Central token.
Directions wait until the current provider turn ends, then run one at a time.
Directions accepted before publication must be answered before the PR is opened.
Once publication starts, new directions are refused; Stop remains available.
Stop terminates the local process group, but cannot undo a push or PR that GitHub
has already accepted. Failed and stopped runs leave the task blocked with a
reason and keep the checkout for inspection.
This is a local process adapter, not OS isolation. Commands have the account's
normal filesystem and network permissions. Provider credentials stay in the
provider's local login, and git uses the machine's existing GitHub authentication.
No provider credential or broad GitHub OAuth token is exchanged with Central.
For documentation-only work, --tools Read,Write,Edit,Glob,Grep restricts the
built-in tools available to the provider while retaining its normal permission
checks. Interactive provider permissions currently stop the run with an explicit error;
attended sign-in and permission handling are separate work. This command runs one
task; it does not enable the autonomous queue or provision a cloud sandbox.
Routine shipping worker
CLI v0.9.10 adds central ship for Jesse's Central board pilot. The repository
build contains this command, also bundled in the published Central v0.1.185.
npm publication remains pending. The real queue proof (CEN-1154) completed a
docs-only review, checks and merge of PR #1323, without a desktop release.
CEN-1156 fixes external PR states and dependency copying; CEN-1157 validates the
PR together with live main. These fixes are included in the published Central
v0.1.186 bundle and the current repository build; npm publication remains pending.
node client/dist/cli.js ship --root /path/to/installed/central --watch
# To also build desktop releases from a separate, clean Mac clone:
node client/dist/cli.js ship --root /path/to/installed/central --watch \
--release-root /path/to/clean/central-releaseUse the owner's personal Central token through the existing login or
CENTRAL_TOKEN. Node.js 22+, git, gh, pnpm, and an already signed-in
Claude CLI with restricted mode are required. The worker uses existing
repository dependencies; changed lockfiles block without installing anything.
After matching the lockfile, it copies both root and CLI node_modules into
the review checkout, using copy-on-write where supported. Relative pnpm links
stay intact. The copy checks for Stop between entries and has a five-minute
timeout. External directory symlinks do not work here: Turbopack refuses
dependencies outside the review checkout's filesystem root.
Start the process explicitly, then resume Settings → Projects → Routine
shipping. Deployment alone starts nothing. Shipping defaults to paused and
Publish desktop updates defaults to off; task pickup has its own pause control.
The worker discovers Central dev PRs linked from tasks in review. For each PR,
it fetches main and merges the exact PR head into a local candidate commit.
That candidate is never pushed. An independent restricted Claude review with
Read,Glob,Grep inspects the resulting diff against the fetched main commit;
repository tests and the production build run on the combined tree, with
TEST_BASE set to that main commit. Applicable Rust tests and GitHub checks
must also pass. A conflict or candidate with no change to main blocks shipping.
Only a routine review with no findings and passing checks can reach the normal
squash merge. Before merging, the worker independently reads GitHub's live main
ref and checks the PR head and readiness again; PR baseRefOid can be stale.
A changed head or main pauses shipping. Use Retry review, then Resume
shipping, to validate a fresh candidate; main movement is not retried
silently. A busy main branch may therefore need repeated explicit retries. If GitHub already reports a PR merged or closed
before the queue starts its merge, the job is recorded as skipped, with the
observed head, URL and merge commit when present. It releases the queue lock
without inventing a passed review or treating an external merge as a source for
a desktop release. An operation already started by this queue still follows
interruption reconciliation. Temporary PR checkouts and their dependency copies
are removed when the attempt ends, after child processes settle. Review and
check logs, review.diff and validation.json remain one level up under
~/central/shipping. The validation file records the PR head, fetched main and
local candidate commit. The configured release clone is never removed by this
cleanup.
Review and test children receive no Central or release credentials through the
worker's environment. This is still local execution with the account's normal
filesystem permissions, not an OS sandbox.
With desktop publishing enabled, merged changes to the bundled frontend, shell, CLI or build inputs are collected into a release. Documentation-only work does not trigger one. The release clone needs existing dependencies and the signing/notarisation environment in the release handover. A fresh version must already be merged to main; the worker does not bump it. It reviews the complete change since the previous published tag, builds from clean main, and verifies the signed assets, immutable tag and public updater before recording publication. Queue and manual desktop builds share a lock.
One durable job runs at a time across workers. Pause prevents new steps and asks the worker to stop within 30 seconds; an operation already sent to GitHub may finish and is recorded if verified. Ctrl-C also stops this worker's child process groups. A restart observes an interrupted merge or publication instead of repeating it; an uncertain build stays blocked for inspection. Settings supports ending an interrupted operation only after confirming the previous worker and children stopped and recording the evidence. Existing tags stay reserved. Blocked and skipped PRs offer Retry review in Settings, including when a previously closed PR has been reopened. Retry clears the previous review, checks, merge URL/commit and native-release eligibility before fresh work. Blocked reviews also accept directions through the shared questions inbox. Retry does not resume a paused queue or bypass review. See the pause recovery guide for operational steps.
--watch checks bounded queue metadata once a minute when idle, without
starting a model. Without it, the command makes one pass. It installs no
background service, provisions no cloud machine and spends no cloud budget.
