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

# Genesis on Docker

> Run Genesis locally using a container-based distribution. Docker CLI is the only requirement.

<Note>
  The only requirement is the Docker CLI.
</Note>

## Quick start

Just want to run Genesis locally? Here's how:

```bash theme={null}
# 0. Install docker (https://www.docker.com/)

Obtain Install Script from Genesis by Contacting support@genesiscomputing.ai

# 1. Install Genesis (one-time setup)

# 2. Start the Genesis server
~/bin/genesis_server

# 3. Open Genesis UI in your browser
# Navigate to: http://localhost:8080 (React GUI) or http://localhost:8082 (Streamlit GUI)

# 4. Connect an LLM provider from Config -> AI Providers, or with the
#    config API (see "Configuring the LLM provider" below).
```

Genesis is now running locally on your machine. Until step 4 succeeds the server
starts and answers, but the bots have no LLM — so run the CLI only after a provider
is configured and active:

```bash theme={null}
# 5. Only after step 4: talk to a bot from a new terminal.
~/bin/genesis_cli "Hello, what can you help me with?"
```

### Need the latest version?

```bash theme={null}
~/bin/genesis_update              # Pull the latest container
~/bin/genesis_server              # Restart the server
```

***

## Installation

```bash theme={null}
Obtain Install Script from Genesis by Contacting support@genesiscomputing.ai
```

Installs four scripts in `~/bin`:

* **`genesis_server`** — Local Genesis server with persistent SQLite database
* **`genesis_cli`** — CLI for local or Snowflake native app operations
* **`genesis_update`** — Pulls latest container version
* **`mcp_bridge`** — Bridge script to connect Genesis with MCP servers

***

## `genesis_server` command line arguments

```bash theme={null}
genesis_server [-d] [-i image]
```

### Options

| Flag | Description | Default |
| - | - | - |
| `-d` | Run container in detached mode (background) | Interactive mode |
| `-i image` | Use custom image name | `genesis` |
| `-h` | Display help | - |

### Examples

```bash theme={null}
genesis_server                                    # Run interactively with default image
genesis_server -d                                 # Run in background
genesis_server -i genesis-back-front-dev          # Use development branch image
genesis_server -d -i genesis-back-front-dev       # Detached mode with dev image
```

### Available images

* **`genesis-back-front-dev`** — Built from back/front-dev branch

### Exposed ports

* **`8080`** — FastAPI (Primary system with React GUI and modern APIs)
* **`8082`** — Flask (UDF proxy, OAuth, Streamlit GUI, external integrations)
* **`8501`** — Retired Streamlit UI when `LAUNCH_GUI` is not `false`. The self-hosted
  server image sets `LAUNCH_GUI=False`, leaving this port available for a customer
  service reached through an Outpost. If the UI is enabled, it follows the Outpost
  listener bind rule rather than claiming the wildcard address: it answers on
  `127.0.0.1:8501`, so `kubectl port-forward` reaches it, and on the container's own
  address, so a published port or Kubernetes Service reaches it.
* **`21234`** — Shell In A Box debug shell

The application images built from `container/Dockerfile.app` and
`container/Dockerfile.app.prebuilt` set `GENESIS_BIND_LISTENERS_FOR_OUTPOSTS=TRUE` by
default. This binds Genesis's wildcard listeners to explicit addresses so an Outpost can
route to a customer service even when it uses a port Genesis also uses, such as `8080`.

### Product documentation links

Genesis can serve an offline Mintlify export from the same FastAPI backend that serves the app (`/client-docs`, `/docs/...`, `/api-reference/...`). Whether in-app documentation links (for example **Help**, changelog links) open this internal export or hosted Mintlify is a **runtime** setting — the unified app-config flag `docs.use_internal_docs` (default `true`). Leave it `true` to keep UI links inside the running deployment, or set it `false` (Admin → Advanced Settings → **docs**, the Genesis config file, or `GENESIS__DOCS__USE_INTERNAL_DOCS=false`) to open the hosted pages at `docs.genesiscomputing.com` directly. Only if Mintlify JWT authentication is enabled for the hosted site does Genesis need a PKCS#8 Ed25519 signing key, configured through the secret field `docs.mintlify_jwt_private_key` or its default `MINTLIFY_JWT_PRIVATE_KEY` environment variable. No frontend rebuild is required to change the routing flag; docs routing is not controlled by a build-time Vite variable.

