Skip to main content
The only requirement is the Docker CLI.

Quick start

Just want to run Genesis locally? Here’s how:
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:

Need the latest version?


Installation

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

Options

Examples

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. 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. 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:
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. 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:
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 and the optional 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:
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:
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 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:
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.
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 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:
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. 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:

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.
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. For the card / llm-type naming table, the other providers, and the embedding identity rules, see Configuring a provider through the config API and AI model setup. LITELLM_EMBEDDING_MODEL is no longer read as an input.
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.

CLI commands

Thread management

Data Agent management

Configuration management

Example — connect to Snowflake native app:

Model Context Protocol (MCP)

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:
Examples:
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:
Tool execution:

Updates

Options

Examples


Volume mounts

genesis_server automatically mounts the following directories:
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 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).
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). 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.
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.