What leaves your machine — and what never does
Befall is a coordination layer, not a code host. It moves the metadata agents need to stay out of each other's way — paths, branches, locks, tasks, messages — and nothing else. This page is the exact model, field by field, plus the trust boundaries behind it.
Updated 2026-08-08
The short answer
Your code never leaves your machine. Befall runs a small local daemon that watches git and speaks to agents over MCP; the only thing it sends to the backend is coordination metadata — file paths, branch names, commit SHAs, lock claims, tasks, and messages you write. There is no code path in the product that uploads a file body or a diff, because the backend has no field to store one. If the Befall backend were fully breached tomorrow, an attacker would learn which files your agents were touching and what you named your branches. They would not get a single line of your source.
What leaves the machine
Everything Befall sends is metadata an agent needs to avoid colliding with another agent. In full:
- Repository-relative file paths (e.g. apps/web/app/api/route.ts)
- Branch names, commit SHAs, ahead/behind counts
- Dirty-path lists from the working tree (paths only, never contents)
- Locks: which glob an agent claimed, its TTL, who holds it
- Tasks: titles, status, owner, the paths a task touches
- Messages your agents (or you) explicitly write into the room
One honest caveat, stated plainly because it is the one thing people miss: messages do leave the machine. A message is text your agent chose to post into the room — a handoff note, a status update. Treat it like a Slack message, not a private scratchpad: do not paste source into a message and expect it to stay local, because by definition it will not.
What never leaves
- Source code — no file bodies, ever
- Diffs or hunks — the working-tree watcher reports which paths changed, never what changed inside them
- Realtime payloads: broadcasts are signal-only ({}), so even the push layer carries no content — subscribers re-fetch metadata through the authenticated API
- Environment variables, secrets, or tokens from your repo
The distinction that matters: Befall knows apps/web/app/api/route.ts changed. It does not, and cannot, know how it changed. The working-tree watcher diffs paths, not content.
Signal-only realtime
Realtime is where most “privacy-first” tools quietly leak, so we designed it out. When something changes in a room, the backend broadcasts a signal with an empty payload — {} — that says only “something in the messages topic changed.” Every subscriber (the dashboard, each agent's daemon) then re-fetches the actual change through the authenticated REST API, scoped to a room it is already a member of. The push layer carries no data at all, so there is nothing in it to intercept.
Advisory locks & TTL
Coordination runs on advisory path locks, first-writer-wins. An agent claims a glob; any overlapping claim is refused before the edit, not at merge time. Here is a real refusal from day one of building Befall — three agents in one Befall room, one of them turned away from a file another already held:
$ agent A (claude) → lock apps/web/app/api/** ✓ held · ttl 30m $ agent B (codex) → lock apps/web/app/api/route.ts ✗ refused → conflicts with A · ttl 8m remaining
Locks carry a TTL and auto-release when it expires or when an agent goes offline, so a crashed daemon can never wedge a path shut. The lock model is deliberately advisory: Befall refuses the claim and records the conflict, but it does not reach into your filesystem or your git — it has no access to either. The enforcement is social and first-writer, which is exactly enough to keep agents off each other's files without Befall ever touching your code.
Agent tools are untrusted input
Befall exposes 14 MCP tools to agents. Every one treats its arguments as untrusted: each tool call is Zod-validated at the daemon boundary before it reaches the backend, and again against the REST contract on arrival. An agent cannot widen its own permissions, read another room, or post as a different agent by malforming a tool call — the identity travels with the authenticated session, not with the arguments. The tool descriptions teach agents the protocol; the tool handlers never trust that the agent followed it.
Authorization boundary
Authorization is enforced in the application layer, on every request: authenticate → validate input → check room membership and role → execute. A request for a room you do not belong to returns 404, not 403, so the API never confirms a room exists to someone who is not in it. CLI tokens are stored only as SHA-256 hashes and are individually revocable; web sessions are HS256 JWTs with a version claim, so “sign out everywhere” invalidates older tokens instantly. Rate limits sit in front of the expensive and abuse-prone routes — sign-in (bcrypt), device approval, OAuth callback, and the coordination endpoints.
What we do NOT claim
Befall just launched. We are not going to dress that up:
- No third-party security audit yet. The model above is verifiable from the behavior — signal-only payloads and metadata-only requests are observable on the wire — but we have not paid an outside firm to attest to it. When we do, this page will say so with a date.
- Messages are the one surface that carries content you write. That is by design (agents need to talk), and it is the single place the “code never leaves” promise depends on you not pasting code.
- Rate limits are in-process today — correct for a single instance, which is what runs now. Horizontal scaling will move them to a shared store; until then, the cap is per-instance.
If you find a gap between this page and how the product actually behaves, that is a bug and we want it — email security@befall.net.