The static export directory defaults to `config/genesis-docs-static` in the repo and `GENESIS_DOCS_STATIC_FOLDER=/app/config/genesis-docs-static` in container images. Generate it locally with `make offline-docs` (runs `scripts/docs/export_mintlify_offline.py`; run `git lfs pull` first so image assets are hydrated).

If you build the application image yourself from `container/Dockerfile.app` or `container/Dockerfile.app.prebuilt`, the Dockerfiles **always** run the offline export during the image build. The checkout used by `container/Dockerfile.app` hydrates Git LFS objects, so screenshots arrive as real bytes in the static export; `--allow-missing-local-assets` remains a guard for any future page that references an asset before it is added. Immediately after the export, they remove Mintlify, npm, and Puppeteer build caches (`/root/.mintlify`, `/root/.npm`, `/root/.cache/puppeteer`, `/root/.config/mintlify`) so a build-only chrome-for-testing binary is not shipped in the final image — see [Mintlify docs-export cleanup](#container-image-security-hardening). No extra build arg is required for the docs export. For a faster local build, `make -C container build` uses `Dockerfile.app.prebuilt` and copies in the dashboard built on the host; its application code and image setup match `Dockerfile.app`. This Make target passes `GENESIS_COMMIT_SHA` and a UTC `BUILD_TIMESTAMP` automatically. For a direct build with either Dockerfile, pass `GENESIS_COMMIT_SHA` to include the source commit in the image's healthcheck and MCP status, and `BUILD_TIMESTAMP` to include the build time in `/api/health/build-info`; both args default to an empty string:

```bash theme={null}
docker build \
  --build-arg BASE_IMAGE=<your-base-image> \
  --build-arg GENESIS_COMMIT_SHA=$(git rev-parse HEAD) \
  --build-arg BUILD_TIMESTAMP=$(date -u +%Y_%m_%d_%H_%M_%S) \
  -f container/Dockerfile.app \
  -t genesis:custom .
```

The default `Dockerfile.app` target (`genesis`) and the `genesis-spcs` target the Snowflake
Native App uses are the same image: the Outpost tunnel runs as a Genesis Python worker, so
neither carries a separate tunnel binary. Build the Native App image with
`--target genesis-spcs` when using `Dockerfile.app`, or run
`make -C container build TARGET=genesis-spcs` to build it locally (the target name is
appended to the normal image tag). Outposts are not
available in the Native App; see [Genesis Outposts](/docs/Setup/Outposts-Overview).

For a local `make offline-docs` run (outside Docker), the export still fails loudly on unhydrated Git LFS pointers or missing local assets — run `git lfs pull` first if you need every screenshot present in the static export.

### Remote Genesis App runner image

Remote Genesis Apps (Docker, EKS, Railway) run inside the lightweight
`genesis-app-runner` image built from `container/Dockerfile.app-runner`:

```bash theme={null}
docker build -f container/Dockerfile.app-runner -t genesis-app-runner .
```

The image uses `python:3.12-slim` and bundles `genesis_spcs_auth` at
`/opt/genesis/genesis_spcs_auth` so `runner.py` can obtain Snowflake OAuth
tokens for SPCS ingress when `GENESIS_SPCS_MODE=true` and the related
`GENESIS_SPCS_USER`, `GENESIS_SPCS_ENDPOINT`, and private-key variables are
set.

The image adds the microapp `runtime_support/` shim to `PYTHONPATH` so
interpreter startup (`sitecustomize.py`) installs the same Genesis API token
forwarding used by locally hosted apps. That patch injects fresh
`X-Genesis-App-Token` values on outbound `requests` and `urllib.request`
calls — swapping stale startup tokens for per-request viewer tokens or
rotating process tokens — so long-lived remote dashboards do not start
returning `401` on dataset calls after the token TTL (\~6 hours).

### Sandbox Claude Code runner image

The optional [sandbox thread runner](/docs/Setup/Advanced-Settings#sandbox-thread-runner-prototype)
and the optional [direct CLI terminal](/docs/Setup/Advanced-Settings#direct-cli-terminal)
use a separate container image that bundles Node.js, Python, git, the
`@anthropic-ai/claude-code` CLI, and `tmux`. The main Genesis image does not include
the Claude Code CLI, so operators build this image alongside the Genesis server when
enabling either feature. The thread runner uses one container per thread; direct CLI
terminal uses one persistent workspace container per user and named tmux sessions so a
Claude Code process can survive a terminal disconnect or backend restart.

Build from the repository root:

```bash theme={null}
docker build -f container/Dockerfile.sandbox-claude -t genesis-sandbox-claude:latest .
```

This build installs the latest available Claude Code CLI by default. To pin the
CLI version used in the image, pass the `CLAUDE_CODE_VERSION` build argument:

```bash theme={null}
docker build -f container/Dockerfile.sandbox-claude \
  --build-arg CLAUDE_CODE_VERSION=1.2.3 \
  -t genesis-sandbox-claude:latest .
```

The image runs as the non-root `node` user (uid 1000) with `/workspace` as the
working directory. At container start, Genesis injects `ANTHROPIC_BASE_URL` (from
`GENESIS_SANDBOX_RUNNER_PROXY_BASE_URL` or `GENESIS_CLI_TERMINAL_PROXY_BASE_URL`) and
a scoped token as
`ANTHROPIC_API_KEY` so LLM calls route through Genesis's
[sandbox LLM proxy](/docs/Genesis-API/API-Reference#internal-sandbox-llm-proxy-endpoints)
and the real org key never enters the sandbox. Snowsql, dbt, and AWS CLIs are
not pre-installed — add them per deployment as needed to keep cold-start lean.

Claude Code is installed in a node-owned npm prefix, so it can update itself
between sessions without requiring root access. The npm bin directory is appended
to `PATH` for regular and login shells; this keeps the image's root-owned system
CLI launchers from being shadowed by files created inside the sandbox.

Configure Genesis with `GENESIS_SANDBOX_RUNNER_BOT_IDS` and
`GENESIS_SANDBOX_RUNNER_PROXY_BASE_URL` before starting the server. On Docker
Desktop, `host.docker.internal` usually reaches the host from inside the
sandbox container; on Linux, use the host IP or set
`GENESIS_SANDBOX_RUNNER_NETWORK=host`.

***

## Container image security hardening

Genesis production container images (`genesis`, Snowflake Native App service
images, and Helm-deployed images) are built from `container/Dockerfile.base`.
The final base-image steps harden the runtime filesystem:

| Hardening step | What it does |
| - | - |
| **Restricted user for agent code** | The main Genesis process runs as root; code agents write or choose runs as the restricted `cortex_sandbox` user (uid and gid 995) instead: `execute_python_code`, the Claude Code, Codex and Cortex Code CLIs, dashboard rendering, the Databricks `execute_python` execution process, and local Talend jobs. Those processes get no server credentials in their environment and cannot read the Genesis installation, its configuration or its storage. If an image lacks the `cortex_sandbox` user, dashboard rendering, the Databricks execution process and Talend jobs run as root, as in earlier releases. |
| **SUID/SGID stripping** | Removes setuid and setgid bits from every file on the root filesystem to eliminate local privilege-escalation vectors (for example `passwd`, `mount`, `su`). The main Genesis process runs as root, so `sudo` still drops privileges to `cortex_sandbox` and microapp users without relying on setuid bits. |
| **Build cache purge** | Deletes `/var/cache/*`, `/var/log/*`, and most of `/root/.cache` to shrink the image. `/usr/share/doc` and `/usr/share/man` are kept for licence compliance; `/root/.cache/chroma` (ONNX embedding model for air-gapped support-doc indexing) is preserved. |
| **Playwright X.Org removal** | After Playwright installs Chromium with OS dependencies (`--with-deps`), removes the X.Org virtual display packages that come with them (`xvfb`, `xserver-common`, and `libxfont2`; `apt-get purge`). Genesis runs Chromium headless and never starts Xvfb; `xvfb` and `xserver-common` each carry a HIGH CVE with no upstream fix, and `libxfont2` is installed only for them. They are removed in the same build step that installed them, so no image layer holds their files. The build stops if the removal would take any other package, and afterwards launches the same Chromium binary Genesis uses at run time to confirm it still starts. |
| **npm bundled dependency patching** | After `npm install -g npm@latest`, replaces or patches vulnerable packages still bundled inside npm's own `node_modules` (`brace-expansion` 5.0.11 for CVE-2026-14257, CVE-2026-69152, CVE-2026-102276, and CVE-2026-102278; `ip-address` 10.3.1 for CVE-2026-69192; `picomatch` inside `tinyglobby` for CVE-2026-33671, kept as npm ships it when that is 4.0.4 or newer and otherwise replaced with 4.0.4, touching only that directory so that `tinyglobby`'s development dependencies are not installed; `undici` 6.28.1 for CVE-2026-12151 and CVE-2026-19534; and `tar` 7.5.22 for CVE-2026-73566). The amd64 Railway CLI installation also uses `tar` 7.5.22. Registry tarballs are used where in-tree `npm install` would hit workspace resolution errors. Clears fixable HIGH CVEs flagged by image scanners; npm is build-time tooling in the base image. |
| **Eval-only Pydantic AI packages** | Removes `pydantic-ai`, `pydantic-ai-slim`, `pydantic-evals`, and `pydantic-graph` from the production image. Genesis does not import these eval-harness libraries at runtime, and the compatible pinned `pydantic` and `anthropic` runtime prevents installing a fixed `pydantic-ai` release for CVE-2026-107295. |
| **libexpat CVE patching** | Upgrades `libexpat1` (shipped with `python:3.12-slim`) to patched Debian packages (`apt-get install --only-upgrade`). `libexpat1-dev` is not in the image. Addresses CVE-2025-59375 and related HIGH libexpat advisories flagged by image scanners. |
| **linux-libc-dev CVE patching** | Upgrades `linux-libc-dev` (shipped with `python:3.12-slim`) to patched Debian packages (`apt-get install --only-upgrade`). Addresses CVE-2026-63970 and related HIGH kernel header advisories flagged by image scanners. |
| **jq/libjq1 CVE patching** | Upgrades `jq` and `libjq1` (shipped with the base image apt layer) to patched Debian packages (`apt-get install --only-upgrade`). Addresses CVE-2026-32316 (integer overflow / heap buffer overflow in jq) flagged by image scanners. |
| **rclone upgrade** | Updates the statically built `rclone` used to transfer state snapshots with `export-state` and `import-state` from v1.75.1 to v1.75.2. The build verifies architecture-specific SHA-256 checksums for amd64 and arm64. |
| **Snowflake Cortex Code CLI** | By default, the Snowflake Native App image installs Cortex Code CLI `1.1.104+041358.66de1c44636f` from Snowflake's release tarball. The build selects the amd64 or arm64 build and verifies its SHA-256 checksum before installation, so rebuilding with the default build arguments does not silently pick up a newer CLI release. |
| **Mintlify docs-export cleanup** | After the offline docs export in `Dockerfile.app` and `Dockerfile.app.prebuilt`, deletes `/root/.mintlify`, `/root/.npm`, `/root/.cache/puppeteer`, and `/root/.config/mintlify`. The Mintlify export pulls a chrome-for-testing binary via Puppeteer that image scanners (including Snowflake's) can flag as CVE-vulnerable; it is build-time-only and is not used at runtime. Snowflake Native App images (`container/Dockerfile.snowflake`) re-delete `/root/.cache/puppeteer` after the Cortex overlay in case a later build step repopulates it. Runtime headless browser automation uses Playwright Chromium at `PLAYWRIGHT_BROWSERS_PATH=/app/playwright-browsers`. |
| **Package manager removal** | Removes `apt`, `apt-get`, and `dpkg` executables plus apt source lists so a compromised runtime process cannot install software. The dpkg metadata database under `/var/lib/dpkg` is **kept** so image scanners (Trivy, Grype) can still enumerate installed OS packages for CVE reporting. |

<Info>
  You cannot install Debian packages inside a running Genesis container with
  `apt` or `dpkg`. Tools such as `ripgrep` (`rg`), Playwright browsers, and
  Python dependencies are pre-installed at image build time. If you previously
  layered a custom Dockerfile on top of Genesis images solely to strip apt/dpkg,
  that wrapper is no longer necessary.
</Info>

When building custom application images from `container/Dockerfile.app` or
`container/Dockerfile.app.prebuilt`, all OS package installs happen in the base
image — downstream Dockerfiles copy application code and run the docs export
without calling apt.

The auxiliary `genesis-app-runner` image (`container/Dockerfile.app-runner`)
builds from upstream Python/Playwright bases, not `Dockerfile.base`, so it is
unaffected.

***

## Out-of-process wedge diagnostics

Every Genesis container image starts `container/wedge_sentinel.py` in the
background from `container/launch.sh` (before Tailscale and before the
SPCS/standalone fork). The sentinel runs on the **system** Python interpreter
(`/usr/local/bin/python3 -I -S`), not `/app/.venv`, so it does not share
site-packages or `sys.path` with the Genesis process it observes.

In-process diagnostics such as `SYS_PRESSURE`, `LOOP_IDENTITY`, and the
loop-stall dump from GEN-2398 are emitted from inside the Genesis Python
process. When that process wedges, those lines stop at the same instant. The
wedge sentinel keeps writing compact `WEDGE_SENTINEL` lines to container
**stdout** on a fixed interval (default 60 s) so a hang can still be diagnosed
from exported logs without shell access to the container.

On Snowflake Native App / SPCS deployments, stdout is exported to the
customer's event table via the service spec's `logExporters` configuration.
See [Snowflake Native App — wedge diagnostics in exported logs](/docs/deployments/Snowflake-Native-App/Installation-And-Configuration#wedge-diagnostics-in-exported-logs)
for how to query those lines.

### Line format and key fields

Each sample is one line in the same house style as `SYS_PRESSURE` and
`MOUNT_HEALTH_FAILURE`: an `WEDGE_SENTINEL` token followed by space-separated
`key=value` pairs (units are baked into key names). Example:

```
WEDGE_SENTINEL seq=42 uptime_s=2520.4 late_s=0.00 emit_dropped_total=0 node_psi_io_full_avg10=0.30 node_load1=2.31 gen_pid=31 gen_state=S gen_cpu_ms_delta=120 tailscaled_pid=27 tailscaled_state=S tailscaled_log_age_s=4.2 tailscaled_log_size=182734 blk=ok blk_ms=12.4 cg_cpu_throttled_us_delta=0
```

| Field group | What it tells you |
| - | - |
| `seq`, `late_s`, `emit_dropped_total` | Whether the sentinel itself is still being scheduled (`seq` should advance each interval; rising `late_s` suggests container-wide descheduling). `emit_dropped_total` counts lines dropped because stdout backpressure made a non-blocking write fail. |
| `gen_*` | Genesis backend process: pid, scheduler state (`R` = running, `S` = sleeping, `D` = uninterruptible sleep), per-interval CPU and I/O deltas, optional `gen_wchan`. `gen_pid=absent` means the process was seen earlier and has since gone; `gen_pid=never` means this sentinel never saw it at all (normal during the startup window). `gen_seen_py` lists visible `.py` script basenames (secret-safe). |
| `tailscaled_*`, `tailscaled_log_*` | Embedded Tailscale (`tailscaled`) process and its log file metadata (`/var/log/tailscaled.log` by default). `tailscaled_pid=never` and `tailscaled_log=absent` are normal when Tailscale is not enabled. These fields were prefixed `ts_*` in earlier releases; the short prefix was misread as "thread service" during an incident, so it now spells out the daemon it watches. |
| `blk`, `blk_ms`, `blk_stuck_s` | Direct write+fsync probe to the block volume (default directory `/opt/block`). `blk=timeout` or `blk=stuck` with rising `blk_stuck_s` is strong evidence of a volume stall during the wedge. `blk=unavailable` means no block volume is mounted at the probe path. |
| `cg_*_delta` | Per-container cgroup CPU throttling and memory-pressure counters (v2 `memory.events` when available; v1 `memory.failcnt` and `memory.oom_control` on SPCS). |
| `node_psi_*`, `node_load1`, `node_procs_*` | **Node-wide** pressure and run-queue depth, not scoped to the Genesis container. Read these as host-level context, not Genesis-specific load. |

Startup and disable messages are written to **stderr** with the `[wedge_sentinel]` prefix (also exported on SPCS). A successful start logs
`[wedge_sentinel] started pid=… interpreter=/usr/local/bin/python3`.

### Environment variables

These are plain container environment variables (not APP\_CONFIG fields). The
sentinel honours them directly because it starts before the database exists.

| Variable | Default | Description |
| - | - | - |
| `GENESIS_WEDGE_SENTINEL_ENABLED` | `true` | Set to `false`, `0`, or `no` to disable the sentinel. When disabled, no `WEDGE_SENTINEL` sample lines are emitted. |
| `GENESIS_WEDGE_SENTINEL_INTERVAL_S` | `60` | Seconds between samples. Must be a positive number. |
| `GENESIS_WEDGE_SENTINEL_PROBE_TIMEOUT_S` | `5` | Seconds before a block-volume or tailscaled-log probe child is killed and reported as `timeout` / `stuck`. |
| `GENESIS_WEDGE_SENTINEL_BLOCK_PROBE_DIR` | `/opt/block` | Directory where the sentinel writes a small probe file to test block-storage latency. Override when your durable volume is mounted elsewhere. |
| `GENESIS_TSNET_LOG_FILE` | `/var/log/tailscaled.log` | Path whose size and mtime the sentinel reads for `tailscaled_log_*` fields. Only metadata is emitted — never log contents. |

On non-Linux hosts (no `/proc`), the sentinel logs once to stderr and exits
without failing container startup. If the script or a system `python3`
interpreter is missing, `launch.sh` logs a disable message and continues under
`set -e`.

***

## Configuration

Installation creates `~/.genesis/config.env`, which carries the container's
metadata-store settings:

```env theme={null}
SQLITE_DB_PATH=/app/.genesis/db/genesis.db

# Snowflake mode (uncomment to enable):
#SNOWFLAKE_METADATA=TRUE
#SNOWFLAKE_ACCOUNT_OVERRIDE=""
#SNOWFLAKE_USER_OVERRIDE=""
#SNOWFLAKE_PASSWORD_OVERRIDE=""
#GENESIS_INTERNAL_DB_SCHEMA="XXX.YYY"
```

### Configuring the LLM provider

The LLM provider does not belong in `config.env`. Start the container first, then
configure the provider against the running server — from **Config -> AI Providers**
in the UI, or through the config API. The configuration is stored in `APP_CONFIG`
and survives every restart afterwards. Keep credentials in a request-body file:
process arguments are visible to every process on the host and land in shell
history.

```bash theme={null}
umask 077
set -o pipefail   # json.tool must not mask a failed curl
GENESIS_URL=http://localhost:8080
BODY=$(mktemp "${TMPDIR:-/tmp}/genesis-llm-body.XXXXXX.json")
CURL_CONFIG=$(mktemp "${TMPDIR:-/tmp}/genesis-curl.XXXXXX")
trap 'rm -f "$BODY" "$CURL_CONFIG"' EXIT
chmod 600 "$BODY" "$CURL_CONFIG"

# The local container runs with authentication disabled by default. With auth on,
# every call needs a bearer token for a user holding access_config_panel; read -rs
# keeps it out of shell history. Omit these lines and --config when auth is off.
read -rsp 'Genesis access token: ' GENESIS_TOKEN && echo
printf 'header = "Authorization: Bearer %s"\n' "$GENESIS_TOKEN" > "$CURL_CONFIG"
unset GENESIS_TOKEN

cat > "$BODY" <<'JSON'
{"api_key": "<openai-api-key>", "test_connection": true}
JSON
curl -sS --fail-with-body --config "$CURL_CONFIG" \
  -X POST -H 'Content-Type: application/json' --data @"$BODY" \
  "$GENESIS_URL/api/config/llm-providers/openai" | python3 -m json.tool

curl -sS --fail-with-body --config "$CURL_CONFIG" \
  -X POST -H 'Content-Type: application/json' -d '{"force": true}' \
  "$GENESIS_URL/api/config/llm-providers/openai/activate" | python3 -m json.tool

curl -sS --fail-with-body --config "$CURL_CONFIG" \
  -X PUT -H 'Content-Type: application/json' \
  -d '{"provider": "openai", "use_defaults": true, "activate_provider": true}' \
  "$GENESIS_URL/api/config/models/main/assignments" | python3 -m json.tool
```

Read each response before running the next call: these routes also answer `200` with
`success: false` (for example when the provider already exists — repeat that call as
a `PUT`). For the card / llm-type naming table and the other providers, see
[the reference procedure](/docs/Setup/Setup-AI-Model#configuring-a-provider-through-the-config-api).

For the card / llm-type naming table, the other providers, and the embedding
identity rules, see
[Configuring a provider through the config API](/docs/Setup/Setup-AI-Model#configuring-a-provider-through-the-config-api)
and [AI model setup](/docs/Setup/Setup-AI-Model). `LITELLM_EMBEDDING_MODEL` is no
longer read as an input.

<Note>
  Some schema fields carry a `default_env_var` binding that seeds them from the
  container environment while nothing is stored, so an image can come up
  pre-seeded. That is bootstrap only — it is not the way to configure a provider,
  and anything saved through the UI or the config API outranks it.
</Note>

***

## CLI commands

### Thread management

| Command | Description |
| - | - |
| `genesis_cli -t` | Display current bot/thread |
| `genesis_cli -t ls` | List all threads (bot/thread format) |
| `genesis_cli -t new` | Create new thread with same bot |
| `genesis_cli -t bot/id` | Switch to bot/thread |

### Data Agent management

| Command | Description |
| - | - |
| `genesis_cli -b` | Display current bot |
| `genesis_cli -b bot_id` | Switch to new thread on bot |

### Configuration management

```bash theme={null}
genesis_cli -c                    # Display all config key/values
genesis_cli -c <key> <value>      # Set config value
```

**Example — connect to Snowflake native app:**

```bash theme={null}
genesis_cli -c server_url snowflake://user@domain:pass@account/database/app
```

***

## Model Context Protocol (MCP)

| Command | Description |
| - | - |
| `genesis_cli -mo` | Offer Genesis tools as MCP server |
| `mcp_bridge <server_cmd>` | Add locally hosted MCP servers to Genesis |

#### Adding MCP servers

The `mcp_bridge` utility allows you to add locally hosted MCP servers to Genesis, giving you access to additional tools and capabilities.

**Usage:**

```bash theme={null}
mcp_bridge <mcp_server_command> [args...]
```

**Examples:**

```bash theme={null}
# Add filesystem access tools
mcp_bridge npx -y @modelcontextprotocol/server-filesystem /tmp

# Add custom MCP server tools
mcp_bridge python my_mcp_server.py --config config.json

# Add database access tools
mcp_bridge npx -y @modelcontextprotocol/server-sqlite /path/to/database.db
```

Once connected, the MCP server's tools will be available to Genesis for use in conversations and workflows.

***

## Programmatic usage

`genesis_cli` is designed for use in programs — can run prompts, call tools, and offer MCP services.

### Examples

**Basic interaction:**

```bash theme={null}
$ genesis_cli -t new
switched to Eve/completion_thread_154d87de-a40d-493e-b5e1-c4a42f7e0db6: New Chat

$ genesis_cli "list bots"
[Bot list output...]
```

**Tool execution:**

```bash theme={null}
$ genesis_cli \!manage_todos action=LIST, for_bot_id="DEng-DBT-EngineerBot"
{
    "success": true,
    "todos": [...]
}
```

***

## Updates

```bash theme={null}
genesis_update [-i image]
```

### Options

| Flag | Description | Default |
| - | - | - |
| `-i image` | Update specific image | `genesis` |
| `-h` | Display help | - |

### Examples

```bash theme={null}
genesis_update                              # Update default genesis image
genesis_update -i genesis-back-front-dev    # Update development branch image
```

***

## Volume mounts

`genesis_server` automatically mounts the following directories:

| Host Directory | Container Path | Purpose |
| - | - | - |
| `~/.genesis/db` | `/app/.genesis/db` | SQLite database |
| `~/.genesis/bot_git` | `/app/bot_git` | Git repositories |
| `~/.genesis/bot_storage` | `/app/bot_storage` | Bot storage |
| `~/.genesis/customer_demos` | `/app/customer_demos` | Demo files |
| `~/.genesis/tmp` | `/app/tmp` | Temporary files |

<Note>
  On container startup Genesis prepares the mounted Git workspace at `GIT_PATH`
  (default `/app/bot_git`). It ensures `repos/`, `worktrees/`, and
  `.genesis_runtime/` exist, starts the shared group-write repair in the
  background using `GENESIS_BOT_GIT_SHARED_GROUP` (default
  `cortex_sandbox`) so slow recursive permission fixes do not block container
  startup, and by default adds `*` to system Git `safe.directory` unless
  `GENESIS_TRUST_ALL_GIT_DIRS=false`.

  The mounted Git workspace also stores named local Python environments and
  must persist to retain them. See [Managed local environments](/docs/Genbot-Toolkit/Code-Executor-Tools#managed-local-environments) for their location and startup migration.

  Before any service starts, Genesis also attempts to remove other-user access from the
  mounted data directories — `/app/bot_storage` (or `STORAGE_PATH`), the
  directory holding `SQLITE_DB_PATH`, `/app/.genesis` and the log directory — so
  the unprivileged user that runs agent code cannot read the database or the
  credentials in it. Only each directory itself is changed, never what is inside
  it, so this is fast on large volumes. Where a secret sits in a directory agent
  code must still reach (`genesis.db` or a log file directly in `/app`, or
  credential files such as `g-workspace-sa-credentials.json` in the working
  directory), that file itself loses other-user access instead. A mount that refuses permission changes is
  logged as a warning (`Could not lock ...`) and left as it was, so check the
  startup log on such storage. Genesis runs as root and is unaffected; to
  inspect these directories, open a root shell through the container runtime (for
  example `docker exec -u 0 -it <container> bash`).
</Note>

<Info>
  Current Genesis container images include `ripgrep` (`rg`) out of the box. If you open a shell inside the container for troubleshooting, you can search mounted files under paths such as `/app/bot_storage` and `/app/bot_git` without installing extra packages — `apt` and `dpkg` are not available at runtime (see [Container image security hardening](#container-image-security-hardening)). The same images also bundle the in-repo `genesis_sdk` package under `/app/genesis_sdk` (for `execute_python_code` local execution — not installable from PyPI), the `llm_wiki` package under `/app/llm_wiki`, the `estatechar` package under `/app/estatechar` (source-contract characterization REST and store glue), and the `genesis_spcs_auth` package under `/app/genesis_spcs_auth` (Snowflake SPCS ingress OAuth used by remote Genesis Apps and the Teams SPCS relay), so the SDK, wiki APIs, estatechar workflows, SPCS authentication helpers, and tools shipped with Genesis are available without rebuilding the image.
</Info>

The **Estate** (Prover) top-level nav is exposed by default and needs no container environment variable. The web client reads `show_estate` from `GET /api/config/frontend`, which is `true` unless the deployment turned Prover off one of the two supported ways: setting `features.show_estate` to `false` through the config API (Advanced Settings, or `PUT /api/config/advanced/value`), which stays editable in the UI; or setting `GENESIS__FEATURES__SHOW_ESTATE=false` on the container environment, which outranks that write and locks the Advanced Settings toggle. Either way the estate routes keep answering — only navigation is hidden. The former Prover-specific `GENESIS_SHOW_ESTATE` opt-in is retired and no longer read.

To expose **Requests**, set `GENESIS_SHOW_WORK=TRUE` (or `1`, `YES`, or `ON`). Requests stays hidden by default during its staged rollout; the web client reads `show_work` from `GET /api/config/frontend` and applies the gate to desktop navigation, mobile navigation, and direct `/work/` visits.
