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.

LayerLocationContent
Declarationenvironment.yaml in the agent repoEnvironment variable names and purposes only. Writing values is rejected
Approval~/aachat/.state/env.toml on the owner's local machineThe list of names allowed to be passed, per agent (deny-by-default)
Valueprovider (~/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.

yaml
config:
  env:
    - name: OPENAI_API_KEY
      purpose: OpenAI API access
  • Each entry may contain only name (required) and purpose (optional). Writing any other key such as value is 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 with AA_ 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.

toml
schema_version = 1
default_provider = "run_env"

[providers.run_env]
path = "~/aachat/.run/.env"

[agents."researcher.kensaku"]
env = ["OPENAI_API_KEY"]
  • schema_version is fixed at 1. default_provider is "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 env safely appends missing values to the file at providers.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

  1. Install the infisical CLI and log in with infisical login (in CI and similar environments, the environment variable INFISICAL_TOKEN can authenticate instead; INFISICAL_TOKEN takes precedence over the login). infisical init and .infisical.json are not needed; the target project is specified explicitly in the configuration
  2. Write ~/aachat/.state/env.toml as follows
toml
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"]
  1. 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:

text
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 asMeaningFix
value missingDeclared, but the provider has no valueRun aachat env; for Infisical, add it provider-side
approval requiredDeclared, but not approved for this AgentUse aachat env or aachat env approve
readyDeclaration, approval, and value are presentWait for the next process spawn
no longer requestedA local approval remains after the declaration was removedUse aachat env revoke if desired
provider_unavailableThe provider itself could not be read; a bounded provider_failure category explains whyFollow 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.type does 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
  • packages is 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.

  1. Add the names-only declaration shown above to the Agent repo, review it, and commit and push.
  2. On the owner's runtime machine, run aachat env list. Use aachat env in 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.
  3. Run aachat env list --all and confirm ready for the intended Agent. Do not print the value to test it.
  4. Start a new Session process and perform a small authorized task that requires the value. Check its result and any redacted provider warning. ready proves configuration readiness, not successful authentication with the destination service.
  5. 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