Run it locally
A run needs five things configured across two processes and the harness UI. Any one missing surfaces as a 422 or a 403 mid-run, worded from the harness's point of view rather than yours.
So the first useful command is not dev, it is doctor — which checks all five up front and tells you which one is missing and how to fix it.
Prerequisites
- Node.js 22.14+ — the harness’s floor. Under WSL, source
scripts/wsl-node.shfirst: it activates the right version and refuses to continue on a Windows interop Node, which is otherwise picked up silently. - A model provider key — OpenAI, Anthropic, Gemini, OpenRouter, or any OpenAI-compatible endpoint.
- No Daytona key, on Linux or macOS. TrueForge’s local sandbox provider activates once
bwrap,socatandrgare onPATH. See Sandbox execution.
The five steps
- 1
Start the ops MCP server
npm installlistens on http://localhost:8940/mcpnpm run dev:mcpA read-only view of the estate is served alongside it at
/estate/state,/estate/auditand/estate/tools. - 2
Start the harness
opens at http://localhost:8790npx @truefoundry/trueforge@latest - 3
Configure it — or let provision do it
By hand, in the TrueForge UI:
- Settings → Models — add your provider and key.
- Settings → Sandbox providers — only if
doctorreports the local fallback is not active. Otherwise skip entirely. - Settings → Connectors → Add MCP Server — name it
sentinel-ops, URLhttp://localhost:8940/mcp, no auth. The name must match the agent spec. - Settings → Skills — register this repository,
refyour branch,pathskills/incident-response.
Or all three at once, idempotently:
reads .env; never registers a provider without a key; never touches an existing resourcenpm run provision - 4
Create the agent
Take
agent/sentinel-agent.agent.json, replaceREPLACE_WITH_YOUR_MODELwith your configured model, and create the agent.agent spec"model": "anthropic/claude-sonnet-4-6", "require_approval_for_tools": [ "@write", "@destructive", "rollback_deployment", // literal names too — belt and braces "restart_service" ] - 5
Preflight
npm run doctornpm run doctor✓.env filepresent✓SENTINEL_MODELopenrouter/claude-sonnet-4-5✓SENTINEL_UI_TOKENset (48 chars)✓ops MCP serversentinel-ops v0.1.0 on http://127.0.0.1:8940✓tool annotations10 tools, 0 unannotated, 3 approval-gated✓harnessreachable at http://localhost:8790✓model provideropenrouter✓sandbox providernone configured — local fallback active✓connector 'sentinel-ops'registered✓skill 'incident-response'registeredReady to run. 1 warning above.It exits non-zero when anything is blocking, so it composes into a script. And it re-verifies the safety model live: it calls
tools/liston the running ops server and fails if any tool is unannotated, because an unannotated tool is exempt from approval — the one failure mode that looks like success.
Then start the console
npm run dev:webEvery script, and what it does
| Command | Does |
|---|---|
npm run doctor | Preflight: config, connectivity, live annotation check. |
npm run provision | Register model provider + connector + skill over the API. |
npm run prove:gate | Approval-gate conformance suite — Gate Prover |
npm run dev:mcp | Ops MCP server, watch mode. |
npm run dev:web | Next.js UI on 127.0.0.1:3000. |
npm test | Full suite — 149 tests (72 MCP + 54 UI + 23 script/oracle). |
npm run typecheck | tsc --noEmit, strict, across both workspaces. |
npm run check | Biome lint + format, writing fixes. |
npm run ci | biome ci + typecheck + tests — what CI runs. |
Environment
See .env.example. A provider key is the one real external credential this project ever handles, and only provision reads it — once, to hand it to the harness, never again. Generate your own tokens for the rest:
openssl rand -hex 24Confirm the safety model before you trust it
npm testcurl -s -X POST http://localhost:8940/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'