Stashbase

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 codex

This creates .stashbase/agents/codex.toml with no egress destinations granted. It never overwrites an existing profile unless you pass --force.

Profile reference

SettingPurpose
[secrets]Configure the Stashbase project/environment or local file 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.environmentSelect the Stashbase environment from which configured secret sources are loaded. Both are required when using remote secrets.
secrets.fileRead configured secret sources from a dotenv, YAML, or JSON file. File values take precedence over remote values.
egress_hostsAllow ordinary HTTP(S) traffic without a Stashbase-managed credential.
deny_hostsBlock destinations even if another allow rule matches.
[commands] deniedDeny executable names for the agent and its descendants. See Command restrictions.
[filesystem] deny_readDeny reads from the listed paths and their descendants. See Filesystem restrictions.
[filesystem] deny_writeDeny writes to the listed paths and their descendants.
secrets.<binding>.hostsLimit where that binding's placeholder can be exchanged for its real secret.
secrets.<binding>.rulesAllow or deny credential injection by destination host, HTTP method, and normalized URL path. See credential rules.
secrets.<binding>.source_nameSelect a Stashbase secret name that differs from the binding name.
secrets.<binding>.envChoose the environment variable through which the child receives the placeholder.
secrets.<binding>.headerUse a credential header other than Authorization.
secrets.<binding>.placeholderSet an opaque, format-compatible placeholder for clients that validate token shape before sending a request.

Remote secret sources

Without source_name, the profile key is also the secret name loaded from Stashbase.

.stashbase/agents/coding.toml
[secrets]
project = "project"
environment = "environment"

egress_hosts = ["api.openai.com"]

[secrets.GH_TOKEN]
hosts = ["api.github.com"]

[secrets.OPENAI_API_KEY]
hosts = ["api.openai.com"]

Use source_name 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.

.stashbase/agents/agent.toml
[secrets.GH_TOKEN]
source_name = "GITHUB_TOKEN"
hosts = ["api.github.com"]

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.

.stashbase/agents/agent.toml
[secrets.TOOL_TOKEN]
env = "TOOL_API_KEY"
hosts = ["api.example.com"]
header = "x-api-key"

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:

.stashbase/agents/agent.toml
[secrets.TOOL_TOKEN]
placeholder = "provider-shaped-but-non-secret-placeholder"

This compatibility value is not a credential. Stashbase still gets the real secret from source_name (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.

.stashbase/agents/coding.toml
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 secrets.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.

.stashbase/agents/agent.toml
[secrets]
file = "../../.env.local"

[secrets.GH_TOKEN]
hosts = ["api.github.com"]

How Stashbase chooses secret sources

Each configured secret is identified by its source_name value, or by its profile key when source_name is omitted. Stashbase reads configured sources from secrets.file first, then fetches only the still-missing sources from secrets.project and secrets.environment.

Profile configurationWhere configured sources come fromAPI key required
secrets.project + secrets.environmentStashbase fetches every configured source name from that environment.Yes
secrets.fileThe local file supplies every configured source name.No
secrets.project + secrets.environment + secrets.fileThe 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:

.stashbase/agents/agent.toml
[secrets]
project = "project"
environment = "environment"
file = ".env.local"

[secrets.GH_TOKEN]
source_name = "GITHUB_TOKEN"
hosts = ["api.github.com"]

[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 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.

Restrict commands and filesystem access

See the dedicated Command restrictions and Filesystem restrictions pages for platform behavior, diagnostics, and troubleshooting.

Use [commands] denied to prevent the agent and processes it launches from running selected executables. Use [filesystem] deny_read and [filesystem] deny_write to protect sensitive files and directories:

.stashbase/agents/coding.toml
[commands]
denied = ["ssh", "sudo", "docker"]

[filesystem]
deny_read = [".env", "~/.ssh", "~/.aws"]
deny_write = [".git", "~/.ssh"]

Command restrictions cover normal PATH lookups and, where OS-level enforcement is available, absolute executable paths as well. Shell built-ins are not executable files and are outside the command policy. Denied commands exit with status 126 and return a structured command_denied policy error.

Filesystem entries are explicit paths, not globs. They may be relative to the working directory, home-directory paths such as ~/.ssh, or absolute paths. A matching entry also covers its directory descendants. Invalid paths and glob characters are rejected during validation.

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. Existing file descriptors and data already loaded into process memory are outside filesystem restrictions.

A remote session still requires at least one Stashbase-managed secret or Personal Credential; a policy-only profile cannot be used with --remote.

Use the command inspection and validation commands before starting an agent:

stashbase agent command --profile coding --command curl
stashbase agent command --profile coding --command curl --json
stashbase agent validate --profile coding

The command report shows whether a command is denied and whether enforcement is OS-level or uses the PATH-wrapper fallback. Denials observed directly by the proxy appear in the audit log as command_denied or 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 project, environment, and file into the [secrets] table. Top-level project and environment fields are rejected.
  • Rename a remote secret binding's from field to source_name.
  • If using value_template, use {value} as the placeholder instead of {secret}.
  • Audit metadata uses binding_name and binding_source to 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.

.stashbase/agents/full-stack.toml
egress_hosts = ["registry.npmjs.org", "pypi.org", "docs.rs"]

[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:

.stashbase/agents/coding.toml
egress_hosts = ["*"]
deny_hosts = ["api.stashbase.dev"]

[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 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.

.stashbase/agents/codex.toml
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].

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]
hosts = ["mcp.context7.com"]
header = "CONTEXT7_API_KEY"

Next steps

On this page