close
Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.agent-vault.dev/llms.txt

Use this file to discover all available pages before exploring further.

A Service is a per-vault configuration that defines which upstream traffic agents can reach through the proxy and how Agent Vault authenticates to each one. When an agent makes a proxied request, Agent Vault matches the request against the vault’s services by host pattern (which may include an inline path glob like slack.com/api/*), attaches the configured credentials, and forwards the request. If no service matches, the request is forwarded as plain proxy traffic by default; vault admins can flip a vault into strict deny mode (unmatched_host_policy=deny in vault settings) to reject unmatched requests with 403 instead. Each service contains:
  • Name: A canonical per-vault identifier (slug, 3–64 lowercase alphanumeric/hyphen chars, no leading/trailing hyphen, no consecutive hyphens). Required on write for new services — pick a deliberate name like stripe, slack-bot, or internal-billing. name may be omitted only when host + path uniquely matches an existing service (the server adopts that service’s name, the same pattern as host-based delete). Legacy services persisted without a name before this contract are auto-slugified from host + path on read so they remain addressable; the slug becomes durable on the next write.
  • Host: The single matcher field. Accepts a bare hostname (api.stripe.com), a one-level wildcard (*.github.com), or an inline path-scoped form (slack.com/api/*). Reads and writes use the same shape: writes accept any of those forms; reads return the joined inline form so you see exactly what you wrote.
  • Auth config: How Agent Vault authenticates. Five types are supported: bearer, basic, api-key, custom, and passthrough (opt out of injection).
The /discover endpoint returns each service’s name and host (joined inline form). Agents use this to know which services are already available before raising a proposal. When two services share the same bare host but scope to different paths (e.g. Slack with separate Bot and Connection rules), distinguish them by name.
Similar to credentials, services can be configured in two ways:
  • Automatically: As agents do their work, they can raise proposals to add or modify services. You review each proposal, provide any required credentials, and approve. This is the recommended workflow for working with Agent Vault.
  • Manually: You can set services directly via the CLI by applying a YAML file or by using the interactive builder. This can be useful for pre-configuring a vault before inviting agents.

Service structure

Services are defined in a YAML file. Here’s what a single service looks like:
stripe-services.yaml
services:
  - name: stripe
    host: api.stripe.com
    auth:
      type: bearer
      token: STRIPE_KEY
agent-vault vault service set -f stripe-services.yaml --vault my-vault
The host tells Agent Vault which requests this service applies to. The auth block tells Agent Vault how to authenticate, referencing credential keys by name (not the actual credential values). The following section covers all five auth types.

Auth types

Every service must include an auth config that tells Agent Vault how to authenticate to the target host. The auth config references credential key names (not the actual credential values) stored in the vault.

Bearer

Attaches an Authorization: Bearer <token> header. The token field references a credential key.
services:
  - name: api-stripe-com
    host: api.stripe.com
    auth:
      type: bearer
      token: STRIPE_KEY
Common services: Stripe, GitHub, OpenAI.

Basic

Attaches an Authorization: Basic <base64> header using HTTP Basic authentication. The username field is required; password is optional (defaults to empty).
services:
  - name: api-ashbyhq-com
    host: api.ashbyhq.com
    auth:
      type: basic
      username: ASHBY_API_KEY
With a password:
services:
  - name: yoursite-atlassian-net
    host: yoursite.atlassian.net
    auth:
      type: basic
      username: JIRA_EMAIL
      password: JIRA_API_TOKEN

API key

Attaches a credential value to a named header with an optional prefix. The header field defaults to Authorization if omitted.
services:
  - name: api-anthropic-com
    host: api.anthropic.com
    auth:
      type: api-key
      key: ANTHROPIC_KEY
      header: x-api-key
With a prefix:
services:
  - name: api-example-com
    host: api.example.com
    auth:
      type: api-key
      key: EXAMPLE_KEY
      header: Authorization
      prefix: "ApiKey "

Custom

Freeform header templates with {{ SECRET }} placeholders. Each placeholder is resolved to the corresponding credential at proxy time. Use this when none of the typed auth methods fit.
services:
  - name: api-acme-internal
    host: api.acme.internal
    auth:
      type: custom
      headers:
        X-API-Key: "{{ ACME_API_KEY }}"
        X-Tenant-ID: "{{ ACME_TENANT }}"

Passthrough

Allowlists the host without injecting a credential. No credential is stored, read, or attached; client request headers (including Authorization and Cookie) flow through to the upstream — same as for credentialed services, just without a broker-injected auth header on top.
services:
  - name: api-example-com
    host: api.example.com
    auth:
      type: passthrough
Use passthrough when the operator has decided their client already holds the credential (for example, an existing tool that manages its own token) and wants Agent Vault to provide the host allowlist, netguard, TLS interception, and audit logging without putting the secret in the vault. All the other auth types are the default — reach for passthrough only when you explicitly want Agent Vault not to broker the credential.

Header forwarding

Agent Vault forwards your client’s request headers to the upstream unchanged, except for:
  • Hop-by-hop headers per RFC 7230 (Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, Proxy-Connection, Te, Trailer, Transfer-Encoding, Upgrade).
  • Broker-scoped headers that authenticate the client to Agent Vault itself (X-Vault, Proxy-Authorization).
  • The auth slot — the specific header(s) the configured auth type manages. With auth.type: bearer or basic, the broker overrides Authorization. With api-key, it overrides whatever you named in auth.header. With custom, it overrides every key in auth.headers. With passthrough, nothing.
This means vendor headers like anthropic-version, OpenAI-Beta, If-Match, and tracing IDs reach the upstream regardless of auth type. The broker only takes over the headers it’s responsible for injecting.
Passthrough auth configs reject every credential field (token, username, password, key, header, prefix, headers). Setting any of them returns a validation error — if you want Agent Vault to inject a credential, use one of the credentialed auth types instead.
Every credential key referenced in an auth config (whether directly or via {{ KEY }} templates) must resolve to either an existing credential in the vault or a credential slot in the same proposal. Agent Vault returns 400 if a key is missing. This does not apply to passthrough services, which reference no credentials.

Substitutions

Auth types only inject HTTP headers. Some upstream APIs want a credential value in the URL path or query string instead — Twilio’s /Accounts/{AccountSID}/Messages.json, legacy services that take ?api_key=. For those, declare a substitutions block alongside the auth.
services:
  - name: api-twilio-com
    host: api.twilio.com
    auth:
      type: basic
      username: TWILIO_ACCOUNT_SID
      password: TWILIO_AUTH_TOKEN
    substitutions:
      - key: TWILIO_ACCOUNT_SID
        placeholder: __account_sid__
        in: [path]
The agent then sends GET https://api.twilio.com/2010-04-01/Accounts/__account_sid__/Messages.json (routed through the broker via HTTPS_PROXY/HTTP_PROXY). Agent Vault:
  1. Resolves the basic auth credentials and injects Authorization: Basic <base64(SID:TOKEN)>.
  2. Scans only the path (the only surface in in:), finds __account_sid__, replaces it with the URL-encoded SID.
  3. Forwards the request.

Field reference

  • key — UPPER_SNAKE_CASE credential reference. Must resolve to a credential in the vault or a slot in the same proposal.
  • placeholder — the exact wire string Agent Vault matches case-sensitively as a literal. Operators choose the string; the broker does not auto-wrap delimiters around it. The recommended convention is __name__ (double-underscore-bounded snake_case).
  • in — list of surfaces the broker is allowed to scan. Subset of path, query, header. Defaults to [path, query] if omitted. body is reserved for a future version.

Scoping is the security boundary

Agent Vault only scans surfaces listed in in. If an agent embeds the placeholder in a non-declared surface (a JSON body to round-trip via an echo upstream, a header that wasn’t declared), the literal string passes through to upstream — the broker will not substitute. There is no way to coerce the broker into substituting somewhere the operator did not authorize. Use this property to pick a narrow in for strong secrets that happen to live in URLs (legacy ?api_key= APIs): keep in: [query] and the agent cannot exfiltrate the value through a body or a different header.

Placeholder safety rules

The validator rejects placeholders that would cause false-positive substitutions in legitimate URL content:
  • Length ≥ 4 characters.
  • Must contain a __ sequence or a non-[A-Za-z0-9_] character — so a bare word like account_sid is rejected (it could appear as a real path segment), while __account_sid__, sid.value, sid-val, and ~sid~ all pass.
  • At least one alphanumeric character — strings made entirely of delimiters like ____ or ~~~~ are rejected because they would aggressively match URL punctuation.
  • Only RFC 3986 unreserved characters [A-Za-z0-9_-.~] are permitted, so the placeholder survives any HTTP client / SDK / middlebox without percent-encoding round-trips.

header scope is request-wide

When in includes header, the broker scans every outbound header for the placeholder — not one specific named header. Pick a unique placeholder so a typo or a copy-pasted value can’t accidentally land in a header you didn’t intend to rewrite. (Path and query are scoped to those URL components and don’t have this concern.)

Composes with all auth types

Substitutions and auth are independent. A service can use either, both, or neither:
  • Twilio: auth: basic (header) + path substitution for the SID.
  • Legacy ?api_key= API: auth: api-key for an audit header + query substitution for the actual key.
  • A pure-substitution case (e.g. an internal API where the only secret lives in the path): auth: passthrough + path substitution.
Modifying substitutions requires re-supplying auth in the same proposal. Auth-only or enable/disable-only set proposals preserve existing substitutions; to clear them, delete and recreate the service.

Matching rules

The host pattern is the single matcher knob. It can carry just a hostname (api.stripe.com), a wildcard host (*.github.com), or an inline path glob (slack.com/api/*). Host portion supports two modes:
  • Exact match: api.stripe.com matches only api.stripe.com.
  • Wildcard: *.github.com matches api.github.com, uploads.github.com, etc. The * replaces exactly one subdomain segment.
Path portion (optional, follows the host with a /) is a URL glob. A bare host with no path matches any path; a non-empty path must start with / and may use * as a greedy glob (cross-/). **, ?, regex, and a bare * are rejected.

Matching priority

When two host patterns could match a request, the winner is chosen deterministically:
  1. Host tier first. A pattern whose host portion is an exact match of the request host always beats one with a wildcard host (*.example.com) — even when the wildcard rule has a more specific path portion.
  2. Path specificity within a host tier. Among patterns in the same host tier, the rule with the longest literal path prefix wins (characters in the path portion before the first *). A bare-host pattern (no path) scores 0 (catch-all).
  3. Declaration order on tie. If two rules tie on host tier and literal path-prefix length, the rule appearing first in the configured service list wins.
Worked example — Slack with two credentials at the same host:
Requestslack-bot (slack.com/api/*)slack-conn (slack.com/api/apps.connections.*)Winner
slack.com/api/apps.connections.openmatches, prefix length 5matches, prefix length 22slack-conn
slack.com/api/chat.postMessagematchesdoesn’t matchslack-bot
slack.com/oauth/v2/authorizedoesn’t matchdoesn’t matchnone
What this implies for users writing rules:
  • To override a wildcard-host rule for a specific subdomain, add the exact-host rule — it takes priority no matter what its path portion looks like.
  • To layer two credentials on the same host, give them different path portions; the more specific path will win.
  • The matcher does not run regex, does not match on method/headers/query/body, and does not bound * at path segments. Patterns that tie under rule 2 (e.g. slack.com/api/*/v2 and slack.com/api/*/v3) fall to declaration order.

Example

A vault can define multiple services with different auth types and path scopes:
services.yaml
services:
  - name: stripe
    host: api.stripe.com
    auth:
      type: bearer
      token: STRIPE_KEY

  - name: github
    host: "*.github.com"
    auth:
      type: bearer
      token: GITHUB_TOKEN

  - name: anthropic
    host: api.anthropic.com
    auth:
      type: api-key
      key: ANTHROPIC_KEY
      header: x-api-key

  - name: jira
    host: yoursite.atlassian.net
    auth:
      type: basic
      username: JIRA_EMAIL
      password: JIRA_API_TOKEN

  # Slack uses two credentials at the same host — distinguish via inline-path host.
  - name: slack-bot
    host: slack.com/api/*
    auth:
      type: bearer
      token: SLACK_BOT_TOKEN

  - name: slack-conn
    host: slack.com/api/apps.connections.*
    auth:
      type: bearer
      token: SLACK_CONNECTION_TOKEN
agent-vault vault service set -f services.yaml --vault my-vault
Any agent scoped to the vault named my-vault can now proxy requests to these hosts, and Agent Vault attaches the real credentials at request time.

Managing services

Set from a file

agent-vault vault service set -f services.yaml --vault my-vault
Replaces the entire service configuration with the contents of the file. This is idempotent, running it twice with the same file produces the same result.

Set interactively

agent-vault vault service set --vault my-vault
Walks you through adding services, auth configs, and credential references one at a time. Requires a TTY (won’t work in scripts).

View current services

agent-vault vault service list --vault my-vault
Prints the active services as YAML. If no services are configured, the output is empty.

Clear all services

agent-vault vault service clear --vault my-vault
Removes all services. Agents scoped to this vault will get 403 on every proxy request until new services are configured. Prompts for confirmation unless you pass --yes.
The --vault flag defaults to default on all service commands. You only need to specify it when working with additional vaults.
vault service remove, enable, and disable accept either the canonical service name or the bare host. When several path-scoped services share a host (e.g. Slack with slack.com/api/* and slack.com/api/apps.connections.*), passing the bare host returns 409 multiple services match host … with a candidates array of {name, host} (each host carries the joined inline form). Retry with the specific name shown in agent-vault vault service list.
Agents don’t edit service configurations directly. Instead, they propose changes through proposals, bundles of service and credential modifications that a human reviews and approves.Each service in a proposal has an action field:
  • set: Idempotent upsert keyed by canonical name (slug). Adds the service when no entry has that name, or replaces it when one does. name is required for new services. It may be omitted only when host + path uniquely matches an existing service — the server adopts that entry’s name (the same pattern as host-based delete), so an agent that knows the host but not the canonical name can still target an existing service.
  • delete: Removes the service matching the given name. When name is omitted, the bare host portion of host is used as a fallback — a unique host match is resolved automatically; a host shared by multiple path-scoped services returns 409 multiple services match host … with a candidates list, and the proposal must be retried with an explicit name.
When you approve a proposal, Agent Vault atomically merges all service changes into the vault’s configuration in a single transaction. Identity for both set and delete is name.This means agents can request access to new services without you manually editing YAML files. You just review and click “Allow” in the browser approval page.
When a proxy request targets a host not covered by any service, Agent Vault returns 403 with a proposal_hint in the response body. The hint includes the denied host and the endpoint to create a proposal.Well-behaved agents use this hint to automatically raise a proposal requesting access. You receive a browser link to review the request and provide any needed credentials.