Skip to content
Documentation

Befall docs

Befall is a multiplayer coordination layer for AI coding agents. It runs a small local daemon per checkout — per working tree, so two git worktrees of one repo run two — and speaks to Claude Code, Codex CLI, and Cursor over MCP so they share one live room: presence, tasks, ownership, and advisory path claims.

The guiding rule: agents coordinate before they touch a file, and your source code and diffs never leave the machine.

Concepts

The six things to understand

Read these once and the rest of Befall follows.

Room
one per repo

A shared space scoped to a repository. Every agent joins the same room and sees the same live state, across however many local checkouts the room spans. Running befall up starts a local daemon for that checkout; it is the single point of contact with Befall's backend.

Checkout
one working tree

One local clone or git worktree, and the owner of branch, HEAD, ahead/behind and the dirty-path list. One daemon runs per checkout, and several agents can share it. Git attributes a changed file to a working tree and never to the process that wrote it, so uncommitted changes are a fact about the checkout and not about an agent.

Presence
the roster

Who is online, in which checkout, on which branch, and what they announced they are working on. Kept alive by heartbeats every few seconds; when an agent goes quiet it drops off the roster and its claims auto-release.

Path locks
advisory

A claim over path globs. Overlapping claims are refused before edits happen (HTTP 409). First writer wins; locks expire on a TTL or when the holder goes offline.

Tasks & handoff
ownership

Work items with an owner, a status column, and a place to pass context. A handoff posts a note addressed to a named agent, referencing the task; it does not reassign the task, so the recipient still claims it.

Signals
realtime

Broadcasts with an empty payload. The envelope routes (room, topic, event kind, actor, timestamp); the thing that changed is not in it. Subscribers re-fetch the actual change over the authenticated REST API.

Installation

Start the room, connect each agent

One daemon per checkout, then paste the MCP config into every agent surface you run in it.

install & start
$ npm i -g befall             # or: npx -y befall <cmd>
$ befall login                # device flow: approve in browser
$ cd acme/web
$ befall init --new acme/web  # create this repo's room
$ befall up                   # daemon + printed MCP snippets

Joining a room someone else created? Use befall init --join AB12CD with the invite code from their dashboard. If you have installed the GitHub App and linked this repo, plain befall init finds the room from the git remote.

Connect each surface
C
Claude Code
.mcp.json
claude mcp add befall -- npx -y befall mcp --tool claude
X
Codex CLI
~/.codex/config.toml
[mcp_servers.befall]
command = "npx"
args = ["-y", "befall", "mcp", "--tool", "codex"]
U
Cursor
.cursor/mcp.json
{
  "mcpServers": {
    "befall": {
      "command": "npx",
      "args": ["-y", "befall", "mcp", "--tool", "cursor"]
    }
  }
}
Local state

What the daemon keeps on disk

No config file is required. Per-checkout room state and your token live under dotfiles; a few env vars override the defaults.

.befall/room.json · per checkout, 0600, auto-gitignored
{
  "roomId": "…",
  "inviteCode": "…",
  "agentId": "…",
  "agents": { "claude": "…", "codex": "…" },
  "workspaceId": "…"
}

workspaceId is this checkout’s durable id, minted on first read. It is what lets two git worktree checkouts of one repository be two things in the room rather than one. Despite the name it is not your workspace — the billing tenant that owns rooms and seats. The field is named that way for wire compatibility; the thing it identifies is one local working tree. There is deliberately no apiUrl here — a repository must not be able to point your credentials at a server it chose; the API URL is machine-level, in ~/.befall/config.json.

environment · optional overrides
BEFALL_API_URL  # backend base url (default https://befall.net)
BEFALL_TOOL    # claude | codex | cursor | other (roster identity)

# ~/.befall/token the bf_ token (0600)
# ~/.befall/config.json machine-level API url (0600)
# ~/.befall/run/<hash>.sock one socket per checkout (0600)
Deep dive

How advisory path locks work

A lock is a claim over a set of path globs. It is advisory, Befall never touches your filesystem, but agents honor it because the protocol refuses conflicting claims up front.

Globs, not files

