Skip to main content

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.

Server configuration

okto-pulse serve is one Python process running two uvicorn listeners — the API + Web UI on 8100 and the MCP server on 8101 (80-pulse-feature-inventory.md:213–215). Configuration is read from environment variables and an optional .env file via pydantic-settings. Every field on CoreSettings accepts an env-var override using its uppercase field name (80-pulse-feature-inventory.md:178–180). This page covers the runtime knobs you actually need to touch: ports, bind hosts, CORS, logging, and worker tuning. For the full env-var reference, see Environment variables. For where Pulse stores data, see Storage paths.

Ports

Two listeners, two defaults.
ListenerDefault portSource
API + Web UI8100DEFAULT_API_PORT in cli.py:20 (inventory:213)
MCP server8101DEFAULT_MCP_PORT in cli.py:21 (inventory:214)

Override on the command line

okto-pulse serve --api-port 9100 --mcp-port 9101 --accept-terms
--api-port writes OKTO_PULSE_PORT and --mcp-port writes OKTO_PULSE_MCP_PORT into the process environment before importing okto_pulse.community.main — that module evaluates app = create_community_app() at import time and bakes the port values into /config.js for the Web UI (inventory:53–60). Setting them later, after the import, is too late.

Override via environment

export OKTO_PULSE_PORT=9100
export OKTO_PULSE_MCP_PORT=9101
okto-pulse serve --accept-terms
Okto Pulse listening on:
  API + UI  http://127.0.0.1:9100
  MCP       http://127.0.0.1:9101/mcp
Both ports must be free on the bind host before serve starts. Run okto-pulse status to confirm the current binding (inventory:63–80).

Bind addresses

Pulse separates the two listeners’ bind hosts on purpose: the API (port 8100) defaults to loopback because it serves the Web UI and admin endpoints, while the MCP server (port 8101) needs to be reachable from the agent.
FieldDefaultEnv varNotes
host127.0.0.1HOSTAPI + Web UI bind. Loopback only by design (CoreSettings.host, inventory:761)
MCP host0.0.0.0 (Docker) / 127.0.0.1 (local)MCP_HOSTRead at runtime in community/main.py (since v0.1.12) and in core/mcp/server.py. Docker images sed-patch the binding line so MCP_HOST takes effect there too.
Both listeners bind 127.0.0.1. Reachable only from the same machine. This is the safe default — your agent connects via http://localhost:8101/mcp?api_key=....
okto-pulse serve --accept-terms
INFO  uvicorn  Started server process [12345]
INFO  uvicorn  Uvicorn running on http://127.0.0.1:8100
INFO  okto_pulse.mcp  MCP listening on http://127.0.0.1:8101/mcp
Never bind 0.0.0.0 on a public network without a firewall. The MCP API key is the only thing between an attacker and full board control. Use 127.0.0.1 for local work, a private network plus firewall for shared workstations, and a reverse proxy with TLS termination (Caddy, nginx, Traefik) if you must expose Pulse beyond the host.

CORS

The API enforces CORS on the Web UI and any third-party browser client.
FieldDefault (core)Default (community)Env var
cors_originshttp://localhost:5173,http://localhost:3000*CORS_ORIGINS
The community edition overrides the core default to * so the bundled Web UI works regardless of how you reach it (inventory:765, inventory:191). Override per environment by setting CORS_ORIGINS to a comma-separated list:
CORS_ORIGINS="http://localhost:5173,https://pulse.internal.example.com" \
  okto-pulse serve --accept-terms
INFO  okto_pulse.api  CORS allow_origins=['http://localhost:5173', 'https://pulse.internal.example.com']
CORS is enforced by the API, not the MCP server. MCP requests are server-to-server and not subject to CORS — the API key is the access control there.

Logging

Pulse uses Python’s standard logging module. Logs stream to stdout/stderr by default.

Log level

Set via DEBUG=true or by configuring logging directly with standard Python tooling. There is no dedicated LOG_LEVEL env var; DEBUG toggles INFODEBUG for okto_pulse.* loggers.
Env varDefaultEffect
DEBUGfalseWhen true, raises okto_pulse.* loggers from INFO to DEBUG and surfaces SQLAlchemy echo on the API. Source: CoreSettings.debug (inventory:753)
ENVIRONMENTdevelopmentFree-form label, used in startup banners and exposed at GET /health. Source: CoreSettings.environment (inventory:754)
DEBUG=true okto-pulse serve --accept-terms
DEBUG  okto_pulse.api  request POST /api/v1/cards
DEBUG  sqlalchemy.engine  BEGIN (implicit)
DEBUG  sqlalchemy.engine  SELECT cards.id, cards.title FROM cards WHERE ...
INFO   okto_pulse.mcp  tool call okto_pulse_create_card → ok (32ms)

Log destinations

By default, logs go to:
  • stdout for INFO and below
  • stderr for WARNING, ERROR, CRITICAL
  • No file logging — the process does not write a log file. Capture stdout/stderr if you need persistence.
