Skip to content

Configuration

What you'll do: look up every OCCAM_* environment variable the host and operator scripts read.

Core host variables live under src/FFOccamMcp.Core/; doctor / install helpers under scripts/ are listed where operators need them. CLI flags override env where noted in Transports.


Required for production

Variable Purpose
OCCAM_HOME Install root; resolves worker scripts. Without it: workers_unavailable

Paths and workers

Variable Default Purpose
OCCAM_HTTP_EXTRACT_SCRIPT auto Override HTTP worker entry (pair with browser override)
OCCAM_BROWSER_EXTRACT_SCRIPT auto Override browser worker entry
OCCAM_NODE_BIN stamped by launcher from install record / process.execPath; else {OCCAM_HOME}/bin/node / well-known paths / PATH Absolute Node used to spawn all workers. Advanced override only — GUI MCP host configs should not set this. Install writes {OCCAM_HOME}/runtime/node-bin; scripts/launch-mcp-host.mjs and occam-wrapper.sh stamp OCCAM_NODE_BIN for Core.
OCCAM_DOM_SKELETON_SCRIPT auto Override DOM skeleton script for heal
OCCAM_FORCE_DOTNET_RUN off Launcher uses dotnet run instead of AOT binary
OCCAM_WORKERS_FORCE_INSTALL off Doctor / occam install-workers: force npm ci/npm install even when HTTP worker markers already resolve. Repair empty or corrupt workers/node_modules without deleting the tree by hand

Doctor and occam install-workers verify that @mozilla/readability, jsdom, turndown, and undici resolve from workers/http-extract — a present-but-empty node_modules directory is treated as broken. Prefer npm ci when workers/package-lock.json is present. Playwright Chromium is not part of this repair; use occam install-workers --with-browser or occam install-browser when the page needs a browser.


Session profiles

Variable Default Purpose
OCCAM_SESSIONS_ROOT ~/.occam/sessions/ Directory for <id>.json session profiles
OCCAM_ALLOW_PRIVATE_URLS off 1 allows localhost/private URLs (local dev only)
OCCAM_REQUEST_HEADERS_FILE none JSON file of extra HTTP headers for workers

Export profiles: node scripts/occam-session.mjs export-state --profile <id>.

After a browser extract, Occam may replay the same URL once over HTTP with first-party cookies harvested from that navigation. That harvest is in-call only (temp headers file, deleted after the retry). It is not a session profile, is not persisted, and cookie values are never written to receipts or the MCP response.


Browser and Playwright

Variable Default Purpose
PLAYWRIGHT_BROWSERS_PATH Playwright cache Standard browser cache path
OCCAM_PLAYWRIGHT_BROWSERS_PATH — Occam-specific override
OCCAM_BROWSER_CHANNEL auto chrome | msedge | chromium | unset. Unset (default): prefer an installed system Chrome/Edge when found, else bundled Playwright Chromium. Set chromium to force the bundled browser.
OCCAM_BROWSER_PREFER_SYSTEM on When OCCAM_BROWSER_CHANNEL is unset, prefer system Chrome/Edge if present. Set 0 to always use bundled Chromium unless a channel/path is explicit.
OCCAM_BROWSER_AUTOINSTALL on On first genuine browser need with no browser installed, occam provisions the user-level Chromium itself and reports browser_provisioned. Set 0 to instead return a typed browser_required failure to run manually. System libraries (root) are never auto-installed. Auto-provision is skipped when a system browser is configured or auto-detected.
OCCAM_BROWSER_EXECUTABLE_PATH — Absolute browser binary
OCCAM_CHROME_PATH — Alias for executable path
OCCAM_BROWSER_PROFILE shared shared/daemon/lean = daemon pool; isolated/parallel = one-shot
OCCAM_BROWSER_DAEMON on 0 forces isolated one-shot extracts
OCCAM_BROWSER_POOL_SIZE 1 Daemon slots (1–8)
OCCAM_BROWSER_POOL_BASE_PORT 39217 Base port for pool slot 0
OCCAM_BROWSER_DAEMON_PORT 39217 Legacy port when pool size = 1
OCCAM_BROWSER_MAX_PARALLEL 2 Max concurrent browser extracts (1–16)
OCCAM_BROWSER_TIMEOUT_MS 60000 Per-extract timeout (15k–180k)
OCCAM_BROWSER_DAEMON_SCRIPT auto Override browser-daemon.mjs
OCCAM_BROWSER_DAEMON_IDLE_TTL_MS 120000 Idle shutdown; 0 = always warm
OCCAM_BROWSER_NODE_MAX_OLD_SPACE_MB — Node heap cap for browser worker
OCCAM_NODE_MAX_OLD_SPACE_MB — Node heap cap for HTTP worker

