Skip to main content
Docker Compose runs the full fracta stack in containers: control plane, gateway, strategy runner, Postgres, FalkorDB. Your machine runs only a thin client. MCP backend servers (Elastic, Vendor, your own) are added by extending the scaffolded compose file.
Your machine                         Docker Compose stack
┌──────────────────┐                ┌──────────────────────────┐
│ Claude / Codex / │                │ controlplane    (:19090) │
│ OpenCode         │                │ gateway         (:8080)  │
│   └─ fracta serve ─┼──── HTTP ────>│ strategy-runner          │
│                  │                │ postgres        (:5432)  │
│ fracta spawn (CLI)│                │ falkordb       (:16379)  │
│ fracta list  (CLI)│                │ + your MCP backends      │
└──────────────────┘                └──────────────────────────┘

Prerequisites

  • fracta CLI installed and on PATH (fracta --help works). See installation.
  • Docker with Compose V2 — docker compose version.
  • A git repository to scaffold into. fracta init runs in your own project root.
You do not need runtime CLIs (claude, codex, opencode) installed on your host — they’re bundled in the fracta image.

1. Initialize fracta in your project

From the root of any git repository:
fracta init --scaffold docker-compose
You’ll see:
Fracta initialized successfully.
  scaffold: docker-compose
  source:   embedded (fracta vX.Y.Z)
  files:    N written, 0 skipped
This drops the docker-compose scaffold:
your-project/
├── fracta.yaml                              # thin-client config
├── .fracta/                                 # gitignored runtime state (logs)
└── deployment/
    ├── docker-compose.yml                   # full stack: falkordb, postgres, controlplane, gateway, strategy-runner
    ├── configs/
    │   ├── controlplane.yaml                # server-side config inside the controlplane container
    │   └── gateway.yaml                     # gateway config
    └── auth-helpers/
        ├── README.md
        └── fetch-token-example              # 0755 generic helper template; edit before use
fracta.yaml and everything under deployment/ are yours to edit.

2. Set up auth helpers

The scaffolded deployment/auth-helpers/fetch-token-example is a deliberately non-functional template that fails loudly until you edit it. Open the file — its header comments include reference snippets for AWS Bedrock STS, Vertex AI via gcloud, mounted Anthropic API keys, and custom HTTP token proxies. Pick the one matching your provider. For example, for AWS Bedrock STS:
cat > deployment/auth-helpers/fetch-bedrock-token <<'EOF'
#!/bin/sh
exec aws bedrock get-bearer-token \
  --region "${AWS_REGION:-us-east-1}" \
  --query 'token' --output text
EOF
chmod +x deployment/auth-helpers/fetch-bedrock-token
Update deployment/configs/controlplane.yaml to reference your helper. The default scaffold ships an example profile pointing at fetch-token-example; replace it with a bedrock profile (or whatever name fits) pointing at your script. See the credential pipeline guide for the full profile schema. The compose file bind-mounts ./deployment/auth-helpers/ into every fracta service container at /opt/fracta/auth-helpers/, so resolver command: references find your helpers on PATH inside the container.

3. Start the stack

docker compose -f deployment/docker-compose.yml up -d
Verify all services are healthy:
docker compose -f deployment/docker-compose.yml ps
You should see five services running: falkordb, postgres, controlplane, gateway, strategy-runner.

Secret injection

Compose interpolates ${VAR} from your environment, so any secret manager that sets env vars works. For 1Password:
op run --env-file .op-env -- docker compose -f deployment/docker-compose.yml up -d
For Doppler:
doppler run -- docker compose -f deployment/docker-compose.yml up -d
Use this for any host-side secrets the compose stack needs (database passwords, API keys for MCP backends you add, etc.).

4. Wire fracta into your AI CLI

