@evolvingmachines/evolve 0.0.55-project-sable.20260916.db0bc0bb → 0.0.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/cli/index.cjs +32 -32
  2. package/dist/cli/index.js +27 -27
  3. package/package.json +4 -6
  4. package/skills/evolve/SKILL.md +4 -3
  5. package/skills/evolve-evals/SKILL.md +112 -0
  6. package/{docs-evals → skills/evolve-evals/references}/cli-reference/run.mdx +1 -1
  7. package/{docs-evals → skills/evolve-evals/references}/cli-reference/skills.mdx +4 -4
  8. package/{docs-evals → skills/evolve-evals/references}/core-concepts/agents.mdx +2 -2
  9. package/{docs-evals → skills/evolve-evals/references}/core-concepts/analyze.mdx +1 -1
  10. package/{docs-evals → skills/evolve-evals/references}/core-concepts/jobs.mdx +3 -3
  11. package/{docs-evals → skills/evolve-evals/references}/core-concepts/models.mdx +1 -1
  12. package/{docs-evals → skills/evolve-evals/references}/core-concepts/sandboxes.mdx +2 -2
  13. package/{docs-evals → skills/evolve-evals/references}/core-concepts/secrets.mdx +1 -1
  14. package/{docs-evals → skills/evolve-evals/references}/core-concepts/trial-outputs.mdx +1 -1
  15. package/{docs-evals → skills/evolve-evals/references}/getting-started/quick-start.mdx +1 -1
  16. package/{docs-evals → skills/evolve-evals/references}/index.mdx +1 -1
  17. package/{docs-evals → skills/evolve-evals/references}/sdk/python.mdx +1 -1
  18. package/{docs-evals → skills/evolve-evals/references}/sdk/typescript.mdx +1 -1
  19. package/{docs-evals → skills/evolve-evals/references}/sdk-reference/errors.mdx +2 -2
  20. package/{docs-evals → skills/evolve-evals/references}/sdk-reference/jobs.mdx +2 -2
  21. package/docs-agents/SKILL.md +0 -138
  22. package/docs-agents/index.md +0 -81
  23. package/docs-agents/python/01-getting-started.md +0 -511
  24. package/docs-agents/python/02-configuration.md +0 -855
  25. package/docs-agents/python/03-runtime.md +0 -899
  26. package/docs-agents/python/04-streaming.md +0 -451
  27. package/docs-agents/python/05-swarm-pipeline.md +0 -953
  28. package/docs-agents/python/index.md +0 -122
  29. package/docs-agents/typescript/01-getting-started.md +0 -494
  30. package/docs-agents/typescript/02-configuration.md +0 -841
  31. package/docs-agents/typescript/03-runtime.md +0 -864
  32. package/docs-agents/typescript/04-streaming.md +0 -478
  33. package/docs-agents/typescript/05-swarm-pipeline.md +0 -957
  34. package/docs-agents/typescript/index.md +0 -121
  35. package/docs-evals/SKILL.md +0 -112
  36. package/docs-evals/docs.json +0 -180
  37. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/agent.mdx +0 -0
  38. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/analysis.mdx +0 -0
  39. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/analyze.mdx +0 -0
  40. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/auth.mdx +0 -0
  41. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/check.mdx +0 -0
  42. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/dataset.mdx +0 -0
  43. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/index.mdx +0 -0
  44. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/job.mdx +0 -0
  45. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/secrets.mdx +0 -0
  46. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/skill.mdx +0 -0
  47. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/trial.mdx +0 -0
  48. /package/{docs-evals → skills/evolve-evals/references}/cli-reference/upload.mdx +0 -0
  49. /package/{docs-evals → skills/evolve-evals/references}/core-concepts/check.mdx +0 -0
  50. /package/{docs-evals → skills/evolve-evals/references}/core-concepts/datasets.mdx +0 -0
  51. /package/{docs-evals → skills/evolve-evals/references}/core-concepts/index.mdx +0 -0
  52. /package/{docs-evals → skills/evolve-evals/references}/core-concepts/skills.mdx +0 -0
  53. /package/{docs-evals → skills/evolve-evals/references}/core-concepts/tasks.mdx +0 -0
  54. /package/{docs-evals → skills/evolve-evals/references}/core-concepts/trials.mdx +0 -0
  55. /package/{docs-evals → skills/evolve-evals/references}/core-concepts/upload.mdx +0 -0
  56. /package/{docs-evals → skills/evolve-evals/references}/dashboard/checks.mdx +0 -0
  57. /package/{docs-evals → skills/evolve-evals/references}/dashboard/datasets.mdx +0 -0
  58. /package/{docs-evals → skills/evolve-evals/references}/dashboard/jobs.mdx +0 -0
  59. /package/{docs-evals → skills/evolve-evals/references}/dashboard/traces.mdx +0 -0
  60. /package/{docs-evals → skills/evolve-evals/references}/dashboard/trial-viewer.mdx +0 -0
  61. /package/{docs-evals → skills/evolve-evals/references}/getting-started/installation.mdx +0 -0
  62. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/agents.mdx +0 -0
  63. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/analyses.mdx +0 -0
  64. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/auth.mdx +0 -0
  65. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/checks.mdx +0 -0
  66. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/datasets.mdx +0 -0
  67. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/index.mdx +0 -0
  68. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/meta.mdx +0 -0
  69. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/skills.mdx +0 -0
  70. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/trials.mdx +0 -0
  71. /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/types.mdx +0 -0
  72. /package/{docs-evals → skills/evolve-evals/references}/snippets/global-options.mdx +0 -0
  73. /package/{docs-evals → skills/evolve-evals/references}/snippets/list-flags.mdx +0 -0
