{
  "markdown": "# Builderforce.ai\n\n> **A human-in-the-loop, fully agentic cloud** — train your own AI agents and use them inside your own agent, manage your whole workforce on a Kanban board, and review and approve every action without ever leaving VS Code.\n\n[![Deploy Status](https://img.shields.io/badge/deploy-Cloudflare%20Pages-orange)](https://builderforce.ai)\n[![Worker](https://img.shields.io/badge/api-Cloudflare%20Workers-blue)](https://workers.cloudflare.com)\n[![DB](https://img.shields.io/badge/db-Neon%20Postgres-green)](https://neon.tech)\n\n---\n\n## What is Builderforce.ai?\n\nBuilderforce.ai is a **human-in-the-loop, fully agentic cloud** where ideas become software and software becomes agents. You stay in control of every step while AI agents do the work — train your own specialist agents and put them to work *inside* your own agent, manage the whole workforce from a Kanban board, and review, validate, and approve everything without leaving your editor. It combines a full in-browser IDE with an AI training pipeline, a Workforce Registry for specialist agents, and an orchestration portal for self-hosted [BuilderForce Agents](https://builderforce.ai/agents) meshes.\n\n**Three capabilities at the core:**\n\n| Capability | What it does |\n|---|---|\n| **🔁 Train agents, use them inside your agent** | Train a custom agent in-browser (WebGPU LoRA + AI evaluation), publish it to the Workforce Registry, then hire it and call it from inside your own agent — your specialists become tools your main agent delegates to. |\n| **▦ Kanban board & project management** | Organize work into projects, then plan, assign, and track every task on a live Kanban board (swimlanes per status or per agent, plus table, calendar, and Gantt views). Humans and AI agents share the same board. |\n| **🧩 Never leave VS Code** | The BuilderForce VS Code extension runs the whole platform in your editor — chat with agents, assign and run tasks, review and validate their work, and approve human-in-the-loop actions without leaving your code. |\n\n**One platform. Three roles:**\n\n| Role | What it does |\n|---|---|\n| **Enterprise IDE** | Full Node.js runtime in the browser (WebContainers + Monaco + xterm.js); real-time collaboration; AI pair programming |\n| **AI Training Studio** | In-browser LoRA fine-tuning on instruction datasets; WebGPU-accelerated; models up to 2B parameters; no cloud GPU required |\n| **Orchestration Portal** | BuilderForce Agent fleet management; task assignment; heartbeat monitoring; agent-to-agent mesh relay; approval gates |\n\n---\n\n## Key Capabilities\n\n### In-Browser IDE\n- **Full Node.js runtime** via WebContainers — run `npm install`, Vite dev servers, and interactive shells without leaving the browser\n- **Monaco Editor** with syntax highlighting, IntelliSense, multi-file tabs, and real-time collaborative editing via Yjs CRDT\n- **xterm.js terminal** connected directly to the WebContainer shell — full PTY, shared across collaborators\n- **AI Chat Panel** — streaming AI assistant with full project file context; can apply code changes and create files directly\n- **Live Preview** — iFrame running the Vite dev server; updates on save\n\n### AI Training Studio\n- **In-browser LoRA fine-tuning** — uses [@seanhogg/builderforce-memory](https://www.npmjs.com/package/@seanhogg/builderforce-memory) / Transformers.js with WebGPU; trains Mamba-1/2/3 and GPT-style models up to 2B parameters entirely client-side\n- **Hybrid Local Brain** — Mamba State Engine (`mamba-engine.ts`) runs an O(n) selective scan alongside transformer inference; agent state persists to IndexedDB as a compact Float32 state vector and is embedded in exported `AgentPackage` JSON\n- **Dataset generation** — LLM-assisted JSONL instruction dataset creation with SSE streaming progress\n- **AI evaluation** — independent judge scores model outputs on code correctness, reasoning quality, and hallucination rate (0.0–1.0)\n- **WebGPU fallback** — CPU software path via `forceFallbackAdapter: true`; platform reports `gpuMode: 'cpu-fallback'` transparently\n\n### Workforce Registry\n- **Publish specialist agents** — bundle a LoRA adapter, capability profile, and `MambaStateSnapshot` into a portable `AgentPackage` JSON artifact\n- **Skill-based discovery** — agents are searchable by skills, evaluation score, and hire count\n- **Hire and deploy** — one click to register an agent in your [BuilderForce Agents](https://builderforce.ai/agents) mesh; PowerShell install script for local deployment\n- **Iterative improvement** — `training_sessions` table tracks dataset → training → evaluation → re-training loops for continuous agent quality improvement\n\n### Local LLM Inference Pipeline\n- **Per-agent inference endpoint** — `POST /api/ide/agents/:id/chat` routes inference through OpenRouter with the agent's persona injected into the system prompt; `X-Inference-Mode: lora | hybrid | base | fallback-base` header signals which path ran\n- **Mamba state injection** — v2.0 agents carry a `MambaStateSnapshot`; each inference call prepends `[Memory: step=N signal=X context=\"...\"]` to the system prompt, giving the agent persistent conversational memory without re-training\n- **Mamba state sync** — `PUT /api/ide/agents/:id/mamba-state` accepts a `MambaStateSnapshot` from CoderClaw after each session; upgrades the agent package to v2.0 and recomputes `inference_mode`; `GET /api/ide/agents/:id/mamba-state` retrieves the stored snapshot\n- **Package versioning** — agent packages are v1.0 (LoRA only) or v2.0 (LoRA + Mamba state); `GET /api/ide/agents/:id/package` returns the correct format and increments `request_count`\n- **Workforce routing in chat** — `POST /api/ai/chat` with `model: \"coderclawllm/workforce-<agentId>\"` auto-routes to the agent inference endpoint; no client-side changes required\n- **Inference logging** — `agent_inference_logs` table captures model ref, latency, token counts, status, and inference mode per request for observability and billing\n\n### BuilderForce Agents Orchestration Portal\nBuilderforce.ai is the cloud-side control plane for [BuilderForce Agents](https://builderforce.ai/agents) self-hosted agents:\n\n- **Fleet registration** — agent hosts register at `POST /api/agent-hosts` with machine profile (IP, workspace dirs, ports, tunnel metadata)\n- **Heartbeat + capability sync** — `PATCH /api/agent-hosts/:id/heartbeat` keeps capability maps and machine profiles current\n- **Assignment context** — `GET /api/agent-hosts/:id/assignment-context` delivers assigned project metadata and context hints; the runtime syncs to `.builderforce/context.yaml`\n- **Host-to-host mesh relay** — the `AgentHostRelayDO` Durable Object proxies WebSocket connections between agent hosts; `POST /api/agent-hosts/:id/forward` dispatches tasks to a remote host, authenticated with the SOURCE host's own API key (`?from=<id>&key=…`, or the `X-AgentHost-From` header) and refused across tenants\n- **Approval gates** — human-in-the-loop control for high-impact agent actions; agents request approval before executing; outcomes are audited\n- **Task management** — `tasks` and `executions` tables track work assigned to specific agent hosts; `POST /api/tasks/next` feeds the next task to a waiting agent\n- **Legacy mounts** — `/api/claws` and `/api/agentNodes` still answer for fleets that have not moved, with `Deprecation: true` and a `Link: rel=\"successor-version\"` pointing at `/api/agent-hosts` (`presentation/middleware/legacyAlias.ts`). New callers use the canonical path.\n\n### Multi-Tenant Platform\n- **JWT auth** with web token (global) + tenant token (workspace-scoped) dual-token model\n- **Multi-auth** — email/password, OAuth social login (Google, GitHub, LinkedIn, Microsoft), and magic link sign-in all coexist on the same account\n- **Tenant isolation** — all resources (projects, agent hosts, agents, training jobs) are scoped to a tenant; no cross-tenant data access\n- **Multi-workspace** — users belong to multiple tenants; `bf_default_tenant_id` auto-selects on login\n- **Admin observability** — `/admin` surface for platform admins (superadmin flag); `logs/global-errors.txt` in R2; `/observability` LLM usage metrics\n\n### Billing & Subscriptions (Stripe)\n- **Stripe only** — `src/infrastructure/payment/StripeProvider.ts` (Stripe Checkout + Billing, hosted payment page, webhook-activated). There is deliberately no provider switch and no manual fallback: a fallback that activated plans without charging meant an unconfigured deploy handed out paid plans for free.\n- **PaymentProvider interface** — `src/infrastructure/payment/PaymentProvider.ts` keeps `TenantService` off the concrete Stripe client and lets tests inject a fake; it is not a provider-swap seam.\n- **Checkout flow** — `POST /api/tenants/:id/subscription/checkout` always returns a hosted `checkoutUrl`. The plan activates only when the signed webhook confirms payment — never from the request itself.\n- **Webhook handler** — `POST /api/webhooks/payment` receives Stripe events; HMAC-verified with a 5-minute replay window; activates/cancels subscriptions via normalised `WebhookEvent`\n- **Configuration** — set the `STRIPE_*` Worker secrets (see `src/infrastructure/payment/index.ts`). They are validated lazily: absent secrets return **503** from the billing routes and never break Worker boot.\n\n### Dev Analytics & Team Intelligence\n- **Contributor profiles** — cross-platform developer identity reconciliation (GitHub, Jira, Bitbucket); `GET /api/contributors`\n- **Activity ingestion** — `POST /api/contributors/activity` receives PR opened/merged/reviewed, commit, issue events with automatic daily metric aggregation\n- **Weighted activity score** — per-contributor daily score (commits×1 + PRs×3 + reviews×2 + issues×1.5); active dev day = ≥1 commit or PR action\n- **PR cycle time** — end-to-end hours from `pr_opened` to `pr_merged` events tracked on each activity record\n- **Integration credential manager** — AES-256-GCM encrypted platform credentials stored per-tenant; `GET/POST/PUT/DELETE /api/integrations`; per-provider connectivity tests (`POST /api/integrations/:id/test`)\n- **Team hierarchy** — nested dev teams with manager–member relationships; `GET/POST/PATCH/DELETE /api/dev-teams`; member add/remove endpoints\n- **Standup report** — `GET /api/reports/standup` — daily summary: active contributors, commits, PRs merged, issues resolved; recent PRs and resolved issues\n- **Code review report** — `GET /api/reports/code-review` — 14-day window; stale PRs (>7 days old), average cycle time, reviewer activity\n- **Executive summary** — `GET /api/reports/executive` — KPIs over configurable date range: contributor counts, total commits, PRs merged, lines added, average activity score, top contributors\n- **Report schedules** — `GET/POST/PATCH/DELETE /api/reports/schedules`; cron-style delivery config (daily/weekly) with hour-of-day and recipient list\n- **Report subscriptions** — `GET/POST /api/reports/subscriptions`; per-user opt-in/opt-out per report type\n\n### Platform Infrastructure\n- **Per-tenant rate limiting** — `TenantRateLimiterDO` Cloudflare Durable Object; sliding window (60 RPM FREE, 300 RPM PRO, 1000 RPM TEAMS); `X-RateLimit-Limit/Remaining/Reset` + `Retry-After` headers\n- **Auto-approval rules** — `GET/POST/PATCH/DELETE /api/approval-rules`; rule evaluation on `POST /api/approvals` by actionType, max cost, max files changed; bypasses human gate when conditions match\n- **Approval notifications** — Slack webhook + Resend email alerts on new approval requests and decisions; configurable via `SLACK_APPROVAL_WEBHOOK_URL` + `RESEND_API_KEY`\n- **Escalation cron** — `GET /api/approvals/escalate?secret=` expires timed-out pending approvals and fires Slack alert; suitable for Cloudflare Cron Triggers\n- **OTel telemetry proxy** — `POST /api/telemetry/spans` ingest; `GET /api/telemetry/spans` query; `GET /api/telemetry/traces` list; costs stored as millicent integers; W3C `X-Trace-Id` header forwarded from CoderClaw\n\n---\n\n## Latest Capabilities\n\nThe platform has grown from an IDE-plus-training studio into a full **system of record for agentic work**. These are the most recent additions — the enterprise delivery, quality, knowledge, and FinOps surfaces that sit on top of the agent workforce.\n\n### Planning Spine — Portfolio to Task (mig 0213, 0225)\n- **One dated, cost-bearing hierarchy** — `portfolio → initiative → epic → task`, with **Objectives and Key Results** attaching as a goal layer at any level. Every level is dated and rendered on a single nested Gantt (`PlanningSpineGantt`).\n- **Cost rolls up from the leaf** — LLM spend (priced at write time from `llm_usage_log`) plus human effort (member cost rate × hours) rolls up to every ancestor. No parallel finance system, no backfill.\n- **CAPEX / OPEX split** — each node carries a `cost_class` resolved in priority order (explicit → inherited → agent-classified by investment category → GAAP-conservative default). A child class that contradicts its parent is flagged as an **anomaly** for PM reconciliation.\n- **Endpoints** — `GET /api/pmo/spine`, `GET /api/pmo/spine/export.csv`, `GET /api/pmo/rollup` (portfolio/initiative/workspace), `PATCH /api/pmo/cost-class`, `POST /api/pmo/cost-class/classify`, initiative `POST/DELETE /api/pmo/dependencies` (cycle-checked) → on-demand critical path. Surface: `/projects?tab=portfolio`, gated by `insights.portfolio` / `insights.pm`.\n\n### Quality — Error Observability + One-Click Agent Fix (mig 0240)\n- **Multi-source ingest** — one canonical event shape behind five adapters: **native** (the `@seanhogg/builderforce-quality` browser SDK), **OTLP**, **Sentry**, **PostHog**, **LogRocket** (webhooks HMAC-verified; Sentry connections can backfill).\n- **Fingerprint grouping** — events upsert into `error_groups` keyed by `(tenant, project, fingerprint)` — explicit fingerprint or derived from the top stack frame + normalized message; occurrence + exact distinct-user counts; resolved bugs reopen on recurrence.\n- **One-click fix loop** — `POST /api/quality/groups/:id/fix` creates a board task (titled + prioritized from the error, briefed with the stack trace) and dispatches a cloud agent that ships a **pull request**. Crash → group → task → PR on one surface.\n- **Endpoints** — authenticated `/api/quality/*` (collectors, integrations, rules, groups, fix); public keyed/HMAC ingest `/api/quality-ingest/{events,otlp/v1/logs,otlp/v1/traces,webhooks/:collectorId/:provider}`. Dashboard: `/quality`. Metered as `error_events`.\n\n### Knowledge Management & Compliance (mig 0227)\n- **Versioned SOPs, processes & docs** — live editable body plus an **immutable snapshot on every publish** (version number + change note + publisher).\n- **Audit-ready acknowledgements** — read-acknowledgements bind to a specific version with a timestamp; per-user state is **acknowledged / pending / overdue**, with manager rollups at `GET /api/knowledge/compliance` — evidence for **SOX, TISAX, ISO 27001**.\n- **AI authoring + analysis** — `POST /api/knowledge/ai/draft` streams a Markdown draft; `POST /api/knowledge/documents/:id/analyze` returns structured findings (inefficiency / gap / risk / clarity) + an improved flow. Metered through the LLM gateway.\n- **Real-time co-editing** — Yjs CRDT over `NEXT_PUBLIC_COLLAB_WS_URL` with presence awareness; per-document **editor/viewer** collaborators on top of workspace roles; falls back to autosave when collaboration is unconfigured. Surface: `/knowledge`.\n\n### Single-Pane Board Connectors (mig 0221)\n- **Two-way sync across 10 systems** — each provider implements `fetchTicketsSince(cursor)` + `pushUpdate(externalId, changeSet)`, normalizing to one ticket shape stamped with its source.\n  - **PM / work:** GitHub Issues, Jira, Linear, monday.com, Asana, ClickUp\n  - **ITSM:** ServiceNow, Freshservice\n  - **Incident:** Sentry, PagerDuty\n- **Webhooks where supported** (GitHub, Jira, Linear, monday, Sentry, PagerDuty), polling otherwise. Agents act on a ticket or incident wherever it originates; changes flow back to the system of origin — single pane, no migration.\n- **Endpoints** — `GET /api/board-connections/providers` (catalog), CRUD `/api/board-connections`, `POST /api/board-connections/:id/sync`, `GET /api/board-connections/:id/links`.\n\n### Platform Migration & Integration Hub (mig 0256)\nMove off a competitor tracker without fear, or just sync data in — a **staged** importer on top of the connector framework. Nothing lands in real projects/tasks/members until you commit.\n- **Provider discovery** — `discover()` enumerates external projects, item types, and users for **Jira, monday, Rally, GitLab, Bitbucket, GitHub** (the migration-eligible providers; new Rally/GitLab/Bitbucket adapters added).\n- **Staging buffer** — `import_runs` + `import_staged_{projects,items,users}` + `import_type_mappings`; combine several external projects into one BuilderForce project, map item types → task type/status, and invite/map users — all reviewed before import.\n- **Migrate / sync / both** — one-time historical import, an ongoing `board_connections` sync, or both. The persistent `board_type_mappings` makes ongoing sync land tasks in the mapped type/status (not a hardcoded backlog). Imported items keep their **assignee** (mapped to a member) and **story points**.\n- **Integrations gallery** — `/settings/integrations` is the workspace home: cards by category (PM / SCM / ITSM / incident), per-provider config panel (Credentials · Connections · Activity/diagnostics), and a \"Start migration\" launcher. GitHub/GitLab/Bitbucket connect **both** issues (migration) **and** repositories (code).\n- **Brain-drivable** — the whole flow is in the gateway MCP catalog (`integrations.create_credential`/`test`, `migrations.start`/`set_mappings`/`stage`/`commit`); the Brain (right-docked) opens the migration panel on the **left** via `open_migration_panel`.\n- **Endpoints** — `/api/migrations` (start/list/get/`:id/mappings`/`:id/stage`/`:id/commit`, MANAGER+, cached + version-bumped).\n\n### Agentic Tester — Autonomous QA (mig 0063, 0206)\n- **Heatmap-ranked exploration** — journey events (`POST /api/qa/events`) rank route-and-element zones by recency-weighted frequency (`GET /api/qa/heatmap`); explorations plan from the hottest zones within a budget.\n- **AI-generated Playwright** — `POST /api/qa/generate` turns a flow into an executable spec and resolves a persona credential; a deterministic heatmap-only plan is also available (no model cost).\n- **Authenticated container runs** — a harness claims an exploration, logs in as a real persona (encrypted, developer-gated credentials), walks the plan, and captures console/page errors, failed requests, assertion failures, and crashes.\n- **Findings → board → fix** — findings dedupe by fingerprint; with auto-routing enabled, any finding at/above the severity threshold becomes a board task in a fix lane, firing the **same lane auto-run a human board drag triggers** → a fix agent opens a PR. Schedules run it on cron. Quality trend (escaped vs caught defects) at `GET /api/qa/quality`.\n\n### Consumption Metering (mig 0218)\n- **Meter on consumption, not visibility** — one framework (`/api/consumption`) reports month-to-date usage for `ai_tokens`, `ingestion` (bytes), and `error_events` against the plan allowance, using the **same accountants the gateway and ingestion gate enforce** — so the \"% used\" a member sees equals the cap that's enforced. Cached 60s, keyed per tenant + calendar month.\n\n### Coordinated Role Participation & Accountability (mig 0334)\n- **The right role does the work** — first-class agent↔role capability (`ide_agents.role_keys`) drives role-aware assignment: a producer stage resolves the role from the ticket's `action_type` and dispatches a role-capable agent/human, never a mis-assigned one. Stops the \"a Product Manager was dispatched to write code\" class of failure.\n- **A participation manifest per ticket** — `ticket_participants` derives the required roles from the board's swimlane requirements, resolves each slot by capability, and tracks per-participant state (pending / assigned / in_progress / completed / changes_requested / waived / unstaffed).\n- **An immutable Accountability Report** — an append-only `ticket_role_signoffs` ledger records Who / When / Verdict / Comments / Contribution per role; default-deny RBAC (only role-capable members may sign off as a role); every sign-off emits to the unified activity log. A **Resource Assessment** control adds a needed role beyond the template — an unresolved add surfaces as a blocking resource gap.\n- **Endpoints** — `GET /api/kanban/tasks/:id/accountability`, `/participants`, `POST /participants` (assess) / `/materialize`, plus MCP `kanban.participants` / `kanban.accountability` / `kanban.assess_resource`. Surface: the ticket-drawer **Accountability** tab + a board `X/Y` participants chip.\n\n### Pre-Sales RFP / RFQ Response (mig 0335)\n- **Turn a repo into a proposal** — CTO + Product Owner built-in agents generate a branded, costed proposal from a project's analyzed capabilities: cost / P&L, a phase Gantt, risks, dependencies, and a capability roster matched to the ask.\n- **Co-branded output** — the requester's palette + logo blend with the responder's for a branded, self-contained proposal document (print-to-PDF / download), with freshness-gated grounding (a >5-day-stale scan re-runs the deterministic system audits before answering).\n- **Surface** — a Projects **RFP tab** (list / create) + `/projects/rfp/[id]` detail; `/api/rfp` routes.\n\n### Incident Management & Active Monitoring (mig 0292)\n- **Incidents close the loop** — a Help-Desk / Incident-Manager agent, a Freshdesk connector, on-call rotations, timed escalation, Teams / Slack / email paging, and a per-incident war-room feed. On resolution the RCA is published to Knowledge **and** fed to the project's Evermind, so the workforce learns and stops repeating causes.\n- **A monitoring canvas** — pin heartbeat / HTTP / webhook / metric monitors onto an uploaded architecture diagram; a `*/5` sweep evaluates them and a breach **auto-starts the on-call investigation** (monitor → signal → incident → paging), with reporting on the timeline.\n\n### Meetings & Live Collaboration (mig 0292, 0330)\n- **Video / audio meetings with agents in the room** — mesh WebRTC over a `CeremonyRoomDO` relay; agent attendees speak live via a caption / transcript bridge; recording + transcription produce **AI minutes**. Google / Microsoft calendar sync. Surface: `/meetings`.\n\n### AI Managers — Types & Coaching (mig 0327)\n- **Typed managers tied to the role catalog** — Dev / QA / Service-Desk / DevOps manager types map to `roleCatalog` (custom roles become `role:<key>` types); a human → manager **Coaching Session** carries directive | task modes with expiry / done state, steering how a manager agent runs its reports.\n\n### Memory-First Answering — skip the paid LLM\n- **Answer from the project's own memory before spending a model call** — the web and VS Code webview Brain consult the project's `project_facts` fact tier + its Evermind SSM first and short-circuit the LLM on a confident hit (an exact-repeat Q&A cache + opt-in Evermind-first inference), single-sourced in `resolveMemoryAnswer`. Learning fans out to **every** Evermind under a project (its own head + its IDE builds' heads) via one shared `contributeTextToProjectEverminds`. Endpoints: `GET/POST /api/projects/:id/answer`, `GET /api/projects/:id/evermind/targets`.\n\n---\n\n## Authentication\n\nBuilderforce.ai supports three sign-in methods that coexist on the same account. A single user can link multiple OAuth providers, set a password, and use magic links interchangeably.\n\n### Sign-in methods\n\n| Method | How it works |\n|---|---|\n| **Email + password** | `POST /api/auth/web/login` — PBKDF2 (100k iterations, SHA-256); same generic error for wrong email or wrong password |\n| **OAuth social login** | `GET /api/auth/oauth/:provider` → provider consent → `GET /api/auth/oauth/:provider/callback` → JWT issued; browser redirected to `/auth/callback?token=…` |\n| **Magic link** | `POST /api/auth/magic-link` sends a 15-minute single-use token by email; `GET /api/auth/magic-link/verify?token=…` issues JWT; always returns 200 (no email enumeration) |\n\nSupported OAuth providers: `google`, `github`, `linkedin`, `microsoft`.\n\n### Auth flow diagram\n\n```\nBrowser\n  │\n  ├─ Email/password ──────────────────────────► POST /api/auth/web/login\n  │                                              Returns JWT in JSON body\n  │\n  ├─ OAuth (click button) ────────────────────► GET /api/auth/oauth/:provider\n  │                                              302 → provider consent screen\n  │                                              Provider → GET /api/auth/oauth/:provider/callback\n  │                                              API issues JWT\n  │                                              302 → /auth/callback?token=JWT\n  │                                              Frontend page writes token to localStorage\n  │\n  └─ Magic link ──────────────────────────────► POST /api/auth/magic-link\n                                                 Email sent with /auth/magic-link?token=…\n                                                 Frontend page calls GET /api/auth/magic-link/verify\n                                                 Returns JWT in JSON body\n```\n\n### JWT strategy\n\n- **Web token** (`localStorage key: bf_web_token`) — 24-hour HMAC-SHA-256 JWT; payload: `{ sub, email, username, amr?, sa?, jti, sid }`\n- **Tenant token** (`localStorage key: bf_tenant_token`) — 1-hour workspace-scoped JWT; issued by `POST /api/auth/tenant-token`\n- Every issued token is tracked in the `auth_tokens` table (JTI + session ID); `webAuthMiddleware` validates against this table on every request, enabling instant revocation\n\n### Account management endpoints\n\n| Endpoint | Auth | Description |\n|---|---|---|\n| `GET /api/auth/linked-accounts` | Web JWT | List linked OAuth providers + whether account has a password |\n| `DELETE /api/auth/unlink/:provider` | Web JWT | Unlink a provider; blocked if it would remove the last sign-in method |\n| `POST /api/auth/add-password` | Web JWT | Add a password to an OAuth-only account |\n\n### OAuth security\n\n- **CSRF protection** — OAuth `state` parameter is HMAC-SHA-256 signed (using `JWT_SECRET`) with a nonce and 10-minute expiry; no database required\n- **Account linking** — if an OAuth email matches an existing account, the provider is linked automatically; the user controls their email so this is safe\n- **Email-only users** — OAuth users who haven't set a password are protected from the unlink endpoint; they must `POST /api/auth/add-password` first\n\n### Enabling OAuth providers\n\nEach provider is activated by supplying its client credentials as Cloudflare Worker secrets. Providers with missing credentials silently return `503` — you only need to configure the providers you want.\n\n```bash\n# Google\nwrangler secret put GOOGLE_CLIENT_ID\nwrangler secret put GOOGLE_CLIENT_SECRET\n\n# GitHub\nwrangler secret put GITHUB_CLIENT_ID\nwrangler secret put GITHUB_CLIENT_SECRET\n\n# LinkedIn\nwrangler secret put LINKEDIN_CLIENT_ID\nwrangler secret put LINKEDIN_CLIENT_SECRET\n\n# Microsoft\nwrangler secret put MICROSOFT_CLIENT_ID\nwrangler secret put MICROSOFT_CLIENT_SECRET\n```\n\nRegister the OAuth callback URL in each provider's dashboard:\n\n```\nhttps://api.builderforce.ai/api/auth/oauth/{provider}/callback\n```\n\nReplace `{provider}` with the lowercase provider name: `google`, `github`, `linkedin`, `microsoft`.\n\n#### Provider setup\n\n| Provider | Setup time | Manual review? | Key gotcha |\n|---|---|---|---|\n| Google | ~10 min | No for sign-in; **yes** for Gmail/Calendar/Drive/YouTube scopes | One OAuth client serves every Google flow — register a redirect URI **per flow**, or the connector 400s with `redirect_uri_mismatch` even though sign-in works |\n| LinkedIn | ~10 min | No (auto-approved) | Must add the **\"Sign In with LinkedIn using OpenID Connect\"** product — without it the `/v2/userinfo` endpoint won't return the email address |\n| GitHub | ~5 min | No | Only one callback URL per app — create a second OAuth App for local dev |\n| Microsoft | ~10 min | No | Same one-client-many-flows trap as Google — register the mailbox/calendar/drive redirect URIs alongside sign-in |\n\n---\n\n#### Google\n\n1. Go to [console.cloud.google.com](https://console.cloud.google.com), create or select a project\n2. **APIs & Services → OAuth consent screen**\n   - User Type: **External**\n   - App name, support email, add scopes: `email`, `profile`, `openid` (non-sensitive, no review required)\n   - Connectors need their scopes listed here too, and they are **not** free: Gmail\n     (`gmail.modify`, `gmail.send`) is a *restricted* scope, Calendar/Drive/YouTube are\n     *sensitive*. Both classes work for accounts listed as test users while the app is in\n     Testing, but going public with them requires Google's verification review.\n   - Add your email as a test user while in development\n3. **APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID**\n   - Application type: **Web application**\n   - Authorized redirect URIs — **one entry per flow, not just sign-in.** `GOOGLE_CLIENT_ID`\n     is shared by every Google-family connector, and each builds its own callback path from\n     the request origin. A path that is missing here fails with\n     `Error 400: redirect_uri_mismatch` at consent time — sign-in working proves nothing about\n     the others. Add the production entry for every flow you intend to use, plus the\n     `http://localhost:8787` twin of each one you develop against:\n     ```\n     https://api.builderforce.ai/api/auth/oauth/google/callback   # sign-in / create account\n     https://api.builderforce.ai/api/mailbox/callback/google      # Connect inbox (Gmail)\n     https://api.builderforce.ai/api/calendar/callback/google     # Google Calendar\n     https://api.builderforce.ai/api/drive/callback/google        # Google Drive\n     https://api.builderforce.ai/api/youtube/callback             # YouTube publishing\n     ```\n4. Copy Client ID and Client Secret:\n   ```bash\n   wrangler secret put GOOGLE_CLIENT_ID\n   wrangler secret put GOOGLE_CLIENT_SECRET\n   ```\n\n5. **OAuth consent screen → App domain** — fill in the **Application privacy policy link** and\n   **Application terms of service link**. Google will not verify an app without them, and until they\n   are set the consent screen tells the user it cannot show links to your policies:\n   ```\n   https://builderforce.ai/legal/privacy\n   https://builderforce.ai/legal/terms\n   ```\n   Both are public, server-rendered pages of the CURRENT published document version (see\n   `frontend/src/lib/legalDocs.ts` — one route table, shared by the pages, the footer link, the\n   trust-centre nav and the sitemap). Also add `builderforce.ai` under **Authorized domains**.\n\n> **Publishing:** While in \"Testing\" mode only test users can sign in — and only test users can\n> complete a connector consent, however many redirect URIs are registered. Click **Publish App** on\n> the consent screen when ready for production — `email/profile/openid` are standard scopes and are\n> typically approved immediately with no manual review, but the Gmail/Calendar/Drive/YouTube scopes\n> above are sensitive or restricted and go to Google's verification review, which requires the\n> privacy-policy and terms links from step 5 plus a demo video of the consent flow.\n\n---\n\n#### LinkedIn\n\n1. Go to [linkedin.com/developers](https://www.linkedin.com/developers) → **Create App**\n   - App name, LinkedIn Company Page (required — create one if needed), logo\n2. **Auth tab** → Authorized redirect URLs — add both:\n   ```\n   https://api.builderforce.ai/api/auth/oauth/linkedin/callback\n   http://localhost:8787/api/auth/oauth/linkedin/callback\n   ```\n3. **Products tab** → request **\"Sign In with LinkedIn using OpenID Connect\"** — click Request access (auto-approved instantly). This unlocks the `openid profile email` scopes used by the code. Without it the `/v2/userinfo` endpoint will not return the email address.\n4. Back on the **Auth tab**, copy Client ID and Client Secret:\n   ```bash\n   wrangler secret put LINKEDIN_CLIENT_ID\n   wrangler secret put LINKEDIN_CLIENT_SECRET\n   ```\n\n---\n\n#### GitHub\n\n1. GitHub → **Settings → Developer settings → OAuth Apps → New OAuth App**\n   - Homepage URL: `https://builderforce.ai`\n   - Authorization callback URL:\n     ```\n     https://api.builderforce.ai/api/auth/oauth/github/callback\n     ```\n2. Click **Register application**, then **Generate a new client secret**\n3. Set secrets:\n   ```bash\n   wrangler secret put GITHUB_CLIENT_ID\n   wrangler secret put GITHUB_CLIENT_SECRET\n   ```\n\n> **Local dev:** GitHub allows only one callback URL per app. Create a separate OAuth App (e.g. \"builderforce-dev\") pointing to `http://localhost:8787/api/auth/oauth/github/callback` and use its credentials in `api/.dev.vars`.\n\n---\n\n#### Microsoft\n\n1. [Azure Portal](https://portal.azure.com/) → **Microsoft Entra ID → App registrations → New registration**\n   - Supported account types: **\"Accounts in any organizational directory and personal Microsoft accounts\"**\n   - Redirect URIs (Web) — `MICROSOFT_CLIENT_ID` is shared by every Microsoft flow, so\n     register one per flow you intend to use (add the `http://localhost:8787` twin for local dev):\n     ```\n     https://api.builderforce.ai/api/auth/oauth/microsoft/callback   # sign-in / create account\n     https://api.builderforce.ai/api/mailbox/callback/microsoft      # Connect inbox (Outlook)\n     https://api.builderforce.ai/api/calendar/callback/microsoft     # Outlook Calendar\n     https://api.builderforce.ai/api/drive/callback/microsoft        # OneDrive / SharePoint\n     ```\n2. **Certificates & secrets → New client secret** — copy the value immediately (it's only shown once)\n3. Copy the **Application (client) ID** from the Overview page\n4. Set secrets:\n   ```bash\n   wrangler secret put MICROSOFT_CLIENT_ID\n   wrangler secret put MICROSOFT_CLIENT_SECRET\n   ```\n\n---\n\n#### Local development\n\nFor local development, use `api/.dev.vars` — Wrangler loads this file automatically for `wrangler dev`, and it is gitignored:\n\n```ini\n# api/.dev.vars\nGOOGLE_CLIENT_ID=your_google_client_id\nGOOGLE_CLIENT_SECRET=your_google_client_secret\nLINKEDIN_CLIENT_ID=your_linkedin_client_id\nLINKEDIN_CLIENT_SECRET=your_linkedin_client_secret\nGITHUB_CLIENT_ID=your_github_dev_app_client_id\nGITHUB_CLIENT_SECRET=your_github_dev_app_client_secret\nAPP_URL=http://localhost:3000\n```\n\nThe OAuth callback URL is derived from the incoming request's `Origin` header at runtime, so no extra `API_URL` variable is needed — it resolves to `http://localhost:8787` locally and `https://api.builderforce.ai` in production automatically.\n\n### Magic link email\n\nThe `sendMagicLinkEmail` function in `api/src/presentation/routes/oauthRoutes.ts` is a placeholder that logs the link to the console. Wire it to your email provider (Resend, SendGrid, Mailgun, etc.) before using magic links in production:\n\n```typescript\n// api/src/presentation/routes/oauthRoutes.ts  ~line 253\nasync function sendMagicLinkEmail(to, name, token, frontendUrl) {\n  const magicUrl = `${frontendUrl}/auth/magic-link?token=${encodeURIComponent(token)}`;\n  // TODO: call your email provider here\n}\n```\n\n### Frontend routes added\n\n| Route | File | Purpose |\n|---|---|---|\n| `/auth/callback` | `frontend/src/app/auth/callback/page.tsx` | Receives `?token=JWT` from OAuth redirect, persists session, navigates |\n| `/auth/magic-link` | `frontend/src/app/auth/magic-link/page.tsx` | Calls `/api/auth/magic-link/verify`, persists session, navigates |\n\n---\n\n## Integration with BuilderForce Agents\n\n```\nDeveloper workstation\n  └─ BuilderForce Agents (self-hosted, MIT)\n       ├─ 7-role agent DAG (Code, Review, Test, Debug, Refactor, Document, Architect)\n       ├─ Staged diff review (accept/reject before writing to disk)\n       ├─ Agent-to-agent mesh (remote:<id>, remote:auto[caps], HMAC-signed dispatch)\n       ├─ Workflow telemetry → .builderforce/telemetry/ + portal timeline\n       ├─ Execution lifecycle → running/completed/failed reported to portal\n       ├─ Approval gate → blocks on manager decision from portal\n       ├─ Skill registry → loads portal-assigned skills at startup\n       ├─ Cron scheduler → executes portal-managed jobs on schedule\n       └─ BUILDERFORCE_API_KEY → heartbeat → Builderforce.ai\n                                                      │  ←task.assign / task.broadcast\n                                                      │  ←approval.decision\n                                                      │  ←cron jobs / skill assignments\n                                              ┌───────▼───────┐\n                                              │ Builderforce  │\n                                              │  .ai          │\n                                              │               │\n                                              │ • Fleet view  │\n                                              │ • Task assign │\n                                              │ • Approvals   │\n                                              │ • Audit log   │\n                                              │ • AI training │\n                                              │ • Registry    │\n                                              │ • Cron jobs   │\n                                              │ • Skills mkt  │\n                                              └───────────────┘\n```\n\n**Configure CoderClaw to connect:**\n```bash\nexport BUILDERFORCE_API_KEY=<your-api-key>\nexport BUILDERFORCE_URL=https://api.builderforce.ai\ncoderclaw start\n```\n\nCoderClaw operates fully standalone without Builderforce. The connection unlocks fleet visibility, task assignment with live execution tracking, enforced approval gates, portal-managed skill assignments, scheduled cron execution, and access to the Workforce Registry.\n\n---\n\n## On-Device AI Stack\n\nBuilderforce.ai is built on the open-source `@seanhogg/builderforce-memory` stack for on-device AI:\n\n```\n@seanhogg/builderforce-memory-engine  (engine)\n  └─ WebGPU WGSL kernels: Mamba-1 (S6), Mamba-2 (SSD), Mamba-3 (complex MIMO+ET), causal attention\n        ↓\n@seanhogg/builderforce-memory  (runtime)\n  └─ MambaSession.create() — one-call GPU init, tokenizer, model, checkpoint, persistence\n  └─ Inference routing · distillation · semantic memory · SSMAgent\n        ↓\nBuilderforce.ai IDE\n  └─ mamba-engine.ts  — Hybrid Local Brain (SSM state + IndexedDB)\n  └─ agent-runtime.ts — step() → inference → confidence scoring → cloud escalation\n  └─ webgpu-trainer.ts — LoRA fine-tuning pipeline (Transformers.js + WebGPU)\n```\n\nThe on-device AI layer runs in O(n) time (vs O(n²) for attention), making it suitable for continuous low-latency state updates and fine-tuning entirely in the browser.\n\n> Both packages are published on npm: `@seanhogg/builderforce-memory-engine` (engine) and `@seanhogg/builderforce-memory` (runtime).\n\n### Cross-surface semantic cache (token savings)\n\nThe biggest cost lever in the stack is an **embedding-keyed semantic cache** that reuses a prior answer when a new prompt is a *paraphrase* of one already answered — so the frontier model is never called for semantically-repeated work. It is two-tier and shared across surfaces:\n\n- **L1 (local, free):** in-process cosine match using on-device SSM embeddings — runs in the browser IDE and in each agent.\n- **L2 (shared):** the gateway's `POST /v1/semantic-cache/{lookup,store}` (tenant-scoped, KV-backed). A paraphrase answered in the **web app** is reusable by an **agent**, and vice-versa.\n\nThe same portable [`SemanticCache`](https://github.com/SeanHogg/builderforce-memory) from `@builderforce/memory` powers both surfaces — the embedder (on-device SSM) and the L2 backend are injected, so there is no browser/Node fork. On-device embeddings make L1 free; the gateway L2 turns one tenant's cache hits into platform-wide savings.\n\n### Hybrid retrieval & answer evaluation\n\nBuilderforce.ai implements the full **seven-layer agent stack** — and the two layers most stacks leave conventional-thin (RAG retrieval and evaluation) are built out:\n\n- **Hybrid RAG.** Retrieval fuses **dense** (SSM / OpenAI embeddings, cosine) and **sparse** (Okapi **BM25** keyword) signals with **Reciprocal Rank Fusion**, then reranks with **MMR** for relevance *and* diversity — over documents chunked with a recursive splitter + overlap. Dense search alone misses exact tokens (identifiers, error codes, rare names); the hybrid path catches them. It degrades gracefully (no embedding → BM25-only; no overlap → dense-only). Lives zero-dependency in `@seanhogg/builderforce-memory/retrieval` (`chunkText`, `bm25Search`, `reciprocalRankFusion`, `maximalMarginalRelevance`, `hybridRetrieve`, `MemoryStore.recallHybrid`) and powers the LanceDB long-term-memory extension.\n- **Semantic evaluation + drift.** Every cloud run is scored for **faithfulness**, **answer relevance**, and **hallucination rate** — inline and zero-cost (lexical), with an **LLM-as-judge** upgrade on demand at `POST /api/eval` (billed through the metered gateway). Scores persist on the run record; a **drift monitor** (mean-shift z-score + Population Stability Index) compares baseline vs recent windows per *(action-type × model)* and raises an alert when quality regresses — daily on cron and on demand at `GET /api/eval/drift`. A wrong answer no longer hides behind a green dashboard.\n\nSee the write-up: [The AI Agent Tech Stack, Built](https://builderforce.ai/blog/agent-tech-stack-all-seven-layers).\n\n---\n\n## Architecture\n\n```\n┌─────────────────────────── Browser ──────────────────────────────┐\n│                                                                   │\n│  Next.js (App Router)           WebContainer                      │\n│  ┌─────────────────────┐        ┌──────────────────────────────┐ │\n│  │  Monaco Editor      │◄──────►│  Node.js (in-browser)        │ │\n│  │  xterm.js Terminal  │        │  npm install                 │ │\n│  │  Preview <iframe>   │        │  Vite dev server             │ │\n│  │  AI Chat Panel      │        │  File system (OPFS-backed)   │ │\n│  │  Train Panel        │        └──────────────────────────────┘ │\n│  │  Agent Publish      │                                          │\n│  └──────────┬──────────┘                                          │\n│             │ HTTP / WebSocket                                     │\n└─────────────┼────────────────────────────────────────────────────┘\n              │\n┌─────────────▼──────────── Cloudflare Edge ──────────────────────┐\n│                                                                   │\n│  API (api.builderforce.ai — Hono)    Durable Objects             │\n│  ┌────────────────────────────┐      ┌──────────────────────┐   │\n│  │ /api/auth  /api/tenants    │      │  AgentHostRelayDO    │   │\n│  │ /api/agent-hosts /api/tasks│      │  - host mesh relay   │   │\n│  │ /api/brain /api/projects   │      │  - heartbeat proxy   │   │\n│  │ /api/runtime/executions    │      └──────────────────────┘   │\n│  └────────────────────────────┘      ┌──────────────────────┐   │\n│                                       │  CollaborationRoom   │   │\n│  Worker (worker.builderforce.ai)      │  - Yjs CRDT sync     │   │\n│  ┌────────────────────────────┐      │  - cursor presence   │   │\n│  │ /api/projects (IDE files)  │      │  - terminal relay    │   │\n│  │ /api/datasets /api/training│      └──────────────────────┘   │\n│  │ /api/agents (Registry)     │                                   │\n│  │ /api/ai/chat (streaming)   │      R2 Buckets                  │\n│  └────────────────────────────┘      ┌──────────────────────┐   │\n│                                       │ project files        │   │\n│  Neon Postgres                        │ datasets (.jsonl)    │   │\n│  ┌────────────────────────────┐      │ LoRA artifacts       │   │\n│  │ users · tenants · projects │      │ agent packages       │   │\n│  │ agent_hosts · tasks        │      └──────────────────────┘   │\n│  │ agents · training_jobs     │                                   │\n│  │ agent_inference_logs       │                                   │\n│  │ contributors · dev_teams   │                                   │\n│  │ activity_events · metrics  │                                   │\n│  │ integrations · telemetry   │                                   │\n│  └────────────────────────────┘                                   │\n└───────────────────────────────────────────────────────────────────┘\n```\n\n**Two Cloudflare Workers, one platform:**\n\n| | `api` (api.builderforce.ai) | `worker` (worker.builderforce.ai) |\n|---|---|---|\n| **Purpose** | Auth, tenants, agent hosts, tasks, brain, marketplace, dev analytics | IDE projects, files, datasets, training, collaboration |\n| **Auth** | JWT + tenant isolation | CORS (no auth currently) |\n| **Durable Objects** | AgentHostRelayDO (host mesh relay) | CollaborationRoom (Yjs sync) |\n| **Storage** | R2 `UPLOADS` (brain files, agent-host assets) | R2 `STORAGE` (project files, artifacts, datasets) |\n\n---\n\n## Quick Start\n\n### Local development\n\n```bash\ngit clone https://github.com/SeanHogg/Builderforce.ai\ncd Builderforce.ai\n\n# Install deps\npnpm install          # or npm install in each sub-directory\n\n# Configure\necho \"NEXT_PUBLIC_WORKER_URL=http://localhost:8787\" > frontend/.env.local\necho \"NEON_DATABASE_URL=postgresql://...\" > worker/.env\n\n# Run migrations\ncd worker && npm run migrate && cd ..\n\n# Start (in separate terminals)\ncd worker && npx wrangler dev     # :8787\ncd frontend && npm run dev        # :3000\n```\n\nOpen [http://localhost:3000](http://localhost:3000). WebGPU training requires Chrome 113+.\n\n### Deploy to Cloudflare\n\n```bash\ncd api && npm run secrets:from-env && npm run deploy\n# Frontend: CI/CD via .github/workflows/deploy-frontend.yml\n```\n\n**Required secrets:** `CF_API_TOKEN`, `CF_ACCOUNT_ID`, `NEON_DATABASE_URL`, `JWT_SECRET`, `OPENROUTER_API_KEY`. (SDK publishing uses npm Trusted Publishing OIDC — no `NPM_TOKEN` secret needed; see below.)\n\n**Releases:** [release.yml](.github/workflows/release.yml) runs four independent jobs in parallel: npm packaging, API deployment, frontend deployment, and help-site deployment. The `package-npm` job builds, tests, and publishes each public package only when its `package.json` version is absent from npm, making re-runs idempotent. Auth uses npm Trusted Publishing OIDC (with `NPM_TOKEN` as an optional bootstrap fallback). Configure each package's trusted publisher for Organization `SeanHogg`, Repository `Builderforce.ai`, and Workflow `release.yml`.\n\n**Optional OAuth secrets** (add only the providers you want):\n`GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `LINKEDIN_CLIENT_ID`, `LINKEDIN_CLIENT_SECRET`, `MICROSOFT_CLIENT_ID`, `MICROSOFT_CLIENT_SECRET`\n\n---\n\n## Browser Requirements\n\n| Feature | Required |\n|---|---|\n| WebContainers (in-browser Node.js) | Chrome 90+, Edge 90+ (COOP + COEP headers) |\n| WebGPU LoRA training | Chrome 113+ |\n| Collaborative editing | Any modern browser |\n| CPU fallback training | Any browser (via `forceFallbackAdapter`) |\n\nChrome is the recommended browser. Firefox and Safari do not support WebContainers.\n\n---\n\n## Design System\n\nThe UI follows the **CoderClaw deep space** aesthetic — consistent across Builderforce.ai and CoderClaw:\n\n| Token | Dark | Light |\n|---|---|---|\n| `--bg-deep` | `#050810` | `#fcfeff` |\n| `--bg-surface` | `#0a0f1a` | `#ffffff` |\n| `--coral-bright` | `#4d9eff` | `#3b82f6` |\n| `--cyan-bright` | `#00e5cc` | `#008f87` |\n| `--font-display` | Clash Display | Clash Display |\n| `--font-body` | Satoshi | Satoshi |\n\nTheme persists to `localStorage('bf-theme')` with an anti-FOUC inline script applied before first paint.\n\n---\n\n## Roadmap & Gap Register\n\nPlanned milestones (including **PHASE 4 — Multi-Agent Orchestration at Scale**) and the full **Consolidated Gap Register** — 341 items (53 resolved · 288 open, grouped by revenue impact) plus archived thematic context — now live in **[ROADMAP.md](./ROADMAP.md)**, the single source of truth for planned work and deferred issues. New deferred issues are appended there.\n\n---\n\n## Cloud Agent Types\n\nBuilderforce runs agents on two execution **planes** — **On-Prem (Hosted)** and **Cloud**. There is ONE agent engine (the current version), so the Cloud plane is a single **Cloud Agent** that runs on one of **two surfaces**: a **Durable Object** or a **Node/Container**. The routing decision is a single source of truth in [cloudDispatch.ts](api/src/application/runtime/cloudDispatch.ts) (`resolveCloudSurface` / `cloudAgentTypeLabel`) and [runtimeRoutes.ts](api/src/presentation/routes/runtimeRoutes.ts) (`resolveCloudAgent`); the surface column lives on `ide_agents` (`runtime_surface` migration 0105). The engine is never read from the DB — it is always the current version.\n\n> **Cloud vs. On-Prem is a hard boundary.** A cloud agent executes **only** in the cloud (everything is Cloudflare — Worker, Durable Object, or Container). A cloud agent is **never** dispatched to a client machine. An **On-Prem (Hosted)** agent — an *agentHost*, of which many can run on one machine — runs a task only when a host is **explicitly pinned** to it. See the agent taxonomy ([[agent-types-taxonomy]]).\n\n### At a glance\n\n| Cloud Agent surface | Where it runs | Persistent shell? | Best for |\n|---|---|---|---|\n| **Cloud Agent (Durable Object)** | `durable` — `CloudRunnerDO`, one LLM step per `alarm()` tick. **Default surface.** | No (CI verifies builds) | Most cloud tasks: on-demand, no always-on compute, survives long runs |\n| **Cloud Agent (Node/Container)** | `container` — long-lived Cloudflare Container (`AgentContainerDO`) | **Yes** (`run_command`) | Very long / continuous tasks needing a real shell to install deps + run builds/tests/lint |\n| *(On-Prem Hosted — for contrast)* | Client machine (agentHost), only when pinned | Yes (the host's own machine) | BYO-machine execution; not a cloud agent |\n\n### Cloud Agent (Durable Object) — surface `durable`\n\nThe default. Runs the Claude Agent SDK tool loop fully in the cloud across Durable Object `alarm()` ticks — **one LLM step per tick**, conversation state persisted in DO storage between ticks (`CloudRunnerDO`). Inference routes through the **LLM Gateway** using the tenant's **BYO Anthropic key**.\n\n**Features**\n- One step per `alarm()` tick; each tick is a fresh Worker invocation with a fresh CPU/subrequest budget, so a multi-step run **never hits the ~30s `waitUntil` wall** that kills the interim Worker executor.\n- A cursor in `state.storage` is the idempotency/resume anchor — the loop resumes exactly where it left off.\n- Heartbeats `executions.updated_at` every tick, so the orphan reaper treats an actively-ticking run as alive and only reaps a genuinely silent one.\n- The DO surface pins the **same model** for every tick of a run.\n\n**Pros**\n- On-demand serverless — no always-on compute, nothing to keep warm.\n- Robust to long runs and eviction; the canonical, recommended cloud surface.\n- Full Claude Agent SDK loop: per-tool timeline, steering/chat, approval gates.\n\n**Cons**\n- **No shell** — it cannot run builds/tests itself; correctness is verified by CI, not by the agent before finishing.\n- Per-tick overhead (alarm scheduling, state rehydrate) makes it less efficient for a single very long, chatty session than a persistent process.\n- Requires a tenant Anthropic key wired through the Gateway.\n\n> When the `CloudRunnerDO` binding is absent there is **no fallback executor** — dispatch resolves to `unavailable` and the run fails fast with that reason. An in-request Worker executor used to be documented here as an interim fallback, but it could not survive the ~30s `waitUntil` wall on a multi-step run, so it was never selectable and has been removed: a clear \"no executor bound\" error beats a run that silently dies mid-task and gets orphan-reaped.\n\n### Cloud Agent (Node/Container) — surface `container`\n\nThe Claude Agent SDK loop running in a **persistent Node process inside a real Cloudflare Container** (`AgentContainerDO`). The container boots a small HTTP server; the DO is the Cloudflare-Containers control plane that starts/stops it and proxies the run. The container drives the loop and calls back into the Worker for every LLM step, repo telemetry, and the final PR — so the Worker stays the single source of truth for the Gateway, usage metering, and PR finalize.\n\n**Features**\n- **Real shell** (`run_command`): clone the repo, install deps, run actual builds / tests / lint, and verify before finishing.\n- Persistent process — runs continuously for very long tasks without per-tick overhead.\n- `enableInternet` for Gateway + GitHub reach from inside the container; stays warm `20m` after the last request, then sleeps to stop billing.\n- This is also the surface an **explicitly-pinned host** maps to (a long-lived runtime reached via the relay).\n\n**Pros**\n- Genuine end-to-end verification (the agent runs the build/tests itself, not just CI).\n- Best fit for long-running, continuous, or shell-heavy work.\n\n**Cons**\n- **Container infra is a future build.** Until it lands, a `container` run **falls back to the durable DO** so it still executes in the cloud — so today you do not actually get a persistent shell from this selection.\n- Heaviest/most expensive surface (always-on-ish process, warm-keep billing).\n- Same Gateway / tenant-Anthropic-key requirement as the durable surface.\n\n### How a type is selected at dispatch\n\n`resolveCloudAgent` reads the agent's `runtime_surface` from `ide_agents` (the engine is always the current version, never read); `resolveCloudSurface(agentSurface, hasExplicitHost)` then picks the surface — an explicitly-pinned host ⇒ `container`, otherwise the agent's chosen surface, defaulting to `durable`. `cloudAgentTypeLabel(surface)` produces the human label used for run attribution (`Cloud Agent (Durable Object)` / `Cloud Agent (Node/Container)`).\n\n---\n\n## LLM Surfaces\n\nBuilderforce exposes **three distinct LLM systems** — they are easy to conflate, and each has its own code path. Scope work against the right one:\n\n| # | Surface | What it is | Status | Entry point |\n|---|---------|------------|--------|-------------|\n| **A** | **LLM Gateway** | Multi-vendor hosted chat proxy (failover, cooldowns, per-tenant budgets). Powers IDE Brain chat and studio prompt-expansion. | ✅ Shipped | [api/src/application/llm/](api/src/application/llm/), [PRD](PRD-builderforce-llm-gateway.md) |\n| **B** | **Custom LLM Support** | Serve a user's fine-tuned LoRA agent to the CoderClaw CLI (`POST /api/agents/:id/chat`). | 🟡 Specced — P0 gaps open (see below) | \"## Custom LLM Support\" section below |\n| **C** | **In-IDE `llm` modality** | Build + train a custom model in the browser (dataset → WebGPU LoRA/Mamba → publish), then chat with it. | 🟢 Cloud path live; Local/Hybrid pending | [frontend/src/lib/modality.ts](frontend/src/lib/modality.ts), [LlmStudioPanel.tsx](frontend/src/components/LlmStudioPanel.tsx) |\n\nCloud inference for the in-IDE modality (C) routes through the Gateway (A). On-device **Local** and **Hybrid** inference for (C) are gated until the Mamba WGSL kernel and R2 weights land — see the Consolidated Gap Register.\n\n---\n\n## Custom LLM Support\n\n> **IDE spec reference:** `ide-architecture (1).md` in the repository root — the Builderforce.ai IDE\n> architecture document (v2.0, March 2026).\n\nThis section details every change the Builderforce.ai platform (IDE frontend +\nCloudflare Worker backend) must make to fully support custom LLMs built through the IDE —\nso that fine-tuned agents can be stored, served, versioned, and consumed by coderClaw CLI\nclients in production.\n\n### Current State vs. Required State\n\n#### What exists today\n\n| Component                             | Status | Notes                                            |\n| ------------------------------------- | ------ | ------------------------------------------------ |\n| In-browser LoRA training (WebGPU)     | ✅     | `frontend/src/lib/webgpu-trainer.ts`             |\n| Adapter storage in R2                 | ✅     | `artifacts/{projectId}/{jobId}/adapter.bin`      |\n| Workforce Registry (publish / browse) | ✅     | `POST /api/agents`, `GET /api/agents`            |\n| Agent package download                | ✅     | `GET /api/agents/:id/package` → v1.0 JSON        |\n| AI chat inference                     | ✅     | `POST /api/ai/chat` → Cloudflare AI / OpenRouter |\n| Mamba State Engine (in-browser)       | ✅     | `frontend/src/lib/mamba-engine.ts`               |\n| Agent Runtime SDK (in-browser)        | ✅     | `frontend/src/lib/agent-runtime.ts`              |\n\n#### What is missing\n\n| Gap                                             | Impact                                            | Priority |\n| ----------------------------------------------- | ------------------------------------------------- | -------- |\n| **No inference endpoint for custom agents**     | CoderClaw CLI cannot run a trained agent          | P0       |\n| **No LoRA adapter loading on inference server** | Training produces `.bin` but nothing serves it    | P0       |\n| **No `mamba_state` in DB / package**            | v2.0 agents cannot round-trip their memory        | P0       |\n| **No CLI auth token**                           | CLI has no way to call Builderforce inference API | P0       |\n| **`POST /api/ai/chat` ignores `model` field**   | Cannot route to `workforce-<id>`                  | P1       |\n| **No agent streaming inference**                | CLI needs SSE chunked responses                   | P1       |\n| **No rate limiting per API key**                | Inference endpoint open to abuse                  | P1       |\n| **No agent package v2.0**                       | Mamba state not shipped with download             | P1       |\n| **No usage tracking per agent**                 | Cannot bill or monitor custom model usage         | P2       |\n| **No model artifact versioning**                | Cannot distinguish adapter generations            | P2       |\n\n### Database Schema Changes\n\n#### `agents` table — new columns\n\n```sql\nALTER TABLE agents\n  ADD COLUMN package_version  TEXT    NOT NULL DEFAULT '1.0',\n  ADD COLUMN mamba_state      JSONB,\n  ADD COLUMN inference_mode   TEXT    NOT NULL DEFAULT 'base',\n  --   'base'    → use base_model directly (no adapter)\n  --   'lora'    → load LoRA adapter from r2_artifact_key\n  --   'hybrid'  → LoRA + Mamba state injection\n  ADD COLUMN request_count    INTEGER NOT NULL DEFAULT 0,\n  ADD COLUMN last_used_at     TIMESTAMPTZ;\n```\n\n#### New `cli_api_keys` table\n\n```sql\nCREATE TABLE cli_api_keys (\n  id            TEXT PRIMARY KEY,\n  user_id       TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n  key_hash      TEXT NOT NULL UNIQUE,\n  label         TEXT,\n  scopes        TEXT NOT NULL DEFAULT 'inference:read',\n  last_used_at  TIMESTAMPTZ,\n  request_count INTEGER NOT NULL DEFAULT 0,\n  rate_limit    INTEGER NOT NULL DEFAULT 1000,\n  created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n  revoked_at    TIMESTAMPTZ\n);\n\nCREATE INDEX cli_api_keys_user_idx ON cli_api_keys(user_id);\nCREATE INDEX cli_api_keys_hash_idx ON cli_api_keys(key_hash);\n```\n\n#### New `agent_inference_logs` table\n\n```sql\nCREATE TABLE agent_inference_logs (\n  id              TEXT PRIMARY KEY,\n  agent_id        TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,\n  cli_key_id      TEXT REFERENCES cli_api_keys(id) ON DELETE SET NULL,\n  model_ref       TEXT NOT NULL,\n  prompt_tokens   INTEGER,\n  completion_tokens INTEGER,\n  latency_ms      INTEGER,\n  status          TEXT NOT NULL,\n  error_message   TEXT,\n  created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE INDEX agent_inference_logs_agent_idx ON agent_inference_logs(agent_id);\nCREATE INDEX agent_inference_logs_key_idx   ON agent_inference_logs(cli_key_id);\n```\n\n### New Worker Routes\n\n#### `POST /api/agents/:id/chat` — Agent Inference\n\nAccepts an OpenAI-compatible chat completion request, resolves the age",
  "bytes": 60000,
  "sha": "1593b187305267e964142068464293bbcb2b34cc17ea7144672e4efbc9b36158",
  "repo_slug": "seanhogg/builderforce.ai",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_seanhogg_builderforce_d5f9ec0d/readme"
}