Get started

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.sh first: 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, socat and rg are on PATH. See Sandbox execution.

The five steps

  1. 1

    Start the ops MCP server

    npm install
    listens on http://localhost:8940/mcp
    npm run dev:mcp

    A read-only view of the estate is served alongside it at /estate/state, /estate/audit and /estate/tools.

  2. 2

    Start the harness

    opens at http://localhost:8790
    npx @truefoundry/trueforge@latest
  3. 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 doctor reports the local fallback is not active. Otherwise skip entirely.
    • Settings → Connectors → Add MCP Server — name it sentinel-ops, URL http://localhost:8940/mcp, no auth. The name must match the agent spec.
    • Settings → Skills — register this repository, ref your branch, path skills/incident-response.

    Or all three at once, idempotently:

    reads .env; never registers a provider without a key; never touches an existing resource
    npm run provision
  4. 4

    Create the agent

    Take agent/sentinel-agent.agent.json, replace REPLACE_WITH_YOUR_MODEL with 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. 5

    Preflight

    npm run doctor
    npm 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'registered
    Ready 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/list on 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

127.0.0.1:3000 — the operator console, and these docs
npm run dev:web

Every script, and what it does

CommandDoes
npm run doctorPreflight: config, connectivity, live annotation check.
npm run provisionRegister model provider + connector + skill over the API.
npm run prove:gateApproval-gate conformance suite — Gate Prover
npm run dev:mcpOps MCP server, watch mode.
npm run dev:webNext.js UI on 127.0.0.1:3000.
npm testFull suite — 149 tests (72 MCP + 54 UI + 23 script/oracle).
npm run typechecktsc --noEmit, strict, across both workspaces.
npm run checkBiome lint + format, writing fixes.
npm run cibiome 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:

for SENTINEL_UI_TOKEN, OPS_MCP_TOKEN, OPS_LAB_TOKEN
openssl rand -hex 24

Confirm the safety model before you trust it

the ones that matter are in apps/mcp-server/src/tools/registry.test.ts
npm test
annotations, on the wire
curl -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":{}}'