Repository Structure
The system is split across two repositories: a server repo (RoamerMcp) that owns the hosted MCP server and its data model, and a distribution repo (RoamerMcpPlugin) that packages the workflows as an optional, installable Agent Skills plugin — a format multiple AI coding clients can consume as-is, from Claude Code to GitHub Copilot, not a Claude-specific integration. The plugin is a convenience on top of the hosted connection, never a requirement. The server never ships client-side install logic; the plugin never touches the database directly.
Each skill is a thin entry point that fetches its workflow text from the server at run time, so changing a workflow is a server deploy — no plugin release, and no copy of the workflow living anywhere but the server.
Core Systems
The tools cover the full surface — registry (get_registry, update_project), specs (list_specs, get_spec_area, log_spec_item), threads (get_threads, log_thread), blockers, and billing. The same data is also exposed read-only as MCP resources under a roamer:// URI scheme — roamer://project/{name}.md, roamer://spec/{name}/{area}.md — so a client can @-reference project state directly without a tool round trip.
The ecosystem overview a session opens with isn't a file — it's BrainSection rows composed at request time by BrainComposer. Sections that mirror the registry, specs, or threads use {{live:*}} tokens that expand against the database on every read, so the parts most likely to drift — project counts, open thread lists, spec item totals — structurally can't. Editing is a tool call (log_brain_section); there is no rebuild or redeploy step.
Spec / SpecArea / SpecItem model each project's requirements as versioned, queryable records instead of markdown a human has to remember to update. Every item carries a priority and a status (draft → ready → code-complete-*), which is what lets "done" be computed rather than asserted — see The Arc Model, below.
EngineeringThread holds the open questions, live incidents, and deferred decisions that don't yet belong in a formal spec — cross-cutting, tied to one or more projects, and explicitly separate from spec items so exploratory reasoning never gets forced into a done/not-done shape before it's ready.
Roamer MCP runs its own OAuth authorization server. Clients connect over streamable HTTP, discover it from the server's protected-resource metadata, register themselves with Dynamic Client Registration, and sign the user in through Entra ID with PKCE — public clients only, so there is no client secret to distribute or leak. Every request carries a Roamer-issued token, validated by the server itself.
Tenant isolation, Owner/Member roles, and per-seat entitlement checks are enforced server-side on every call, not left to the client to respect. create_checkout_session and create_billing_portal_session wrap Stripe Checkout and the Billing Portal directly, gated to tenant Owners.
Project tracks exactly where a project sits on its arc — spec-item status, branch and session history, environments, and both resolved and unresolved blockers — backed by an Azure SQL schema managed through EF Core migrations.
The container sits behind a Cloudflare Tunnel, so the origin has no public ingress. Cloudflare terminates TLS and routes traffic; the app authenticates every request itself, from a person or from another service.
The Arc Model
An arc is the unit of work Roamer MCP actually trusts. Not a status someone typed into a ticket, but something computed live from real data — so "done" means done, not "I think it's done" or "it compiled." It's the mechanism that lets an AI-native workflow claim completion without asking a person to go double-check the claim by hand.
One arc = one spec area — a feature, migration, or fix, tracked from its first spec item through genuine completion, however many threads or branches it touches along the way.
An arc is finished when every blocker, critical, and major item in its area reaches a code-complete status — driven to zero, not just mostly done.
Minor and unprioritized items don't block the arc. They're real backlog — just not the bar for calling the work done.
A spec item's status describes the code and its test coverage — nothing more. Roamer MCP separately tracks whether that code actually shipped: a project's real deployment state is compared against its arc position, so work that's "code-complete" but sitting unmerged, or merged but never deployed, doesn't get to call itself done.
- Closure is pulled, not pushed — a loose thread tied to a finished piece of work surfaces for review on its own, instead of being quietly forgotten.
- Identity survives reorganization — splitting or merging a spec area never duplicates or desyncs an item's status.
- Idle work resurfaces on its own — nothing goes stale silently; it gets flagged for a fresh judgment call instead of aging out of sight.
- Coverage is a gate, not an afterthought — done means tested, not just written.
Request Flow
Every client — Claude Code, claude.ai, Claude Desktop, VS Code, Cursor — talks to the same hosted endpoint over streamable HTTP, using standard MCP authorization. Nothing needs to be installed locally, and no client ID or secret is handed out.
The client calls /mcp without a token and gets a 401 pointing at the server's protected-resource metadata.
It discovers Roamer MCP's own authorization server and registers itself with Dynamic Client Registration — a public client using PKCE.
The user signs in through Entra ID in the browser; the authorization server issues a short-lived Roamer access token and a refresh token.
Every later request carries that token, and the server validates it itself before resolving the caller's tenant.
Clients that prefer a local process can still run npx roamer-device-auth, a stdio bridge that relays every call to the same endpoint and signs in through the same authorization server.
- The same connection works on every MCP client, including ones that can't start a local process, such as web and mobile.
- Dynamic Client Registration means no per-client setup to build, and no client ID or secret for users to copy.
- Every request carries its own token, so a connection never runs on a stale cached identity.
- Tools, workflows and resources all come with the connection; the plugin only adds slash commands on top.
Design Principles
Docs are live queries, not files
The brain overview, registry, and specs are composed from the database on every read. There is no markdown file that a human has to remember to update, and none that can quietly fall out of sync with what's actually true.
One arc, one spec area, gated by priority
A feature counts as done when every blocker, critical, and major item in its spec area reaches code-complete status — directly computable from the data, not a status someone declared in standup. See The Arc Model, above, for the full definition.
One endpoint, standard authorization
Every client connects to the same hosted endpoint and signs in through the server's own OAuth authorization server, with Dynamic Client Registration and PKCE. No client secret, header or local install stands between a user and a working connection.
Threads for what specs can't yet formalize
Open questions, live incidents, and deferred decisions get their own tracked, project-linked record instead of disappearing into chat history or getting force-fit into a spec item before they're ready to be one.
Multi-tenant from the start
Owner/Member roles, per-seat Stripe billing, and tenant-scoped data isolation are enforced server-side as core parts of the data model — not a retrofit bolted onto a server that was originally built single-tenant.