Credential custody

Custody controls which runners are allowed to touch a credential. Every vault credential carries a custody policy, and the Browser Agent API enforces it as a hard constraint: when a run references a credential, the runner candidate set is filtered to the policy before any routing decision is made. Smart routing, fallback recovery, parallel races, and learning probes all operate strictly inside the allowed set — routing quality is always subject to the custody constraint, never the other way around. Secrets are injected at run time onto the runner routing selected, subject to this policy. The create default is trusted_runners; deck_only is opt-in.

Policies

  • any — no restriction. Use for read-only or low-risk accounts.
  • trusted_runners — only trusted-tier runners from the catalog. This is the default for new vault credentials. See runner trust tiers.
  • deck_only — opt-in: restricts the credential to the deck runner. Not the vault default.
  • pinned:<runner>[,<runner>…] — an explicit allowlist of runner slugs, e.g. pinned:skyvern or pinned:browserbase,steel.

Set the policy where the credential lives: in Console → Vault, on POST /api/v1/credentials at create time, or later with PATCH /api/v1/credentials/:id. Vault credentials plus a stored policy are the recommended path — see Auth flows.

What enforcement means

The custody filter runs before scoring, so it composes with every routing mode. With routing: "smart" the router picks the best runner inside the allowed set. With routing: "learning"the probe pool is reduced to the allowed set, and the run's banana_peel.routing_note says so. No fallback chain, parallel fan-out, wave, or learning probe can ever dispatch a runner outside the policy.

{
  "model": "banana-peel",
  "input": {
    "url": "https://portal.example-utility.com",
    "goal": "Download the latest bill PDF",
    "credentials_ref": "cred_9f2ab41c77d0e83b4a51"
  },
  "routing": "smart"
}

Every run that enforced a custody policy echoes the applied policy and the effective allowed-runner set under banana_peel.custody, and persists it on the run record — auditors can verify after the fact exactly which runners were eligible.

Conflicts fail fast

If the requested routing and the custody policy have no runner in common — for example a credential marked deck_only with routing: "browserbase" — the request is rejected with 409 and the machine-readable code custody_unsatisfiable before any runner is attempted. Nothing is dispatched and nothing is billed; the vault secret is never decrypted for that request.

{
  "error": {
    "type": "invalid_request_error",
    "code": "custody_unsatisfiable",
    "message": "Custody policy \"deck_only\" excludes every runner in the requested routing (browserbase). Runners this policy allows: deck. Loosen the credential's custody policy (Console → Vault or PATCH /api/v1/credentials/{id}), change the request's `custody`, or pick routing inside the allowed set. No runner was attempted and nothing was billed."
  }
}

Inline credentials

If you pass raw credentials in the task text instead of the vault, set the same policy on the request itself with the custody parameter. When a request uses both a vault credential and a request-level custody, the policies compose: a runner must satisfy both.

{
  "model": "banana-peel",
  "input": "Log into https://portal.example.com with user jdoe and password …, then export the invoice list",
  "routing": "smart",
  "custody": "trusted_runners"
}

Which runners are trusted

trusted_runners resolves against the runner catalog's trustTier — the same classification shown on Runner trust tiers, the security hub, and in the vault UI. Framework + model combos (like playwright-gpt-4o) inherit the tier of their base driver. Runners not in the catalog are conservatively treated as restricted.

For the routing controls themselves, see Routing.

Command Palette

Search for a command to run...