Profile configuration
Define scoped HTTP credential capabilities and ordinary egress for agents
An agent profile lives under agent_profiles in the user-level Stashbase configuration, or as a direct repository-local file at .stashbase/agents/<name>.toml. Each binding gives the child a placeholder and defines exactly when Stashbase may inject the matching real value.
Create a deliberately closed repository-local starter profile with:
stashbase agent init codexThis creates .stashbase/agents/codex.toml with no egress destinations granted. It never overwrites an existing profile unless you pass --force.
Profile reference
| Setting | Purpose |
|---|---|
allow_hooks | Explicitly enable installed agent hooks: dependency_check and secret_scan. |
[secrets] | Configure the Stashbase project/environment used by secret bindings. These settings are no longer valid at the profile root. |
[personal_credentials.<binding>] | Bind an account-owned Personal Credential. Personal Credentials are available only in remote sessions. |
secrets.project and secrets.environment | Select the Stashbase environment from which configured secret sources are loaded. Both are required when using remote secrets. |
file | Top-level profile key. Read configured secret sources from a dotenv, YAML, or JSON file. File values take precedence over remote values. |
egress_hosts | Allow ordinary HTTP(S) traffic without a Stashbase-managed credential. |
deny_hosts | Block destinations even if another allow rule matches. |
allow_network_listeners | On macOS, allow the agent to bind local TCP listeners and temporary Unix sockets. Defaults to false; has no effect on Linux. |
[filesystem] deny_read | Deny reads from the listed paths, globs, or re: regexes and their descendants. See Filesystem restrictions. |
[filesystem] deny_write | Deny writes to the listed paths and their descendants. |
[sandbox] backend | native (default) or docker. See Docker sandbox. |
[sandbox] image | Docker only: run this image instead of the built-in default. Conflicts with dockerfile. |
[sandbox] dockerfile | Docker only: build and run this Dockerfile, relative to the working directory. Conflicts with image. |
[sandbox] memory and [sandbox] cpus | Docker only: cap container memory (2g) and CPUs (1.5). No cap by default. |
[workspace] worktree | Run the agent in its own git worktree. See Git worktrees. |
[config_env] | Plaintext, non-sensitive environment variables for the agent. See Config environment variables. |
secrets.<binding>.hosts | Limit where that binding's placeholder can be exchanged for its real secret. |
secrets.<binding>.rules | Allow or deny credential injection by destination host, HTTP method, and normalized URL path. See credential rules. |
secrets.<binding>.from | Select a Stashbase secret name that differs from the binding name. |
secrets.<binding>.env | Choose the environment variable through which the child receives the placeholder. |
secrets.<binding>.header | Use a credential header other than Authorization. |
secrets.<binding>.placeholder | Set an opaque, format-compatible placeholder for clients that validate token shape before sending a request. |
Remote secret sources
Without from, the profile key is also the secret name loaded from Stashbase.
[secrets]
project = "project"
environment = "environment"
egress_hosts = ["api.openai.com"]
[secrets.GH_TOKEN]
[[secrets.GH_TOKEN.rules]]
effect = "allow"
hosts = ["api.github.com"]
methods = ["GET"]
paths = ["*"]
[secrets.OPENAI_API_KEY]
[[secrets.OPENAI_API_KEY.rules]]
effect = "allow"
hosts = ["api.openai.com"]
methods = ["POST"]
paths = ["*"]Use from when the Stashbase secret name differs from the variable the tool expects. The child receives the profile key as its placeholder; Stashbase fetches the configured source name.
[secrets.GH_TOKEN]
from = "GITHUB_TOKEN"
[[secrets.GH_TOKEN.rules]]
effect = "allow"
hosts = ["api.github.com"]
methods = ["GET"]
paths = ["*"]Child variable names and placeholders
Use env when the child expects a different environment variable name. The value remains an opaque placeholder, never the real secret.
[secrets.TOOL_TOKEN]
env = "TOOL_API_KEY"
header = "x-api-key"
[[secrets.TOOL_TOKEN.rules]]
effect = "allow"
hosts = ["api.example.com"]
methods = ["GET", "POST"]
paths = ["/v1/*"]The child receives TOOL_API_KEY=${STASHBASE_TOOL_TOKEN}. The Agent Proxy exchanges that value only in the x-api-key header at api.example.com.
Some clients check an API-key format before issuing a request. Set placeholder to an opaque value that passes that local check:
[secrets.TOOL_TOKEN]
placeholder = "provider-shaped-but-non-secret-placeholder"This compatibility value is not a credential. Stashbase still gets the real secret from from (or the binding name) and exchanges only the exact configured placeholder.
Personal Credentials
Personal Credentials are account-owned credentials resolved by Stashbase for the authenticated user. Add them under personal_credentials when a remote Agent Proxy session should use a credential that is private to your account rather than a shared project/environment secret.
Personal Credentials are supported only with --remote. They can be used by themselves or alongside [secrets.<binding>] bindings. A Personal-Credential-only profile does not need project, environment, or file, and its remote session request omits project/environment identifiers.
egress_hosts = ["api.openai.com"]
[personal_credentials.LINEAR_API_KEY]
env = "LINEAR_API_KEY"
[[personal_credentials.LINEAR_API_KEY.rules]]
effect = "allow"
hosts = ["mcp.linear.app"]
methods = ["GET", "POST"]
paths = ["/mcp"]Personal Credentials are never fetched, printed, exported, persisted, or logged by the CLI. The remote Agent Proxy resolves them only for approved requests. Service API keys cannot be used for sessions that contain Personal Credentials, and Personal Credential access must be enabled for the workspace.
Local files and overrides
Set the top-level file profile key to load configured source names from a local dotenv, YAML, or JSON file. A file-only profile does not require a Stashbase API key.
file = ".env.local"
[secrets.GH_TOKEN]
[[secrets.GH_TOKEN.rules]]
effect = "allow"
hosts = ["api.github.com"]
methods = ["GET"]
paths = ["*"]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 secrets.project and secrets.environment.
| Profile configuration | Where configured sources come from | API key required |
|---|---|---|
secrets.project + secrets.environment | Stashbase fetches every configured source name from that environment. | Yes |
file | The local file supplies every configured source name. | No |
secrets.project + secrets.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:
file = ".env.local"
[secrets]
project = "project"
environment = "environment"
[secrets.GH_TOKEN]
from = "GITHUB_TOKEN"
[[secrets.GH_TOKEN.rules]]
effect = "allow"
hosts = ["api.github.com"]
methods = ["GET"]
paths = ["*"]
[secrets.OPENAI_API_KEY]
[[secrets.OPENAI_API_KEY.rules]]
effect = "allow"
hosts = ["api.openai.com"]
methods = ["POST"]
paths = ["*"]If .env.local contains GITHUB_TOKEN, Stashbase does not request it remotely. It fetches only OPENAI_API_KEY from the project / environment 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.
Config environment variables
Use [config_env] to give the agent ordinary, non-sensitive configuration. Values are stored in plaintext in the profile and work with both the native and the Docker backend (a Docker container otherwise starts with an empty environment).
[config_env]
NODE_ENV = "development"
RUST_LOG = "info"
PORT = 3000Values can be strings, numbers, or booleans; the agent always receives them as strings. They take precedence over variables inherited from your shell.
To set or override a value for a single run, pass --config-env (repeatable):
stashbase agent run --profile coding --config-env NODE_ENV=test --config-env PORT=4000 -- claudeCredentials don't belong here; use [secrets] so the agent only ever sees a placeholder. Stashbase checks every value, and one that looks like a credential (a name such as *TOKEN* or *API_KEY*, a known token format, a URL with a password, or a long random-looking string) is flagged: agent validate warns, and agent run asks for confirmation, failing when it can't ask (non-interactive or --silent). Flagged values are never printed. If a flagged value really isn't secret, mark it:
[config_env]
BUILD_HASH = { value = "9f86d081884c7d659a2feaa0c55ad015", not_secret = true }Some names are rejected:
- Variables the sandbox sets: proxy and CA variables,
HOME,TMPDIR,FORCE_COLOR, and anything starting withSTASHBASE_. PATH,LD_*, andDYLD_*, which control the programs and libraries that start the sandbox.- A name already provided by a
[secrets]or[personal_credentials]binding.
Each NAME=value can be up to 64 KiB and the whole table up to 256 KiB. Keep larger content in a file in the workspace.
Restrict filesystem access
See the dedicated Filesystem restrictions page for platform behavior, diagnostics, and troubleshooting.
Use [filesystem] deny_read and [filesystem] deny_write to protect sensitive files and directories:
[filesystem]
deny_read = [".env", "~/.ssh", "~/.aws"]
deny_write = [".git", "~/.ssh"]Filesystem entries may be relative to the working directory, home-directory paths such as ~/.ssh, or absolute paths. A matching entry also covers its directory descendants. Entries can also be globs (**/.env*) or re:-prefixed regular expressions; see Filesystem restrictions for backend support. Patterns aren't supported on Windows.
On macOS, filesystem restrictions use the Seatbelt sandbox. On Linux, Stashbase prefers a systemd user session and can use bubblewrap as a fallback. If no supported filesystem-enforcement backend is available, validation and launch fail closed rather than silently weakening the policy. For container isolation with a network-layer firewall on any platform, including Windows, set [sandbox] backend = "docker"; see Docker sandbox. Existing file descriptors and data already loaded into process memory are outside filesystem restrictions.
Allow local network listeners
Agent runs deny incoming network listeners by default. On macOS, set
allow_network_listeners = true when a trusted test or worker process needs to
bind a local TCP listener or use Unix-socket IPC:
allow_network_listeners = trueThis allows localhost TCP connections and Unix sockets under the system
temporary directories so nested test runners such as Nx, Jest, and Rust
workers can communicate. macOS Seatbelt cannot restrict TCP binding to
127.0.0.1, so this also permits binding the host's LAN addresses. Enable it
only for profiles that need it. It does not widen direct internet access, which
remains restricted to the Agent Proxy. On Linux, loopback remains available for
the embedded proxy and this setting has no effect.
A remote session still requires at least one Stashbase-managed secret or Personal Credential; a policy-only profile cannot be used with --remote.
Use validation before starting an agent:
stashbase agent validate --profile codingFilesystem denials observed directly by the proxy appear in the audit log as filesystem_denied events. A nested tool may instead surface the native operating-system error it received.
Configuration changes
Profiles created for older CLI versions need these changes:
- Move
projectandenvironmentinto the[secrets]table. Top-levelprojectandenvironmentfields are rejected.filestays a top-level profile key. - Use a remote secret binding's
fromfield to select a Stashbase secret when its name differs from the binding. - If using
value_template, use{value}as the placeholder instead of{secret}. - Audit metadata uses
binding_nameandbinding_sourceto identify the binding and whether it came from a Stashbase secret or a Personal Credential.
Hosts and egress
hosts is the legacy host-only allowlist for credential injection. It applies when the binding has no rules. 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 controls where the agent may connect, including ordinary HTTP(S) traffic without injecting a Stashbase credential. It remains separate from a secret's credential policy: a matching credential rule never widens ordinary egress.
egress_hosts = ["registry.npmjs.org", "pypi.org", "docs.rs"]
[secrets.GH_TOKEN]
[[secrets.GH_TOKEN.rules]]
effect = "allow"
hosts = ["api.github.com", "github.com"]
methods = ["GET"]
paths = ["*"]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:
egress_hosts = ["*"]
deny_hosts = ["api.stashbase.dev"]
[secrets.GH_TOKEN]
[[secrets.GH_TOKEN.rules]]
effect = "allow"
hosts = ["api.github.com"]
methods = ["GET"]
paths = ["*"]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 secrets or personal_credentials table. It starts the Agent Proxy 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.
egress_hosts = ["api.openai.com", "chatgpt.com"]
deny_hosts = ["api.stashbase.dev"]Stashbase prints an explicit egress-only warning when this mode starts. To prevent accidental credential loading, validation rejects an egress-only profile that defines [secrets] or [personal_credentials].
HTTP MCP servers
Use [mcp_servers.<name>] to associate an HTTP MCP endpoint with a credential binding and restrict its tools. See HTTP MCP servers for configuration, authorization semantics, inspection commands, and local versus remote behavior.
Custom credential headers
By default, Stashbase exchanges a placeholder in an exact Authorization: Bearer <placeholder> header. Use header for providers that use another header.
[secrets.CONTEXT7_API_KEY]
header = "CONTEXT7_API_KEY"
[[secrets.CONTEXT7_API_KEY.rules]]
effect = "allow"
hosts = ["mcp.context7.com"]
methods = ["GET", "POST"]
paths = ["/mcp"]