mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-30 05:02:58 +00:00
* fix(providers): apply configured options at session startup Treat provider options as one opaque record, with provider-owned validation and per-agent overrides over configured defaults. Keep agent overrides separate from defaults so configuration changes apply on the next launch or resume. * test(providers): verify provider-owned validation through Hub * fix(providers): preserve the complete wrapped session interface
210 lines
8.1 KiB
Markdown
210 lines
8.1 KiB
Markdown
---
|
|
title: Provider options
|
|
description: Sandboxing, permissions, and network rules for Codex, Claude, and OpenCode agents created from the SDK.
|
|
nav: Provider options
|
|
order: 55
|
|
category: TypeScript SDK
|
|
---
|
|
|
|
# Provider options
|
|
|
|
Provider options are an opaque `Record<string, unknown>` passed to the provider.
|
|
The provider decides how to validate and apply it. Claude, Codex, and OpenCode
|
|
use strict schemas: an unknown or misspelled key fails agent creation with a
|
|
message naming the bad key. Providers without option handling ignore the record.
|
|
Pi, OMP, ACP, and plugin providers interpret their own keys.
|
|
|
|
You set options in two places:
|
|
|
|
- **Provider defaults:** `config.json` → `agents.providers.<id>.options`.
|
|
- **One agent:** `config.options` in `client.agents.create()`. Its wire name is
|
|
`providerOptions`.
|
|
|
|
The daemon deep-merges the agent's options over the provider defaults at session
|
|
launch or resume. Plain objects merge recursively; arrays, scalars, and `null`
|
|
replace the base value. Only the agent's own options are stored. Changing
|
|
`config.json` defaults takes effect on the next launch or resume.
|
|
|
|
For example, set Codex defaults once:
|
|
|
|
```json
|
|
{
|
|
"agents": {
|
|
"providers": {
|
|
"codex": {
|
|
"options": {
|
|
"sandbox_mode": "read-only",
|
|
"approval_policy": "never",
|
|
"sandbox_workspace_write": { "network_access": false }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Then create one agent with `config.options: { sandbox_mode: "workspace-write" }`.
|
|
It receives `workspace-write`, retains `approval_policy: "never"`, and retains
|
|
`sandbox_workspace_write.network_access: false`. With no per-agent options it
|
|
receives the defaults above. Keys are provider-native; use the sections below
|
|
for the options each provider accepts.
|
|
|
|
Provider options are not a host boundary. They constrain the agent CLI, which runs as your user on your machine. For untrusted work, run the daemon in a container or on a separate machine. See [Security](/docs/security).
|
|
|
|
## Codex
|
|
|
|
Confine writes to one directory, cut off network access, and stop approval prompts so the run is unattended:
|
|
|
|
```ts
|
|
import { createPaseoClient } from "@getpaseo/client";
|
|
|
|
const client = createPaseoClient({ url: "ws://127.0.0.1:6767/ws" });
|
|
await client.connect();
|
|
|
|
const agent = await client.agents.create({
|
|
config: {
|
|
provider: "codex/gpt-5.5",
|
|
options: {
|
|
approval_policy: "never",
|
|
sandbox_mode: "workspace-write",
|
|
sandbox_workspace_write: {
|
|
writable_roots: ["/Users/me/dev/storefront"],
|
|
network_access: false,
|
|
exclude_slash_tmp: true,
|
|
},
|
|
web_search: "disabled",
|
|
},
|
|
},
|
|
cwd: "/Users/me/dev/storefront",
|
|
prompt: "Fix the failing checkout test.",
|
|
});
|
|
|
|
const result = await agent.waitForFinish();
|
|
console.log(result.status, result.lastMessage);
|
|
|
|
await client.close();
|
|
```
|
|
|
|
| Option | Values |
|
|
| ------------------------- | --------------------------------------------------------------------------------- |
|
|
| `approval_policy` | `untrusted`, `on-request`, `never`, or `{ granular: { … } }` |
|
|
| `sandbox_mode` | `read-only`, `workspace-write`, `danger-full-access` |
|
|
| `sandbox_workspace_write` | `writable_roots`, `network_access`, `exclude_slash_tmp`, `exclude_tmpdir_env_var` |
|
|
| `web_search` | `disabled`, `cached`, `indexed`, `live` |
|
|
| `features` | `multi_agent_v2`, `network_proxy` (boolean or a proxy/domain policy object) |
|
|
|
|
`approval_policy: "never"` only removes the prompts. What the agent is allowed to touch is `sandbox_mode`. Setting `never` without a sandbox mode gives an unattended agent full access.
|
|
|
|
## Claude
|
|
|
|
Turn on Claude's own sandbox, restrict writes to the project, deny reads of credential directories, and allow only two domains:
|
|
|
|
```ts
|
|
import { createPaseoClient } from "@getpaseo/client";
|
|
|
|
const client = createPaseoClient({ url: "ws://127.0.0.1:6767/ws" });
|
|
await client.connect();
|
|
|
|
const agent = await client.agents.create({
|
|
config: {
|
|
provider: "claude/claude-sonnet-5",
|
|
options: {
|
|
disallowedTools: ["WebFetch"],
|
|
sandbox: {
|
|
enabled: true,
|
|
failIfUnavailable: true,
|
|
allowUnsandboxedCommands: false,
|
|
filesystem: {
|
|
allowWrite: ["/Users/me/dev/storefront"],
|
|
denyRead: ["/Users/me/.ssh", "/Users/me/.aws"],
|
|
},
|
|
network: {
|
|
allowedDomains: ["registry.npmjs.org", "github.com"],
|
|
strictAllowlist: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
cwd: "/Users/me/dev/storefront",
|
|
prompt: "Install dependencies and run the focused test.",
|
|
});
|
|
|
|
const result = await agent.waitForFinish();
|
|
console.log(result.status, result.lastMessage);
|
|
|
|
await client.close();
|
|
```
|
|
|
|
| Option | Values |
|
|
| ----------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
| `allowedTools` | Tool names the agent may use without asking |
|
|
| `disallowedTools` | Tool names the agent may never use |
|
|
| `additionalDirectories` | Extra directories the agent may access |
|
|
| `sandbox` | `enabled`, `failIfUnavailable`, `allowUnsandboxedCommands`, `excludedCommands`, `filesystem`, `network` |
|
|
| `settings` | `permissions` (`allow`/`ask`/`deny` rule lists) and a nested `sandbox` |
|
|
|
|
`failIfUnavailable: true` makes agent startup fail when the sandbox cannot be established. Leave it off and Claude runs unsandboxed instead.
|
|
|
|
`sandbox.filesystem` takes `allowWrite`, `denyWrite`, `allowRead`, and `denyRead`. `sandbox.network` takes `allowedDomains`, `deniedDomains`, `strictAllowlist`, and proxy settings.
|
|
|
|
## OpenCode
|
|
|
|
Allow reads and edits, deny anything that reaches outside the project, and gate shell commands by pattern:
|
|
|
|
```ts
|
|
import { createPaseoClient } from "@getpaseo/client";
|
|
|
|
const client = createPaseoClient({ url: "ws://127.0.0.1:6767/ws" });
|
|
await client.connect();
|
|
|
|
const agent = await client.agents.create({
|
|
config: {
|
|
provider: "opencode/opencode/gpt-5.5",
|
|
options: {
|
|
permission: {
|
|
read: "allow",
|
|
edit: "allow",
|
|
webfetch: "deny",
|
|
external_directory: "deny",
|
|
bash: {
|
|
"git status": "allow",
|
|
"git diff*": "allow",
|
|
"git push*": "deny",
|
|
"*": "ask",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
cwd: "/Users/me/dev/storefront",
|
|
prompt: "Implement the requested change and show me the diff.",
|
|
});
|
|
|
|
const result = await agent.waitForFinish();
|
|
console.log(result.status, result.lastMessage);
|
|
|
|
await client.close();
|
|
```
|
|
|
|
Every permission is `ask`, `allow`, or `deny`. Tools that take a target — `read`, `edit`, `glob`, `grep`, `list`, `bash`, `task`, `external_directory`, `repo_clone`, `repo_overview`, `lsp`, `skill` — also accept a pattern map, where later keys act as the fallback. Tools without a target — `todowrite`, `question`, `webfetch`, `websearch`, `codesearch`, `doom_loop` — take a bare action.
|
|
|
|
`permission: "deny"` as a bare string applies to everything at once.
|
|
|
|
An `ask` resolves to a permission request in Paseo, and `waitForFinish()` returns `permission` while it is pending. Use `allow` and `deny` for unattended runs. See [Events](/docs/sdk/events) for reacting to a pending request.
|
|
|
|
## Modes and options
|
|
|
|
`modeId` picks a Paseo mode from the provider's published list, which the daemon shows in the app and reports through [provider discovery](/docs/sdk/providers). `options` is the provider's own configuration. They are separate controls and you can set both:
|
|
|
|
```ts
|
|
config: {
|
|
provider: "codex/gpt-5.5",
|
|
modeId: "full-access",
|
|
options: {
|
|
approval_policy: "never",
|
|
sandbox_mode: "read-only",
|
|
},
|
|
}
|
|
```
|
|
|
|
Where the two overlap, `options` wins. Above, Codex runs read-only even though `full-access` would otherwise grant more.
|