HTTP daemon

Variable Default Purpose
OCCAM_HTTP_DAEMON on 0 = one-shot HTTP worker per request
OCCAM_HTTP_DAEMON_PORT 39218 Daemon listen port
OCCAM_HTTP_DAEMON_SCRIPT auto Override http-daemon.mjs
OCCAM_HTTP_DAEMON_IDLE_TTL_MS 120000 Idle shutdown
OCCAM_HTTP_DAEMON_PREWARM on Background warm at host startup

Response size and politeness

Variable Default Purpose
OCCAM_MAX_RESPONSE_BYTES 8388608 (8 MiB) HTTP body cap (64 KiB–16 MiB)
OCCAM_HTTP_OVERSIZE_MODE fail fail or partial (truncated markdown)
OCCAM_MAX_PDF_BYTES 16777216 (16 MiB) PDF body cap
OCCAM_RESPECT_ROBOTS off 1 enforces robots.txt disallow
OCCAM_HOST_THROTTLE_MS 0 Per-host minimum interval between fetches
OCCAM_ROBOTS_TIMEOUT_MS 10000 robots.txt fetch timeout

Transcode cache (opt-in)

Variable Default Purpose
OCCAM_CACHE_DIR {TEMP}/occam-cache In-memory/disk cache dir for cache_ttl_s hits

Receipts

Variable Default Purpose
OCCAM_RECEIPTS on off/0/false disables signing
OCCAM_KEYS_ROOT ~/.occam/keys/ ECDSA P-256 key directory
OCCAM_TIME_ANCHOR off 1 requests RFC3161 token from TSA
OCCAM_TSA_URL — TSA endpoint (required when time anchor on)
OCCAM_TSA_TIMEOUT_MS 3000 TSA round-trip timeout (500–15000)

Capability tiers (experimental)

The exam engine (occam exam selftest / exam tasks / exam grade) grades an agent on four checkable tasks and maps the score to a tool surface. Offline CLI grading is always available.

Score Tier Profile Tools
0–1 weak minimal 1
2–3 medium (default exam result) basic 3
4 strong full 18

A client that never sat the exam is treated as exam-tier medium in the cache API (ExamResult.Default). That value is not auto-applied to a live MCP session.

MCP runtime (opt-in)

Set OCCAM_EXAM_MCP=1 to expose occam_exam_submit and allow mid-session surface changes via notifications/tools/list_changed.

Variable Default Purpose
OCCAM_EXAM_MCP off 1/true enables exam submit + dynamic tool surface

Behaviour when enabled:

  • Session starts at reader (11 tools) unless OCCAM_PROFILE is set (boot default only). Freeze the surface with OCCAM_PROFILE_LOCK=1 (exam + runtime profile= cannot change it).
  • Agent/harness calls occam_exam_submit with the same JSON as occam exam grade.
  • On success: cache by {clientInfo, modelHint, sessionId} (TTL 24h); if not pinned, apply tier→profile and notify tools/list_changed.
  • Flag off (default): identical to historical hosts — fixed profile, no exam tool.

See ADR-0016.

A client that never sat the exam is assumed competent for the host default (reader); starving a capable agent is a silent failure, while over-trusting a weak one is visible and recoverable.


Proof-of-read canary

Tunables for the MCP tools (occam_canary_issue / occam_canary_verify), the occam canary CLI verbs, and the probe endpoints. Defaults are the normative protocol values from PROBE_PROTOCOL.md §8 — change them only with that document open, because several interact.