@@ -1,855 +0,0 @@
1
- # Configuration
2
-
3
- ## Sandbox Providers
4
-
5
- Works with both Gateway mode (`EVOLVE_API_KEY`) and Direct Provider Key Mode (local BYOK provider keys). With `EVOLVE_API_KEY` only, sandbox defaults to **E2B**. Add a sandbox provider key to auto-resolve to that provider.
6
-
7
- All providers use the `evolve-all` image with pre-installed CLIs.
8
-
9
- | Provider | Env Vars | Auto-Resolves When | First Time Setup |
10
- |----------|----------|-------------------|------------------|
11
- | E2B | `E2B_API_KEY` | Default, or `E2B_API_KEY` set | None — instant |
12
- | Modal | `MODAL_TOKEN_ID` + `MODAL_TOKEN_SECRET` | Both Modal vars set | None — auto-builds image on first run (~2 min) |
13
- | Daytona | `DAYTONA_API_KEY` | `DAYTONA_API_KEY` set | None — auto-creates snapshot on first run (~5 min) |
14
-
15
- See [assets/README.md](https://github.com/evolving-machines-lab/evolve/blob/main/assets/README.md) for detailed setup instructions.
16
-
17
- ---
18
-
19
- ### Auto-Resolution
20
-
21
- Set env vars and the SDK auto-resolves the provider—no `sandbox=` needed:
22
-
23
- ```bash
24
- # .env - Gateway mode with Modal (auto-resolves to Modal)
25
- EVOLVE_API_KEY=sk-...
26
- MODAL_TOKEN_ID=ak-...
27
- MODAL_TOKEN_SECRET=as-...
28
-
29
- # .env - Gateway mode with Daytona (auto-resolves to Daytona)
30
- EVOLVE_API_KEY=sk-...
31
- DAYTONA_API_KEY=...
32
-
33
- # .env - Direct Provider Key Mode with E2B (auto-resolves to E2B)
34
- ANTHROPIC_API_KEY=sk-ant-...
35
- E2B_API_KEY=e2b_...
36
- ```
37
-
38
- ```python
39
- from evolve import Evolve, AgentConfig
40
-
41
- # No sandbox= needed — SDK picks the right provider from env
42
- evolve = Evolve(
43
- agent=AgentConfig(type="claude"),
44
- )
45
-
46
- await evolve.run(prompt="Hello")
47
- ```
48
-
49
- Only use explicit provider creation (below) if you need custom settings like timeout or app name.
50
-
51
- Setting `EVOLVE_API_KEY` together with your own sandbox key is how you control sandbox billing
52
- separately: the sandbox is created and billed on your provider account, while model traffic still
53
- routes through the Evolve gateway on a session-scoped token. One bound to remember — on your own
54
- sandbox account the routing token expires 24 hours after the sandbox comes up, so a single
55
- session is bounded at a day; reconnecting to the sandbox starts a fresh one. Platform-managed
56
- sandboxes carry no such clock; their tokens live and die with the sandbox.
57
-
58
- ---
59
-
60
- ### Managed Sandboxes
61
-
62
- With `EVOLVE_API_KEY` and no provider key, the platform runs the sandbox for you: Evolve
63
- authenticates your key, creates the box on its own account, and records who owns it. You never
64
- hold an E2B, Daytona, or Modal credential, and you are never billed by them directly.
65
-
66
- That is already what auto-resolution does when only `EVOLVE_API_KEY` is set — it gives you a
67
- managed **E2B** sandbox. To run on a different provider, say which one:
68
-
69
- ```python
70
- from evolve import AgentConfig, Evolve, ManagedProvider
71
-
72
- evolve = Evolve(
73
- config=AgentConfig(type='claude'),
74
- sandbox=ManagedProvider(provider='daytona'),
75
- )
76
-
77
- await evolve.run(prompt='Hello')
78
- ```
79
-
80
- `ManagedProvider()` with no argument is managed E2B — the same sandbox auto-resolution gives you.
81
- The provider is an argument rather than an environment variable on purpose: which provider your
82
- program runs on is part of the program.
83
-
84
- Beyond the provider name, `ManagedProvider` carries the Evolve key (when it should not come
85
- from `EVOLVE_API_KEY`) plus sandbox-shape defaults applied to every sandbox it creates.
86
- Every default rides the same validated path as a create-time option — a provider or managed
87
- door that cannot enforce a value refuses it loudly, never silently ignores it:
88
-
89
- ```python
90
- sandbox = ManagedProvider(
91
- provider='daytona',
92
- api_key='sk-...', # (optional) Default: EVOLVE_API_KEY
93
- timeout_ms=7_200_000, # (optional) Lifetime cap for every create
94
- resources={'cpu': 2}, # (optional) Sizing; refused where not enforceable
95
- )
96
- ```
97
-
98
- Managed Daytona carries both of Daytona's planes through the Dashboard — creating and listing
99
- sandboxes, and every command and file operation the agent performs, including streamed command
100
- output. Images come from the snapshots the platform publishes: a managed create names one and
101
- never builds one, so a `resources` request that an existing snapshot cannot honor is refused
102
- rather than silently ignored.
103
-
104
- Managed Modal — `ManagedProvider(provider='modal')` — runs commands and file operations through
105
- the Dashboard's Modal door. Command output streams live, chunk by chunk, and each command's
106
- duration is bounded by the door: 60 minutes by default, 120 minutes at most — a longer
107
- `timeout_ms` is refused with an error naming the bound, never silently shortened. Two Modal
108
- traits carry over: there is no pause — persist progress with Evolve checkpoints instead — and
109
- a running command cannot be interrupted. Sizing, network policy, and the sandbox user are the
110
- platform's; a create that asks for them is refused rather than silently ignored. File writes
111
- ride the door one JSON body at a time, capped at 1 MiB per request — and the cap is on WIRE
112
- bytes, base64 inflation included, so the largest binary payload one write can carry is about
113
- 768 KiB (text rides as-is and gets the full 1 MiB). An over-cap write is refused with a typed
114
- error before anything is sent; split the payload into smaller writes.
115
-
116
- ---
117
-
118
- ### E2B (default)
119
- ```bash
120
- # .env - Gateway mode
121
- EVOLVE_API_KEY=sk-...
122
- E2B_API_KEY=e2b_... # Optional with EVOLVE_API_KEY (auto-resolves)
123
-
124
- # .env - Direct Provider Key Mode
125
- ANTHROPIC_API_KEY=sk-ant-... # Or OPENAI_API_KEY, GEMINI_API_KEY, CLAUDE_CODE_OAUTH_TOKEN
126
- E2B_API_KEY=e2b_... # Required in Direct Provider Key Mode
127
- ```
128
-
129
- ```python
130
- from evolve import E2BProvider
131
-
132
- sandbox = E2BProvider(
133
- api_key=os.getenv('E2B_API_KEY'), # (optional) Auto-resolves from env
134
- timeout_ms=3600000, # (optional) Default: 3600000 (1 hour)
135
- template_id='my-custom-template', # (optional) E2B template ID. Default: 'evolve-all'
136
- )
137
- ```
138
-
139
- ### Modal
140
- ```bash
141
- # .env - Gateway mode
142
- EVOLVE_API_KEY=sk-...
143
- MODAL_TOKEN_ID=ak-...
144
- MODAL_TOKEN_SECRET=as-...
145
-
146
- # .env - Direct Provider Key Mode
147
- ANTHROPIC_API_KEY=sk-ant-... # Or OPENAI_API_KEY, GEMINI_API_KEY, CLAUDE_CODE_OAUTH_TOKEN
148
- MODAL_TOKEN_ID=ak-...
149
- MODAL_TOKEN_SECRET=as-...
150
- ```
151
-
152
- ```python
153
- from evolve import ModalProvider
154
-
155
- sandbox = ModalProvider(
156
- token_id=os.getenv('MODAL_TOKEN_ID'), # (optional) Auto-resolves from env
157
- token_secret=os.getenv('MODAL_TOKEN_SECRET'), # (optional) Auto-resolves from env
158
- app_name='my-app', # (optional) Default: 'evolve-sandbox'
159
- timeout_ms=3600000, # (optional) Default: 3600000 (1 hour)
160
- endpoint='https://api.modal.com:443', # (optional) Default: https://api.modal.com:443
161
- image_name='evolve-all', # (optional) Default: 'evolve-all'
162
- )
163
- ```
164
-
165
- ### Daytona
166
- ```bash
167
- # .env - Gateway mode
168
- EVOLVE_API_KEY=sk-...
169
- DAYTONA_API_KEY=...
170
-
171
- # .env - Direct Provider Key Mode
172
- ANTHROPIC_API_KEY=sk-ant-... # Or OPENAI_API_KEY, GEMINI_API_KEY, CLAUDE_CODE_OAUTH_TOKEN
173
- DAYTONA_API_KEY=...
174
- ```
175
-
176
- ```python
177
- from evolve import DaytonaProvider
178
-
179
- sandbox = DaytonaProvider(
180
- api_key=os.getenv('DAYTONA_API_KEY'), # (optional) Auto-resolves from env
181
- api_url='https://app.daytona.io/api', # (optional) Default: https://app.daytona.io/api
182
- target='us', # (optional) Target region. Default: 'us'
183
- timeout_ms=3600000, # (optional) Default: 3600000 (1 hour) - converted to minutes for auto-stop
184
- snapshot_name='my-snapshot', # (optional) Default: the current release snapshot ('evolve-all-c-<12hex>', tag derived from the image build inputs); explicit names pass through untouched. Custom snapshots via build.sh daytona
185
- )
186
- ```
187
-
188
- If a snapshot is found in a terminally failed state, the SDK deletes it and rebuilds it, so one bad build does not leave the name unusable. It only does this when it can rebuild the image itself — the reference carries a real tag or digest — and never for a bare name that resolves to no image, such as `my-team-env`.
189
-
190
-
191
- ---
192
-
193
- ## Sandbox Create Options
194
-
195
- `sandbox_create_options` sets provider-neutral options used whenever Evolve creates a fresh sandbox — image, env vars, metadata, timeout, working directory, outbound network policy, and the user/home the agent runs as:
196
-
197
- ```python
198
- from evolve import Evolve
199
-
200
- evolve = Evolve(
201
- sandbox_create_options={
202
- 'image': 'my-eval-template', # (optional) Sandbox image/template ID (provider default if omitted)
203
- 'envs': {'TASK_ID': 'swe-042'}, # (optional) Extra env vars (Evolve-owned runtime vars win on conflict)
204
- 'metadata': {'suite': 'nightly'}, # (optional) Provider metadata
205
- 'timeoutMs': 3600000, # (optional) Sandbox timeout
206
- 'workingDirectory': '/repo', # (optional) Working directory for agent commands
207
- 'network': { # (optional) Outbound network policy applied at boot
208
- 'outbound': 'blocked', # 'open' | 'blocked'
209
- 'allowedDestinations': ['registry.npmjs.org', '10.0.0.0/8'],
210
- },
211
- 'user': 'root', # (optional) Run all commands and file ops as this user
212
- 'homeDir': '/root', # (optional) Home dir for agent config paths
213
- },
214
- )
215
- ```
216
-
217
- **Network policy.** `'outbound': 'blocked'` denies all outbound traffic except `allowedDestinations` (hostnames, IPs, or CIDR ranges). Providers that cannot enforce a requested policy reject it with an error — a policy is never silently ignored.
218
-
219
- **User and home directory.** `user` runs every command and file operation as that user; providers that cannot enforce it reject it (E2B supports run-as-root). `homeDir` controls where agent config files (settings, session state, skills) are written. Defaults: `/root` when `user` is `'root'`, `/home/<user>` for other users, `/home/user` when no user is given. The default working directory follows as `<homeDir>/workspace`.
220
-
221
- Constraints:
222
-
223
- - A `user` can only be enforced at sandbox creation — combining it with `sandbox_id=`/`set_session()` (an existing sandbox) raises.
224
- - Checkpoint storage (`storage=`) and managed browser features require the default `/home/user` home; combining them with a custom `user`/`homeDir` raises.
225
- - `envs` entries are validated like `secrets=` values — Evolve-reserved variable names are rejected.
226
-
227
- ---
228
-
229
- ## Workspace Modes
230
-
231
- `workspace_mode` controls what Evolve sets up in the working directory on first run:
232
-
233
- | Mode | Workspace setup | Use it for |
234
- |------|-----------------|------------|
235
- | `'knowledge'` (default) | Creates `context/`, `scripts/`, `temp/`, `output/` + writes the system prompt file | General agent work with structured deliverables |
236
- | `'swe'` | Same as knowledge + `repo/` for code repositories | Software-engineering tasks on cloned repos |
237
-
238
- ```python
239
- evolve = Evolve(
240
- workspace_mode='swe',
241
- sandbox_create_options={'image': 'my-ci-template'},
242
- )
243
- ```
244
-
245
- ---
246
-
247
- ## Evolve Instance
248
-
249
- ```python
250
- import os
251
- from evolve import Evolve, AgentConfig, E2BProvider, StorageConfig, IntegrationsSetup, ManagedSecretRef
252
-
253
- # Sandbox provider (auto-resolved from E2B_API_KEY, or explicit)
254
- sandbox = E2BProvider(
255
- api_key=os.getenv('E2B_API_KEY'), # (optional) Auto-resolves from E2B_API_KEY env var
256
- timeout_ms=3600000, # (optional) Default sandbox timeout (default: 1 hour)
257
- )
258
- ```
259
-
260
- ```python
261
- import os
262
-
263
- evolve = Evolve(
264
-
265
- # Agent configuration (optional if EVOLVE_API_KEY set, defaults to claude)
266
- config=AgentConfig(
267
- type='codex', # 'claude' | 'codex' | 'gemini' | 'qwen' | 'kimi' | 'opencode' | 'droid' - defaults to 'claude'
268
- model='gpt-5.3-codex', # (optional) Uses default if omitted. Use 'fable' for Claude Fable 5.1 or 'sonnet[1m]' / 'opus[1m]' for 1M context (Claude only)
269
- reasoning_effort='medium', # (optional) Native reasoning/thinking control; valid values vary by agent/model. Omitted = Evolve stamps its pinned per-harness default (see Getting Started → Agent Reference)
270
- # max_context_size=128000, # (optional) Context/completion ceiling for CLIs that must be told one (see Getting Started → Harness and Model Pairing)
271
- api_key=os.getenv('EVOLVE_API_KEY'), # (optional) Gateway mode - auto-resolves from env
272
- # provider_api_key=os.getenv('ANTHROPIC_API_KEY'), # (optional) Direct Provider Key Mode
273
- # oauth_token=os.getenv('CLAUDE_CODE_OAUTH_TOKEN'), # (optional) Claude Max subscription
274
- ),
275
-
276
- # Sandbox provider (auto-resolved from E2B_API_KEY, or use sandbox from above)
277
- sandbox=sandbox,
278
-
279
- # (optional) Workspace mode: 'knowledge' (default) | 'swe' (see Workspace Modes above)
280
- workspace_mode='knowledge',
281
-
282
- # (optional) Provider-neutral options for fresh sandbox creation (see Sandbox Create Options above)
283
- sandbox_create_options={
284
- 'image': 'my-task-image',
285
- 'network': {'outbound': 'blocked', 'allowedDestinations': ['pypi.org']},
286
- 'user': 'root',
287
- },
288
-
289
- # (optional) Uploads to /home/user/workspace/context/ on first run
290
- context={
291
- 'docs/readme.txt': 'User provided context...',
292
- 'data.json': '{"key": "value"}',
293
- },
294
-
295
- # (optional) System prompt appended to default instructions
296
- system_prompt='You are a careful pair programmer.',
297
-
298
- # (optional) Schema for structured output (agent writes result.json, validated on get_output_files())
299
- # Accepts Pydantic models or JSON Schema dicts
300
- schema=MyPydanticModel,
301
-
302
- # (optional) Gateway browser automation
303
- browser={'provider': 'agent-browser', 'remote': True},
304
-
305
- # (optional) Install plugins/extensions for the selected agent before first run
306
- plugins={
307
- 'marketplace': 'https://github.com/org/codex-plugins.git',
308
- 'sparse': ['.agents/plugins'],
309
- },
310
-
311
- # (optional) Skills for the agent — skills.sh / git / local references
312
- skills=['anthropics/skills', './my-skill'],
313
-
314
- # (optional) Managed integrations (gateway mode only)
315
- integrations=IntegrationsSetup(user_id='root', apps=['gmail', 'notion']),
316
-
317
- # (optional) Dashboard-stored managed secrets (gateway mode only)
318
- managed_secrets=[
319
- ManagedSecretRef(name='GITHUB_TOKEN'),
320
- ManagedSecretRef(name='SLACK_BOT_TOKEN', as_name='SLACK_TOKEN'),
321
- ],
322
-
323
- # (optional) Prefix for observability logs
324
- session_tag_prefix='my-agent',
325
-
326
- # (optional) Storage for checkpoint persistence (gateway feature — requires EVOLVE_API_KEY)
327
- storage=StorageConfig(),
328
-
329
- # ─────────────────────────────────────────────────────────────
330
- # Advanced
331
- # ─────────────────────────────────────────────────────────────
332
-
333
- # (optional) MCP servers for agent tools
334
- mcp_servers={
335
- 'exa': {
336
- 'command': 'npx',
337
- 'args': ['-y', 'exa-mcp-server'],
338
- 'env': {'EXA_API_KEY': '...'},
339
- },
340
- 'api': {
341
- 'type': 'http',
342
- 'url': 'https://example.com/mcp',
343
- 'headers': {'x-api-key': '...'},
344
- },
345
- },
346
-
347
- # (optional) Environment variables injected into sandbox
348
- secrets={'GITHUB_TOKEN': os.getenv('GITHUB_TOKEN')},
349
-
350
- # (optional) Uploads to /home/user/workspace/ on first run
351
- files={
352
- 'scripts/setup.sh': '#!/bin/bash\necho hello',
353
- },
354
- )
355
- ```
356
-
357
- **Note:**
358
- - Configuration parameters can be combined in any order.
359
- - The sandbox is created on the first `run()` or `execute_command()` call (see below).
360
- - Context files, workspace files, MCP servers, and system prompt are set up once on the first call.
361
- - Using `sandbox_id` parameter to reconnect skips setup since the sandbox already exists.
362
- - `schema` accepts both Pydantic model classes and JSON Schema dicts.
363
-
364
- **McpServerConfig** — MCP server connection (STDIO or HTTP/SSE):
365
-
366
- | Fields | Transport |
367
- |--------|-----------|
368
- | `command` | stdio (local subprocess) |
369
- | `url` + `type: "http"` | HTTP (remote) |
370
- | `url` (no type) | SSE (remote, default) |
371
-
372
- ```python
373
- McpServerConfig = {
374
- 'type': str, # "stdio" | "http" | "sse" (auto-detected)
375
- 'command': str, 'args': list, 'cwd': str, # STDIO
376
- 'url': str, 'headers': dict[str, str], # HTTP/SSE
377
- 'env': dict[str, str], # Common
378
- }
379
- ```
380
-
381
- ## Browser Automation
382
-
383
- Browser automation is opt-in. Use `browser={'provider': 'agent-browser', 'remote': True}` for browser, QA, dogfooding, and website automation tasks.
384
-
385
- ```python
386
- Evolve(browser={'provider': 'agent-browser', 'remote': True}) # managed browser with dashboard live view and replay
387
- ```
388
-
389
- Evolve automatically configures the browser runtime. In Gateway mode, the managed browser gives you:
390
-
391
- - `event["browser"]["live_url"]` from the `browser_ready` lifecycle event
392
- - `result.browser["live_url"]` after `run()` returns
393
- - `result.session_id`, which is the id to use for traces and browser replay
394
- - `sessions().browser_replay(session_id)`, which returns replay and raw `.mp4` download URLs after cleanup
395
- - `replay.suggested_start_seconds`, when present, which is the recommended replay start time in seconds
396
- - `replay.size_bytes` and `replay.ready_at`, when present, which describe the raw recording size and replay readiness time
397
-
398
- `remote` controls where the browser session runs:
399
-
400
- - `remote: True` creates an Evolve-managed cloud browser session, wires it into the sandbox, and exposes dashboard live view plus replay.
401
- - `remote: False` runs browser automation locally inside the sandbox. Use it only when you do not need managed live view or replay.
402
-
403
- Use the default managed remote browser unless you have a reason not to:
404
-
405
- ```python
406
- Evolve(browser={'provider': 'agent-browser', 'remote': True})
407
- # recommended: managed remote browser
408
-
409
- Evolve(browser={'provider': 'agent-browser', 'remote': False})
410
- # local agent-browser, no managed live/replay
411
- ```
412
-
413
- Use a browser profile to reuse logged-in browser state across managed browser sessions:
414
-
415
- ```python
416
- evolve = Evolve(
417
- browser={'profile': 'ramp-qa'},
418
- )
419
- ```
420
-
421
- Profiles are gateway-only and work only with managed remote browser sessions. Evolve stores and resolves profile state server-side; the SDK never receives raw browser state.
422
-
423
- Profile lifecycle:
424
-
425
- - First use: if the profile does not exist for the authenticated Evolve user, Dashboard creates an empty server-side browser profile and starts the managed browser with it.
426
- - Reuse: if the profile already exists, Dashboard starts the browser with the existing state and updates `last_used_at`.
427
- - Persist: browser state changes made during the session, such as successful logins, are saved when the managed browser is stopped. Call `kill()` when done so cleanup and replay processing run.
428
- - Visibility: the profile appears in Dashboard **Secrets** under Browser Profiles and in `browser_profiles().list()`. Only metadata is returned; cookies and storage stay server-side.
429
-
430
- Recommended profile creation flow:
431
-
432
- 1. Add the browser login in Dashboard **Secrets**, or manage browser logins from the SDK and note the `account_label`.
433
- 2. Start a managed browser with both a `profile` and scoped browser credentials.
434
- 3. Ask the agent to sign in with the saved login.
435
- 4. Call `kill()` when done so the authenticated browser state is saved into the profile.
436
-
437
- ```python
438
- from evolve import Evolve, BrowserCredentialsConfig
439
-
440
- evolve = Evolve(
441
- browser={'profile': 'ramp-qa'},
442
- browser_credentials=BrowserCredentialsConfig(
443
- allow=[{'website': 'github.com', 'account_label': 'qa-admin'}],
444
- ),
445
- )
446
-
447
- try:
448
- await evolve.run(
449
- prompt='Open GitHub, sign in with the saved qa-admin login, and confirm the account is authenticated.'
450
- )
451
- finally:
452
- await evolve.kill()
453
- ```
454
-
455
- Future runs can reuse the saved state with `browser={'profile': 'ramp-qa'}`; include `browser_credentials` again only when the agent needs access to saved login tools.
456
-
457
- List or delete profiles from the SDK:
458
-
459
- ```python
460
- from evolve import browser_profiles
461
-
462
- profiles = await browser_profiles().list()
463
-
464
- await browser_profiles().delete(profile='ramp-qa')
465
- ```
466
-
467
- To disable browser automation, omit the `browser` argument.
468
-
469
- Full browser run with live view and replay:
470
-
471
- ```python
472
- from evolve import Evolve, sessions
473
-
474
- evolve = Evolve(
475
- browser={'provider': 'agent-browser', 'remote': True},
476
- session_tag_prefix='checkout-qa',
477
- )
478
-
479
- browser_session = {'id': None}
480
- session_id = None
481
-
482
- def on_lifecycle(event):
483
- if event['reason'] == 'browser_ready' and event.get('browser'):
484
- show_live_browser(event['browser']['live_url'])
485
- browser_session['id'] = event['browser']['session_id']
486
-
487
- evolve.on('lifecycle', on_lifecycle)
488
-
489
- try:
490
- result = await evolve.run(
491
- prompt='Open the app, test the checkout flow, and report issues.'
492
- )
493
-
494
- session_id = result.session_id or browser_session['id']
495
- if result.browser and result.browser.get('live_url'):
496
- show_live_browser(result.browser['live_url'])
497
- finally:
498
- await evolve.kill()
499
-
500
- if not session_id:
501
- raise RuntimeError('Missing dashboard session id')
502
-
503
- async with sessions() as session:
504
- replay = await session.browser_replay(
505
- session_id,
506
- timeout_ms=600_000,
507
- interval_ms=5_000,
508
- )
509
-
510
- show_replay(replay.replay_url)
511
- save_download_link(replay.download_url)
512
- set_replay_start_time(replay.suggested_start_seconds or 0)
513
- show_replay_metadata(
514
- size_bytes=replay.size_bytes,
515
- ready_at=replay.ready_at,
516
- )
517
- ```
518
-
519
- Replay processing starts when the managed browser is cleaned up, usually during `kill()`.
520
- If replay is not ready before `timeout_ms`, call `browser_replay()` again later with the same `session_id`.
521
- The `replay_url` already applies `suggested_start_seconds`; use the field separately only if your UI needs to display or store the recommended start time.
522
- The `status` is `'ready'` once `browser_replay()` returns.
523
-
524
- ## Browser Credentials
525
-
526
- Browser credentials let managed remote `agent-browser` runs sign in with saved website logins without exposing passwords to the agent.
527
-
528
- Availability:
529
-
530
- - Requires Gateway mode and managed remote `agent-browser`.
531
- - Use `browser={'provider': 'agent-browser', 'remote': True}`.
532
- - Not available with local browser mode, Direct Provider Key Mode, or existing sandbox sessions.
533
-
534
- Dashboard setup:
535
-
536
- 1. Open the Evolve Dashboard.
537
- 2. Go to **Secrets**.
538
- 3. Add a browser login with `Account label`, `Website`, `Email`, and `Password`.
539
- 4. Use `Website` for the domain, such as `github.com`; use `Account label` as one word with no spaces, such as `qa-admin`, `work`, or `personal`, to distinguish multiple saved accounts for the same website. It is not the website username or email.
540
-
541
- Passwords are encrypted client-side with RSA-OAEP-SHA256 against the dashboard's published public key before upload — the SDK verifies it is handed a genuine `rsaEncryption` key before encrypting, and a plaintext password never leaves the machine. The dashboard and SDK list only login metadata: account label, website, email, and last-used time.
542
-
543
- Expose saved logins to a run:
544
-
545
- ```python
546
- from evolve import Evolve, BrowserCredentialsConfig
547
-
548
- evolve = Evolve(
549
- browser={'provider': 'agent-browser', 'remote': True},
550
- browser_credentials=BrowserCredentialsConfig(
551
- allow=[{'website': 'github.com', 'account_label': 'qa-admin'}],
552
- ),
553
- )
554
-
555
- await evolve.run(
556
- prompt='Open GitHub, sign in with the saved qa-admin login, and verify the repository settings page.'
557
- )
558
-
559
- await evolve.kill()
560
- ```
561
-
562
- If `allow` is omitted, all enabled browser logins for the Evolve account are available to that run:
563
-
564
- ```python
565
- from evolve import Evolve, BrowserCredentialsConfig
566
-
567
- evolve = Evolve(
568
- browser={'provider': 'agent-browser', 'remote': True},
569
- browser_credentials=BrowserCredentialsConfig(),
570
- )
571
- ```
572
-
573
- The agent receives a run-scoped `browser-login` MCP server with these tools:
574
-
575
- - `browser_list_logins` lists available website logins: website, account_label, and email only.
576
- - `browser_login` fills the stored password and submits the current browser sign-in tab.
577
- - `browser_complete_signup` generates a password, submits the current browser signup tab, and saves the new login.
578
-
579
- Manage browser logins from the SDK:
580
-
581
- ```python
582
- import os
583
- from evolve import browser_credentials
584
-
585
- credentials = browser_credentials()
586
-
587
- await credentials.create(
588
- website='github.com',
589
- account_label='qa-admin',
590
- email='qualityassurance@example.com',
591
- password=os.environ['QA_GITHUB_PASSWORD'],
592
- )
593
-
594
- page = await credentials.list(website='github.com')
595
-
596
- await credentials.delete(
597
- website='github.com',
598
- account_label='qa-admin',
599
- )
600
- ```
601
-
602
- ## Agent Plugins
603
-
604
- `plugins=` installs plugins/extensions into the sandbox user profile before the first agent command. The selected agent determines the accepted shape:
605
-
606
- ```python
607
- # droid
608
- plugins={
609
- 'marketplace': 'https://github.com/Factory-AI/factory-plugins',
610
- 'plugin': 'droid-control@factory-plugins',
611
- }
612
-
613
- # claude
614
- plugins={
615
- 'marketplace': 'anthropics/claude-code',
616
- 'plugin': 'commit-commands@anthropics-claude-code',
617
- }
618
-
619
- # gemini
620
- plugins={
621
- 'source': 'https://github.com/org/gemini-extension',
622
- 'ref': 'main',
623
- }
624
-
625
- # codex marketplace registration
626
- plugins={
627
- 'marketplace': 'https://github.com/org/codex-plugins.git',
628
- 'sparse': ['.agents/plugins'],
629
- }
630
- ```
631
-
632
- If `config=AgentConfig(...)` is omitted, plugins target the default agent (`claude`).
633
-
634
- ## Agent Skills
635
-
636
- Skills are folders of instructions and helper files — a `SKILL.md` manifest plus anything it needs — that the agent's harness discovers natively. The `skills` option takes real references; there is no built-in catalog:
637
-
638
- ```python
639
- from evolve import Evolve
640
-
641
- evolve = Evolve(
642
- skills=[
643
- 'skills.sh/vercel-labs/agent-skills/frontend-design', # one named skill from a skills.sh-listed repo
644
- 'anthropics/skills', # every skill a GitHub repo publishes
645
- 'anthropics/skills@main', # pinned to a branch, tag, or commit
646
- 'https://github.com/org/repo/tree/main/skills/my-skill', # any https git URL, down to a subfolder
647
- './my-skill', # a local folder containing SKILL.md
648
- ],
649
- )
650
-
651
- await evolve.run(prompt='Create a slide deck summarizing the uploaded notes.')
652
- ```
653
-
654
- Browse [skills.sh](https://skills.sh) for published skills. The SKILL.md format is the open standard described at [agentskills.io](https://agentskills.io/home).
655
-
656
- How references resolve:
657
-
658
- - Git references are pinned to their exact commit, fetched as a sparse checkout of only the skill content, and cached by commit under `~/.cache/evolve/skills` — the same reference always mounts the same bytes.
659
- - A whole-repo reference discovers skills in the ecosystem's standard places: a `SKILL.md` at the repo root (one skill, named after the repo), `skills/`, `skills/.curated/`, `skills/.experimental/`, `skills/.system/`, and `.claude/skills/`.
660
- - A local path, or an explicit `/tree/<ref>/<subdir>` URL, must be one skill folder containing `SKILL.md` — or a root whose immediate child directories each contain one. A child without `SKILL.md` is a loud refusal naming the child.
661
- - Duplicate skill names resolve last-wins, and each skill mounts into the harness's native skills directory (for example `~/.claude/skills/<name>`), where the agent discovers it on its own.
662
-
663
- ## Managed Secrets
664
-
665
- Managed secrets are available only in gateway mode (`EVOLVE_API_KEY`). Store the secret with a **Name**, an optional **Label**, and a **delivery mode** — in Dashboard **Secrets**, or programmatically through the SDK's `set()` / the CLI's `evolve secrets set` (below). Secrets are unique by `(name, label)` — several values of one name live side by side (`API_KEY` at `staging` and at `prod`) and a run attaches one by label. The SDK can list available names and attach the selected secrets to a run.
666
-
667
- The delivery mode is chosen when the secret is saved and decides how the value reaches the sandbox:
668
-
669
- - **`brokered`** — the value never enters any sandbox. The sandbox sees an opaque placeholder, and Evolve substitutes the real value only for HTTPS egress toward the secret's allowed hosts, paths, and methods (required for brokered secrets). This works for header-based HTTPS APIs.
670
- - **`direct`** — the raw value is placed in the sandbox environment. This is the mode for keys the HTTPS broker cannot carry: URL-parameter keys, gRPC, websockets. Direct secrets carry no host/path/method scoping — nothing brokers a raw env value.
671
-
672
- ```python
673
- from evolve import Evolve, ManagedSecretRef, managed_secrets
674
-
675
- available = await managed_secrets().list() # includes label + delivery
676
-
677
- evolve = Evolve(
678
- managed_secrets=[
679
- ManagedSecretRef(name='GITHUB_TOKEN'), # 'default'-labeled row
680
- ManagedSecretRef(name='API_KEY', label='prod'), # a specific labeled row
681
- ManagedSecretRef(name='SLACK_BOT_TOKEN', as_name='SLACK_TOKEN'), # renamed in the sandbox
682
- ],
683
- )
684
- ```
685
-
686
- An omitted `label` resolves by the server's one shared law (the same law hosted-evals job secrets use): the `default`-labeled row when one exists, the single row when exactly one exists, and a typed refusal naming every label when several match and none is `default` — never a guess.
687
-
688
- Runtime behavior:
689
-
690
- - Brokered secrets: the sandbox receives the requested env var names with opaque sandbox-scoped values; code and tools read them normally, and Evolve validates allowed host, path, method, and live sandbox binding before substituting the real value on egress. Request and response bodies are limited to 10 MiB each.
691
- - Direct secrets: the sandbox receives the raw value as a plain env var. When every attached secret is direct, the in-sandbox egress proxy is not started at all.
692
- - `secrets` is still for local raw env injection; `managed_secrets` is for Dashboard-stored values.
693
-
694
- ### Storing secrets programmatically
695
-
696
- `managed_secrets()` also writes: `set()` creates an env secret (or updates one — see the collision rule), and `delete()` removes one. The value travels in the HTTPS request body and is sealed server-side with the platform vault cipher; no read ever returns it. Values are limited to 190 bytes.
697
-
698
- ```python
699
- import os
700
- from evolve import managed_secrets
701
-
702
- secrets = managed_secrets()
703
-
704
- await secrets.set(
705
- name='GITHUB_TOKEN',
706
- value=os.environ['GITHUB_TOKEN'],
707
- delivery='brokered',
708
- allowed_hosts=['api.github.com'],
709
- allowed_path_prefixes=['/'],
710
- allowed_methods=['GET'],
711
- )
712
-
713
- await secrets.set(
714
- name='STRIPE_KEY',
715
- label='staging',
716
- value=os.environ['STRIPE_TEST_KEY'],
717
- delivery='direct', # direct secrets carry no scoping
718
- )
719
-
720
- await secrets.delete(name='STRIPE_KEY', label='staging')
721
- ```
722
-
723
- Or from the terminal — the value comes from `--value` or piped stdin (piping keeps it out of shell history):
724
-
725
- ```bash
726
- printf %s "$GITHUB_TOKEN" | evolve secrets set GITHUB_TOKEN \
727
- --delivery brokered \
728
- --allowed-host api.github.com --allowed-path-prefix / --allowed-method GET
729
-
730
- evolve secrets list
731
- evolve secrets delete GITHUB_TOKEN
732
- ```
733
-
734
- The write rules, all typed and machine-readable (the HTTP error body carries a `code`):
735
-
736
- - `delivery` is required. `brokered` requires at least one allowed host, path prefix, and method; `direct` refuses scoping fields — an unscoped value in the sandbox environment cannot honor them.
737
- - An existing `(name, label)` is **never overwritten with a different value**: the request is refused (`secret_exists`, HTTP 409). Rotate by `delete` + `set`, or store the new value under another label. Restating the **same value byte-for-byte** succeeds as an update — that is where the delivery mode and scoping are editable, and every runtime grant already minted against the row is revoked.
738
- - `delete` with a bare name resolves the label like everything else (the `default` row, else the single row, else a typed ambiguity refusal naming every label).
739
- - A **read-only API key** can `list` but not `set`/`delete` (`read_only_key`, HTTP 403).
740
- - **LLM provider keys (BYOK) cannot be stored through this door.** A provider key gates billing — the routing preference behind it decides whose account pays for model traffic — so provider keys are managed only in the signed-in Dashboard **Secrets** page.
741
-
742
- ---
743
-
744
- ## Managed Integrations
745
-
746
- Managed integrations are available only in gateway mode (`EVOLVE_API_KEY`); integration credentials stay server-side and agents receive an Evolve-scoped MCP proxy.
747
-
748
- Available apps:
749
-
750
- | `apps` value | App | What agents can do |
751
- | --- | --- | --- |
752
- | `gmail` | Gmail | Read, search, draft, and send email. |
753
- | `agent_mail` | Agent Mail | Use an agent inbox to send, receive, and act on email. |
754
- | `slack` | Slack | Search channels, read conversations, and send team messages. |
755
- | `github` | GitHub | Work with repositories, issues, pull requests, and code. |
756
- | `googlecalendar` | Google Calendar | Read and manage calendar events. |
757
- | `notion` | Notion | Read and update pages, databases, docs, and workspace content. |
758
- | `linear` | Linear | Read and manage issues, teams, projects, and comments. |
759
-
760
- ```bash
761
- # .env
762
- EVOLVE_API_KEY=sk-...
763
- ```
764
-
765
- ```python
766
- from evolve import Evolve, IntegrationsSetup
767
-
768
- evolve = Evolve(
769
- integrations=IntegrationsSetup(
770
- user_id='root',
771
- apps=['github', 'gmail'],
772
- ),
773
- )
774
-
775
- await evolve.run(prompt='Create a GitHub issue for the login bug')
776
- ```
777
-
778
- ### Root vs SDK Users
779
-
780
- Use `user_id='root'` for accounts connected in the Evolve dashboard for private agents and test accounts.
781
-
782
- For an application with end users, pass your stable SDK user ID. Evolve namespaces that ID under the authenticated Evolve account before creating private integration sessions.
783
-
784
- ```python
785
- from evolve import Evolve, IntegrationsSetup
786
-
787
- link = await Evolve.integrations.auth(
788
- user_id='customer_123',
789
- app='gmail',
790
- account_label='work',
791
- )
792
-
793
- evolve = Evolve(
794
- integrations=IntegrationsSetup(
795
- user_id='customer_123',
796
- apps=['gmail'],
797
- ),
798
- )
799
- ```
800
-
801
- ### Account Helpers
802
-
803
- ```python
804
- accounts = await Evolve.integrations.accounts.list(
805
- user_ids=['customer_123'],
806
- app='gmail',
807
- statuses=['ACTIVE'],
808
- )
809
-
810
- await Evolve.integrations.accounts.update(
811
- account_id='account_id_from_list',
812
- account_label='work',
813
- )
814
-
815
- # If the user connected multiple Gmail accounts, choose an account label or account ID returned by accounts.list().
816
- evolve = Evolve(
817
- integrations=IntegrationsSetup(
818
- user_id='customer_123',
819
- apps=['gmail'],
820
- accounts={'gmail': ['work']},
821
- ),
822
- )
823
-
824
- # Disconnect by account ID.
825
- await Evolve.integrations.accounts.delete(account_id='account_id_from_list')
826
- ```
827
-
828
- ### Custom Auth Configs and API Keys
829
-
830
- Use `auth_configs` to select a custom auth config for an app. For apps with an API-key auth config, pass the matching key in `keys`; Evolve creates the connected account server-side and does not store the raw key in the session.
831
-
832
- ```python
833
- evolve = Evolve(
834
- integrations=IntegrationsSetup(
835
- user_id='customer_123',
836
- apps=['github'],
837
- auth_configs={'github': 'ac_custom_github'},
838
- keys={'github': os.environ['GITHUB_TOKEN']},
839
- ),
840
- )
841
- ```
842
-
843
- ### Type Reference
844
-
845
- ```python
846
- @dataclass
847
- class IntegrationsSetup:
848
- user_id: str # "root" or your stable SDK user ID
849
- apps: List[str]
850
- accounts: Optional[Dict[str, List[str]]] = None # app -> account labels or account IDs
851
- auth_configs: Optional[Dict[str, str]] = None # app -> custom auth config ID
852
- keys: Optional[Dict[str, str]] = None # app -> API key, requires auth_configs[app]
853
- ```
854
-
855
- ---