--- name: c0-config description: Use when changing c0 deployment configuration, runtime-editable global settings, auth providers, AI providers, MCP Context Forge, discovered registries, secret references, or open-source deployment configuration. --- # c0 Config Use this skill whenever work changes c0 configuration or the boundary between deployment-managed and runtime-managed state. ## Canonical Deployment Configuration The selected `config/.config.jsonc` file is the only source of truth for non-secret operator configuration. Keep configuration readable, reviewable, and shareable there rather than encoding objects in environment variables. - Keep complete, independent `config/dev.config.jsonc`, `config/test.config.jsonc`, `config/pre.config.jsonc`, and `config/prod.config.jsonc` files in the repository's `config/` directory. Do not add cross-file inheritance, partial overrides, or profile merging. - Keep the stage JSONC files, `config/example.config.jsonc`, and `config/c0.config.schema.json` tracked. Ignore secret-bearing `config/.env` and `config/.*.vars` files while tracking their example templates. - Map preview stages such as `pre-123` to `config/pre.config.jsonc`. Other supported stages map directly to `config/.config.jsonc`. - Fail before creating Alchemy resources when the selected file does not exist or fails schema validation. - Parse and schema-decode only the selected file once at the Alchemy deployment boundary. - Use that same resolved object for infrastructure decisions and Worker bindings so build-time and runtime configuration cannot drift structurally. - Keep `schemaVersion` explicit and regenerate `config/c0.config.schema.json` when the schema changes. - Point every stage file at the generated `config/c0.config.schema.json`. Run `nub run config:check` after editing any stage file or its schema. Run `nub run config:schema` intentionally when the generated schema needs to change. - Define the external JSON contract with Effect Schema and generate the editor schema from that same contract. `Schema.Struct` is appropriate for plain JSON DTOs; use `Schema.Class` only when configuration values need class identity, constructors, methods, or branding. Do not parse stage JSONC in a Worker or web request. Do not add a serialized JSON environment variable or a duplicate defaults layer. ## Cloudflare Binding Boundary Alchemy compiles the resolved config into bounded bindings: - Pass cohesive, small server domains as native Cloudflare JSON bindings, such as `C0_CONFIG_AUTH` or `C0_CONFIG_MCPCF`. - Pass browser-safe values as explicit `VITE_*` scalars. Never expose a secret or the full server configuration to the browser. - Do not pass the entire configuration as one large binding. Cloudflare applies binding-count and per-binding size limits. - Keep deployment-time binding budget checks close to the infrastructure code. - Derive Worker env types from the Alchemy resources. Do not hand-write or cast a parallel env contract when resource inference is available. Native JSON bindings arrive as objects. Runtime code should schema-decode them as objects and must not accept legacy JSON strings as a hidden fallback. ## Secrets Secret values never belong in a stage config file. Reference them explicitly at the field that consumes them: ```jsonc { "apiKey": { "env": "C0_LITELLM_API_KEY" } } ``` - Secret reference names must be explicit, stable uppercase environment binding names. - Do not derive secret names from JSON paths or KV keys. - Only secrets explicitly marked with `"generateIfMissing": true` may be generated by Alchemy. - Generated secrets must use stable Alchemy logical ids so they persist in Alchemy state across deployments. - A referenced active secret must resolve or deployment must fail closed. Do not silently fall back to a KV secret when the JSONC field explicitly names a missing deployment secret. - Disabled integrations and providers should not require their otherwise-unused secrets. - `config/.dev.vars`, `config/.test.vars`, `config/.pre.vars`, and `config/.prod.vars` contain secrets and deployment credentials only, never non-secret configuration objects. - Use `nub run config:write-stage-vars -- ` to reconcile a stage file with the active secret references before syncing or deploying it. - Never print secret values during validation or handoff. Names-only inspection is safe. ## Deployment and Runtime Precedence For a domain that supports Admin editing, use this precedence: 1. An explicit domain in the selected stage config is deployment-managed and locked in Admin. 2. If the domain is omitted, read its editable value from `C0_CONFIG` KV. 3. If neither exists, use the domain's documented default or unconfigured state. The lock message must identify the active stage config location, for example `config/prod.config.jsonc:aiProviders.litellm`, and explain that the field must be removed from deployment configuration and redeployed before Admin can edit it. Do not add long-lived compatibility fallbacks for old env names. Migrate callers and delete the obsolete path. Authentication is deployment-managed because it defines which providers may establish identity. Provider kind does not grant authority: provider capabilities independently control sign-in, user provisioning, and explicit account linking. Keep implicit account linking disabled and keep provider secrets as explicit secret references. ## Runtime-Owned State Use `C0_CONFIG` KV for runtime-editable settings and externally discovered registries. Keep stable string keys and JSON values. Runtime-editable setup values: - `config/ai-providers/litellm` - `secrets/ai-providers/litellm/api-key` - `config/mcpcf` - `secrets/mcpcf/admin-api-token` Runtime-discovered registry data: - `registry/ai-providers/litellm/models` - `registry/mcpcf/server-index` - `registry/mcpcf/servers/{serverId}` - `registry/ai-search/sources/{sourceId}` Do not put discovered catalogs or runtime-created sources in JSONC, infrastructure bindings, `.vars` files, GitHub variables, or stage metadata. Refresh and edit them through the owning runtime/admin workflow. Sensitive KV values must use the app-level encrypted-value envelope. Exports from Admin should distinguish these boundaries: - Export deployment-managed setup as a JSONC fragment plus separate secret assignments. - Export runtime registry data as portable runtime data, not as environment overrides. - Never export discovered registries into GitHub secrets. ## Configuration Digest Compute the deployment digest from canonicalized resolved configuration and expose it for health diagnostics, support, and cache invalidation. The digest is observability metadata, not a startup equality gate: Alchemy already uses one resolved object for infrastructure and runtime bindings. ## Storage Boundaries - Use D1 for c0-owned relational state with a schema we control, especially user-owned rows and reporting tables. - Keep `user_mcpcf_server_configs` in D1 because it is user-related relational state. - Use `USER_WORKFLOW_KV` for user-namespaced workflow `kv-put` and `kv-get` storage. - Keep `REPOS_CACHE` for repo/workflow-builder internal caches. - Keep `WORKFLOW_SESSION_RESPONSE_CACHE` for workflow session-node response caching. - Do not add hidden D1/KV fallback paths. When state moves, provide an explicit migration and make the new source authoritative. ## Change Checklist When adding or moving a configuration field: 1. Classify it as public build-time, server deployment-time, secret, runtime-editable, or runtime-discovered. 2. Add it to the shared Effect schema and every complete stage file where it applies. 3. Add an explicit secret reference only if the value is secret. 4. Compile it through the existing Alchemy resolver into the narrowest appropriate binding. 5. Update runtime precedence, Admin lock state, and export behavior where the domain is runtime-editable. 6. Regenerate the JSON schema and Alchemy-derived env types when their sources change. 7. Update stage secret generation/sync workflows if a new active secret name is introduced. 8. Validate with `nub run config:check`, focused tests, and the repository-required typecheck, lint, and format commands.