Run and Deploy
You don't need a cluster to try Polychrome: polychrome doctor, init, and start bring up a local stack with a stub model provider until you set a real one. When you're ready, the same workspace deploys to Kubernetes through four overlays.
Prerequisites
Rust 1.95+ (pinned via rust-toolchain.toml), protoc, and libprotobuf-dev. just check runs fmt, clippy, and the tests.
just check
cargo build --workspaceQuickstart (no cluster)
The polychrome CLI's own lifecycle verbs are the fastest path to a working conversation on a laptop — no cluster, no hand-run processes.
cargo build --release -p polyc-cli # or: cargo install --path crates/cli
polychrome doctor # preflight: engine, free ports, disk, platform
polychrome init # write a config.toml pinned to this CLI version
polychrome start # bring the stack up, print the API URL
polychrome send <conv-id> "hello" # drive AgentService.Connect end-to-enddoctor reports one concrete next step per failing check instead of a bare non-zero exit. start picks container when a container engine (container/docker/podman/nerdctl) is on PATH, otherwise native (supervised host processes) — override with --mode. With no model set, the stack runs a stub provider; set POLYCHROME_MODEL (plus provider config) as an environment variable before start to route to a real one. polychrome stop tears the local stack back down.
Manual two-process (dev/debugging)
For working on the control plane or harness themselves, run the two binaries directly instead of through start.
# harness — stub provider unless POLYCHROME_MODEL is set
POLYCHROME_HARNESS_ADDR=127.0.0.1:50053 \
POLYCHROME_SIDE_ADDR=127.0.0.1:8181 \
cargo run -p polyc-harness
# control plane — routes turns through the harness above
POLYCHROME_GRPC_ADDR=127.0.0.1:50052 \
POLYCHROME_SIDE_ADDR=127.0.0.1:8081 \
POLYCHROME_HARNESS_ADDR=http://127.0.0.1:50053 \
cargo run -p polyc-control-plane --bin polychrome-control-planeTo drive a turn end to end, send a properly framed Connect request — the operator CLI does this for you, and crates/slack/tests/integration.rs shows the canonical client shape.
Cluster
local builds images into the host Docker daemon; k3s and gke pull prebuilt public images from GHCR, so they need no local Docker.
docker buildx build --target control-plane -t polychrome:latest --load .
docker buildx build --target harness -t polychrome-harness:latest --load .
docker buildx build --target slack -t polychrome-slack:latest --load .
kubectl apply -k manifests/overlays/local # OrbStack / kind / minikube (built images)
kubectl apply -k manifests/overlays/k3s # self-hosted k3s — Docker-free (GHCR images)
kubectl apply -k manifests/overlays/gke # GKE Autopilot or Standard (Filestore PVC)The k3s overlay is the Docker-free target: k3s bundles its own containerd, so only the cluster host runs k3s and your machine needs nothing but kubectl and the CLI. It enforces NetworkPolicy out of the box. On macOS, run k3s inside a Linux VM (limactl start template://k3s or colima start --kubernetes). A fourth overlay, apple, runs the stack inside Apple's native container runtime (Apple silicon + macOS 26, no third-party VM or daemon) — polychrome up auto-detects it from the polychrome-apple* context name. Overlays otherwise differ only in the StorageClass for the shared event-log PVC; manifests/README.md documents the workload-identity binding for the cloud service account.
Configuration
Every environment variable starts with POLYCHROME_. The model backend is provider-agnostic: every provider sits behind one LlmProvider trait, so a deployment selects a managed cloud provider or a self-hosted, OpenAI-compatible endpoint, with neither privileged. The most useful control-plane vars:
| Env | What it does |
|---|---|
POLYCHROME_MODEL | Managed cloud provider model id; empty → stub provider |
POLYCHROME_PROVIDERS, POLYCHROME_OPENAI_BASE_URL | Comma-separated backends the harness registers (for example, zai,vertex,stub; first that builds wins), or a self-hosted, OpenAI-compatible backend: POLYCHROME_PROVIDERS=openai + POLYCHROME_OPENAI_BASE_URL=http://host:port/v1 |
POLYCHROME_PREFLIGHT | Startup probe of the openai backend (tool-calling + structured output): off / warn / strict |
POLYCHROME_SUMMARY_MODEL | Cheaper model for anchored-iterative summarization |
POLYCHROME_ZAI_API_KEY | z.ai key for the zai (GLM API) / zai-coding (GLM Coding Plan) providers, for example glm-5.2 |
POLYCHROME_HARNESS_ADDR | Shared-Service harness path (http://host:port) |
POLYCHROME_PER_CONVERSATION_HARNESS | Resolve a harness pod per Conversation CR |
POLYCHROME_EVENTLOG_DIR | Commonware journal storage root |
POLYCHROME_LEASE_NAMESPACE | Enables cross-replica single-writer via a Lease |
POLYCHROME_APPROVAL_MODE | How a gated call is resolved: human (default), reviewer (auto-approve provably low-risk calls), or approve-all-dangerous (verification rigs only) |
Observability works the same way in every binary: OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_SERVICE_NAME enable the OTLP exporter, and RUST_LOG / RUST_LOG_FORMAT tune the tracing subscriber.