Environment
The server always starts, even when configuration is missing. Each RPC that needs the
missing piece answers with a precise FailedPrecondition naming it. The pod does not
crash-loop over a missing secret. Secrets are read through the platform secret backend:
the environment locally, a mounted file in production.
Identity and access
| Variable | Purpose | When unset |
|---|---|---|
CORE_FORGE_IDENTITY_KEY | Required. Base64 of at least 32 random bytes, shared only with CORE’s console proxy. Verifies every request’s X-Core-Identity. forge dev proxy reads the same variable. | Every RPC answers FailedPrecondition naming it (fail closed). This also applies if the value is not base64 or is shorter than 32 bytes. |
FORGE_OWNER_EMAIL | Optional extra allowlist: comma, semicolon or space separated, and case-insensitive. Read on every RPC. | CORE’s sign-in is the only gate. |
GitHub
| Variable | Purpose | When unset |
|---|---|---|
CORE_GH_APP_ID, CORE_GH_APP_PRIVATE_KEY or CORE_GH_APP_PRIVATE_KEY_FILE | The platform’s GitHub App. FORGE mints an installation token from it. The token stays in memory and is never persisted. | The server runs, and GitHub-backed RPCs answer “not connected to GitHub”. |
FORGE_GITHUB_ORG | The organisation that holds forged repos | org-runink |
FORGE_GITHUB_TOKEN | Dev only, never a deployment. A personal token used instead of the App. The server logs DEV: acting as a personal GitHub token, not the platform App. | The App is used. |
FORGE_TEMPLATE_REPO | owner/name template for new single-kind web apps (CreateApp) | Seeded from the embedded web skeleton |
FORGE_TEMPLATE_REPO_PIPELINE | The same for pipelines. It deliberately does not fall back to FORGE_TEMPLATE_REPO. | Seeded from the embedded pipeline skeleton |
Storage
| Variable | Purpose | When unset |
|---|---|---|
CORE_ENVELOPE_KEK | Required for chats and every write. FORGE derives its appfs key from it with HKDF (label runink/appfs/forge). | appfs does not mount. Chats and approvals answer FailedPrecondition. WhoAmI and the ForgeService reads still work. |
FORGE_APPFS_DIR | The local encrypted appfs root, used when no object store is configured. A pod must mount a persistent volume here, or every restart loses the audit and the chats. | ~/.local/state/forge/appfs |
OBJECTSTORE_ENDPOINT, OBJECTSTORE_ACCESS_KEY, OBJECTSTORE_SECRET_KEY | Put the appfs root on objectd (bucket forge) | The local fallback is used. If these are set but broken, appfs does not mount; it never falls back to local disk silently. |
Planner
| Variable | Purpose | When unset |
|---|---|---|
INFERENCE_URL | The in-cluster OpenAI-compatible plane. Point it at the general tier. | ProposePlan answers FailedPrecondition. Typed commands are unaffected. |
INFERENCE_MODEL | Required for the planner. The model name sent in the request. There is deliberately no default. | The same FailedPrecondition, naming it |
FORGE_JUDGEMENT | The planner’s judging gate | On. Only off, false, 0, no or disabled turn it off. |
Serving
| Variable | Purpose | Default |
|---|---|---|
PORT | The port for gRPC, gRPC-web and the bundle (flag --port) | 0 (auto-assign) |
FORGE_LISTEN_HOST | The listen address (flag --host) | 127.0.0.1 by hand. The image sets ::, because the platform’s pod network is IPv6 single-stack and 0.0.0.0 would be unreachable. |
FORGE_WEB_DIR | The Flutter web bundle directory, served from the same origin. The bundle must be built with --base-href /forge/. | — |
CORS_ALLOWED_ORIGINS | Comma-separated origins allowed for gRPC-web | * |
Sources
CLAUDE.md (“Environment”); grpc/cmd/serve.go; grpc/internal/auth/identity.go;
grpc/internal/ghforge/ghforge.go (FromEnv); grpc/internal/appstate/appstate.go;
grpc/internal/planner/planner.go (ConfigFromEnv).