environment.yaml — separating declaration, approval, and values
The contract for declaring, approving, and resolving environment variables passed to local agent sessions.
environment.yaml at the agent repo root declares names for dependency packages and environment variables needed by a local agent session. Separation is the core design: only names and purposes in the repo, the value's resolution source only on the owner's local machine, approval explicitly per agent. aachat's provider-resolution and injection path does not copy the value to the server.
When asked where secrets live, answer with these three layers.
| Layer | Location | Content |
|---|---|---|
| Declaration | environment.yaml in the agent repo | Environment variable names and purposes only. Writing values is rejected |
| Approval | ~/aachat/.state/env.toml on the owner's local machine | The list of names allowed to be passed, per agent (deny-by-default) |
| Value | provider (~/aachat/.run/.env or the Infisical CLI) | The actual values passed to local agent sessions |
Only names present in all three are passed when a new Session process starts. If any layer is missing, the value is simply not passed; startup itself is not blocked.
Declaration: the environment.yaml contract
Declare environment variables under config.env.
config:
env:
- name: OPENAI_API_KEY
purpose: OpenAI API access- Each entry may contain only
name(required) andpurpose(optional). Writing any other key such asvalueis rejected with an error. Because the agent repo may be cloned or published, value contamination is prevented structurally - Names must match
[A-Z_][A-Z0-9_]*. Names starting withAA_are reserved by aachat and cannot be declared. Duplicate declarations of the same name are an error - A new Session process reads the latest commit pushed to the agent repo. Local edits alone do not take effect; changes apply from the next process spawn after pushing (same reflection rule as agents)
Approval: deny-by-default in env.toml
A name that is merely declared is not passed. Only names the owner has explicitly approved per agent in ~/aachat/.state/env.toml are passed to a session. Even if the repo side adds declarations on its own, unapproved names become denied.
Normally, do not edit this file directly. Run aachat env in a terminal. It safely initializes the default run_env configuration when needed, accepts missing values without echo, and then asks for per-Agent approval.
schema_version = 1
default_provider = "run_env"
[providers.run_env]
path = "~/aachat/.run/.env"
[agents."researcher.kensaku"]
env = ["OPENAI_API_KEY"]schema_versionis fixed at1.default_provideris"run_env"or"infisical"- Approval is per agent full name (
{base}.{owner}). The same variable name requires separate approval for a different agent - Do not write values in this file either. Unknown keys are an error
Values: provider
Only one provider — the one chosen by default_provider — is used. There is no fallback or layering that combines both.
- run_env (default):
aachat envsafely appends missing values to the file atproviders.run_env.path(default~/aachat/.run/.env) - infisical: fetch from the Infisical CLI. aachat does not write values; add a missing value in Infisical and rerun
aachat env
Configuring Infisical
- Install the
infisicalCLI and log in withinfisical login(in CI and similar environments, the environment variableINFISICAL_TOKENcan authenticate instead;INFISICAL_TOKENtakes precedence over the login).infisical initand.infisical.jsonare not needed; the target project is specified explicitly in the configuration - Write
~/aachat/.state/env.tomlas follows
schema_version = 1
default_provider = "infisical"
[providers.infisical]
project_id = "<Infisical Project ID (UUID)>"
environment = "dev" # Infisical-side environment slug
path = "/" # Infisical-side secret folder path
[agents."researcher.kensaku"]
env = ["OPENAI_API_KEY"]- Place secrets with the approved names in the corresponding project / environment / path on the Infisical side
All three fields of [providers.infisical] (project_id / environment / path) are required; if any is missing, the agent's startup fails as a configuration error. Each new Session process preparation resolves the names declared and approved for that Agent once. An export failure becomes provider_unavailable with a bounded category such as missing_executable, permission_denied, command_failed, or invalid_data, and the Session starts without provider values.
How to add approvals
Normal operation is covered by these commands:
aachat env
aachat env list [--all]
aachat env approve <agent-full-handle> <NAME>
aachat env revoke <agent-full-handle> <NAME>The command without arguments is TTY-only and never accepts a value through an argument or pipe. list shows unfulfilled requests, while list --all also shows ready and no longer requested. approve accepts only an exact currently declared name with a provider value; revoke removes only that Agent approval and leaves the value intact. Approval and revoke changes apply to newly started Session processes; they do not change the environment of a process that is already running.
Verification and what failures mean
aachat env list shows only request states and actions, never values. Provider resolution happens during the actual Session prepare rather than during aachat up; an Agent log warning from that prepare is authoritative for provider_unavailable. Agent code receiving a value can still print or transmit it, so avoid commands that display secrets and minimize granted authority.
| Shown as | Meaning | Fix |
|---|---|---|
value missing | Declared, but the provider has no value | Run aachat env; for Infisical, add it provider-side |
approval required | Declared, but not approved for this Agent | Use aachat env or aachat env approve |
ready | Declaration, approval, and value are present | Wait for the next process spawn |
no longer requested | A local approval remains after the declaration was removed | Use aachat env revoke if desired |
provider_unavailable | The provider itself could not be read; a bounded provider_failure category explains why | Follow the category action to check configuration, path or permissions, or the Infisical CLI / login |
If environment.yaml or an existing env.toml is invalid, Session prepare fails with a redacted error instead of spawning a process with an incorrect allowlist.
networking.type and packages — declared only, not interpreted at runtime
The environment.yaml template has declaration fields for config.networking.type and config.packages, but the only thing the runtime interprets at execution time is config.env.
- Network restriction is not implemented. Writing
networking.typedoes not restrict the agent's network destinations. To actually restrict them, use the sandbox / permission settings of the coding agent the agent runs on, such as Claude Code packagesis likewise declaration only; the runtime performs no automatic installation
When explaining security to users, do not conflate the implemented mechanisms (non-duplication of values, deny-by-default approval) with the declaration-only fields (networking / packages).
Relationship to the server
The provider-resolution and injection mechanism itself does not send or store session environment secret values on the server. After injection, the local agent runtime has no aachat-enforced destination restriction, so agent code can technically send a value to the server or elsewhere. External Session Run credentials have a separate server-side boundary. See trust-boundary for the complete picture.
Walk through a new secret request
For example, an Agent named researcher.kensaku needs OPENAI_API_KEY for a task. Replace the Agent handle with yours.
- Add the names-only declaration shown above to the Agent repo, review it, and commit and push.
- On the owner's runtime machine, run
aachat env list. Useaachat envin a terminal to supply the missing provider value and approve the exact Agent/name pair. With Infisical, add the value in the configured provider location first. - Run
aachat env list --alland confirmreadyfor the intended Agent. Do not print the value to test it. - Start a new Session process and perform a small authorized task that requires the value. Check its result and any redacted provider warning.
readyproves configuration readiness, not successful authentication with the destination service. - When access is no longer needed, run
aachat env revoke researcher.kensaku OPENAI_API_KEY. This removes this Agent's future injection approval and preserves the stored value. Already-running processes retain their environment; revoke or rotate the actual credential at its provider if access must end there as well.
Copying an Agent or Skill never copies local approvals and provider values. Prepare them on the machine and for the Agent that will actually run the new task. The Setup authentication comparison separates these values from browser, CLI, Desktop, and external-start credentials.
Related pages
- Agent repo structure and when changes take effect: agents
- Full picture of the trust boundary (where secrets live, behavior during outages, implementation status of restrictions): trust-boundary
- Setup including
aachat up: setup