Profile configuration
Define secret bindings, credential destinations, and ordinary egress for agents
An agent profile lives under agent_profiles in either the user-level Stashbase configuration or a project-local stashbase-agent.toml. Each secret binding gives the child a placeholder and defines exactly where Stashbase may inject the matching real value.
Remote secret sources
Without from, the profile key is also the source name loaded from Stashbase.
[agent_profiles.coding]
project = "platform"
environment = "development"
[agent_profiles.coding.secrets.GH_TOKEN]
hosts = ["api.github.com"]
[agent_profiles.coding.secrets.OPENAI_API_KEY]
hosts = ["api.openai.com"]Use from when the source name differs from the variable the tool expects. The child receives the profile key as its placeholder; Stashbase fetches the configured source name.
[agent_profiles.copilot.secrets.GH_TOKEN]
from = "GITHUB_TOKEN"
hosts = ["api.github.com"]Local files and overrides
Set file to load configured source names from a local dotenv, YAML, or JSON file. A file-only profile does not require a Stashbase API key.
[agent_profiles.local-coding]
file = ".env.agent"
[agent_profiles.local-coding.secrets.GH_TOKEN]
hosts = ["api.github.com"]How Stashbase chooses secret sources
Each configured secret is identified by its from value, or by its profile key when from is omitted. Stashbase reads configured sources from file first, then fetches only the still-missing sources from the configured project and environment.
| Profile configuration | Where configured sources come from | API key required |
|---|---|---|
project + environment | Stashbase fetches every configured source name from that environment. | Yes |
file | The local file supplies every configured source name. | No |
project + environment + file | The file wins for sources it contains; Stashbase fetches only the remaining configured sources. | Only when one or more sources are missing from the file |
A combined profile is useful when a developer keeps one credential locally but gets the rest from Stashbase:
[agent_profiles.coding]
project = "platform"
environment = "development"
file = ".env.local"
[agent_profiles.coding.secrets.GH_TOKEN]
from = "GITHUB_TOKEN"
hosts = ["api.github.com"]
[agent_profiles.coding.secrets.OPENAI_API_KEY]
hosts = ["api.openai.com"]If .env.local contains GITHUB_TOKEN, Stashbase does not request it remotely. It fetches only OPENAI_API_KEY from the platform / development environment. The agent receives placeholders named GH_TOKEN and OPENAI_API_KEY, never either real value.
Never place secret values or API keys in an untrusted file.
Hosts and egress
hosts is the allowlist for credential injection. Keep each list limited to destinations that should receive that specific credential. A leading wildcard such as *.githubcopilot.com matches subdomains, not the apex domain.
egress_hosts allows ordinary HTTP(S) traffic without injecting a Stashbase credential. Keep it separate from a secret's hosts list.
[agent_profiles.full-stack]
egress_hosts = ["registry.npmjs.org", "pypi.org", "docs.rs"]
[agent_profiles.full-stack.secrets.GH_TOKEN]
hosts = ["api.github.com", "github.com"]egress_hosts = ["*"] permits unrestricted HTTP(S) egress, but does not expand a secret's injection hosts. Prefer a small destination allowlist.
Block destinations explicitly
Use deny_hosts to block a destination even when it would otherwise be allowed by egress_hosts or a secret's hosts list. Deny rules always take precedence.
This is especially useful when an agent needs broad ordinary egress but must not reach the Stashbase API with the developer's normal local credentials:
[agent_profiles.coding]
egress_hosts = ["*"]
deny_hosts = ["api.stashbase.dev"]
[agent_profiles.coding.secrets.GH_TOKEN]
hosts = ["api.github.com"]With this profile, the agent can make ordinary HTTP(S) requests to any host and can use GH_TOKEN only at api.github.com. Requests to api.stashbase.dev are denied, regardless of any matching allow rule.
If you use a custom Stashbase API endpoint, add the hostname from STASHBASE_API_URL instead. Keep the denylist narrow and use egress_hosts as the primary allow policy; deny_hosts is an explicit override for destinations that must never be reachable.
Egress-only profiles
An egress-only profile has no file, project, environment, or secrets table. It starts the broker solely to enforce destination policy and grants the child no Stashbase-managed credentials. This is useful for Codex with an existing local sign-in or MCP-only workflows that authenticate independently.
[agent_profiles.codex]
egress_hosts = [
"api.openai.com",
"auth.openai.com",
"chatgpt.com",
"mcp.context7.com",
"mcp.linear.app",
]
deny_hosts = ["api.stashbase.dev"]Stashbase prints an explicit egress-only warning when this mode starts. To prevent accidental secret loading, validation rejects an egress-only profile that defines file, project, or environment.
Examples
Codex with Context7, Linear, and Stripe MCP
This profile starts Codex with its existing sign-in; Stashbase does not provide an OpenAI API key. It loads the Context7 and Linear credentials from the selected Stashbase project environment, then injects each only at its MCP host. Stripe remains egress-only and uses its existing OAuth session.
egress_hosts is limited to Codex and Stripe traffic. Context7 and Linear are not egress hosts: their destinations are allowed through their secret-specific hosts rules. deny_hosts keeps a nested Stashbase CLI from reaching the Stashbase API with the developer's normal local credentials.
[agent_profiles.codex-mcp]
project = "project"
environment = "agents-local_dev"
egress_hosts = [
"api.openai.com",
"auth.openai.com",
"chatgpt.com",
"mcp.stripe.com",
]
# Context7 expects its key in a custom header.
[agent_profiles.codex-mcp.secrets.CONTEXT7_API_KEY]
hosts = ["mcp.context7.com"]
header = "CONTEXT7_API_KEY"
# Linear accepts its API key as Authorization: Bearer <key>.
[agent_profiles.codex-mcp.secrets.LINEAR_API_KEY]
hosts = ["mcp.linear.app"]The child receives placeholders named CONTEXT7_API_KEY and LINEAR_API_KEY, never their real values. CONTEXT7_API_KEY is exchanged only in Context7's required CONTEXT7_API_KEY header at mcp.context7.com; LINEAR_API_KEY is exchanged only in the default Bearer header at mcp.linear.app.
Start Codex with the profile:
stashbase agent validate --profile codex-mcp --profile-source directory
stashbase agent run --profile codex-mcp --profile-source directory -- codexIf your organization uses a custom Stashbase API endpoint, replace api.stashbase.dev with the hostname from STASHBASE_API_URL.
Configure the Context7, Linear, and Stripe MCP servers in Codex before launching this profile. Codex and Stripe use their existing sign-in or OAuth sessions; Stashbase injects only the Context7 and Linear keys.
If your Codex authentication flow needs an additional OpenAI host, add it to egress_hosts after confirming the denied destination with stashbase agent logs --action host_denied. Do not add mcp.context7.com or mcp.linear.app to egress_hosts; their secret-specific host rules already permit them.
Custom credential headers
By default, Stashbase exchanges a placeholder in an exact Authorization: Bearer <placeholder> header. Use header for providers that use another header.
[agent_profiles.claude.secrets.ANTHROPIC_API_KEY]
hosts = ["api.anthropic.com"]
header = "x-api-key"Validate before running
Validation does not read secret values or start a broker. It checks the selected source, local-file availability, duplicate bindings, host rules, and header templates.
stashbase agent validate --profile coding
stashbase agent validate --profile coding --profile-source directory
stashbase agent validate --profile coding --json