The only requirement is the Docker CLI.
Quick start
Just want to run Genesis locally? Here’s how:Need the latest version?
Installation
~/bin:
genesis_server— Local Genesis server with persistent SQLite databasegenesis_cli— CLI for local or Snowflake native app operationsgenesis_update— Pulls latest container versionmcp_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 whenLAUNCH_GUIis notfalse. The self-hosted server image setsLAUNCH_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 on127.0.0.1:8501, sokubectl port-forwardreaches it, and on the container’s own address, so a published port or Kubernetes Service reaches it.21234— Shell In A Box debug shell
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. 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:
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 lightweightgenesis-app-runner image built from container/Dockerfile.app-runner:
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:
CLAUDE_CODE_VERSION build argument:
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.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 startscontainer/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 asSYS_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 inconfig.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.
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
Model Context Protocol (MCP)
Adding MCP servers
Themcp_bridge utility allows you to add locally hosted MCP servers to Genesis, giving you access to additional tools and capabilities.
Usage:
Programmatic usage
genesis_cli is designed for use in programs — can run prompts, call tools, and offer MCP services.
Examples
Basic interaction: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.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.