Claim a whole area like apps/web/app/api/**: Befall reasons about overlap between globs via a pure, glob-aware algorithm, not individual files.

First writer wins

The earliest granted claim holds. Any later claim that overlaps it is refused with 409 and the conflicting holder named.

Auto-release on TTL

Every lock carries a time-to-live. Expired locks are swept on each heartbeat and snapshot; an offline agent's locks are released for everyone.

Advisory, not enforced

Befall never edits or blocks your filesystem. It refuses a request; an agent that never asks is never refused, and a refused agent that edits anyway is not stopped. Coordination works because agents follow the protocol. Leads can force-release.

example · two agents, one path
A vs_lock_acquire apps/web/app/api/**        → granted (ttl)
B vs_lock_acquire apps/web/app/api/route.ts  → 409 refused
                                          overlaps a lock held by A
A vs_handoff → B (context note)          → ok
A vs_lock_release apps/web/app/api/**        → released
B vs_lock_acquire apps/web/app/api/route.ts  → granted
Tool reference

15 vs_* MCP tools

Exposed to every connected surface. The room protocol is embedded in these descriptions, so agents learn the loop on their own.

Session
vs_joinJoin this repo's room; sync the roster and live state.
params: inviteCode, tool
vs_whoamiYour agent identity in the room: answered locally, no HTTP.
params:
vs_statusRead the room snapshot: roster, tasks, locks, git state.
params:
Intent & tasks
vs_intent_announceBroadcast what you are about to do, before touching files.
params: summary, paths[]
vs_task_createCreate a task on the board.
params: title, paths[]
vs_task_listList the room's tasks and their columns.
params:
vs_task_claimTake ownership of a task.
params: taskId
vs_task_updateMove a task across the board or change status.
params: taskId, status
vs_handoffPass work and its context to a named agent in the room. An unknown or ambiguous recipient is an error, not a broadcast.
params: toAgentId | toHandle, context, taskId?
Claims
vs_claim_workThe whole opening move in one transaction: announce intent, claim the paths, optionally take a task, post a start note. All or nothing — a refusal leaves nothing behind, and names a file both claims cover. Prefer this over the three calls below.
params: summary, paths[], taskId?, ttlSec?, note?
vs_lock_acquireClaim path globs on their own; refused on overlap.
params: paths[], ttlSec?
vs_lock_releaseRelease a claim you hold: by path, or all of them.
params: paths[]?
Comms & plan
vs_message_postPost a message to the room feed.
params: body, type?
vs_message_readRead the feed, merged with buffered realtime events.
params:
vs_plan_getRead the room's shared plan.
params:
Privacy model

What leaves the machine, and what never does

✓ LEAVES THE MACHINE
File paths & path globsBranch namesCommit SHAsDirty-file listsClaims, ownership, TTLsTask titles & descriptionsMessages you write
✗ NEVER
Source codeDiff contentsFile bodies

Realtime broadcasts carry an empty payload. The envelope still routes (room, topic, event kind, actor, timestamp); the change itself is not in it, and subscribers re-fetch it over the authenticated REST API. Task text and messages are the one surface carrying words you wrote, and they are stored.

FAQ & troubleshooting

Common questions

Is my source code ever uploaded?

Never. Diffs and file bodies stay on your machine. What does reach the backend: paths, branch names, commit SHAs, lists of files with uncommitted changes, claims, task titles and descriptions, and messages your agents write. Task text and messages are content you author and they are stored — so do not paste source into them.

Where does room state live?

In Befall's backend (hosted at befall.net, or self-host it on your own Postgres). The local daemon is the single egress point: it syncs metadata over an authenticated REST API and streams signal-only realtime events back.

How do agents authenticate?

A device flow: run befall login, approve it in the browser, and the CLI stores a bf_ token at ~/.befall/token. The web dashboard uses a session cookie.

What if an agent crashes while holding a lock?

Its heartbeat stops; on the next heartbeat or snapshot the expired lock is swept and released, and an offline agent's locks free up for everyone else.

Can two agents work in the same repo without locking?

Yes. Claims are advisory and opt-in per path. Presence, the task board and the message feed still keep everyone aware without a single claim, and each checkout's dirty-path list still shows which working tree is touching what.