Genesis k8s deployment inputs + named environment profiles¶
CONCEPT:AU-OS.deployment.genesis-environment-profiles — this page is the current architecture record for the capability.
Genesis already resolves a topology profile — tiny / single-node-prod /
enterprise (agent_utilities.deployment.config_generator.PROFILES), answering
how big is this deployment. It did not answer which named environment a given
topology deploys into — a single-node-prod box can be dev, test, or prod,
and an enterprise cluster commonly runs dev/test/prod/uat/sit namespaces
side by side. agent_utilities.deployment.genesis_environments adds that second,
independent axis.
The ten input categories¶
A profile is ten closed-schema sections assembled into one EnvironmentProfile:
environment, target, release, runtime, filesystem, configuration,
secrets, network, identity, validation. Every field a section declares must
be present in the profile's YAML file — an omitted or an unrecognized key is a
load-time error naming the exact section and key. Nothing is filled in silently by
a Python-side default, so a profile is fully reviewable from the file alone.
filesystem expresses the writable-path exceptions the read-only-root-filesystem
hardening work is uncovering (writable_paths: [{mount_path, medium, reason,
size_limit}]) — each exception must name why it exists — plus, since BUG-ROFS-1
(services/graph-os's readOnlyRootFilesystem rollout had to rediscover its
image's real $HOME by reading a live container's /etc/passwd), an explicit
runtime_paths: [{env_var, path, writable_path_ref}] binding for every one of
HOME/XDG_CACHE_HOME/XDG_CONFIG_HOME/XDG_DATA_HOME/XDG_STATE_HOME/
AGENT_UTILITIES_DATA_DIR — each must be bound exactly once, to an absolute path
anchored under a writable_paths mount this same profile already declared. validation expresses
what must be proven post-deploy, not merely observed as "not crashing": every
profile must declare at least one functional_checks entry of kind
mcp-tools-list — a real MCP tools/list call, per this repo's standing rule that
/health alone is not enough evidence a deployment works.
Secrets are references, never values — "this repository do not infer credentials"¶
secrets.required is a list of {name, ref, keys}. ref must use one of four
schemes: env://VAR, vault://path, secret://path, or
k8s-secret://<namespace>/<name> (the last one names a pre-existing Kubernetes
Secret object, matching the graph-os production manifest's
envFrom.secretRef.name: graph-os-secrets shape). A required secret with an empty
or missing ref raises MissingSecretReferenceError at load time — never a
default, an empty value, or a guessed lookup path. identity.client_secret_ref
(when set) must name an entry actually declared in secrets.required.
configuration.env — the one place free-form non-secret settings are allowed — is
checked against the same secret-suffix heuristic config_generator._is_secret
already uses, so a *_TOKEN/*_PASSWORD key cannot be smuggled into the
"safe to read out loud" section.
Extension — the named set is data, not a closed enum¶
flowchart LR
subgraph Discover["list_environment_profiles()"]
B["deploy/environments/*.yaml\n(repo-shipped: dev, test, prod)"]
X["~/.config/agent-utilities/environments/*.yaml\n(operator extension dir)"]
end
B -->|"stem = profile name"| M["name -> path catalog\n(extension dir overrides a\nbuilt-in of the same name)"]
X -->|"stem = profile name"| M
M --> L["load_environment_profile(name)"]
L -->|"YAML -> ten typed sections"| P["_profile_from_mapping\n(fails loud: missing/extra key)"]
P --> V["validate_environment_profile"]
V -->|"secret ref scheme, identity->secret\nname, non-secret env, writable-path\nreason, genesis.yaml enum\ncross-check, prod digest-pin,\nmcp-tools-list required"| OK["EnvironmentProfile"]
V -.->|"any failure"| ERR["EnvironmentProfileError /\nMissingSecretReferenceError\n(names the exact field)"]
G["genesis.yaml\nrun_plan.orchestrators /\nsubstrate_authority / idp"] -.->|"read as data,\nnot imported"| V
Dropping a new uat.yaml (or any name) into either directory makes --profile
uat immediately valid — no PR to this repo. load_environment_profile on an
undiscovered name fails naming exactly what was found and where a new file
will go; it never falls back to a "closest" name.
Where this fits, and where it does not¶
This module defines, discovers, loads, and validates the schema only. It does
not render a profile into live Kubernetes objects — that remains graph-os's
graphos-genesis skill's Phase 4 (references/kubernetes-and-helm.md in the
skill) and the existing deploy/k8s/production-cell/ render pipeline
(scripts/release/render_production_cell.py). A validated EnvironmentProfile is
a typed input those phases can consume, not a second renderer.
CLI + programmatic access¶
setup-config environments list # discovered profile names -> source file
setup-config environments show prod # fully-resolved, reviewable JSON (refs only, no values)
setup-config environments validate uat # load + validate; exit 1 and name the problem on failure
from agent_utilities.deployment.genesis_environments import load_environment_profile
profile = load_environment_profile("prod") # raises loudly on any problem
Categories judged thin or overlapping¶
identityandsecretspartially collapse by design.identitycarries no credential shape of its own —client_secret_refis a name that must resolve intosecrets.required, so the actual reference scheme/validation lives in one place.configurationandsecretsare a deliberate pair, not a merge.configuration.envis validated against the same secret-suffix heuristicsecrets.requiredentries are exempt from, specifically so a secret can never be expressed as a literal in the "safe" section.targetis currently narrow in practice —orchestratoris always"kubernetes"in the three shipped profiles, since this work is scoped to genesis k8s deployment inputs. The field stays generic (validated againstgenesis.yaml's fullrun_plan.orchestratorslist, not a kubernetes-only enum) for forward consistency with genesis's broader non-k8s targets, rather than being narrowed to a boolean.