Devlog · Aug 19, 2026 · 5 min read

A project is not a repo

Products span repos — a website here, an API there — but session bootstrap assumed one remote per brain. Now a project claims satellite repos, and the discovery flow lives where an agent will actually read it: inside the error message.

LLMBrain's session bootstrap has one great trick: the agent hands over its git remote and gets back the right project, no slug required. But the mapping was one repo per project — and products don't work that way. A product is a website and an API and a mobile app, three remotes that are one body of work, one architecture, one roadmap.

The failure was concrete: start a session in a marketing-site repo and the brain shrugs — untracked. The agent's natural next move is to create a fresh project for it, and now the product's memory is split across two brains that will never agree. A twin project isn't a small mess; it's the cross-repo amnesia this whole product exists to end, reintroduced one repo at a time.

Satellites, not a list

So a project now spans multiple remotes. The primary repo stays where it always was, on the project record itself — every existing consumer untouched — and additional remotes attach as satellite rows, each optionally labeled ("website", "api"). Any of them bootstraps a session into the same project, through the same resolution path, inheriting the same grants.

One boundary got written down early, because it's the kind that erodes silently:

A repo row is an address, not an access rule. Attaching a repo changes where the project answers from — never who can reach it.

Access is decided by ownership and grants, in one choke point, same as before. The repo list is routing.

The error message is the UI

The most considered part of the feature isn't the table — it's what happens when a remote doesn't resolve. For an agent-first product, an error message isn't diagnostics; it's the only user interface present at the moment of failure, read by a user who can act on instructions instantly.

So the untracked error carries the discovery flow inside it. When a remote resolves to nothing, the brain looks for likely parents by slug prefix — zenve3d-website suggests zenve3d — and the error says: these projects look related; ask the user whether this repo belongs to one of them; if so, attach it with update_project(add_repo=…) — and don't create a twin. The tool that creates projects carries the same guard in its description, at exactly the decision point where an agent would reach for it.

The brain never auto-attaches, though. The heuristic is advisory because it's a heuristic — a wrong attachment made silently would corrupt the mapping the whole bootstrap trusts, and confirming takes the agent one question. Suggest loudly, act never.

Small feature, no new surface

The write side is two operations — attach and detach — with per-account uniqueness across all of an owner's projects, primary and satellites alike, so one remote can't be claimed twice; a conflict names the project holding it. On MCP, no new tool: attach and detach ride on update_project, because every tool description is context-window overhead in every session, and a capability that fits an existing tool should cost zero new tokens.

Fittingly, the first satellite attached in production was the repo this very website lives in. The brain that tracks LLMBrain's development now answers from all of it — API, dashboard, CLI, and the site you're reading.

ProjectsMCPAgent UX