For a containerized deployment, let the container runtime capture the streams:
docker logs -f okto-pulse > pulse.log 2>&1
For a systemd unit, journald captures both streams automatically:
journalctl -u okto-pulse.service -f

MCP call tracing

Independent of the standard logger, Pulse can record every MCP tool call to a JSONL trace.
Env varDefaultPurpose
MCP_TRACE_ENABLEDunsetSet to 1 (or true/yes) to enable tracing. Source: core/mcp/trace_middleware.py:49
MCP_TRACE_DIR${KG_BASE_DIR}/mcp_tracesOutput directory; one session_*.jsonl per MCP session. Source: core/mcp/trace_middleware.py:13
MCP_TRACE_ENABLED=1 okto-pulse serve --accept-terms
$ ls ~/.okto-pulse/mcp_traces/
session_2026-05-07T14-12-03_a3f9.jsonl
$ head -1 ~/.okto-pulse/mcp_traces/session_2026-05-07T14-12-03_a3f9.jsonl
{"ts":"2026-05-07T14:12:04Z","tool":"okto_pulse_get_active_board","args":{},"result_summary":"ok","ms":8}
Use traces to debug tool selection or to replay sessions against the MCP test harness. See Troubleshooting for replay tooling.

Worker tuning (uvicorn)

Pulse runs with a single uvicorn worker, by default and by design. okto-pulse serve exposes --api-port, --mcp-port, and --accept-terms only — there is no --workers flag (okto-pulse/src/okto_pulse/community/cli.py:223–276 / inventory:53–60). The KG consolidation pipeline, the queue scheduler, and the embedded LadybugDB graph all assume one writer per process; spawning multiple uvicorn workers would create concurrent writers, lock contention, and split queue state.
Do not bypass the CLI to run Pulse with multiple uvicorn workers. The single-worker model is required for KG correctness — concurrent writers will hit the LadybugDB advisory lock and dead-letter queue entries. Scale by running multiple Pulse instances on different ports against different data directories instead — one Pulse process per board cluster.
What you can tune:
Concurrency surfaceSettingDefaultRange
KG consolidation workers (asyncio tasks inside the single process)KG_QUEUE_MAX_CONCURRENT_WORKERS41–16
KG queue poll intervalKG_QUEUE_MIN_INTERVAL_MS1000–1000 ms
LadybugDB connection poolKG_CONNECTION_POOL_SIZE81–32
LadybugDB buffer pool (memory)KG_KUZU_BUFFER_POOL_MB25616–512 MB
Sources: CoreSettings fields kg_queue_max_concurrent_workers, kg_queue_min_interval_ms, kg_connection_pool_size, kg_kuzu_buffer_pool_mb (inventory:780–784).
The KG_KUZU_* and kg_kuzu_* field names are legacy — Pulse uses LadybugDB (the Kùzu-derived engine) under the hood since 2026-05-03. The variable names are kept stable for backward compatibility; the underlying engine is LadybugDB.
KG_QUEUE_* and KG_DECAY_TICK_* fields are hot-reloadable. APScheduler re-reads them with a 5-second debounce and kg_decay_tick_* can be updated through PUT /settings/runtime without a restart (inventory:790–793).

Reverse proxy notes

If you front Pulse with Caddy, nginx, or Traefik:
  • Bind Pulse to 127.0.0.1 and let the proxy terminate TLS and forward.
  • Set MCP_HOST=127.0.0.1 to keep the MCP listener loopback-only behind the proxy.
  • Forward Host, X-Forwarded-For, and X-Forwarded-Proto so the API renders absolute URLs correctly.
  • WebSockets are not used by the API or MCP — plain HTTP/1.1 is sufficient. Streamable HTTP responses (MCP SSE) require the proxy to disable response buffering on /mcp.
pulse.internal.example.com {
    @mcp path /mcp*
    handle @mcp {
        reverse_proxy 127.0.0.1:8101 {
            flush_interval -1
        }
    }
    handle {
        reverse_proxy 127.0.0.1:8100
    }
}

Verifying the running config

okto-pulse status reads the SQLite metadata and probes the configured ports:
okto-pulse status
Okto Pulse status
─────────────────
Data dir:     /Users/you/.okto-pulse
Database:     /Users/you/.okto-pulse/data/pulse.db (412 KB)
Boards:       1   Cards: 23   Specs: 4   Agents: 2
API server:   running on 127.0.0.1:8100
MCP server:   running on 127.0.0.1:8101
Source: cli.py:567–614 (cmd_status) (inventory:67–78). The 198 MCP tools exposed by the running process are listed in the MCP reference.

Storage paths

Where Pulse keeps its database, attachments, and per-board knowledge graphs.

Environment variables

Full reference of every CoreSettings field and its env-var name.

Docker install

Run Pulse in a container with the right HOST and MCP_HOST defaults.

MCP setup

Connect Claude Code, Cursor, Cline, Windsurf, or Codex to your board.
Last modified on May 8, 2026