> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oktolabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker

> Run Okto Pulse in a container. Signed image, pre-baked model, persistent volume. MCP server reachable from the host out of the box.

# Docker install

The official image ships from GitHub Container Registry with a pre-baked embedding model, Sigstore keyless signatures, SLSA provenance, and a CycloneDX SBOM. No first-run download. No account required.

***

## Pull and run

```bash theme={null}
docker run -d \\
  --name okto-pulse \\
  -p 127.0.0.1:8100:8100 \\
  -p 127.0.0.1:8101:8101 \\
  -e HOST=0.0.0.0 \\
  -e MCP_HOST=0.0.0.0 \\
  -e DATA_DIR=/data \\
  -e KG_BASE_DIR=/data \\
  -v okto-pulse-data:/data \\
  ghcr.io/oktolabsai/okto-pulse:latest
```

Open `http://localhost:8100` once the container starts. The board is ready.

***

## Why `MCP_HOST=0.0.0.0` is required

<Warning>
  Without `MCP_HOST=0.0.0.0`, the MCP server binds to `127.0.0.1` **inside** the container — a loopback address unreachable from your host even with `-p 8101:8101` published. Your agent will time out trying to connect.

  Always set `MCP_HOST=0.0.0.0` when running in Docker. The published port binding (`127.0.0.1:8101:8101`) ensures the MCP port is visible only to your machine, not your LAN — so setting `0.0.0.0` inside the container is safe.
</Warning>

The same applies to `HOST=0.0.0.0` for the web board and API on port 8100.

***

## Connect your agent

After the container starts, generate `.mcp.json` and copy it to your project directory:

```bash theme={null}
docker exec okto-pulse okto-pulse init --agents
docker cp okto-pulse:/app/.mcp.json ./.mcp.json
```

Add `.mcp.json` to `.gitignore` — it contains a scoped agent API key.

To generate config for one agent only (Claude Code, for example):

```bash theme={null}
docker exec okto-pulse okto-pulse init --agents claude
docker cp okto-pulse:/app/.mcp.json ./.mcp.json
```

Get the API key directly if you need it for manual MCP client config:

```bash theme={null}
docker exec okto-pulse okto-pulse api-key
```

***

## Environment variables

| Variable            | Container default  | Purpose                                                                              |
| ------------------- | ------------------ | ------------------------------------------------------------------------------------ |
| `HOST`              | `0.0.0.0`          | API + UI uvicorn bind host. Must be `0.0.0.0` inside a container.                    |
| `MCP_HOST`          | `0.0.0.0`          | MCP uvicorn bind host. Must be `0.0.0.0` inside a container.                         |
| `DATA_DIR`          | `/data`            | Root for the SQLite database and uploads. Mount a volume here.                       |
| `KG_BASE_DIR`       | `/data`            | Root for per-board knowledge graphs. Set to the same path as `DATA_DIR`.             |
| `HF_HOME`           | `/opt/hf-cache`    | Sentence-transformers cache. Pre-warmed at build time — do not mount over this path. |
| `MCP_TRACE_ENABLED` | unset              | Set to `1` to record every MCP tool call to `${MCP_TRACE_DIR}/session_*.jsonl`.      |
| `MCP_TRACE_DIR`     | `/data/mcp_traces` | Trace output directory when `MCP_TRACE_ENABLED=1`.                                   |

***

## Data persistence

The container writes all state to `/data`:

```text theme={null}
/data/
  data/pulse.db            SQLite database (boards, specs, cards, decisions)
  boards/{id}/graph.lbug   per-board knowledge graph
  uploads/                 card file attachments
  global/discovery.lbug    cross-board discovery index
  mcp_traces/              MCP call traces (when MCP_TRACE_ENABLED=1)
```

Use a **named volume** (survives container replacement):

```bash theme={null}
docker volume create okto-pulse-data
docker run -d \\
  --name okto-pulse \\
  -p 127.0.0.1:8100:8100 \\
  -p 127.0.0.1:8101:8101 \\
  -e HOST=0.0.0.0 \\
  -e MCP_HOST=0.0.0.0 \\
  -e DATA_DIR=/data \\
  -e KG_BASE_DIR=/data \\
  -v okto-pulse-data:/data \\
  ghcr.io/oktolabsai/okto-pulse:latest
```

Or a **host path** (easier to inspect and back up):

```bash theme={null}
docker run -d \\
  --name okto-pulse \\
  -p 127.0.0.1:8100:8100 \\
  -p 127.0.0.1:8101:8101 \\
  -e HOST=0.0.0.0 \\
  -e MCP_HOST=0.0.0.0 \\
  -e DATA_DIR=/data \\
  -e KG_BASE_DIR=/data \\
  -v /your/host/path:/data \\
  ghcr.io/oktolabsai/okto-pulse:latest
```

<Warning>
  Do not mount over `/opt/hf-cache`. The embedding model is pre-baked into the image and the container starts offline-capable. Mounting over it forces a re-download.
</Warning>

***

## Docker Compose

Two compose files ship with the `okto-pulse` repo.

### Pinned release (recommended)

`docker-compose.prod.yml` installs a pinned version from PyPI. Clone only the `okto-pulse` repo — no sibling repo needed.

```bash theme={null}
git clone https://github.com/OktoLabsAI/okto-pulse
cd okto-pulse
docker compose -f docker-compose.prod.yml build
docker compose -f docker-compose.prod.yml up -d
docker compose -f docker-compose.prod.yml logs -f
```

Export `.mcp.json` after first boot:

```bash theme={null}
docker compose -f docker-compose.prod.yml exec okto-pulse okto-pulse init --agents
docker compose -f docker-compose.prod.yml cp okto-pulse:/app/.mcp.json ./.mcp.json
```

### Build from source

`docker-compose.yml` builds wheels from local source. Use this when modifying `okto-pulse-core` or `okto-pulse`.

Both repos must be cloned as siblings:

```text theme={null}
OktoLabsAI/
  okto-pulse/
  okto-pulse-core/
```

```bash theme={null}
cd okto-pulse
docker compose build
docker compose up -d
docker compose logs -f
```

Export `.mcp.json`:

```bash theme={null}
docker compose exec okto-pulse okto-pulse init --agents
docker compose cp okto-pulse:/app/.mcp.json ./.mcp.json
```

***

## LAN access

Both compose files bind to `127.0.0.1` by default — the container is reachable from your machine only. To allow LAN access, change the `ports` mapping in the compose file:

```yaml theme={null}
ports:
  - "0.0.0.0:8100:8100"
  - "0.0.0.0:8101:8101"
```

Put the host behind a reverse proxy with authentication before exposing to a LAN. The MCP API key is the only auth layer Pulse provides.

***

## Updating

```bash theme={null}
docker pull ghcr.io/oktolabsai/okto-pulse:latest
docker stop okto-pulse && docker rm okto-pulse
# re-run the same docker run command — the named volume persists
```

With compose:

```bash theme={null}
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
```

***

## Verify

```bash theme={null}
docker exec okto-pulse okto-pulse status
curl -s http://localhost:8100/api/v1/kg/settings
```

***

## Next steps

<CardGroup cols={2}>
  <Card title="Connect your agent" href="/mcp-setup">
    Wire Claude Code, Cursor, Cline, or Windsurf to the running MCP server.
  </Card>

  <Card title="First workflow" href="/first-board">
    Ideation → spec → cards in a single session.
  </Card>
</CardGroup>