The scaffolded fracta.yaml points at http://localhost:19090 — the host-mapped port for the compose controlplane container. Your AI CLI runs fracta serve from your project root, which reads ./fracta.yaml. Claude Code (.mcp.json at the project root):
{
  "mcpServers": {
    "fracta": {
      "command": "fracta",
      "args": ["serve"]
    }
  }
}
Codex (.codex/config.toml):
[mcp_servers.fracta]
command = "fracta"
args = ["serve"]
If you need to inject secrets into the host-side fracta serve, wrap it the same way you wrap docker compose up.

5. Connect and verify

Restart Claude Code or run /mcp to reconnect MCP servers. The thin client connects to localhost:19090. You should see fracta tools: fracta_spawn, fracta_list, graph_query, etc. If you’ve added MCP backend services to deployment/docker-compose.yml, you’ll also see their tools.

6. Spawn your first agent

From the CLI:
fracta spawn \
  --task hello-compose \
  --contract "Say hello and list what MCP tools you can see"
From within Claude Code (via MCP):
fracta_spawn(task="hello-compose", contract="Say hello and list what MCP tools you can see")
Check status and output:
fracta list
fracta peek --name hello-compose
Or via MCP: fracta_list() and fracta_peek(name="hello-compose"). Note: Docker Compose uses DirectoryWorkspace, not git worktrees. Agents work in directories under /workspace/agents/<task>. Git merge semantics are not available — for git-based workflows, use local process mode.

7. View logs

docker compose -f deployment/docker-compose.yml logs                   # tail all
docker compose -f deployment/docker-compose.yml logs controlplane      # specific service
docker compose -f deployment/docker-compose.yml logs gateway

8. Stop and clean up

docker compose -f deployment/docker-compose.yml down
To also remove persistent volumes (Postgres data, FalkorDB data):
docker compose -f deployment/docker-compose.yml down -v

Adding MCP backend services

The scaffolded deployment/docker-compose.yml ships only the fracta core. Add MCP backend services by editing the compose file. For example, to add Elasticsearch MCP:
services:
  # ...existing services...

  elastic-mcp:
    image: docker.elastic.co/mcp/elasticsearch:latest
    command: ["http", "--address", "0.0.0.0:8000", "--sse"]
    environment:
      ES_URL: "${ELASTIC_URL}"
      ES_API_KEY: "${ELASTIC_API_KEY}"
Then reference it from deployment/configs/gateway.yaml:
mcp_servers:
  servers:
    elastic:
      remote:
        url: http://elastic-mcp:8000/mcp
        transport: streamable-http
Restart the gateway container to pick up the change:
docker compose -f deployment/docker-compose.yml restart gateway

What differs from local process

Local ProcessDocker Compose
Control planeHost daemon (:9090)Container (:19090 on host)
GatewayDaemon subprocess (:8080)Container (:8080)
StateSQLitePostgres
QueueIn-memoryPostgres
AgentsHost subprocessesContainer subprocesses
WorkspaceGit worktreesDirectories (no git merge)
MCP backendsHost subprocessesContainer HTTP
LLM authHost command (resolved on host PATH)Container command (resolved at /opt/fracta/auth-helpers/)
Secret injectionWraps fracta serveWraps docker compose up
The client attachment is identical: both use RemoteControlPlaneClient over HTTP.

Strategy runner gateway plumbing

Strategies that call MCP tools inline (ctx.mcp.call_tool(...)) require gateway access from the runner. Since v0.5.2 the Compose scaffold ships this wired by default:
  • deployment/configs/gateway.yaml declares strategy.gateway_access: true — so strategy_run invocations include the gateway URL and the calling agent’s task in the per-request payload.
  • The strategy-runner service in deployment/docker-compose.yml boots with --gateway-url http://gateway:8080 --agent-task default, providing a fallback gateway connection for strategies that need one before any per-request URL arrives.
If you author a strategy that calls ctx.mcp.call_tool(), declare it in contract.yaml:
requires:
  graph: true
  mcp: true   # runner refuses to start if ctx.mcp would be None

Next steps