Variable Default Range Purpose
OCCAM_CANARY_BUCKET_SECONDS 300 30–3600 Time-bucket width; the sentinel changes every bucket
OCCAM_CANARY_FRESH_TOLERANCE 1 0–8 Buckets on either side still counted READ_VERIFIED (absorbs clock skew)
OCCAM_CANARY_STALE_HORIZON 24 1–512 Oldest bucket still recognised as READ_STALE
OCCAM_CANARY_SENTINEL_BYTES 32 16–32 Tag length; 16 gives a 22-character sentinel, 32 gives 43
OCCAM_CANARY_ISSUE_LOG_HOURS 24 1–168 Issuance retention — drives REPLAY_SUSPECT detection
OCCAM_CANARY_ISSUE_LOG_CAPACITY 8192 256–1048576 Hard cap on retained issuance records
OCCAM_CANARY_RATE_LIMIT 30 1–10000 Requests per window, per session and client
OCCAM_CANARY_RATE_WINDOW_SECONDS 60 1–3600 Rate-limit window width
OCCAM_CANARY_MCP_PORT 0 (OS pick) 0–65535 Loopback probe port for MCP-issued URLs

Notes that matter:

  • The secret is not configurable. It is generated per process from the platform CSPRNG, never persisted and never logged. Restarting the host invalidates every outstanding sentinel by design.
  • Setting OCCAM_CANARY_STALE_HORIZON at or below OCCAM_CANARY_FRESH_TOLERANCE is rejected at startup: it makes READ_STALE unreachable, so the verifier would silently lose a verdict.
  • Shortening OCCAM_CANARY_ISSUE_LOG_HOURS below STALE_HORIZON × BUCKET_SECONDS makes genuine older reads report as REPLAY_SUSPECT, because their issuance record has been evicted.
  • Out-of-range values are clamped with a note on stderr rather than accepted silently.

Playbooks

Variable Purpose
OCCAM_PLAYBOOKS_LOCAL_ROOT Local learn tier directory
WT_PLAYBOOKS_PATH User/org playbook tier
OCCAM_SITE_GENOME_FETCH 1 enables well-known site playbook fetch on resolve

Variable Purpose
OCCAM_SEARCH_PROVIDER Unset and OCCAM_SEARCH_PROVIDERS unset → default fan-out duckduckgo+mojeek (provider=fanout). Explicit singular: duckduckgo | mojeek | qwant | startpage | bing | searxng | brave | tavily | external_cli. off | none → search_unconfigured. Ignored when OCCAM_SEARCH_PROVIDERS is set.
OCCAM_SEARCH_PROVIDERS Optional CSV fan-out. Wins over singular. Token keyless → all built-in HTML SERPs without key/URL (duckduckgo,mojeek,qwant,startpage,bing). Example: keyless or duckduckgo,brave. Response provider=fanout + providersUsed[].
OCCAM_CRAWL_MCP 1 enables experimental occam_crawl (ADR-0018). Off by default; not in reader.
OCCAM_SEARCH_URL Required for SearXNG base URL
OCCAM_SEARCH_API_KEY Required for Brave/Tavily
OCCAM_SEARCH_TIMEOUT_MS HttpClient ceiling. Default 20000 (1k–120k)
OCCAM_SEARCH_PROVIDER_TIMEOUT_MS Per-provider cancel in fan-out. Default 3000 (1k–30k). Slow arms are dropped; others continue.
OCCAM_SEARCH_FANOUT_TIMEOUT_MS Overall fan-out cancel. Default provider+500 clamped (1k–35k).
OCCAM_SEARCH_DEGRADE_MINUTES After 429 / CAPTCHA (202) / timeout, skip that provider for N minutes. Default 5 (1–120).
OCCAM_SEARCH_RATE_MAX Per-provider fixed-window permit count. Default 30 (1–10000).
OCCAM_SEARCH_RATE_WINDOW_S Rate-limit window seconds. Default 60 (1–3600).
OCCAM_EXTERNAL_SEARCH_PATH Optional absolute path to a local external_cli binary (OCCAM_SEARCH_PROVIDER=external_cli). Otherwise external_cli must be on PATH. Never bundled — BYO binary.

Occam does not index the web. The DuckDuckGo default is disclosed discovery for first-run Research; operators who want a dedicated backend set SearXNG/Brave/Tavily (or off for air-gap). DuckDuckGo may soft-block automated egress with an anomaly challenge — Occam returns search_http_202 and does not solve CAPTCHAs. Fan-out skips degraded/rate-limited providers and logs switches on stderr as [occam.search] event=… provider=… reason=… untilUtc=….


PDF OCR (optional, scanned PDFs)

Off by default. After pdf_no_text_layer, the HTTP worker may call a local helper:

Variable Purpose
OCCAM_PDF_OCR 1 / true enables the OCR attempt
OCCAM_PDF_OCR_BIN Executable (or node) that accepts the PDF path as the last argv and prints text to stdout
OCCAM_PDF_OCR_ARGS Optional extra argv before the PDF path (e.g. path to a .mjs helper)
OCCAM_PDF_OCR_TIMEOUT_MS Default 60000 (1k–300k)

Honest notes on failure: pdf_ocr_unconfigured, pdf_ocr_timeout, pdf_ocr_failed, pdf_ocr_empty. Occam does not ship an OCR engine. Evaluation and implementation-budget decision: PDF/OCR capability eval.


Translation

Variable Default Purpose
OCCAM_TRANSLATE_URL — LibreTranslate base URL
OCCAM_TRANSLATE_API_KEY — Optional API key
OCCAM_TRANSLATE_TIMEOUT_MS 20000 Translation timeout

Egress proxy

Variable Purpose
OCCAM_HTTP_PROXY HTTP forward proxy
OCCAM_HTTPS_PROXY HTTPS proxy (falls back to HTTP proxy)
OCCAM_NO_PROXY Comma-separated bypass list
OCCAM_PROXY_LIST Rotating proxy pool (one-shot spawns)
OCCAM_PROXY_LIST_FILE File-based proxy pool (wins over list)

When a proxy pool is active, HTTP and browser daemons are disabled (rotation requires one-shot workers).


Digest parallelism

Variable Default Purpose
OCCAM_DIGEST_PARALLEL on 0 forces fully sequential (all hosts)
OCCAM_DIGEST_MAX_PARALLEL — Cap 1–8 hosts in flight; URLs that share a host are always serial

Opt-in MCP tools

Variable Registers
OCCAM_BATCH_MCP=1 occam_batch_submit, occam_batch_status, occam_batch_results
OCCAM_WATCH_MCP=1 occam_watch
OCCAM_CONSENSUS_MCP=1 occam_crosscheck
OCCAM_ATLAS_MCP=1 occam_failure_atlas + per-host telemetry
OCCAM_BROWSER_ACTIONS_MCP=1 occam_browser_interact (declarative click/type/scroll then materialize; never cached)

Tool surface profile (OCCAM_PROFILE)

Narrows which core tools appear in tools/list (and in boot server instructions). Product default stays reader (11 day-to-day tools) — not full. Do not set OCCAM_PROFILE=full as the global product default; use boot OCCAM_PROFILE=full only on authoring hosts, or switch at runtime (below). Contract fingerprint may spawn full for the 18-tool schema check (#52) — that is not the product default.

Runtime switch (no MCP restart): call occam_client_capabilities({ "profile": "full" }) (or reader / researcher / auditor). The host sends notifications/tools/list_changed — the client must re-list tools. Hermes: no config.yaml edit and no process restart.

Hard freeze: OCCAM_PROFILE_LOCK=1 — boot profile stays fixed (exam + profile= are no-ops). Use for CI / contract hosts only. Setting OCCAM_PROFILE alone does not lock.

Opt-in tools above are independent — still require their own flags.

Value Core tools exposed
minimal occam only — one tool, so tool selection cannot go wrong
basic occam, occam_digest, occam_search — read one page, read several, find pages
reader (default) occam_client_capabilities, occam, occam_transcode, occam_probe, occam_digest, occam_map, occam_search, occam_extract_knowledge, occam_verify, occam_canary_issue, occam_canary_verify
researcher reader + occam_claim_check
auditor researcher + occam_attest, occam_dataset_export, occam_playbook_lint
full All eighteen (includes playbook resolve/heal/save)

Surfaces are nested: widening a profile never removes a tool a narrower one had. Each profile also gets its own instructions text, and no profile's instructions name a tool it does not expose — advertising an absent tool is how an agent ends up calling something missing from its tools/list.

minimal and basic exist for the capability tiers above. minimal deliberately omits occam_client_capabilities: declaring a context budget is useful, but on a one-tool surface it is one more thing to get wrong, and OCCAM_CLIENT_CONTEXT_TOKENS does the same job from the operator side.

Invalid values fall back to reader with a one-line [occam.config] warning on stderr.


Client context budget (OCCAM_CLIENT_CONTEXT_TOKENS)

MCP does not tell servers the model's context window. Occam sizes extracts to the client in two ways:

Mechanism How
Tool (preferred) Call occam_client_capabilities once with context_tokens (the model knows its window)
Env (operator) OCCAM_CLIENT_CONTEXT_TOKENS (1024–2000000); optional OCCAM_CLIENT_MODEL_ID label

After configure, occam_transcode / occam_digest that omit max_tokens / per_url_max_tokens use ~20% of the context (clamped 512–16384). Explicit max_tokens always wins. Response includes suggestedProfile (reader / researcher / full) as advisory; pass profile= on the same tool to actually switch the live surface (unless OCCAM_PROFILE_LOCK=1).

Batch

Variable Default Purpose
OCCAM_BATCH_PORT 5051 Batch HTTP server port
OCCAM_BATCH_DB_PATH ~/.occam/jobs/jobs.db Job store
OCCAM_BATCH_MAX_URLS 64 Max URLs per submit
OCCAM_BATCH_PARALLEL 4 Concurrent transcodes (1–16)

Watch

Variable Default Purpose
OCCAM_WATCH_DB_PATH ~/.occam/watch/watch.json Per-URL baseline store

Remote MCP (TLS + JWT)

Variable Default Purpose
OCCAM_TLS_CERT_PATH — TLS certificate (PFX or PEM) for --remote
OCCAM_TLS_CERT_PASSWORD — PFX password
OCCAM_JWT_ISSUER occam-mcp Expected JWT iss
OCCAM_JWT_AUDIENCE occam-mcp Expected JWT aud
OCCAM_JWT_METADATA_URI issuer discovery HTTPS OpenID Connect metadata document; its jwks_uri supplies rotating signing keys
OCCAM_REMOTE_MAX_SESSIONS 4 Concurrent authenticated WSS sessions (1–32)
OCCAM_MCP_MAX_MESSAGE_BYTES 4194304 Maximum local/remote WebSocket MCP text message (65536–16777216)

Remote startup requires either an HTTPS OCCAM_JWT_ISSUER suitable for OpenID Connect discovery or an explicit OCCAM_JWT_METADATA_URI. The deprecated OCCAM_JWT_JWKS_URI alias is still read as a metadata-document URI; do not point it directly at raw JWKS JSON. Access tokens belong only in the WebSocket handshake's Authorization: Bearer header. URI query tokens are rejected.


Logging (stderr only)

Variable Fallback Default Purpose
OCCAM_BANNER WT_OCCAM_BANNER on 0 hides startup banner
OCCAM_LOG WT_OCCAM_LOG off 1 enables transcode profiler

Domain tiers (probe)

Variable Purpose
OCCAM_DOMAIN_TIERS_PATH Extra domain tier JSON files

Install scripts (not read by host)

Variable Default / purpose
OCCAM_REPO_URL Git remote — default public identity https://github.com/ContextForgeAI/occam.git
OCCAM_REF / OCCAM_BRANCH Pin tag or branch
OCCAM_INSTALL_DIR Install target directory
OCCAM_RELEASE_URL Release tarball URL
OCCAM_RELEASE_MANIFEST_URL Manifest with sha256
OCCAM_RELEASE_BASE Release download base — default in get-ff-occam.sh: https://github.com/ContextForgeAI/occam/releases/download/v<version>
OCCAM_RELEASE_BASE_URL Same for @ff-occam/mcp — https://github.com/ContextForgeAI/occam/releases/download (version appended by wrapper)
OCCAM_GET_URL Raw get-ff-occam.sh URL — default https://raw.githubusercontent.com/ContextForgeAI/occam/v1.3.0/scripts/get-ff-occam.sh
OCCAM_RELEASE_ALLOW_HTTP 1 — allow HTTP release URLs (non-default; HTTPS GitHub is preferred)
OCCAM_RELEASES_API_URL Override for update-check — default https://api.github.com/repos/ContextForgeAI/occam/releases/latest (stable-only; set OCCAM_LATEST_VERSION during prerelease)
OCCAM_CONNECT_ALL 1 — non-interactive connect every detected Tier-A host
OCCAM_CONNECT_ONLY Host id(s) — non-interactive connect those Tier-A hosts only (ignored if OCCAM_CONNECT_ALL=1)
OCCAM_HOST Legacy fallback snippet preset (cursor, hermes) — not connect pre-select; use OCCAM_CONNECT_ONLY
OCCAM_CONFIG Onboard config path (~/.occam/onboard.json)

Example Cursor env block

"env": {
  "OCCAM_HOME": "C:\\path\\to\\ff-occam",
  "OCCAM_BANNER": "0"
}