@ellipsis-dev/sdk 0.22.0 → 0.25.0

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.
@@ -1,1136 +1,6 @@
1
1
  {
2
2
  "components": {
3
3
  "schemas": {
4
- "AgentConfig": {
5
- "additionalProperties": false,
6
- "properties": {
7
- "budget": {
8
- "$ref": "#/components/schemas/AgentConfigBudget",
9
- "default": {}
10
- },
11
- "claude": {
12
- "$ref": "#/components/schemas/AgentConfigClaude",
13
- "default": {
14
- "system": ""
15
- }
16
- },
17
- "codex": {
18
- "anyOf": [
19
- {
20
- "$ref": "#/components/schemas/AgentConfigCodex"
21
- },
22
- {
23
- "type": "null"
24
- }
25
- ]
26
- },
27
- "ellipsis": {
28
- "$ref": "#/components/schemas/AgentConfigEllipsis",
29
- "default": {
30
- "enabled": true,
31
- "metadata": {
32
- "annotations": {},
33
- "labels": []
34
- },
35
- "version": "v1"
36
- }
37
- },
38
- "environment": {
39
- "anyOf": [
40
- {
41
- "type": "string"
42
- },
43
- {
44
- "$ref": "#/components/schemas/AgentConfigEnvironment"
45
- }
46
- ],
47
- "default": {
48
- "compute": {},
49
- "hooks": {},
50
- "image": {},
51
- "mcp_servers": [],
52
- "repositories": [],
53
- "variables": []
54
- },
55
- "title": "Environment"
56
- },
57
- "input": {
58
- "anyOf": [
59
- {
60
- "$ref": "#/components/schemas/AgentConfigInput"
61
- },
62
- {
63
- "type": "null"
64
- }
65
- ]
66
- },
67
- "output": {
68
- "anyOf": [
69
- {
70
- "$ref": "#/components/schemas/AgentConfigOutput"
71
- },
72
- {
73
- "type": "null"
74
- }
75
- ]
76
- },
77
- "permissions": {
78
- "$ref": "#/components/schemas/AgentConfigPermissions",
79
- "default": {
80
- "ellipsis": true,
81
- "github": {}
82
- }
83
- },
84
- "skills": {
85
- "default": [],
86
- "items": {
87
- "$ref": "#/components/schemas/AgentConfigSkill"
88
- },
89
- "title": "Skills",
90
- "type": "array"
91
- },
92
- "trigger": {
93
- "anyOf": [
94
- {
95
- "discriminator": {
96
- "mapping": {
97
- "cron": "#/components/schemas/AgentConfigCronTrigger",
98
- "mention": "#/components/schemas/AgentConfigMentionTrigger",
99
- "react": "#/components/schemas/AgentConfigReactTrigger"
100
- },
101
- "propertyName": "type"
102
- },
103
- "oneOf": [
104
- {
105
- "$ref": "#/components/schemas/AgentConfigCronTrigger"
106
- },
107
- {
108
- "$ref": "#/components/schemas/AgentConfigReactTrigger"
109
- },
110
- {
111
- "$ref": "#/components/schemas/AgentConfigMentionTrigger"
112
- }
113
- ]
114
- },
115
- {
116
- "type": "null"
117
- }
118
- ],
119
- "title": "Trigger"
120
- }
121
- },
122
- "title": "AgentConfig",
123
- "type": "object"
124
- },
125
- "AgentConfigBudget": {
126
- "additionalProperties": false,
127
- "properties": {
128
- "day": {
129
- "anyOf": [
130
- {
131
- "type": "number"
132
- },
133
- {
134
- "type": "null"
135
- }
136
- ],
137
- "title": "Day"
138
- },
139
- "month": {
140
- "anyOf": [
141
- {
142
- "type": "number"
143
- },
144
- {
145
- "type": "null"
146
- }
147
- ],
148
- "title": "Month"
149
- },
150
- "session": {
151
- "anyOf": [
152
- {
153
- "type": "number"
154
- },
155
- {
156
- "type": "null"
157
- }
158
- ],
159
- "title": "Session"
160
- },
161
- "week": {
162
- "anyOf": [
163
- {
164
- "type": "number"
165
- },
166
- {
167
- "type": "null"
168
- }
169
- ],
170
- "title": "Week"
171
- }
172
- },
173
- "title": "AgentConfigBudget",
174
- "type": "object"
175
- },
176
- "AgentConfigClaude": {
177
- "additionalProperties": false,
178
- "properties": {
179
- "effort": {
180
- "anyOf": [
181
- {
182
- "$ref": "#/components/schemas/EffortLevel"
183
- },
184
- {
185
- "type": "null"
186
- }
187
- ]
188
- },
189
- "fallback_model": {
190
- "anyOf": [
191
- {
192
- "type": "string"
193
- },
194
- {
195
- "type": "null"
196
- }
197
- ],
198
- "title": "Fallback Model"
199
- },
200
- "max_turns": {
201
- "anyOf": [
202
- {
203
- "exclusiveMinimum": 0.0,
204
- "type": "integer"
205
- },
206
- {
207
- "type": "null"
208
- }
209
- ],
210
- "title": "Max Turns"
211
- },
212
- "model": {
213
- "anyOf": [
214
- {
215
- "type": "string"
216
- },
217
- {
218
- "type": "null"
219
- }
220
- ],
221
- "title": "Model"
222
- },
223
- "settings": {
224
- "anyOf": [
225
- {
226
- "$ref": "#/components/schemas/AgentConfigSettingsRef"
227
- },
228
- {
229
- "type": "null"
230
- }
231
- ]
232
- },
233
- "system": {
234
- "anyOf": [
235
- {
236
- "type": "string"
237
- },
238
- {
239
- "$ref": "#/components/schemas/AgentConfigSystemFileRef"
240
- },
241
- {
242
- "items": {
243
- "anyOf": [
244
- {
245
- "type": "string"
246
- },
247
- {
248
- "$ref": "#/components/schemas/AgentConfigSystemFileRef"
249
- }
250
- ]
251
- },
252
- "type": "array"
253
- }
254
- ],
255
- "default": "",
256
- "title": "System"
257
- }
258
- },
259
- "title": "AgentConfigClaude",
260
- "type": "object"
261
- },
262
- "AgentConfigCodex": {
263
- "additionalProperties": false,
264
- "description": "The `codex:` block \u2014 run this agent on OpenAI's Codex CLI instead of\nClaude Code. Declaring the block at all is what selects the harness\n(`AgentConfig.harness`).\n\nDeliberately a small subset of `AgentConfigClaude`: the fields omitted here\nare ones Codex has no equivalent for (`effort`, `fallback_model`,\n`settings`) or that the platform does not yet wire through for this harness\n(`max_turns`, `skills`, MCP servers). They are omitted rather than\naccepted-and-ignored, because `StrictConfigModel` forbids extra keys \u2014 so a\nconfig that sets one fails loudly at parse time instead of silently not doing\nit. The budget still bounds a run regardless.",
265
- "properties": {
266
- "model": {
267
- "default": "gpt-5.6-terra",
268
- "title": "Model",
269
- "type": "string"
270
- },
271
- "system": {
272
- "anyOf": [
273
- {
274
- "type": "string"
275
- },
276
- {
277
- "$ref": "#/components/schemas/AgentConfigSystemFileRef"
278
- },
279
- {
280
- "items": {
281
- "anyOf": [
282
- {
283
- "type": "string"
284
- },
285
- {
286
- "$ref": "#/components/schemas/AgentConfigSystemFileRef"
287
- }
288
- ]
289
- },
290
- "type": "array"
291
- }
292
- ],
293
- "default": "",
294
- "title": "System"
295
- }
296
- },
297
- "title": "AgentConfigCodex",
298
- "type": "object"
299
- },
300
- "AgentConfigCompute": {
301
- "additionalProperties": false,
302
- "description": "Sandbox compute sizing. Every field is optional; None inherits the\nplatform default (1 vCPU / 4096 MiB / 3600s \u2014 see DEFAULT_MODAL_* in\nmodels/ellipsis/sandboxes/sandbox.py). A resolved value outside the platform\nbounds fails validation loudly (a sync error on the config) rather than\nbeing clamped silently.\n\n`memory` and `timeout` each accept a shorthand string (\"8GB\", \"30m\") or an\nexplicit units object ({gb: 8}, {minutes: 30}); the `memory_mib` /\n`timeout_seconds` properties resolve either form to the canonical integer\nthe sandbox driver consumes.\n\n`timeout` is the max wall-clock the agent may run before the sandbox is\nkilled, capped at 1h (MAX_SANDBOX_TIMEOUT_SECONDS \u2014 equal to the default, so\ntoday the knob only shortens a session; the cap matches the 1-hour validity\nof the sandbox's GitHub token). The worker's lease/visibility heartbeat\nceiling is derived from that cap, so a run at the max stays owned by its\nworker for its whole life.\n\nCompute is billed on the requested allocation over the sandbox's\nwall-clock lifetime, so a bigger/longer box costs proportionally more.",
303
- "properties": {
304
- "cpu": {
305
- "anyOf": [
306
- {
307
- "maximum": 16.0,
308
- "minimum": 0.125,
309
- "type": "number"
310
- },
311
- {
312
- "type": "null"
313
- }
314
- ],
315
- "title": "Cpu"
316
- },
317
- "memory": {
318
- "anyOf": [
319
- {
320
- "type": "string"
321
- },
322
- {
323
- "$ref": "#/components/schemas/AgentConfigMemorySize"
324
- },
325
- {
326
- "type": "null"
327
- }
328
- ],
329
- "title": "Memory"
330
- },
331
- "timeout": {
332
- "anyOf": [
333
- {
334
- "type": "string"
335
- },
336
- {
337
- "$ref": "#/components/schemas/AgentConfigDuration"
338
- },
339
- {
340
- "type": "null"
341
- }
342
- ],
343
- "title": "Timeout"
344
- }
345
- },
346
- "title": "AgentConfigCompute",
347
- "type": "object"
348
- },
349
- "AgentConfigCronTrigger": {
350
- "additionalProperties": false,
351
- "properties": {
352
- "schedule": {
353
- "title": "Schedule",
354
- "type": "string"
355
- },
356
- "type": {
357
- "const": "cron",
358
- "default": "cron",
359
- "title": "Type",
360
- "type": "string"
361
- }
362
- },
363
- "required": [
364
- "schedule"
365
- ],
366
- "title": "AgentConfigCronTrigger",
367
- "type": "object"
368
- },
369
- "AgentConfigDuration": {
370
- "additionalProperties": false,
371
- "description": "A duration as explicit units, summed. Set any of `hours`/`minutes`/\n`seconds` (at least one). The alternative to the `30m`-style shorthand\nstring wherever a duration is accepted.",
372
- "properties": {
373
- "hours": {
374
- "anyOf": [
375
- {
376
- "minimum": 0.0,
377
- "type": "integer"
378
- },
379
- {
380
- "type": "null"
381
- }
382
- ],
383
- "title": "Hours"
384
- },
385
- "minutes": {
386
- "anyOf": [
387
- {
388
- "minimum": 0.0,
389
- "type": "integer"
390
- },
391
- {
392
- "type": "null"
393
- }
394
- ],
395
- "title": "Minutes"
396
- },
397
- "seconds": {
398
- "anyOf": [
399
- {
400
- "minimum": 0.0,
401
- "type": "integer"
402
- },
403
- {
404
- "type": "null"
405
- }
406
- ],
407
- "title": "Seconds"
408
- }
409
- },
410
- "title": "AgentConfigDuration",
411
- "type": "object"
412
- },
413
- "AgentConfigEllipsis": {
414
- "additionalProperties": false,
415
- "description": "The Ellipsis product namespace for a config file: which schema this is\n(`version`), the human-facing identity (`name`/`description`), freeform\norganizational `metadata`, and whether the agent is `enabled`. The\npresence of a top-level `ellipsis:` mapping is what marks a YAML file as\nan Ellipsis agent config (vs arbitrary YAML that merely lives under a\nconfig directory) \u2014 see `yaml_is_ellipsis_config`.\n\n`enabled` is agent behavior, not freeform metadata, so it stays inside\nthe config `sha` (only `metadata` is sha-excluded). Whether a session\naccepts messages is a per-run choice (POST /v1/sessions `interactive`),\nnot a config one.",
416
- "properties": {
417
- "description": {
418
- "anyOf": [
419
- {
420
- "type": "string"
421
- },
422
- {
423
- "type": "null"
424
- }
425
- ],
426
- "title": "Description"
427
- },
428
- "enabled": {
429
- "default": true,
430
- "title": "Enabled",
431
- "type": "boolean"
432
- },
433
- "metadata": {
434
- "$ref": "#/components/schemas/AgentConfigMetadata",
435
- "default": {
436
- "annotations": {},
437
- "labels": []
438
- }
439
- },
440
- "name": {
441
- "anyOf": [
442
- {
443
- "type": "string"
444
- },
445
- {
446
- "type": "null"
447
- }
448
- ],
449
- "title": "Name"
450
- },
451
- "version": {
452
- "default": "v1",
453
- "title": "Version",
454
- "type": "string"
455
- }
456
- },
457
- "title": "AgentConfigEllipsis",
458
- "type": "object"
459
- },
460
- "AgentConfigEllipsisPermissions": {
461
- "additionalProperties": {
462
- "anyOf": [
463
- {
464
- "$ref": "#/components/schemas/Level"
465
- },
466
- {
467
- "$ref": "#/components/schemas/EllipsisGrant"
468
- },
469
- {
470
- "items": {
471
- "anyOf": [
472
- {
473
- "$ref": "#/components/schemas/Level"
474
- },
475
- {
476
- "$ref": "#/components/schemas/EllipsisGrant"
477
- }
478
- ]
479
- },
480
- "type": "array"
481
- }
482
- ]
483
- },
484
- "description": "`permissions.ellipsis` as a map: resource \u2192 level | grant | list of\ngrants. Levels are hierarchical (read < write < delete), so `write`\nincludes `read`. An unlisted resource is denied. The whole block is\nintersected with the platform's sandbox ceiling at token mint \u2014 it can\nnarrow what a sandbox token may do, never exceed it.",
485
- "propertyNames": {
486
- "$ref": "#/components/schemas/Resource"
487
- },
488
- "title": "AgentConfigEllipsisPermissions",
489
- "type": "object"
490
- },
491
- "AgentConfigEnvironment": {
492
- "additionalProperties": false,
493
- "description": "Everything about the environment (the sandbox) the agent runs in: which\n`repositories` are cloned into it, which environment `variables` it gets,\nits `compute` sizing, how its `image` is customized, and lifecycle `hooks`.\nWhat the agent may *do* from that environment is the top-level\n`permissions:` block, not this one.\n\nEach `variables` entry names a variable to inject; with an inline `value` it\nis hardcoded, without one it is resolved from the account's sandbox-secrets\nstore. Only the named variables reach this agent; the rest of the account's\nstored variables never do. This is how a config brings in the config and\ncredentials a custom CLI needs.",
494
- "properties": {
495
- "compute": {
496
- "$ref": "#/components/schemas/AgentConfigCompute",
497
- "default": {}
498
- },
499
- "hooks": {
500
- "$ref": "#/components/schemas/AgentConfigEnvironmentHooks",
501
- "default": {}
502
- },
503
- "image": {
504
- "$ref": "#/components/schemas/AgentConfigEnvironmentImage",
505
- "default": {}
506
- },
507
- "mcp_servers": {
508
- "default": [],
509
- "items": {
510
- "anyOf": [
511
- {
512
- "type": "string"
513
- },
514
- {
515
- "$ref": "#/components/schemas/AgentConfigMcpServer"
516
- },
517
- {
518
- "$ref": "#/components/schemas/AgentConfigMcpStdioServer"
519
- },
520
- {
521
- "$ref": "#/components/schemas/AgentConfigMcpRemoteServer"
522
- }
523
- ]
524
- },
525
- "title": "Mcp Servers",
526
- "type": "array"
527
- },
528
- "repositories": {
529
- "default": [],
530
- "items": {
531
- "$ref": "#/components/schemas/AgentConfigRepository"
532
- },
533
- "title": "Repositories",
534
- "type": "array"
535
- },
536
- "variables": {
537
- "default": [],
538
- "items": {
539
- "$ref": "#/components/schemas/AgentConfigEnvironmentVariable"
540
- },
541
- "title": "Variables",
542
- "type": "array"
543
- }
544
- },
545
- "title": "AgentConfigEnvironment",
546
- "type": "object"
547
- },
548
- "AgentConfigEnvironmentHooks": {
549
- "additionalProperties": false,
550
- "description": "Shell scripts run at points in the sandbox lifecycle, each as the sandbox\nuser with the sandbox's environment variables available. A non-zero exit\nfails the run (exit_status = LIFECYCLE_HOOK_FAILED) and is not retried.\n\n`post_start` runs after the container starts, before any repo is cloned \u2014\nrepo-independent setup (authenticate a CLI, e.g. `doppler setup`). On Modal\nthe repo is baked into the image so it is incidentally present, but\n`post_start` must not depend on repo contents (that's `post_clone`).\n\n`post_clone` runs after all repos are cloned/checked out, before the agent \u2014\nrepo-dependent setup (`pip install -r requirements.txt`, codegen).\n\nHooks run on every run and their output is never cached. A dependency\ninstall whose result should be reused across runs belongs in `image.setup`\n(baked into the cached image) instead; keep hooks for per-run work \u2014 e.g.\nanything that touches run-scoped credentials.",
551
- "properties": {
552
- "post_clone": {
553
- "anyOf": [
554
- {
555
- "type": "string"
556
- },
557
- {
558
- "type": "null"
559
- }
560
- ],
561
- "title": "Post Clone"
562
- },
563
- "post_start": {
564
- "anyOf": [
565
- {
566
- "type": "string"
567
- },
568
- {
569
- "type": "null"
570
- }
571
- ],
572
- "title": "Post Start"
573
- }
574
- },
575
- "title": "AgentConfigEnvironmentHooks",
576
- "type": "object"
577
- },
578
- "AgentConfigEnvironmentImage": {
579
- "additionalProperties": false,
580
- "description": "How to customize the container image the agent runs in. You\ncontribute appended layers (`dockerfile_append`) and a build-time script\n(`setup`) only \u2014 Ellipsis owns FROM / base tooling / entrypoint / user.\nToday only inline bodies are supported; a file reference (resolved at the\nrun's SHA) will come later.\n\nThe split: `dockerfile_append` runs when the image is assembled, before any\nrepo exists \u2014 toolchain installs (a package manager binary, apt packages).\n`setup` runs at image-build time *after* the configured repositories are\nchecked out, and its output is captured by the filesystem snapshot that\nbecomes the cached image \u2014 dependency installs (`poetry install`,\n`npm install`), so later runs start with deps already on disk. Neither runs\nper run; that's `hooks.post_start` / `hooks.post_clone`.",
581
- "properties": {
582
- "dockerfile_append": {
583
- "anyOf": [
584
- {
585
- "type": "string"
586
- },
587
- {
588
- "type": "null"
589
- }
590
- ],
591
- "title": "Dockerfile Append"
592
- },
593
- "setup": {
594
- "anyOf": [
595
- {
596
- "type": "string"
597
- },
598
- {
599
- "type": "null"
600
- }
601
- ],
602
- "title": "Setup"
603
- }
604
- },
605
- "title": "AgentConfigEnvironmentImage",
606
- "type": "object"
607
- },
608
- "AgentConfigEnvironmentVariable": {
609
- "additionalProperties": false,
610
- "description": "One environment variable injected into the agent's sandbox.\n\n`value`, when set, is a literal injected as-is \u2014 use it for non-secret\nconfig (LOG_LEVEL, an API base URL). When `value` is omitted the value is\nresolved at run time from the account's sandbox-secrets store (dashboard\n/ `PUT /v1/secrets`) by `name`, so a secret can be injected without\never putting it in the config file. Either way the variable only reaches\nagents that name it.",
611
- "properties": {
612
- "name": {
613
- "title": "Name",
614
- "type": "string"
615
- },
616
- "value": {
617
- "anyOf": [
618
- {
619
- "type": "string"
620
- },
621
- {
622
- "type": "null"
623
- }
624
- ],
625
- "title": "Value"
626
- }
627
- },
628
- "required": [
629
- "name"
630
- ],
631
- "title": "AgentConfigEnvironmentVariable",
632
- "type": "object"
633
- },
634
- "AgentConfigGithubPermissions": {
635
- "additionalProperties": false,
636
- "description": "The agent's GitHub access: the scope of the installation token minted for\nits sandbox \u2014 the credential `git`, `gh`, and the GitHub MCP server\nauthenticate with.\n\nBy default the token carries the installation's full permissions on all of\nthe installation's repositories. `permissions` narrows what it may do:\nthe string `read_only` grants read access to contents, issues, metadata and\npull requests; a map requests explicit levels per GitHub App permission\nscope (e.g. `{contents: read, pull_requests: write}`) and may never exceed\nwhat the installation granted. `repositories` scopes the token to exactly\nthe listed repos, by name (they must belong to the installation).\n\nRestriction is enforced by GitHub, not by Ellipsis: the token itself is\nminted with the reduced scope, so nothing running in the sandbox can\nexceed it.",
637
- "properties": {
638
- "permissions": {
639
- "anyOf": [
640
- {
641
- "const": "read_only",
642
- "type": "string"
643
- },
644
- {
645
- "additionalProperties": {
646
- "type": "string"
647
- },
648
- "type": "object"
649
- },
650
- {
651
- "type": "null"
652
- }
653
- ],
654
- "title": "Permissions"
655
- },
656
- "repositories": {
657
- "anyOf": [
658
- {
659
- "items": {
660
- "type": "string"
661
- },
662
- "type": "array"
663
- },
664
- {
665
- "type": "null"
666
- }
667
- ],
668
- "title": "Repositories"
669
- }
670
- },
671
- "title": "AgentConfigGithubPermissions",
672
- "type": "object"
673
- },
674
- "AgentConfigInput": {
675
- "additionalProperties": false,
676
- "description": "The typed input contract: what goes INTO a session (the trigger is\nwhen it happens; this is what goes in).\n\n`json_schema` types the payload a caller-started session takes\n(`POST /v1/sessions` `input`, validated at the door; required when\ndeclared). It is illegal on a react-triggered agent \u2014 react payloads are\nplatform-shaped (the published surface field sets), not caller-shaped.\n\n`message` is the initial-message template: exact `{{path}}` substitution\nover the caller payload (or, on a react agent, over the surface's\npublished fields), no conditionals/loops/filters. Refs are validated at\ndeploy time against the governing field set (see AgentConfig's\n`_check_input`).",
677
- "properties": {
678
- "json_schema": {
679
- "anyOf": [
680
- {
681
- "additionalProperties": true,
682
- "type": "object"
683
- },
684
- {
685
- "type": "null"
686
- }
687
- ],
688
- "title": "Json Schema"
689
- },
690
- "message": {
691
- "anyOf": [
692
- {
693
- "type": "string"
694
- },
695
- {
696
- "type": "null"
697
- }
698
- ],
699
- "title": "Message"
700
- }
701
- },
702
- "title": "AgentConfigInput",
703
- "type": "object"
704
- },
705
- "AgentConfigMcpRemoteServer": {
706
- "additionalProperties": false,
707
- "description": "A bring-your-own remote MCP server: the harness talks HTTP to `url`.\nNothing runs in the sandbox image. `headers` carry static auth (e.g.\n`Authorization: Bearer ${TOKEN}`); values may embed `${NAME}` secret\nreferences, resolved at run time from the account's secrets store.",
708
- "properties": {
709
- "headers": {
710
- "additionalProperties": {
711
- "type": "string"
712
- },
713
- "default": {},
714
- "title": "Headers",
715
- "type": "object"
716
- },
717
- "name": {
718
- "title": "Name",
719
- "type": "string"
720
- },
721
- "url": {
722
- "title": "Url",
723
- "type": "string"
724
- }
725
- },
726
- "required": [
727
- "name",
728
- "url"
729
- ],
730
- "title": "AgentConfigMcpRemoteServer",
731
- "type": "object"
732
- },
733
- "AgentConfigMcpServer": {
734
- "additionalProperties": false,
735
- "description": "One built-in MCP server this agent opts into by name (`linear`/`slack`).\nA name reference over the connected built-in set \u2014 the platform manages the\nserver's transport and credentials. It only matters when the named\nintegration is set to `opt_in` inclusion; an integration in the default\n`all_sessions` mode is added regardless. For a server the platform does not\nprovide, define it instead (`AgentConfigMcpStdioServer` /\n`AgentConfigMcpRemoteServer`).",
736
- "properties": {
737
- "name": {
738
- "title": "Name",
739
- "type": "string"
740
- }
741
- },
742
- "required": [
743
- "name"
744
- ],
745
- "title": "AgentConfigMcpServer",
746
- "type": "object"
747
- },
748
- "AgentConfigMcpStdioServer": {
749
- "additionalProperties": false,
750
- "description": "A bring-your-own stdio MCP server: the harness spawns `command` inside\nthe sandbox and speaks JSON-RPC over its stdin/stdout. The command must be\nrunnable in the sandbox image \u2014 install its runtime via `image.setup` /\n`image.dockerfile_append` if the base image lacks it.\n\n`env` values may embed `${NAME}` references, resolved at run time from the\naccount's secrets store (see `mcp_secret_refs`); everything else is passed\nliterally.",
751
- "properties": {
752
- "args": {
753
- "default": [],
754
- "items": {
755
- "type": "string"
756
- },
757
- "title": "Args",
758
- "type": "array"
759
- },
760
- "command": {
761
- "title": "Command",
762
- "type": "string"
763
- },
764
- "env": {
765
- "additionalProperties": {
766
- "type": "string"
767
- },
768
- "default": {},
769
- "title": "Env",
770
- "type": "object"
771
- },
772
- "name": {
773
- "title": "Name",
774
- "type": "string"
775
- }
776
- },
777
- "required": [
778
- "name",
779
- "command"
780
- ],
781
- "title": "AgentConfigMcpStdioServer",
782
- "type": "object"
783
- },
784
- "AgentConfigMemorySize": {
785
- "additionalProperties": false,
786
- "description": "A memory size as explicit units, summed (binary: 1GB = 1024MB = 1024MiB).\nSet any of `gb`/`mb` (at least one). The alternative to the `8GB`-style\nshorthand string.",
787
- "properties": {
788
- "gb": {
789
- "anyOf": [
790
- {
791
- "minimum": 0.0,
792
- "type": "integer"
793
- },
794
- {
795
- "type": "null"
796
- }
797
- ],
798
- "title": "Gb"
799
- },
800
- "mb": {
801
- "anyOf": [
802
- {
803
- "minimum": 0.0,
804
- "type": "integer"
805
- },
806
- {
807
- "type": "null"
808
- }
809
- ],
810
- "title": "Mb"
811
- }
812
- },
813
- "title": "AgentConfigMemorySize",
814
- "type": "object"
815
- },
816
- "AgentConfigMentionPlatform": {
817
- "description": "The surface an @ellipsis mention can come from.\n\nNo SLACK member: Slack routing is not a trigger on an agent config, it is the\n`slack.yaml` routing file (`SlackConfig`), which answers the questions a\nplatform list cannot \u2014 which channel, and whose DM. A mention trigger listing\n`slack` is therefore a config error, not a silently-never-fires config.",
818
- "enum": [
819
- "github",
820
- "linear"
821
- ],
822
- "title": "AgentConfigMentionPlatform",
823
- "type": "string"
824
- },
825
- "AgentConfigMentionTrigger": {
826
- "additionalProperties": false,
827
- "properties": {
828
- "platforms": {
829
- "default": [],
830
- "items": {
831
- "$ref": "#/components/schemas/AgentConfigMentionPlatform"
832
- },
833
- "title": "Platforms",
834
- "type": "array"
835
- },
836
- "type": {
837
- "const": "mention",
838
- "default": "mention",
839
- "title": "Type",
840
- "type": "string"
841
- }
842
- },
843
- "title": "AgentConfigMentionTrigger",
844
- "type": "object"
845
- },
846
- "AgentConfigMetadata": {
847
- "additionalProperties": false,
848
- "properties": {
849
- "annotations": {
850
- "additionalProperties": {
851
- "type": "string"
852
- },
853
- "default": {},
854
- "title": "Annotations",
855
- "type": "object"
856
- },
857
- "labels": {
858
- "default": [],
859
- "items": {
860
- "type": "string"
861
- },
862
- "title": "Labels",
863
- "type": "array"
864
- }
865
- },
866
- "title": "AgentConfigMetadata",
867
- "type": "object"
868
- },
869
- "AgentConfigOutput": {
870
- "additionalProperties": false,
871
- "description": "The typed output contract: the JSON Schema the agent must exit through\n(the StructuredOutput exit tool). Read back via\nGET /v1/sessions/{id}/output.",
872
- "properties": {
873
- "json_schema": {
874
- "additionalProperties": true,
875
- "title": "Json Schema",
876
- "type": "object"
877
- }
878
- },
879
- "required": [
880
- "json_schema"
881
- ],
882
- "title": "AgentConfigOutput",
883
- "type": "object"
884
- },
885
- "AgentConfigPermissions": {
886
- "additionalProperties": false,
887
- "description": "What the agent is allowed to touch, per credential the platform mints\ninto its sandbox. Distinct from `environment:`, which is where the agent\nruns; this is what it may do from there.\n\n`ellipsis` scopes the sandbox's Ellipsis API token\n(`ELLIPSIS_API_TOKEN`, what the in-sandbox `agent` CLI authenticates\nwith). `true` / the string `all` (the default) grant the full sandbox\nceiling \u2014 everything a sandbox token can ever do. A map narrows it per\nresource (see `AgentConfigEllipsisPermissions`); the minted token carries\nthe intersection, so a config can only ever reduce access. `false` fails\nvalidation \u2014 an agent with no API token cannot report its own progress.\n\n`github` scopes the sandbox's GitHub installation token (`GH_TOKEN`) \u2014\nsee `AgentConfigGithubPermissions`. GitHub enforces it at mint time.",
888
- "properties": {
889
- "ellipsis": {
890
- "anyOf": [
891
- {
892
- "enum": [
893
- true,
894
- "all"
895
- ]
896
- },
897
- {
898
- "$ref": "#/components/schemas/AgentConfigEllipsisPermissions"
899
- }
900
- ],
901
- "default": true,
902
- "title": "Ellipsis"
903
- },
904
- "github": {
905
- "$ref": "#/components/schemas/AgentConfigGithubPermissions",
906
- "default": {}
907
- }
908
- },
909
- "title": "AgentConfigPermissions",
910
- "type": "object"
911
- },
912
- "AgentConfigReactTrigger": {
913
- "additionalProperties": false,
914
- "properties": {
915
- "issue": {
916
- "anyOf": [
917
- {
918
- "$ref": "#/components/schemas/ReactIssue"
919
- },
920
- {
921
- "type": "null"
922
- }
923
- ]
924
- },
925
- "linear_issue": {
926
- "anyOf": [
927
- {
928
- "$ref": "#/components/schemas/ReactLinearIssue"
929
- },
930
- {
931
- "type": "null"
932
- }
933
- ]
934
- },
935
- "pull_request": {
936
- "anyOf": [
937
- {
938
- "$ref": "#/components/schemas/ReactPullRequest"
939
- },
940
- {
941
- "type": "null"
942
- }
943
- ]
944
- },
945
- "push": {
946
- "anyOf": [
947
- {
948
- "$ref": "#/components/schemas/ReactPush"
949
- },
950
- {
951
- "type": "null"
952
- }
953
- ]
954
- },
955
- "sentry": {
956
- "anyOf": [
957
- {
958
- "$ref": "#/components/schemas/ReactSentry"
959
- },
960
- {
961
- "type": "null"
962
- }
963
- ]
964
- },
965
- "slack_channel": {
966
- "anyOf": [
967
- {
968
- "$ref": "#/components/schemas/ReactSlackChannel"
969
- },
970
- {
971
- "type": "null"
972
- }
973
- ]
974
- },
975
- "type": {
976
- "const": "react",
977
- "default": "react",
978
- "title": "Type",
979
- "type": "string"
980
- }
981
- },
982
- "title": "AgentConfigReactTrigger",
983
- "type": "object"
984
- },
985
- "AgentConfigRepository": {
986
- "additionalProperties": false,
987
- "properties": {
988
- "name": {
989
- "title": "Name",
990
- "type": "string"
991
- },
992
- "owner": {
993
- "anyOf": [
994
- {
995
- "type": "string"
996
- },
997
- {
998
- "type": "null"
999
- }
1000
- ],
1001
- "title": "Owner"
1002
- },
1003
- "ref": {
1004
- "anyOf": [
1005
- {
1006
- "type": "string"
1007
- },
1008
- {
1009
- "type": "null"
1010
- }
1011
- ],
1012
- "title": "Ref"
1013
- }
1014
- },
1015
- "required": [
1016
- "name"
1017
- ],
1018
- "title": "AgentConfigRepository",
1019
- "type": "object"
1020
- },
1021
- "AgentConfigSettingsRef": {
1022
- "additionalProperties": false,
1023
- "description": "A config-declared Claude Code settings.json, resolved at run start and\npassed to `claude --settings <path>`. That is the CLI settings tier \u2014 BELOW\nEllipsis's managed-settings.json floor \u2014 so it customizes behavior (model\npermissions, includeCoAuthoredBy, statusLine, ...) but can never weaken a\nsecurity setting. Lets a team point the cloud agent at the same settings file\nthey already use with Claude Code locally instead of re-encoding it as YAML.",
1024
- "properties": {
1025
- "path": {
1026
- "title": "Path",
1027
- "type": "string"
1028
- },
1029
- "repository": {
1030
- "anyOf": [
1031
- {
1032
- "$ref": "#/components/schemas/AgentConfigRepository"
1033
- },
1034
- {
1035
- "type": "null"
1036
- }
1037
- ]
1038
- }
1039
- },
1040
- "required": [
1041
- "path"
1042
- ],
1043
- "title": "AgentConfigSettingsRef",
1044
- "type": "object"
1045
- },
1046
- "AgentConfigSkill": {
1047
- "additionalProperties": false,
1048
- "description": "One config-declared Claude Code skill: a repository directory containing\na SKILL.md, resolved at run start and installed at the sandbox's personal\nskill level (`~/.claude/skills/<basename(path)>/`). This is how a config\nbrings in skills its cloned repositories don't provide \u2014 cross-repo refs\n(an org-wide skills repo), public third-party repos, and repo-less runs.\nSkills under a cloned repo's own `.claude/skills/` load by themselves and\ndon't need an entry here.",
1049
- "properties": {
1050
- "path": {
1051
- "title": "Path",
1052
- "type": "string"
1053
- },
1054
- "repository": {
1055
- "anyOf": [
1056
- {
1057
- "$ref": "#/components/schemas/AgentConfigRepository"
1058
- },
1059
- {
1060
- "type": "null"
1061
- }
1062
- ]
1063
- }
1064
- },
1065
- "required": [
1066
- "path"
1067
- ],
1068
- "title": "AgentConfigSkill",
1069
- "type": "object"
1070
- },
1071
- "AgentConfigSource": {
1072
- "description": "Where a session's config came from. Total: every session has exactly one\nsource, including the ones that never touch defaults resolution.\n\nNot derivable from the row \u2014 `agent_config_id` says WHICH saved config, not\nhow it was chosen, and is null for inline, platform-default, and built-in\nconfigs alike \u2014 so it is persisted for audit and the published wire.",
1073
- "enum": [
1074
- "explicit",
1075
- "inline",
1076
- "template",
1077
- "repo_default",
1078
- "account_default",
1079
- "platform_default",
1080
- "trigger",
1081
- "builtin"
1082
- ],
1083
- "title": "AgentConfigSource",
1084
- "type": "string"
1085
- },
1086
- "AgentConfigSourceGithub": {
1087
- "description": "Identifies the file a GitHub-sourced agent config is synced from.\n\nKeyed on the repository ID (not owner/name) so repository and org renames\ndon't orphan the config; resolve display names from gh_repositories at\nread time.",
1088
- "properties": {
1089
- "branch": {
1090
- "title": "Branch",
1091
- "type": "string"
1092
- },
1093
- "path": {
1094
- "title": "Path",
1095
- "type": "string"
1096
- },
1097
- "repo_id": {
1098
- "title": "Repo Id",
1099
- "type": "integer"
1100
- }
1101
- },
1102
- "required": [
1103
- "repo_id",
1104
- "path",
1105
- "branch"
1106
- ],
1107
- "title": "AgentConfigSourceGithub",
1108
- "type": "object"
1109
- },
1110
- "AgentConfigSystemFileRef": {
1111
- "additionalProperties": false,
1112
- "properties": {
1113
- "file": {
1114
- "title": "File",
1115
- "type": "string"
1116
- },
1117
- "repository": {
1118
- "anyOf": [
1119
- {
1120
- "$ref": "#/components/schemas/AgentConfigRepository"
1121
- },
1122
- {
1123
- "type": "null"
1124
- }
1125
- ]
1126
- }
1127
- },
1128
- "required": [
1129
- "file"
1130
- ],
1131
- "title": "AgentConfigSystemFileRef",
1132
- "type": "object"
1133
- },
1134
4
  "AgentTemplate": {
1135
5
  "description": "A built-in agent template: a ready-to-use agent config plus the\nmetadata that describes it in the template gallery.",
1136
6
  "properties": {
@@ -1672,20 +542,9 @@
1672
542
  "Automation": {
1673
543
  "description": "An automation: a saved agent definition that runs on its trigger or\nwhen invoked, plus where it syncs from and the state of that sync.",
1674
544
  "properties": {
1675
- "agent_config": {
1676
- "$ref": "#/components/schemas/AgentConfig",
1677
- "description": "The agent definition itself, in the same schema as a YAML file under agents/."
1678
- },
1679
- "agent_config_source_details": {
1680
- "anyOf": [
1681
- {
1682
- "$ref": "#/components/schemas/AgentConfigSourceGithub"
1683
- },
1684
- {
1685
- "type": "null"
1686
- }
1687
- ],
1688
- "description": "The repository, path, and branch the automation syncs from. Null only transiently, before the creating pull request's file lands on the branch."
545
+ "config": {
546
+ "$ref": "#/components/schemas/AutomationConfig",
547
+ "description": "The automation definition itself, in the same schema as its YAML file: identity, trigger, input contract, and the session block."
1689
548
  },
1690
549
  "created_at": {
1691
550
  "description": "When the automation was created.",
@@ -1727,38 +586,192 @@
1727
586
  "format": "date-time",
1728
587
  "type": "string"
1729
588
  },
1730
- {
1731
- "type": "null"
1732
- }
1733
- ],
1734
- "description": "When that most recent session was created.",
1735
- "title": "Last Session Created At"
589
+ {
590
+ "type": "null"
591
+ }
592
+ ],
593
+ "description": "When that most recent session was created.",
594
+ "title": "Last Session Created At"
595
+ },
596
+ "last_session_id": {
597
+ "anyOf": [
598
+ {
599
+ "type": "string"
600
+ },
601
+ {
602
+ "type": "null"
603
+ }
604
+ ],
605
+ "description": "The most recent session this automation started, or null if it has never run.",
606
+ "title": "Last Session Id"
607
+ },
608
+ "last_sync_error": {
609
+ "anyOf": [
610
+ {
611
+ "type": "string"
612
+ },
613
+ {
614
+ "type": "null"
615
+ }
616
+ ],
617
+ "description": "The parse or validation error from the most recent sync attempt, or null when it succeeded. A non-null value means the automation is not running the YAML currently on the branch.",
618
+ "title": "Last Sync Error"
619
+ },
620
+ "last_synced_commit_sha": {
621
+ "anyOf": [
622
+ {
623
+ "type": "string"
624
+ },
625
+ {
626
+ "type": "null"
627
+ }
628
+ ],
629
+ "description": "The last commit the automation was synced from.",
630
+ "title": "Last Synced Commit Sha"
631
+ },
632
+ "managed_by": {
633
+ "$ref": "#/components/schemas/ConfigManagedBy",
634
+ "description": "Which writer owns this automation. \"github\" automations are defined by a file in a repository and are changed by editing that file; \"api\" automations have no file and are changed through this API."
635
+ },
636
+ "name": {
637
+ "anyOf": [
638
+ {
639
+ "type": "string"
640
+ },
641
+ {
642
+ "type": "null"
643
+ }
644
+ ],
645
+ "description": "The automation's account-unique addressable name (a slug of its display name); usable anywhere an automation is referenced, interchangeably with the id.",
646
+ "title": "Name"
647
+ },
648
+ "pending_pull_request_url": {
649
+ "anyOf": [
650
+ {
651
+ "type": "string"
652
+ },
653
+ {
654
+ "type": "null"
655
+ }
656
+ ],
657
+ "description": "The open pull request that adds this automation's file. Non-null means the automation is not live yet: it starts running once the pull request merges and syncs.",
658
+ "title": "Pending Pull Request Url"
659
+ },
660
+ "sha": {
661
+ "description": "The definition's content identity: the version fingerprint frozen onto each session that runs it.",
662
+ "title": "Sha",
663
+ "type": "string"
664
+ },
665
+ "source_details": {
666
+ "anyOf": [
667
+ {
668
+ "$ref": "#/components/schemas/GithubSourceDetails"
669
+ },
670
+ {
671
+ "type": "null"
672
+ }
673
+ ],
674
+ "description": "The repository, path, and branch the automation syncs from. Null only transiently, before the creating pull request's file lands on the branch."
675
+ },
676
+ "updated_at": {
677
+ "description": "When the automation was last updated.",
678
+ "format": "date-time",
679
+ "title": "Updated At",
680
+ "type": "string"
681
+ }
682
+ },
683
+ "required": [
684
+ "id",
685
+ "sha",
686
+ "created_at",
687
+ "updated_at",
688
+ "managed_by",
689
+ "config"
690
+ ],
691
+ "title": "Automation",
692
+ "type": "object"
693
+ },
694
+ "AutomationConfig": {
695
+ "additionalProperties": false,
696
+ "description": "A saved automation, as written in its YAML file: identity\n(`ellipsis`), when it runs (`trigger`), what goes in (`input`), and the\n`session:` block every session it starts is frozen from. Field order is\nthe canonical key order for files and `to_yaml` exports.",
697
+ "properties": {
698
+ "ellipsis": {
699
+ "$ref": "#/components/schemas/AutomationIdentity",
700
+ "default": {
701
+ "enabled": true,
702
+ "metadata": {
703
+ "annotations": {},
704
+ "labels": []
705
+ },
706
+ "version": "v1"
707
+ }
1736
708
  },
1737
- "last_session_id": {
709
+ "input": {
1738
710
  "anyOf": [
1739
711
  {
1740
- "type": "string"
712
+ "$ref": "#/components/schemas/InputContract"
1741
713
  },
1742
714
  {
1743
715
  "type": "null"
1744
716
  }
1745
- ],
1746
- "description": "The most recent session this automation started, or null if it has never run.",
1747
- "title": "Last Session Id"
717
+ ]
1748
718
  },
1749
- "last_sync_error": {
719
+ "session": {
720
+ "$ref": "#/components/schemas/SessionConfig",
721
+ "default": {
722
+ "budget": {},
723
+ "claude": {
724
+ "system": ""
725
+ },
726
+ "environment": {
727
+ "compute": {},
728
+ "hooks": {},
729
+ "image": {},
730
+ "mcp_servers": [],
731
+ "repositories": [],
732
+ "variables": []
733
+ },
734
+ "permissions": {
735
+ "ellipsis": true,
736
+ "github": {}
737
+ },
738
+ "skills": []
739
+ }
740
+ },
741
+ "trigger": {
1750
742
  "anyOf": [
1751
743
  {
1752
- "type": "string"
744
+ "discriminator": {
745
+ "mapping": {
746
+ "cron": "#/components/schemas/CronTrigger",
747
+ "react": "#/components/schemas/ReactTrigger"
748
+ },
749
+ "propertyName": "type"
750
+ },
751
+ "oneOf": [
752
+ {
753
+ "$ref": "#/components/schemas/CronTrigger"
754
+ },
755
+ {
756
+ "$ref": "#/components/schemas/ReactTrigger"
757
+ }
758
+ ]
1753
759
  },
1754
760
  {
1755
761
  "type": "null"
1756
762
  }
1757
763
  ],
1758
- "description": "The parse or validation error from the most recent sync attempt, or null when it succeeded. A non-null value means the automation is not running the YAML currently on the branch.",
1759
- "title": "Last Sync Error"
1760
- },
1761
- "last_synced_commit_sha": {
764
+ "title": "Trigger"
765
+ }
766
+ },
767
+ "title": "AutomationConfig",
768
+ "type": "object"
769
+ },
770
+ "AutomationIdentity": {
771
+ "additionalProperties": false,
772
+ "description": "The Ellipsis product namespace for a config file: which schema this is\n(`version`), the human-facing identity (`name`/`description`), freeform\norganizational `metadata`, and whether the agent is `enabled`. The\npresence of a top-level `ellipsis:` mapping is what marks a YAML file as\nan Ellipsis agent config (vs arbitrary YAML that merely lives under a\nconfig directory) \u2014 see `yaml_is_ellipsis_config`.\n\n`enabled` is agent behavior, not freeform metadata, so it stays inside\nthe config `sha` (only `metadata` is sha-excluded). Whether a session\naccepts messages is a per-run choice (POST /v1/sessions `interactive`),\nnot a config one.",
773
+ "properties": {
774
+ "description": {
1762
775
  "anyOf": [
1763
776
  {
1764
777
  "type": "string"
@@ -1767,12 +780,19 @@
1767
780
  "type": "null"
1768
781
  }
1769
782
  ],
1770
- "description": "The last commit the automation was synced from.",
1771
- "title": "Last Synced Commit Sha"
783
+ "title": "Description"
1772
784
  },
1773
- "managed_by": {
1774
- "$ref": "#/components/schemas/ConfigManagedBy",
1775
- "description": "Which writer owns this automation. \"github\" automations are defined by a file in a repository and are changed by editing that file; \"api\" automations have no file and are changed through this API."
785
+ "enabled": {
786
+ "default": true,
787
+ "title": "Enabled",
788
+ "type": "boolean"
789
+ },
790
+ "metadata": {
791
+ "$ref": "#/components/schemas/ConfigMetadata",
792
+ "default": {
793
+ "annotations": {},
794
+ "labels": []
795
+ }
1776
796
  },
1777
797
  "name": {
1778
798
  "anyOf": [
@@ -1783,42 +803,42 @@
1783
803
  "type": "null"
1784
804
  }
1785
805
  ],
1786
- "description": "The automation's account-unique addressable name (a slug of its display name); usable anywhere an automation is referenced, interchangeably with the id.",
1787
806
  "title": "Name"
1788
807
  },
1789
- "pending_pull_request_url": {
1790
- "anyOf": [
1791
- {
1792
- "type": "string"
1793
- },
1794
- {
1795
- "type": "null"
1796
- }
1797
- ],
1798
- "description": "The open pull request that adds this automation's file. Non-null means the automation is not live yet: it starts running once the pull request merges and syncs.",
1799
- "title": "Pending Pull Request Url"
1800
- },
1801
- "sha": {
1802
- "description": "The definition's content identity: the version fingerprint frozen onto each session that runs it.",
1803
- "title": "Sha",
808
+ "version": {
809
+ "default": "v1",
810
+ "title": "Version",
1804
811
  "type": "string"
812
+ }
813
+ },
814
+ "title": "AutomationIdentity",
815
+ "type": "object"
816
+ },
817
+ "AutomationMetricsResponse": {
818
+ "description": "An automation's session distribution and trailing spend.",
819
+ "properties": {
820
+ "samples": {
821
+ "description": "One entry per finished session, unordered.",
822
+ "items": {
823
+ "$ref": "#/components/schemas/AutomationSessionSample"
824
+ },
825
+ "title": "Samples",
826
+ "type": "array"
1805
827
  },
1806
- "updated_at": {
1807
- "description": "When the automation was last updated.",
1808
- "format": "date-time",
1809
- "title": "Updated At",
1810
- "type": "string"
828
+ "spend_windows": {
829
+ "description": "Trailing spend versus the budget, one entry per window (1, 7, and 28 days).",
830
+ "items": {
831
+ "$ref": "#/components/schemas/AutomationSpendWindow"
832
+ },
833
+ "title": "Spend Windows",
834
+ "type": "array"
1811
835
  }
1812
836
  },
1813
837
  "required": [
1814
- "id",
1815
- "sha",
1816
- "created_at",
1817
- "updated_at",
1818
- "managed_by",
1819
- "agent_config"
838
+ "samples",
839
+ "spend_windows"
1820
840
  ],
1821
- "title": "Automation",
841
+ "title": "AutomationMetricsResponse",
1822
842
  "type": "object"
1823
843
  },
1824
844
  "AutomationResponse": {
@@ -1835,6 +855,66 @@
1835
855
  "title": "AutomationResponse",
1836
856
  "type": "object"
1837
857
  },
858
+ "AutomationSessionSample": {
859
+ "description": "One finished session of the automation, reduced to the three figures\nthe distributions are drawn from.",
860
+ "properties": {
861
+ "cost": {
862
+ "description": "What the session cost, in millicents.",
863
+ "title": "Cost",
864
+ "type": "integer"
865
+ },
866
+ "duration_seconds": {
867
+ "description": "Wall-clock seconds from the session's creation to its last update.",
868
+ "title": "Duration Seconds",
869
+ "type": "number"
870
+ },
871
+ "tokens_total": {
872
+ "description": "Tokens the session consumed across every lane, including prompt-cache reads and writes.",
873
+ "title": "Tokens Total",
874
+ "type": "integer"
875
+ }
876
+ },
877
+ "required": [
878
+ "duration_seconds",
879
+ "cost",
880
+ "tokens_total"
881
+ ],
882
+ "title": "AutomationSessionSample",
883
+ "type": "object"
884
+ },
885
+ "AutomationSpendWindow": {
886
+ "description": "The automation's trailing spend against its budget over one window.",
887
+ "properties": {
888
+ "limit_usd": {
889
+ "description": "The enforced cap for the window, in US dollars: the automation's own budget clamped to the platform maximum, or the maximum itself when the budget is unset.",
890
+ "title": "Limit Usd",
891
+ "type": "number"
892
+ },
893
+ "platform_max_usd": {
894
+ "description": "The platform ceiling for the window, in US dollars; a budget above it is clamped to it.",
895
+ "title": "Platform Max Usd",
896
+ "type": "number"
897
+ },
898
+ "spent_usd": {
899
+ "description": "What the automation's sessions cost over the window, in US dollars.",
900
+ "title": "Spent Usd",
901
+ "type": "number"
902
+ },
903
+ "window_days": {
904
+ "description": "The trailing window, in days: 1, 7, or 28.",
905
+ "title": "Window Days",
906
+ "type": "integer"
907
+ }
908
+ },
909
+ "required": [
910
+ "window_days",
911
+ "spent_usd",
912
+ "limit_usd",
913
+ "platform_max_usd"
914
+ ],
915
+ "title": "AutomationSpendWindow",
916
+ "type": "object"
917
+ },
1838
918
  "AutomationsListResponse": {
1839
919
  "description": "The caller's automations.",
1840
920
  "properties": {
@@ -1872,6 +952,57 @@
1872
952
  "title": "BudgetCeiling",
1873
953
  "type": "object"
1874
954
  },
955
+ "BudgetConfig": {
956
+ "additionalProperties": false,
957
+ "properties": {
958
+ "day": {
959
+ "anyOf": [
960
+ {
961
+ "type": "number"
962
+ },
963
+ {
964
+ "type": "null"
965
+ }
966
+ ],
967
+ "title": "Day"
968
+ },
969
+ "month": {
970
+ "anyOf": [
971
+ {
972
+ "type": "number"
973
+ },
974
+ {
975
+ "type": "null"
976
+ }
977
+ ],
978
+ "title": "Month"
979
+ },
980
+ "session": {
981
+ "anyOf": [
982
+ {
983
+ "type": "number"
984
+ },
985
+ {
986
+ "type": "null"
987
+ }
988
+ ],
989
+ "title": "Session"
990
+ },
991
+ "week": {
992
+ "anyOf": [
993
+ {
994
+ "type": "number"
995
+ },
996
+ {
997
+ "type": "null"
998
+ }
999
+ ],
1000
+ "title": "Week"
1001
+ }
1002
+ },
1003
+ "title": "BudgetConfig",
1004
+ "type": "object"
1005
+ },
1875
1006
  "BudgetSource": {
1876
1007
  "description": "Which layer actually determined the enforced budget.\n\nNot derivable from the run row alone (the run does not store the config\ncents or the account default), so we persist it for the UI / audit.",
1877
1008
  "enum": [
@@ -1948,24 +1079,110 @@
1948
1079
  "description": "When the budget period ends, as an ISO timestamp.",
1949
1080
  "title": "End"
1950
1081
  },
1951
- "start": {
1082
+ "start": {
1083
+ "anyOf": [
1084
+ {
1085
+ "type": "string"
1086
+ },
1087
+ {
1088
+ "type": "null"
1089
+ }
1090
+ ],
1091
+ "description": "When the budget period started, as an ISO timestamp.",
1092
+ "title": "Start"
1093
+ }
1094
+ },
1095
+ "required": [
1096
+ "start",
1097
+ "end"
1098
+ ],
1099
+ "title": "BudgetWindow",
1100
+ "type": "object"
1101
+ },
1102
+ "ClaudeConfig": {
1103
+ "additionalProperties": false,
1104
+ "properties": {
1105
+ "effort": {
1106
+ "anyOf": [
1107
+ {
1108
+ "$ref": "#/components/schemas/EffortLevel"
1109
+ },
1110
+ {
1111
+ "type": "null"
1112
+ }
1113
+ ]
1114
+ },
1115
+ "fallback_model": {
1116
+ "anyOf": [
1117
+ {
1118
+ "type": "string"
1119
+ },
1120
+ {
1121
+ "type": "null"
1122
+ }
1123
+ ],
1124
+ "title": "Fallback Model"
1125
+ },
1126
+ "max_turns": {
1127
+ "anyOf": [
1128
+ {
1129
+ "exclusiveMinimum": 0.0,
1130
+ "type": "integer"
1131
+ },
1132
+ {
1133
+ "type": "null"
1134
+ }
1135
+ ],
1136
+ "title": "Max Turns"
1137
+ },
1138
+ "model": {
1139
+ "anyOf": [
1140
+ {
1141
+ "type": "string"
1142
+ },
1143
+ {
1144
+ "type": "null"
1145
+ }
1146
+ ],
1147
+ "title": "Model"
1148
+ },
1149
+ "settings": {
1150
+ "anyOf": [
1151
+ {
1152
+ "$ref": "#/components/schemas/SettingsRef"
1153
+ },
1154
+ {
1155
+ "type": "null"
1156
+ }
1157
+ ]
1158
+ },
1159
+ "system": {
1952
1160
  "anyOf": [
1953
1161
  {
1954
1162
  "type": "string"
1955
1163
  },
1956
1164
  {
1957
- "type": "null"
1165
+ "$ref": "#/components/schemas/SystemFileRef"
1166
+ },
1167
+ {
1168
+ "items": {
1169
+ "anyOf": [
1170
+ {
1171
+ "type": "string"
1172
+ },
1173
+ {
1174
+ "$ref": "#/components/schemas/SystemFileRef"
1175
+ }
1176
+ ]
1177
+ },
1178
+ "type": "array"
1958
1179
  }
1959
1180
  ],
1960
- "description": "When the budget period started, as an ISO timestamp.",
1961
- "title": "Start"
1181
+ "default": "",
1182
+ "title": "System"
1962
1183
  }
1963
1184
  },
1964
- "required": [
1965
- "start",
1966
- "end"
1967
- ],
1968
- "title": "BudgetWindow",
1185
+ "title": "ClaudeConfig",
1969
1186
  "type": "object"
1970
1187
  },
1971
1188
  "ClaudeSessionRecord": {
@@ -2263,6 +1480,44 @@
2263
1480
  "title": "CodexCommandExecutionItem",
2264
1481
  "type": "object"
2265
1482
  },
1483
+ "CodexConfig": {
1484
+ "additionalProperties": false,
1485
+ "description": "The `codex:` block \u2014 run this agent on OpenAI's Codex CLI instead of\nClaude Code. Declaring the block at all is what selects the harness\n(`AutomationConfig.harness`).\n\nDeliberately a small subset of `ClaudeConfig`: the fields omitted here\nare ones Codex has no equivalent for (`effort`, `fallback_model`,\n`settings`) or that the platform does not yet wire through for this harness\n(`max_turns`, `skills`, MCP servers). They are omitted rather than\naccepted-and-ignored, because `StrictConfigModel` forbids extra keys \u2014 so a\nconfig that sets one fails loudly at parse time instead of silently not doing\nit. The budget still bounds a run regardless.",
1486
+ "properties": {
1487
+ "model": {
1488
+ "default": "gpt-5.6-terra",
1489
+ "title": "Model",
1490
+ "type": "string"
1491
+ },
1492
+ "system": {
1493
+ "anyOf": [
1494
+ {
1495
+ "type": "string"
1496
+ },
1497
+ {
1498
+ "$ref": "#/components/schemas/SystemFileRef"
1499
+ },
1500
+ {
1501
+ "items": {
1502
+ "anyOf": [
1503
+ {
1504
+ "type": "string"
1505
+ },
1506
+ {
1507
+ "$ref": "#/components/schemas/SystemFileRef"
1508
+ }
1509
+ ]
1510
+ },
1511
+ "type": "array"
1512
+ }
1513
+ ],
1514
+ "default": "",
1515
+ "title": "System"
1516
+ }
1517
+ },
1518
+ "title": "CodexConfig",
1519
+ "type": "object"
1520
+ },
2266
1521
  "CodexErrorEvent": {
2267
1522
  "additionalProperties": true,
2268
1523
  "properties": {
@@ -3032,6 +2287,55 @@
3032
2287
  "title": "CodexWebSearchItem",
3033
2288
  "type": "object"
3034
2289
  },
2290
+ "ComputeConfig": {
2291
+ "additionalProperties": false,
2292
+ "description": "Sandbox compute sizing. Every field is optional; None inherits the\nplatform default (1 vCPU / 4096 MiB / 3600s \u2014 see DEFAULT_MODAL_* in\nmodels/ellipsis/sandboxes/sandbox.py). A resolved value outside the platform\nbounds fails validation loudly (a sync error on the config) rather than\nbeing clamped silently.\n\n`memory` and `timeout` each accept a shorthand string (\"8GB\", \"30m\") or an\nexplicit units object ({gb: 8}, {minutes: 30}); the `memory_mib` /\n`timeout_seconds` properties resolve either form to the canonical integer\nthe sandbox driver consumes.\n\n`timeout` is the max wall-clock the agent may run before the sandbox is\nkilled, capped at 1h (MAX_SANDBOX_TIMEOUT_SECONDS \u2014 equal to the default, so\ntoday the knob only shortens a session; the cap matches the 1-hour validity\nof the sandbox's GitHub token). The worker's lease/visibility heartbeat\nceiling is derived from that cap, so a run at the max stays owned by its\nworker for its whole life.\n\nCompute is billed on the requested allocation over the sandbox's\nwall-clock lifetime, so a bigger/longer box costs proportionally more.",
2293
+ "properties": {
2294
+ "cpu": {
2295
+ "anyOf": [
2296
+ {
2297
+ "maximum": 16.0,
2298
+ "minimum": 0.125,
2299
+ "type": "number"
2300
+ },
2301
+ {
2302
+ "type": "null"
2303
+ }
2304
+ ],
2305
+ "title": "Cpu"
2306
+ },
2307
+ "memory": {
2308
+ "anyOf": [
2309
+ {
2310
+ "type": "string"
2311
+ },
2312
+ {
2313
+ "$ref": "#/components/schemas/MemorySize"
2314
+ },
2315
+ {
2316
+ "type": "null"
2317
+ }
2318
+ ],
2319
+ "title": "Memory"
2320
+ },
2321
+ "timeout": {
2322
+ "anyOf": [
2323
+ {
2324
+ "type": "string"
2325
+ },
2326
+ {
2327
+ "$ref": "#/components/schemas/Duration"
2328
+ },
2329
+ {
2330
+ "type": "null"
2331
+ }
2332
+ ],
2333
+ "title": "Timeout"
2334
+ }
2335
+ },
2336
+ "title": "ComputeConfig",
2337
+ "type": "object"
2338
+ },
3035
2339
  "ConfigManagedBy": {
3036
2340
  "description": "Which writer owns an agent: the repository file it is defined in, or\nthis API. Every agent has exactly one owner, fixed when it is created and\nchanged only by linking or unlinking it.",
3037
2341
  "enum": [
@@ -3041,6 +2345,29 @@
3041
2345
  "title": "ConfigManagedBy",
3042
2346
  "type": "string"
3043
2347
  },
2348
+ "ConfigMetadata": {
2349
+ "additionalProperties": false,
2350
+ "properties": {
2351
+ "annotations": {
2352
+ "additionalProperties": {
2353
+ "type": "string"
2354
+ },
2355
+ "default": {},
2356
+ "title": "Annotations",
2357
+ "type": "object"
2358
+ },
2359
+ "labels": {
2360
+ "default": [],
2361
+ "items": {
2362
+ "type": "string"
2363
+ },
2364
+ "title": "Labels",
2365
+ "type": "array"
2366
+ }
2367
+ },
2368
+ "title": "ConfigMetadata",
2369
+ "type": "object"
2370
+ },
3044
2371
  "ContributorUsage": {
3045
2372
  "description": "An author who merged a pull request in the window. The pull-request and\nline counts cover their merged pull requests; `reviews` counts reviews this\nperson also submitted.",
3046
2373
  "properties": {
@@ -3103,7 +2430,7 @@
3103
2430
  "description": "Parameters for creating an automation.",
3104
2431
  "properties": {
3105
2432
  "automation": {
3106
- "$ref": "#/components/schemas/AgentConfig",
2433
+ "$ref": "#/components/schemas/AutomationConfig",
3107
2434
  "description": "The automation's definition, in the same schema as a YAML file under agents/."
3108
2435
  }
3109
2436
  },
@@ -3117,7 +2444,7 @@
3117
2444
  "description": "Parameters for creating an environment.",
3118
2445
  "properties": {
3119
2446
  "environment": {
3120
- "$ref": "#/components/schemas/EnvironmentConfig",
2447
+ "$ref": "#/components/schemas/EnvironmentDocument",
3121
2448
  "description": "The environment's definition."
3122
2449
  }
3123
2450
  },
@@ -3241,6 +2568,70 @@
3241
2568
  "title": "CreateReviewRequest",
3242
2569
  "type": "object"
3243
2570
  },
2571
+ "CronTrigger": {
2572
+ "additionalProperties": false,
2573
+ "properties": {
2574
+ "schedule": {
2575
+ "title": "Schedule",
2576
+ "type": "string"
2577
+ },
2578
+ "type": {
2579
+ "const": "cron",
2580
+ "default": "cron",
2581
+ "title": "Type",
2582
+ "type": "string"
2583
+ }
2584
+ },
2585
+ "required": [
2586
+ "schedule"
2587
+ ],
2588
+ "title": "CronTrigger",
2589
+ "type": "object"
2590
+ },
2591
+ "Duration": {
2592
+ "additionalProperties": false,
2593
+ "description": "A duration as explicit units, summed. Set any of `hours`/`minutes`/\n`seconds` (at least one). The alternative to the `30m`-style shorthand\nstring wherever a duration is accepted.",
2594
+ "properties": {
2595
+ "hours": {
2596
+ "anyOf": [
2597
+ {
2598
+ "minimum": 0.0,
2599
+ "type": "integer"
2600
+ },
2601
+ {
2602
+ "type": "null"
2603
+ }
2604
+ ],
2605
+ "title": "Hours"
2606
+ },
2607
+ "minutes": {
2608
+ "anyOf": [
2609
+ {
2610
+ "minimum": 0.0,
2611
+ "type": "integer"
2612
+ },
2613
+ {
2614
+ "type": "null"
2615
+ }
2616
+ ],
2617
+ "title": "Minutes"
2618
+ },
2619
+ "seconds": {
2620
+ "anyOf": [
2621
+ {
2622
+ "minimum": 0.0,
2623
+ "type": "integer"
2624
+ },
2625
+ {
2626
+ "type": "null"
2627
+ }
2628
+ ],
2629
+ "title": "Seconds"
2630
+ }
2631
+ },
2632
+ "title": "Duration",
2633
+ "type": "object"
2634
+ },
3244
2635
  "DurationPercentiles": {
3245
2636
  "description": "Percentiles of a duration distribution, in hours. p0 = fastest,\np100 = slowest; the spread shows how merge latency varies.",
3246
2637
  "properties": {
@@ -3362,6 +2753,37 @@
3362
2753
  "title": "EllipsisGrant",
3363
2754
  "type": "object"
3364
2755
  },
2756
+ "EllipsisPermissions": {
2757
+ "additionalProperties": {
2758
+ "anyOf": [
2759
+ {
2760
+ "$ref": "#/components/schemas/Level"
2761
+ },
2762
+ {
2763
+ "$ref": "#/components/schemas/EllipsisGrant"
2764
+ },
2765
+ {
2766
+ "items": {
2767
+ "anyOf": [
2768
+ {
2769
+ "$ref": "#/components/schemas/Level"
2770
+ },
2771
+ {
2772
+ "$ref": "#/components/schemas/EllipsisGrant"
2773
+ }
2774
+ ]
2775
+ },
2776
+ "type": "array"
2777
+ }
2778
+ ]
2779
+ },
2780
+ "description": "`permissions.ellipsis` as a map: resource \u2192 level | grant | list of\ngrants. Levels are hierarchical (read < write < delete), so `write`\nincludes `read`. An unlisted resource is denied. The whole block is\nintersected with the platform's sandbox ceiling at token mint \u2014 it can\nnarrow what a sandbox token may do, never exceed it.",
2781
+ "propertyNames": {
2782
+ "$ref": "#/components/schemas/Resource"
2783
+ },
2784
+ "title": "EllipsisPermissions",
2785
+ "type": "object"
2786
+ },
3365
2787
  "Environment": {
3366
2788
  "description": "A saved environment: the machine agents run in (repositories,\nvariables, MCP servers, image, compute, hooks), defined once and\nreferenced by name or id from agent configs and session starts.",
3367
2789
  "properties": {
@@ -3383,7 +2805,7 @@
3383
2805
  "description": "The GitHub account that last edited the environment, when known."
3384
2806
  },
3385
2807
  "environment": {
3386
- "$ref": "#/components/schemas/EnvironmentConfig",
2808
+ "$ref": "#/components/schemas/EnvironmentDocument",
3387
2809
  "description": "The environment definition itself, as parsed from its YAML."
3388
2810
  },
3389
2811
  "id": {
@@ -3432,7 +2854,7 @@
3432
2854
  "source_details": {
3433
2855
  "anyOf": [
3434
2856
  {
3435
- "$ref": "#/components/schemas/AgentConfigSourceGithub"
2857
+ "$ref": "#/components/schemas/GithubSourceDetails"
3436
2858
  },
3437
2859
  {
3438
2860
  "type": "null"
@@ -3459,23 +2881,80 @@
3459
2881
  "title": "Environment",
3460
2882
  "type": "object"
3461
2883
  },
3462
- "EnvironmentConfig": {
2884
+ "EnvironmentConfig": {
2885
+ "additionalProperties": false,
2886
+ "description": "Everything about the environment (the sandbox) the agent runs in: which\n`repositories` are cloned into it, which environment `variables` it gets,\nits `compute` sizing, how its `image` is customized, and lifecycle `hooks`.\nWhat the agent may *do* from that environment is the top-level\n`permissions:` block, not this one.\n\nEach `variables` entry names a variable to inject; with an inline `value` it\nis hardcoded, without one it is resolved from the account's sandbox-secrets\nstore. Only the named variables reach this agent; the rest of the account's\nstored variables never do. This is how a config brings in the config and\ncredentials a custom CLI needs.",
2887
+ "properties": {
2888
+ "compute": {
2889
+ "$ref": "#/components/schemas/ComputeConfig",
2890
+ "default": {}
2891
+ },
2892
+ "hooks": {
2893
+ "$ref": "#/components/schemas/EnvironmentHooks",
2894
+ "default": {}
2895
+ },
2896
+ "image": {
2897
+ "$ref": "#/components/schemas/EnvironmentImage",
2898
+ "default": {}
2899
+ },
2900
+ "mcp_servers": {
2901
+ "default": [],
2902
+ "items": {
2903
+ "anyOf": [
2904
+ {
2905
+ "type": "string"
2906
+ },
2907
+ {
2908
+ "$ref": "#/components/schemas/McpServerRef"
2909
+ },
2910
+ {
2911
+ "$ref": "#/components/schemas/McpStdioServer"
2912
+ },
2913
+ {
2914
+ "$ref": "#/components/schemas/McpRemoteServer"
2915
+ }
2916
+ ]
2917
+ },
2918
+ "title": "Mcp Servers",
2919
+ "type": "array"
2920
+ },
2921
+ "repositories": {
2922
+ "default": [],
2923
+ "items": {
2924
+ "$ref": "#/components/schemas/RepositoryRef"
2925
+ },
2926
+ "title": "Repositories",
2927
+ "type": "array"
2928
+ },
2929
+ "variables": {
2930
+ "default": [],
2931
+ "items": {
2932
+ "$ref": "#/components/schemas/EnvironmentVariable"
2933
+ },
2934
+ "title": "Variables",
2935
+ "type": "array"
2936
+ }
2937
+ },
2938
+ "title": "EnvironmentConfig",
2939
+ "type": "object"
2940
+ },
2941
+ "EnvironmentDocument": {
3463
2942
  "additionalProperties": false,
3464
2943
  "description": "A parsed environment document: identity plus the environment body.\n\nThe body fields are flattened to the top level of the file (not nested\nunder an `environment:` key) \u2014 the file *is* the environment, so nesting\nwould be ceremony. `to_environment()` projects the body for substitution\ninto an agent config.",
3465
2944
  "properties": {
3466
2945
  "compute": {
3467
- "$ref": "#/components/schemas/AgentConfigCompute",
2946
+ "$ref": "#/components/schemas/ComputeConfig",
3468
2947
  "default": {}
3469
2948
  },
3470
2949
  "ellipsis": {
3471
- "$ref": "#/components/schemas/EnvironmentConfigEllipsis"
2950
+ "$ref": "#/components/schemas/EnvironmentIdentity"
3472
2951
  },
3473
2952
  "hooks": {
3474
- "$ref": "#/components/schemas/AgentConfigEnvironmentHooks",
2953
+ "$ref": "#/components/schemas/EnvironmentHooks",
3475
2954
  "default": {}
3476
2955
  },
3477
2956
  "image": {
3478
- "$ref": "#/components/schemas/AgentConfigEnvironmentImage",
2957
+ "$ref": "#/components/schemas/EnvironmentImage",
3479
2958
  "default": {}
3480
2959
  },
3481
2960
  "mcp_servers": {
@@ -3486,13 +2965,13 @@
3486
2965
  "type": "string"
3487
2966
  },
3488
2967
  {
3489
- "$ref": "#/components/schemas/AgentConfigMcpServer"
2968
+ "$ref": "#/components/schemas/McpServerRef"
3490
2969
  },
3491
2970
  {
3492
- "$ref": "#/components/schemas/AgentConfigMcpStdioServer"
2971
+ "$ref": "#/components/schemas/McpStdioServer"
3493
2972
  },
3494
2973
  {
3495
- "$ref": "#/components/schemas/AgentConfigMcpRemoteServer"
2974
+ "$ref": "#/components/schemas/McpRemoteServer"
3496
2975
  }
3497
2976
  ]
3498
2977
  },
@@ -3502,7 +2981,7 @@
3502
2981
  "repositories": {
3503
2982
  "default": [],
3504
2983
  "items": {
3505
- "$ref": "#/components/schemas/AgentConfigRepository"
2984
+ "$ref": "#/components/schemas/RepositoryRef"
3506
2985
  },
3507
2986
  "title": "Repositories",
3508
2987
  "type": "array"
@@ -3510,7 +2989,7 @@
3510
2989
  "variables": {
3511
2990
  "default": [],
3512
2991
  "items": {
3513
- "$ref": "#/components/schemas/AgentConfigEnvironmentVariable"
2992
+ "$ref": "#/components/schemas/EnvironmentVariable"
3514
2993
  },
3515
2994
  "title": "Variables",
3516
2995
  "type": "array"
@@ -3519,10 +2998,40 @@
3519
2998
  "required": [
3520
2999
  "ellipsis"
3521
3000
  ],
3522
- "title": "EnvironmentConfig",
3001
+ "title": "EnvironmentDocument",
3002
+ "type": "object"
3003
+ },
3004
+ "EnvironmentHooks": {
3005
+ "additionalProperties": false,
3006
+ "description": "Shell scripts run at points in the sandbox lifecycle, each as the sandbox\nuser with the sandbox's environment variables available. A non-zero exit\nfails the run (exit_status = LIFECYCLE_HOOK_FAILED) and is not retried.\n\n`post_start` runs after the container starts, before any repo is cloned \u2014\nrepo-independent setup (authenticate a CLI, e.g. `doppler setup`). On Modal\nthe repo is baked into the image so it is incidentally present, but\n`post_start` must not depend on repo contents (that's `post_clone`).\n\n`post_clone` runs after all repos are cloned/checked out, before the agent \u2014\nrepo-dependent setup (`pip install -r requirements.txt`, codegen).\n\nHooks run on every run and their output is never cached. A dependency\ninstall whose result should be reused across runs belongs in `image.setup`\n(baked into the cached image) instead; keep hooks for per-run work \u2014 e.g.\nanything that touches run-scoped credentials.",
3007
+ "properties": {
3008
+ "post_clone": {
3009
+ "anyOf": [
3010
+ {
3011
+ "type": "string"
3012
+ },
3013
+ {
3014
+ "type": "null"
3015
+ }
3016
+ ],
3017
+ "title": "Post Clone"
3018
+ },
3019
+ "post_start": {
3020
+ "anyOf": [
3021
+ {
3022
+ "type": "string"
3023
+ },
3024
+ {
3025
+ "type": "null"
3026
+ }
3027
+ ],
3028
+ "title": "Post Start"
3029
+ }
3030
+ },
3031
+ "title": "EnvironmentHooks",
3523
3032
  "type": "object"
3524
3033
  },
3525
- "EnvironmentConfigEllipsis": {
3034
+ "EnvironmentIdentity": {
3526
3035
  "additionalProperties": false,
3527
3036
  "description": "The Ellipsis namespace of an environment file. `kind: environment` is\nwhat routes a synced YAML here instead of to the agent-config parser \u2014\nan agent config carries no `kind` (or `kind: agent`, tolerated nowhere:\nabsence is the agent marker).",
3528
3037
  "properties": {
@@ -3543,7 +3052,7 @@
3543
3052
  "type": "string"
3544
3053
  },
3545
3054
  "metadata": {
3546
- "$ref": "#/components/schemas/AgentConfigMetadata",
3055
+ "$ref": "#/components/schemas/ConfigMetadata",
3547
3056
  "default": {
3548
3057
  "annotations": {},
3549
3058
  "labels": []
@@ -3564,7 +3073,37 @@
3564
3073
  "required": [
3565
3074
  "kind"
3566
3075
  ],
3567
- "title": "EnvironmentConfigEllipsis",
3076
+ "title": "EnvironmentIdentity",
3077
+ "type": "object"
3078
+ },
3079
+ "EnvironmentImage": {
3080
+ "additionalProperties": false,
3081
+ "description": "How to customize the container image the agent runs in. You\ncontribute appended layers (`dockerfile_append`) and a build-time script\n(`setup`) only \u2014 Ellipsis owns FROM / base tooling / entrypoint / user.\nToday only inline bodies are supported; a file reference (resolved at the\nrun's SHA) will come later.\n\nThe split: `dockerfile_append` runs when the image is assembled, before any\nrepo exists \u2014 toolchain installs (a package manager binary, apt packages).\n`setup` runs at image-build time *after* the configured repositories are\nchecked out, and its output is captured by the filesystem snapshot that\nbecomes the cached image \u2014 dependency installs (`poetry install`,\n`npm install`), so later runs start with deps already on disk. Neither runs\nper run; that's `hooks.post_start` / `hooks.post_clone`.",
3082
+ "properties": {
3083
+ "dockerfile_append": {
3084
+ "anyOf": [
3085
+ {
3086
+ "type": "string"
3087
+ },
3088
+ {
3089
+ "type": "null"
3090
+ }
3091
+ ],
3092
+ "title": "Dockerfile Append"
3093
+ },
3094
+ "setup": {
3095
+ "anyOf": [
3096
+ {
3097
+ "type": "string"
3098
+ },
3099
+ {
3100
+ "type": "null"
3101
+ }
3102
+ ],
3103
+ "title": "Setup"
3104
+ }
3105
+ },
3106
+ "title": "EnvironmentImage",
3568
3107
  "type": "object"
3569
3108
  },
3570
3109
  "EnvironmentResponse": {
@@ -3593,6 +3132,32 @@
3593
3132
  "title": "EnvironmentSource",
3594
3133
  "type": "string"
3595
3134
  },
3135
+ "EnvironmentVariable": {
3136
+ "additionalProperties": false,
3137
+ "description": "One environment variable injected into the agent's sandbox.\n\n`value`, when set, is a literal injected as-is \u2014 use it for non-secret\nconfig (LOG_LEVEL, an API base URL). When `value` is omitted the value is\nresolved at run time from the account's sandbox-secrets store (dashboard\n/ `PUT /v1/secrets`) by `name`, so a secret can be injected without\never putting it in the config file. Either way the variable only reaches\nagents that name it.",
3138
+ "properties": {
3139
+ "name": {
3140
+ "title": "Name",
3141
+ "type": "string"
3142
+ },
3143
+ "value": {
3144
+ "anyOf": [
3145
+ {
3146
+ "type": "string"
3147
+ },
3148
+ {
3149
+ "type": "null"
3150
+ }
3151
+ ],
3152
+ "title": "Value"
3153
+ }
3154
+ },
3155
+ "required": [
3156
+ "name"
3157
+ ],
3158
+ "title": "EnvironmentVariable",
3159
+ "type": "object"
3160
+ },
3596
3161
  "EnvironmentsListResponse": {
3597
3162
  "description": "The caller's saved environments.",
3598
3163
  "properties": {
@@ -4345,6 +3910,46 @@
4345
3910
  "title": "GithubMembersListResponse",
4346
3911
  "type": "object"
4347
3912
  },
3913
+ "GithubPermissions": {
3914
+ "additionalProperties": false,
3915
+ "description": "The agent's GitHub access: the scope of the installation token minted for\nits sandbox \u2014 the credential `git`, `gh`, and the GitHub MCP server\nauthenticate with.\n\nBy default the token carries the installation's full permissions on all of\nthe installation's repositories. `permissions` narrows what it may do:\nthe string `read_only` grants read access to contents, issues, metadata and\npull requests; a map requests explicit levels per GitHub App permission\nscope (e.g. `{contents: read, pull_requests: write}`) and may never exceed\nwhat the installation granted. `repositories` scopes the token to exactly\nthe listed repos, by name (they must belong to the installation).\n\nRestriction is enforced by GitHub, not by Ellipsis: the token itself is\nminted with the reduced scope, so nothing running in the sandbox can\nexceed it.",
3916
+ "properties": {
3917
+ "permissions": {
3918
+ "anyOf": [
3919
+ {
3920
+ "const": "read_only",
3921
+ "type": "string"
3922
+ },
3923
+ {
3924
+ "additionalProperties": {
3925
+ "type": "string"
3926
+ },
3927
+ "type": "object"
3928
+ },
3929
+ {
3930
+ "type": "null"
3931
+ }
3932
+ ],
3933
+ "title": "Permissions"
3934
+ },
3935
+ "repositories": {
3936
+ "anyOf": [
3937
+ {
3938
+ "items": {
3939
+ "type": "string"
3940
+ },
3941
+ "type": "array"
3942
+ },
3943
+ {
3944
+ "type": "null"
3945
+ }
3946
+ ],
3947
+ "title": "Repositories"
3948
+ }
3949
+ },
3950
+ "title": "GithubPermissions",
3951
+ "type": "object"
3952
+ },
4348
3953
  "GithubRepositoriesListResponse": {
4349
3954
  "description": "The repositories connected to the account's GitHub installation.",
4350
3955
  "properties": {
@@ -4420,6 +4025,30 @@
4420
4025
  "title": "GithubRepository",
4421
4026
  "type": "object"
4422
4027
  },
4028
+ "GithubSourceDetails": {
4029
+ "description": "Identifies the file a GitHub-sourced agent config is synced from.\n\nKeyed on the repository ID (not owner/name) so repository and org renames\ndon't orphan the config; resolve display names from gh_repositories at\nread time.",
4030
+ "properties": {
4031
+ "branch": {
4032
+ "title": "Branch",
4033
+ "type": "string"
4034
+ },
4035
+ "path": {
4036
+ "title": "Path",
4037
+ "type": "string"
4038
+ },
4039
+ "repo_id": {
4040
+ "title": "Repo Id",
4041
+ "type": "integer"
4042
+ }
4043
+ },
4044
+ "required": [
4045
+ "repo_id",
4046
+ "path",
4047
+ "branch"
4048
+ ],
4049
+ "title": "GithubSourceDetails",
4050
+ "type": "object"
4051
+ },
4423
4052
  "GithubUser": {
4424
4053
  "description": "This is a full user account. It's the most amount of info we need to represent a GitHub user.\n\nRepresents both a public and private user.",
4425
4054
  "properties": {
@@ -4845,6 +4474,37 @@
4845
4474
  "title": "IngestTranscriptRequest",
4846
4475
  "type": "object"
4847
4476
  },
4477
+ "InputContract": {
4478
+ "additionalProperties": false,
4479
+ "description": "The typed input contract: what goes INTO a session (the trigger is\nwhen it happens; this is what goes in).\n\n`json_schema` types the payload a caller-started session takes\n(`POST /v1/sessions` `input`, validated at the door; required when\ndeclared). It is illegal on a react-triggered agent \u2014 react payloads are\nplatform-shaped (the published surface field sets), not caller-shaped.\n\n`message` is the initial-message template: exact `{{path}}` substitution\nover the caller payload (or, on a react agent, over the surface's\npublished fields), no conditionals/loops/filters. Refs are validated at\ndeploy time against the governing field set (see AutomationConfig's\n`_check_input`).",
4480
+ "properties": {
4481
+ "json_schema": {
4482
+ "anyOf": [
4483
+ {
4484
+ "additionalProperties": true,
4485
+ "type": "object"
4486
+ },
4487
+ {
4488
+ "type": "null"
4489
+ }
4490
+ ],
4491
+ "title": "Json Schema"
4492
+ },
4493
+ "message": {
4494
+ "anyOf": [
4495
+ {
4496
+ "type": "string"
4497
+ },
4498
+ {
4499
+ "type": "null"
4500
+ }
4501
+ ],
4502
+ "title": "Message"
4503
+ }
4504
+ },
4505
+ "title": "InputContract",
4506
+ "type": "object"
4507
+ },
4848
4508
  "IssueAction": {
4849
4509
  "enum": [
4850
4510
  "opened",
@@ -5176,58 +4836,137 @@
5176
4836
  "title": "LinkAutomationResponse",
5177
4837
  "type": "object"
5178
4838
  },
5179
- "LinkedGithubIdentity": {
5180
- "description": "The GitHub identity linked to a Slack member.",
4839
+ "LinkedGithubIdentity": {
4840
+ "description": "The GitHub identity linked to a Slack member.",
4841
+ "properties": {
4842
+ "id": {
4843
+ "description": "The linked GitHub account id.",
4844
+ "title": "Id",
4845
+ "type": "integer"
4846
+ },
4847
+ "login": {
4848
+ "anyOf": [
4849
+ {
4850
+ "type": "string"
4851
+ },
4852
+ {
4853
+ "type": "null"
4854
+ }
4855
+ ],
4856
+ "description": "The linked GitHub login, if known.",
4857
+ "title": "Login"
4858
+ }
4859
+ },
4860
+ "required": [
4861
+ "id"
4862
+ ],
4863
+ "title": "LinkedGithubIdentity",
4864
+ "type": "object"
4865
+ },
4866
+ "LinkedSlackIdentity": {
4867
+ "description": "The Slack identity linked to a GitHub member.",
4868
+ "properties": {
4869
+ "slack_email": {
4870
+ "anyOf": [
4871
+ {
4872
+ "type": "string"
4873
+ },
4874
+ {
4875
+ "type": "null"
4876
+ }
4877
+ ],
4878
+ "description": "The linked Slack user's email, if known.",
4879
+ "title": "Slack Email"
4880
+ },
4881
+ "slack_user_id": {
4882
+ "description": "The linked Slack user id.",
4883
+ "title": "Slack User Id",
4884
+ "type": "string"
4885
+ }
4886
+ },
4887
+ "required": [
4888
+ "slack_user_id"
4889
+ ],
4890
+ "title": "LinkedSlackIdentity",
4891
+ "type": "object"
4892
+ },
4893
+ "McpRemoteServer": {
4894
+ "additionalProperties": false,
4895
+ "description": "A bring-your-own remote MCP server: the harness talks HTTP to `url`.\nNothing runs in the sandbox image. `headers` carry static auth (e.g.\n`Authorization: Bearer ${TOKEN}`); values may embed `${NAME}` secret\nreferences, resolved at run time from the account's secrets store.",
4896
+ "properties": {
4897
+ "headers": {
4898
+ "additionalProperties": {
4899
+ "type": "string"
4900
+ },
4901
+ "default": {},
4902
+ "title": "Headers",
4903
+ "type": "object"
4904
+ },
4905
+ "name": {
4906
+ "title": "Name",
4907
+ "type": "string"
4908
+ },
4909
+ "url": {
4910
+ "title": "Url",
4911
+ "type": "string"
4912
+ }
4913
+ },
4914
+ "required": [
4915
+ "name",
4916
+ "url"
4917
+ ],
4918
+ "title": "McpRemoteServer",
4919
+ "type": "object"
4920
+ },
4921
+ "McpServerRef": {
4922
+ "additionalProperties": false,
4923
+ "description": "One built-in MCP server this agent opts into by name (`linear`/`slack`).\nA name reference over the connected built-in set \u2014 the platform manages the\nserver's transport and credentials. It only matters when the named\nintegration is set to `opt_in` inclusion; an integration in the default\n`all_sessions` mode is added regardless. For a server the platform does not\nprovide, define it instead (`McpStdioServer` /\n`McpRemoteServer`).",
5181
4924
  "properties": {
5182
- "id": {
5183
- "description": "The linked GitHub account id.",
5184
- "title": "Id",
5185
- "type": "integer"
5186
- },
5187
- "login": {
5188
- "anyOf": [
5189
- {
5190
- "type": "string"
5191
- },
5192
- {
5193
- "type": "null"
5194
- }
5195
- ],
5196
- "description": "The linked GitHub login, if known.",
5197
- "title": "Login"
4925
+ "name": {
4926
+ "title": "Name",
4927
+ "type": "string"
5198
4928
  }
5199
4929
  },
5200
4930
  "required": [
5201
- "id"
4931
+ "name"
5202
4932
  ],
5203
- "title": "LinkedGithubIdentity",
4933
+ "title": "McpServerRef",
5204
4934
  "type": "object"
5205
4935
  },
5206
- "LinkedSlackIdentity": {
5207
- "description": "The Slack identity linked to a GitHub member.",
4936
+ "McpStdioServer": {
4937
+ "additionalProperties": false,
4938
+ "description": "A bring-your-own stdio MCP server: the harness spawns `command` inside\nthe sandbox and speaks JSON-RPC over its stdin/stdout. The command must be\nrunnable in the sandbox image \u2014 install its runtime via `image.setup` /\n`image.dockerfile_append` if the base image lacks it.\n\n`env` values may embed `${NAME}` references, resolved at run time from the\naccount's secrets store (see `mcp_secret_refs`); everything else is passed\nliterally.",
5208
4939
  "properties": {
5209
- "slack_email": {
5210
- "anyOf": [
5211
- {
5212
- "type": "string"
5213
- },
5214
- {
5215
- "type": "null"
5216
- }
5217
- ],
5218
- "description": "The linked Slack user's email, if known.",
5219
- "title": "Slack Email"
4940
+ "args": {
4941
+ "default": [],
4942
+ "items": {
4943
+ "type": "string"
4944
+ },
4945
+ "title": "Args",
4946
+ "type": "array"
5220
4947
  },
5221
- "slack_user_id": {
5222
- "description": "The linked Slack user id.",
5223
- "title": "Slack User Id",
4948
+ "command": {
4949
+ "title": "Command",
4950
+ "type": "string"
4951
+ },
4952
+ "env": {
4953
+ "additionalProperties": {
4954
+ "type": "string"
4955
+ },
4956
+ "default": {},
4957
+ "title": "Env",
4958
+ "type": "object"
4959
+ },
4960
+ "name": {
4961
+ "title": "Name",
5224
4962
  "type": "string"
5225
4963
  }
5226
4964
  },
5227
4965
  "required": [
5228
- "slack_user_id"
4966
+ "name",
4967
+ "command"
5229
4968
  ],
5230
- "title": "LinkedSlackIdentity",
4969
+ "title": "McpStdioServer",
5231
4970
  "type": "object"
5232
4971
  },
5233
4972
  "MemoriesListResponse": {
@@ -5360,6 +5099,38 @@
5360
5099
  "title": "MemoryResponse",
5361
5100
  "type": "object"
5362
5101
  },
5102
+ "MemorySize": {
5103
+ "additionalProperties": false,
5104
+ "description": "A memory size as explicit units, summed (binary: 1GB = 1024MB = 1024MiB).\nSet any of `gb`/`mb` (at least one). The alternative to the `8GB`-style\nshorthand string.",
5105
+ "properties": {
5106
+ "gb": {
5107
+ "anyOf": [
5108
+ {
5109
+ "minimum": 0.0,
5110
+ "type": "integer"
5111
+ },
5112
+ {
5113
+ "type": "null"
5114
+ }
5115
+ ],
5116
+ "title": "Gb"
5117
+ },
5118
+ "mb": {
5119
+ "anyOf": [
5120
+ {
5121
+ "minimum": 0.0,
5122
+ "type": "integer"
5123
+ },
5124
+ {
5125
+ "type": "null"
5126
+ }
5127
+ ],
5128
+ "title": "Mb"
5129
+ }
5130
+ },
5131
+ "title": "MemorySize",
5132
+ "type": "object"
5133
+ },
5363
5134
  "MemorySummary": {
5364
5135
  "description": "One entry in the index: a memory with every field except `content`.\n\nContent is the only omission, and it's the whole reason this shape exists \u2014\nan account can hold 2,000 memories of 100 KB each, so a listing that carried\ncontent would be a 200 MB response.",
5365
5136
  "properties": {
@@ -5597,6 +5368,22 @@
5597
5368
  "title": "OrganizationSettings",
5598
5369
  "type": "object"
5599
5370
  },
5371
+ "OutputConfig": {
5372
+ "additionalProperties": false,
5373
+ "description": "The typed output contract: the JSON Schema the agent must exit through\n(the StructuredOutput exit tool). Read back via\nGET /v1/sessions/{id}/output.",
5374
+ "properties": {
5375
+ "json_schema": {
5376
+ "additionalProperties": true,
5377
+ "title": "Json Schema",
5378
+ "type": "object"
5379
+ }
5380
+ },
5381
+ "required": [
5382
+ "json_schema"
5383
+ ],
5384
+ "title": "OutputConfig",
5385
+ "type": "object"
5386
+ },
5600
5387
  "ParentKind": {
5601
5388
  "description": "How a session relates to its predecessor (parent_agent_session_id) \u2014\nthe ONE \"preceded-by\" chain for every predecessor relationship. Routing\nreads this when the distinction matters.\n\nCONTINUATION \u2014 a follow-up in the same conversation surface (e.g. a Slack\nthread reply spawning a fresh session on the same thread).\nRESUME \u2014 a conversation re-hosted on a new box after its sandbox was torn\ndown (interactive platform; later phase).",
5602
5389
  "enum": [
@@ -5606,6 +5393,33 @@
5606
5393
  "title": "ParentKind",
5607
5394
  "type": "string"
5608
5395
  },
5396
+ "PermissionsConfig": {
5397
+ "additionalProperties": false,
5398
+ "description": "What the agent is allowed to touch, per credential the platform mints\ninto its sandbox. Distinct from `environment:`, which is where the agent\nruns; this is what it may do from there.\n\n`ellipsis` scopes the sandbox's Ellipsis API token\n(`ELLIPSIS_API_TOKEN`, what the in-sandbox `agent` CLI authenticates\nwith). `true` / the string `all` (the default) grant the full sandbox\nceiling \u2014 everything a sandbox token can ever do. A map narrows it per\nresource (see `EllipsisPermissions`); the minted token carries\nthe intersection, so a config can only ever reduce access. `false` fails\nvalidation \u2014 an agent with no API token cannot report its own progress.\n\n`github` scopes the sandbox's GitHub installation token (`GH_TOKEN`) \u2014\nsee `GithubPermissions`. GitHub enforces it at mint time.",
5399
+ "properties": {
5400
+ "ellipsis": {
5401
+ "anyOf": [
5402
+ {
5403
+ "enum": [
5404
+ true,
5405
+ "all"
5406
+ ]
5407
+ },
5408
+ {
5409
+ "$ref": "#/components/schemas/EllipsisPermissions"
5410
+ }
5411
+ ],
5412
+ "default": true,
5413
+ "title": "Ellipsis"
5414
+ },
5415
+ "github": {
5416
+ "$ref": "#/components/schemas/GithubPermissions",
5417
+ "default": {}
5418
+ }
5419
+ },
5420
+ "title": "PermissionsConfig",
5421
+ "type": "object"
5422
+ },
5609
5423
  "PollCliAuthResponse": {
5610
5424
  "description": "The state of a device-code flow. Poll until `status` leaves `pending`.",
5611
5425
  "properties": {
@@ -6103,6 +5917,79 @@
6103
5917
  "title": "ReactSlackChannel",
6104
5918
  "type": "object"
6105
5919
  },
5920
+ "ReactTrigger": {
5921
+ "additionalProperties": false,
5922
+ "properties": {
5923
+ "issue": {
5924
+ "anyOf": [
5925
+ {
5926
+ "$ref": "#/components/schemas/ReactIssue"
5927
+ },
5928
+ {
5929
+ "type": "null"
5930
+ }
5931
+ ]
5932
+ },
5933
+ "linear_issue": {
5934
+ "anyOf": [
5935
+ {
5936
+ "$ref": "#/components/schemas/ReactLinearIssue"
5937
+ },
5938
+ {
5939
+ "type": "null"
5940
+ }
5941
+ ]
5942
+ },
5943
+ "pull_request": {
5944
+ "anyOf": [
5945
+ {
5946
+ "$ref": "#/components/schemas/ReactPullRequest"
5947
+ },
5948
+ {
5949
+ "type": "null"
5950
+ }
5951
+ ]
5952
+ },
5953
+ "push": {
5954
+ "anyOf": [
5955
+ {
5956
+ "$ref": "#/components/schemas/ReactPush"
5957
+ },
5958
+ {
5959
+ "type": "null"
5960
+ }
5961
+ ]
5962
+ },
5963
+ "sentry": {
5964
+ "anyOf": [
5965
+ {
5966
+ "$ref": "#/components/schemas/ReactSentry"
5967
+ },
5968
+ {
5969
+ "type": "null"
5970
+ }
5971
+ ]
5972
+ },
5973
+ "slack_channel": {
5974
+ "anyOf": [
5975
+ {
5976
+ "$ref": "#/components/schemas/ReactSlackChannel"
5977
+ },
5978
+ {
5979
+ "type": "null"
5980
+ }
5981
+ ]
5982
+ },
5983
+ "type": {
5984
+ "const": "react",
5985
+ "default": "react",
5986
+ "title": "Type",
5987
+ "type": "string"
5988
+ }
5989
+ },
5990
+ "title": "ReactTrigger",
5991
+ "type": "object"
5992
+ },
6106
5993
  "RecentPullRequest": {
6107
5994
  "description": "One pull request in the recent-activity table.",
6108
5995
  "properties": {
@@ -6310,6 +6197,42 @@
6310
6197
  }
6311
6198
  ]
6312
6199
  },
6200
+ "RepositoryRef": {
6201
+ "additionalProperties": false,
6202
+ "properties": {
6203
+ "name": {
6204
+ "title": "Name",
6205
+ "type": "string"
6206
+ },
6207
+ "owner": {
6208
+ "anyOf": [
6209
+ {
6210
+ "type": "string"
6211
+ },
6212
+ {
6213
+ "type": "null"
6214
+ }
6215
+ ],
6216
+ "title": "Owner"
6217
+ },
6218
+ "ref": {
6219
+ "anyOf": [
6220
+ {
6221
+ "type": "string"
6222
+ },
6223
+ {
6224
+ "type": "null"
6225
+ }
6226
+ ],
6227
+ "title": "Ref"
6228
+ }
6229
+ },
6230
+ "required": [
6231
+ "name"
6232
+ ],
6233
+ "title": "RepositoryRef",
6234
+ "type": "object"
6235
+ },
6313
6236
  "RepositorySelection": {
6314
6237
  "enum": [
6315
6238
  "all",
@@ -7209,11 +7132,44 @@
7209
7132
  "ReviewPullRequest": {
7210
7133
  "description": "The pull request a review ran on.",
7211
7134
  "properties": {
7135
+ "author": {
7136
+ "anyOf": [
7137
+ {
7138
+ "$ref": "#/components/schemas/ReviewPullRequestAuthor"
7139
+ },
7140
+ {
7141
+ "type": "null"
7142
+ }
7143
+ ],
7144
+ "description": "Who opened the pull request, or null when Ellipsis has not ingested the pull request yet."
7145
+ },
7146
+ "base_sha": {
7147
+ "description": "The pull request's base commit when the review was created.",
7148
+ "title": "Base Sha",
7149
+ "type": "string"
7150
+ },
7151
+ "head_sha": {
7152
+ "description": "The pull request's head commit the review ran against (the same as `scope.head`).",
7153
+ "title": "Head Sha",
7154
+ "type": "string"
7155
+ },
7212
7156
  "number": {
7213
7157
  "description": "The pull request number.",
7214
7158
  "title": "Number",
7215
7159
  "type": "integer"
7216
7160
  },
7161
+ "title": {
7162
+ "anyOf": [
7163
+ {
7164
+ "type": "string"
7165
+ },
7166
+ {
7167
+ "type": "null"
7168
+ }
7169
+ ],
7170
+ "description": "The pull request's title, or null when Ellipsis has not ingested the pull request yet.",
7171
+ "title": "Title"
7172
+ },
7217
7173
  "url": {
7218
7174
  "description": "The pull request's URL on GitHub.",
7219
7175
  "title": "Url",
@@ -7222,11 +7178,46 @@
7222
7178
  },
7223
7179
  "required": [
7224
7180
  "number",
7225
- "url"
7181
+ "url",
7182
+ "base_sha",
7183
+ "head_sha"
7226
7184
  ],
7227
7185
  "title": "ReviewPullRequest",
7228
7186
  "type": "object"
7229
7187
  },
7188
+ "ReviewPullRequestAuthor": {
7189
+ "description": "The GitHub account that opened the pull request.",
7190
+ "properties": {
7191
+ "avatar_url": {
7192
+ "description": "The account's avatar URL.",
7193
+ "title": "Avatar Url",
7194
+ "type": "string"
7195
+ },
7196
+ "id": {
7197
+ "description": "The account's GitHub id.",
7198
+ "title": "Id",
7199
+ "type": "integer"
7200
+ },
7201
+ "login": {
7202
+ "description": "The account's GitHub login.",
7203
+ "title": "Login",
7204
+ "type": "string"
7205
+ },
7206
+ "type": {
7207
+ "description": "The account type: \"User\", \"Organization\", or \"Bot\".",
7208
+ "title": "Type",
7209
+ "type": "string"
7210
+ }
7211
+ },
7212
+ "required": [
7213
+ "id",
7214
+ "login",
7215
+ "avatar_url",
7216
+ "type"
7217
+ ],
7218
+ "title": "ReviewPullRequestAuthor",
7219
+ "type": "object"
7220
+ },
7230
7221
  "ReviewRepoFacet": {
7231
7222
  "description": "A repository filter option for the reviews view.",
7232
7223
  "properties": {
@@ -8543,18 +8534,29 @@
8543
8534
  "Session": {
8544
8535
  "description": "An agent session: one conversation with an agent, from trigger to\nterminal state. Returned by `GET /v1/sessions/{id}` and carried by the\nsession stream's `session`/`snapshot` frames \u2014 REST and stream never\ndisagree about what a session looks like.",
8545
8536
  "properties": {
8546
- "agent": {
8547
- "$ref": "#/components/schemas/SessionAgent",
8548
- "description": "The agent that ran: the config the session executed, where that config came from, and any override merged into it."
8549
- },
8550
8537
  "attribution": {
8551
8538
  "$ref": "#/components/schemas/SessionAttribution",
8552
8539
  "description": "The principal this session is attributed to."
8553
8540
  },
8541
+ "automation": {
8542
+ "anyOf": [
8543
+ {
8544
+ "$ref": "#/components/schemas/SessionAutomation"
8545
+ },
8546
+ {
8547
+ "type": "null"
8548
+ }
8549
+ ],
8550
+ "description": "The automation the session was started from, or null for a raw session started with POST /v1/sessions."
8551
+ },
8554
8552
  "budget": {
8555
8553
  "$ref": "#/components/schemas/SessionBudget",
8556
8554
  "description": "The spend budget enforced for this session."
8557
8555
  },
8556
+ "config": {
8557
+ "$ref": "#/components/schemas/SessionConfig",
8558
+ "description": "What the session ran on, frozen when it was created: the harness block, the resolved environment, permissions, skills, output contract, and budget."
8559
+ },
8558
8560
  "context_repository": {
8559
8561
  "anyOf": [
8560
8562
  {
@@ -8579,7 +8581,7 @@
8579
8581
  },
8580
8582
  "environment": {
8581
8583
  "$ref": "#/components/schemas/SessionEnvironment",
8582
- "description": "The environment the session resolved: the saved environment's id and how it was chosen. The environment's frozen body is inside agent.config.environment."
8584
+ "description": "The environment the session resolved: the saved environment's id and how it was chosen. The environment's frozen body is `config.environment`."
8583
8585
  },
8584
8586
  "exit_status": {
8585
8587
  "anyOf": [
@@ -8737,55 +8739,11 @@
8737
8739
  "status",
8738
8740
  "surface",
8739
8741
  "prompting",
8740
- "agent"
8742
+ "config"
8741
8743
  ],
8742
8744
  "title": "Session",
8743
8745
  "type": "object"
8744
8746
  },
8745
- "SessionAgent": {
8746
- "description": "The agent this session ran: the definition it actually executed, where\nthat definition came from, and the diff that was merged in \u2014 the same\neffective-value-plus-provenance shape `SessionBudget` uses.\n\n`config` is the snapshot frozen when the session was created;\n`automation_id` points at the automation as it exists NOW. They diverge\nlegitimately: a YAML edit after the session started, or any `override`,\nleaves the pointer describing something the session never ran.",
8747
- "properties": {
8748
- "automation_id": {
8749
- "anyOf": [
8750
- {
8751
- "type": "string"
8752
- },
8753
- {
8754
- "type": "null"
8755
- }
8756
- ],
8757
- "description": "Identifier of the automation this session's snapshot was taken from. Null for raw sessions (nothing saved behind them), templates, and built-in agents. Points at the automation as it exists now, which may have changed since.",
8758
- "title": "Automation Id"
8759
- },
8760
- "config": {
8761
- "$ref": "#/components/schemas/AgentConfig",
8762
- "description": "The agent definition the session actually ran, frozen when the session was created."
8763
- },
8764
- "override": {
8765
- "anyOf": [
8766
- {
8767
- "additionalProperties": true,
8768
- "type": "object"
8769
- },
8770
- {
8771
- "type": "null"
8772
- }
8773
- ],
8774
- "description": "The partial-config override merged into `config` for this session, or null when the config ran unmodified. `config` is the merged result; this is the diff.",
8775
- "title": "Override"
8776
- },
8777
- "source": {
8778
- "$ref": "#/components/schemas/AgentConfigSource",
8779
- "description": "How this session's config was chosen."
8780
- }
8781
- },
8782
- "required": [
8783
- "config",
8784
- "source"
8785
- ],
8786
- "title": "SessionAgent",
8787
- "type": "object"
8788
- },
8789
8747
  "SessionAttribution": {
8790
8748
  "description": "The principal a session is attributed to: what kind, its id, and \u2014 when\nthe kind is a GitHub user \u2014 the resolved display snippet.",
8791
8749
  "properties": {
@@ -8827,6 +8785,32 @@
8827
8785
  "title": "SessionAttribution",
8828
8786
  "type": "object"
8829
8787
  },
8788
+ "SessionAutomation": {
8789
+ "description": "The automation this session was started from: the definition frozen\nwhen the session was created, and the saved automation it came from as it\nexists NOW. They diverge legitimately \u2014 a YAML edit after the session\nstarted leaves the pointer describing something the session never ran.",
8790
+ "properties": {
8791
+ "config": {
8792
+ "$ref": "#/components/schemas/AutomationConfig",
8793
+ "description": "The automation definition the session was started from, frozen when the session was created."
8794
+ },
8795
+ "id": {
8796
+ "anyOf": [
8797
+ {
8798
+ "type": "string"
8799
+ },
8800
+ {
8801
+ "type": "null"
8802
+ }
8803
+ ],
8804
+ "description": "Identifier of the saved automation this session's snapshot was taken from. Null for a routing-file agent, a code-review stage agent, or the built-in mention agent, which have no saved automation behind them. Points at the automation as it exists now, which may have changed since.",
8805
+ "title": "Id"
8806
+ }
8807
+ },
8808
+ "required": [
8809
+ "config"
8810
+ ],
8811
+ "title": "SessionAutomation",
8812
+ "type": "object"
8813
+ },
8830
8814
  "SessionBudget": {
8831
8815
  "description": "The spend budget actually enforced for this session, and which layer of\nthe cascade set it.",
8832
8816
  "properties": {
@@ -8845,6 +8829,78 @@
8845
8829
  "title": "SessionBudget",
8846
8830
  "type": "object"
8847
8831
  },
8832
+ "SessionConfig": {
8833
+ "additionalProperties": false,
8834
+ "description": "What one session runs on: the harness block(s), where it runs, what it\nmay touch, its skills, its exit contract, and its spend cap. Every session\nfreezes one of these (`agent_sessions.session_config`); an automation\ncarries one under `session:` (`AutomationConfig.session`); and\n`POST /v1/sessions` is this shape flattened onto the request body, plus the\nrun settings. Nothing in here is an automation's identity or trigger \u2014\nthose belong to `AutomationConfig`.\n\nField order is the canonical key order for `session:` blocks and YAML\nexports: what runs (`claude`/`codex`), where (`environment`), what it may\ntouch (`permissions`), then the rest.",
8835
+ "properties": {
8836
+ "budget": {
8837
+ "$ref": "#/components/schemas/BudgetConfig",
8838
+ "default": {}
8839
+ },
8840
+ "claude": {
8841
+ "$ref": "#/components/schemas/ClaudeConfig",
8842
+ "default": {
8843
+ "system": ""
8844
+ }
8845
+ },
8846
+ "codex": {
8847
+ "anyOf": [
8848
+ {
8849
+ "$ref": "#/components/schemas/CodexConfig"
8850
+ },
8851
+ {
8852
+ "type": "null"
8853
+ }
8854
+ ]
8855
+ },
8856
+ "environment": {
8857
+ "anyOf": [
8858
+ {
8859
+ "type": "string"
8860
+ },
8861
+ {
8862
+ "$ref": "#/components/schemas/EnvironmentConfig"
8863
+ }
8864
+ ],
8865
+ "default": {
8866
+ "compute": {},
8867
+ "hooks": {},
8868
+ "image": {},
8869
+ "mcp_servers": [],
8870
+ "repositories": [],
8871
+ "variables": []
8872
+ },
8873
+ "title": "Environment"
8874
+ },
8875
+ "output": {
8876
+ "anyOf": [
8877
+ {
8878
+ "$ref": "#/components/schemas/OutputConfig"
8879
+ },
8880
+ {
8881
+ "type": "null"
8882
+ }
8883
+ ]
8884
+ },
8885
+ "permissions": {
8886
+ "$ref": "#/components/schemas/PermissionsConfig",
8887
+ "default": {
8888
+ "ellipsis": true,
8889
+ "github": {}
8890
+ }
8891
+ },
8892
+ "skills": {
8893
+ "default": [],
8894
+ "items": {
8895
+ "$ref": "#/components/schemas/SkillRef"
8896
+ },
8897
+ "title": "Skills",
8898
+ "type": "array"
8899
+ }
8900
+ },
8901
+ "title": "SessionConfig",
8902
+ "type": "object"
8903
+ },
8848
8904
  "SessionCost": {
8849
8905
  "description": "What a session (or one turn of it) cost, in millicents.\n\n`llm` is deliberately NOT called `tokens`: it would sit beside the `tokens`\nobject and read as \"the token count's cost\" rather than \"the cost of the\nLLM leg\".",
8850
8906
  "properties": {
@@ -8882,8 +8938,35 @@
8882
8938
  "title": "SessionCost",
8883
8939
  "type": "object"
8884
8940
  },
8941
+ "SessionDiffResponse": {
8942
+ "description": "A session's uncommitted working-tree changes, one patch per file.",
8943
+ "properties": {
8944
+ "files": {
8945
+ "description": "One unified-diff section per changed file, `diff --git` header included, exactly as git emitted it. Join to the per-file counts on `git.repos[].files` by (full_name, path). Empty when the tree was clean or no capture ran.",
8946
+ "items": {
8947
+ "$ref": "#/components/schemas/SessionGitPatchFile"
8948
+ },
8949
+ "title": "Files",
8950
+ "type": "array"
8951
+ },
8952
+ "omitted_paths": {
8953
+ "description": "Paths whose hunks were dropped to fit the storage cap, so a viewer can name what is missing instead of showing a silently partial diff.",
8954
+ "items": {
8955
+ "type": "string"
8956
+ },
8957
+ "title": "Omitted Paths",
8958
+ "type": "array"
8959
+ }
8960
+ },
8961
+ "required": [
8962
+ "files",
8963
+ "omitted_paths"
8964
+ ],
8965
+ "title": "SessionDiffResponse",
8966
+ "type": "object"
8967
+ },
8885
8968
  "SessionEnvironment": {
8886
- "description": "The environment this session resolved: which saved environment (as it\nexists now) and how it was chosen. The environment's frozen BODY rides\ninside `agent.config.environment` \u2014 substitution happens before the config\nsnapshot freezes \u2014 so this object is provenance, not payload.",
8969
+ "description": "The environment this session resolved: which saved environment (as it\nexists now) and how it was chosen. The environment's frozen BODY rides\ninside `config.environment` \u2014 substitution happens before the config\nsnapshot freezes \u2014 so this object is provenance, not payload.",
8887
8970
  "properties": {
8888
8971
  "environment_id": {
8889
8972
  "anyOf": [
@@ -9007,6 +9090,30 @@
9007
9090
  "title": "SessionGitFile",
9008
9091
  "type": "object"
9009
9092
  },
9093
+ "SessionGitPatchFile": {
9094
+ "description": "One file's patch, split out of `git diff HEAD` at capture time.\n\nStored per file rather than as one blob because that is how a viewer reads\nit: a row per changed file, opened one at a time. Counts and status are NOT\nrepeated here \u2014 they live on the matching SessionGitFile in\n`agent_sessions.output_git`, which rides on every session read, so a surface\nlists the changed files (and their +/\u2212) before it fetches a single hunk. The\njoin key is (full_name, path).\n\n`patch` is the unified-diff section for this file, `diff --git` header\nincluded, exactly as git emitted it.",
9095
+ "properties": {
9096
+ "full_name": {
9097
+ "title": "Full Name",
9098
+ "type": "string"
9099
+ },
9100
+ "patch": {
9101
+ "title": "Patch",
9102
+ "type": "string"
9103
+ },
9104
+ "path": {
9105
+ "title": "Path",
9106
+ "type": "string"
9107
+ }
9108
+ },
9109
+ "required": [
9110
+ "full_name",
9111
+ "path",
9112
+ "patch"
9113
+ ],
9114
+ "title": "SessionGitPatchFile",
9115
+ "type": "object"
9116
+ },
9010
9117
  "SessionGitPr": {
9011
9118
  "description": "A pull request the session opened in this repo, written the moment the\ncreating tool call's result lands (see extract_session_prs.PrCreateWatcher).\nLive PR state (open/merged/closed) is not stored \u2014 it lives on gh_prs,\njoined via `gh_pr_id` (GET /frontend/agents/sessions/{id}/git). The repo is\nthe parent object, so it is not repeated here.",
9012
9119
  "properties": {
@@ -9719,6 +9826,56 @@
9719
9826
  "title": "SessionsListResponse",
9720
9827
  "type": "object"
9721
9828
  },
9829
+ "SettingsRef": {
9830
+ "additionalProperties": false,
9831
+ "description": "A config-declared Claude Code settings.json, resolved at run start and\npassed to `claude --settings <path>`. That is the CLI settings tier \u2014 BELOW\nEllipsis's managed-settings.json floor \u2014 so it customizes behavior (model\npermissions, includeCoAuthoredBy, statusLine, ...) but can never weaken a\nsecurity setting. Lets a team point the cloud agent at the same settings file\nthey already use with Claude Code locally instead of re-encoding it as YAML.",
9832
+ "properties": {
9833
+ "path": {
9834
+ "title": "Path",
9835
+ "type": "string"
9836
+ },
9837
+ "repository": {
9838
+ "anyOf": [
9839
+ {
9840
+ "$ref": "#/components/schemas/RepositoryRef"
9841
+ },
9842
+ {
9843
+ "type": "null"
9844
+ }
9845
+ ]
9846
+ }
9847
+ },
9848
+ "required": [
9849
+ "path"
9850
+ ],
9851
+ "title": "SettingsRef",
9852
+ "type": "object"
9853
+ },
9854
+ "SkillRef": {
9855
+ "additionalProperties": false,
9856
+ "description": "One config-declared Claude Code skill: a repository directory containing\na SKILL.md, resolved at run start and installed at the sandbox's personal\nskill level (`~/.claude/skills/<basename(path)>/`). This is how a config\nbrings in skills its cloned repositories don't provide \u2014 cross-repo refs\n(an org-wide skills repo), public third-party repos, and repo-less runs.\nSkills under a cloned repo's own `.claude/skills/` load by themselves and\ndon't need an entry here.",
9857
+ "properties": {
9858
+ "path": {
9859
+ "title": "Path",
9860
+ "type": "string"
9861
+ },
9862
+ "repository": {
9863
+ "anyOf": [
9864
+ {
9865
+ "$ref": "#/components/schemas/RepositoryRef"
9866
+ },
9867
+ {
9868
+ "type": "null"
9869
+ }
9870
+ ]
9871
+ }
9872
+ },
9873
+ "required": [
9874
+ "path"
9875
+ ],
9876
+ "title": "SkillRef",
9877
+ "type": "object"
9878
+ },
9722
9879
  "SlackChannel": {
9723
9880
  "description": "One channel in the connected Slack workspace.",
9724
9881
  "properties": {
@@ -9939,7 +10096,7 @@
9939
10096
  },
9940
10097
  "StartAgentSessionRequest": {
9941
10098
  "additionalProperties": false,
9942
- "description": "Parameters for starting a raw session: where it runs, its first\nmessage, and the run's own settings. Flat, in the AgentConfig vocabulary\n\u2014 a `claude:` or `permissions:` block copied from an agents/ YAML file\npastes in verbatim. There is no automation behind a raw session; to run a\nsaved automation, invoke it with POST /v1/automations/{automation_id}/sessions.\n\nExtra keys are a 422, not silently dropped \u2014 a retired field\n(`from_config_id`, `input`, `ellipsis`, `config_id`) must fail loudly on\nan old client, never no-op.",
10099
+ "description": "Parameters for starting a raw session: where it runs, its first\nmessage, and the run's own settings. Flat, in the AutomationConfig vocabulary\n\u2014 a `claude:` or `permissions:` block copied from an agents/ YAML file\npastes in verbatim. There is no automation behind a raw session; to run a\nsaved automation, invoke it with POST /v1/automations/{automation_id}/sessions.\n\nExtra keys are a 422, not silently dropped \u2014 a retired field\n(`from_config_id`, `input`, `ellipsis`, `config_id`) must fail loudly on\nan old client, never no-op.",
9943
10100
  "properties": {
9944
10101
  "budget": {
9945
10102
  "anyOf": [
@@ -9957,7 +10114,7 @@
9957
10114
  "claude": {
9958
10115
  "anyOf": [
9959
10116
  {
9960
- "$ref": "#/components/schemas/AgentConfigClaude"
10117
+ "$ref": "#/components/schemas/ClaudeConfig"
9961
10118
  },
9962
10119
  {
9963
10120
  "type": "null"
@@ -9968,7 +10125,7 @@
9968
10125
  "codex": {
9969
10126
  "anyOf": [
9970
10127
  {
9971
- "$ref": "#/components/schemas/AgentConfigCodex"
10128
+ "$ref": "#/components/schemas/CodexConfig"
9972
10129
  },
9973
10130
  {
9974
10131
  "type": "null"
@@ -9982,13 +10139,13 @@
9982
10139
  "type": "string"
9983
10140
  },
9984
10141
  {
9985
- "$ref": "#/components/schemas/AgentConfigEnvironment"
10142
+ "$ref": "#/components/schemas/EnvironmentConfig"
9986
10143
  },
9987
10144
  {
9988
10145
  "type": "null"
9989
10146
  }
9990
10147
  ],
9991
- "description": "Where the session runs. A STRING is a saved environment's name or `env_...` id. An OBJECT is an inline environment for this session only. Omitted, the session runs in the organization's default environment, else the built-in basic sandbox.",
10148
+ "description": "Where the session runs. A STRING is a saved environment's name or `env_...` id, substituted wholesale. An OBJECT is the whole environment for this session \u2014 `{}` is the bare sandbox; nothing from the organization's default merges in. Omitted, the session runs in the organization's default environment, else the built-in basic sandbox.",
9992
10149
  "title": "Environment"
9993
10150
  },
9994
10151
  "force_rebuild": {
@@ -10015,7 +10172,7 @@
10015
10172
  "output": {
10016
10173
  "anyOf": [
10017
10174
  {
10018
- "$ref": "#/components/schemas/AgentConfigOutput"
10175
+ "$ref": "#/components/schemas/OutputConfig"
10019
10176
  },
10020
10177
  {
10021
10178
  "type": "null"
@@ -10026,7 +10183,7 @@
10026
10183
  "permissions": {
10027
10184
  "anyOf": [
10028
10185
  {
10029
- "$ref": "#/components/schemas/AgentConfigPermissions"
10186
+ "$ref": "#/components/schemas/PermissionsConfig"
10030
10187
  },
10031
10188
  {
10032
10189
  "type": "null"
@@ -10043,14 +10200,29 @@
10043
10200
  "type": "null"
10044
10201
  }
10045
10202
  ],
10046
- "description": "The session's first message. Omit it and the session starts idle: the sandbox spins up, the agent waits at the prompt, and the first message you send opens turn 0.",
10047
- "title": "Prompt"
10203
+ "description": "The session's first message. Omit it and the session starts idle: the sandbox spins up, the agent waits at the prompt, and the first message you send opens turn 0.",
10204
+ "title": "Prompt"
10205
+ },
10206
+ "repositories": {
10207
+ "anyOf": [
10208
+ {
10209
+ "items": {
10210
+ "type": "string"
10211
+ },
10212
+ "type": "array"
10213
+ },
10214
+ {
10215
+ "type": "null"
10216
+ }
10217
+ ],
10218
+ "description": "Repositories to check out in addition to the environment's own, as `owner/name` or a bare `name` (the account's). Each is added only when the resolved environment does not already have it \u2014 the CLI sends the repository it is standing in this way, whatever environment the session runs in.",
10219
+ "title": "Repositories"
10048
10220
  },
10049
10221
  "skills": {
10050
10222
  "anyOf": [
10051
10223
  {
10052
10224
  "items": {
10053
- "$ref": "#/components/schemas/AgentConfigSkill"
10225
+ "$ref": "#/components/schemas/SkillRef"
10054
10226
  },
10055
10227
  "type": "array"
10056
10228
  },
@@ -10153,6 +10325,30 @@
10153
10325
  "title": "StartCliAuthResponse",
10154
10326
  "type": "object"
10155
10327
  },
10328
+ "SystemFileRef": {
10329
+ "additionalProperties": false,
10330
+ "properties": {
10331
+ "file": {
10332
+ "title": "File",
10333
+ "type": "string"
10334
+ },
10335
+ "repository": {
10336
+ "anyOf": [
10337
+ {
10338
+ "$ref": "#/components/schemas/RepositoryRef"
10339
+ },
10340
+ {
10341
+ "type": "null"
10342
+ }
10343
+ ]
10344
+ }
10345
+ },
10346
+ "required": [
10347
+ "file"
10348
+ ],
10349
+ "title": "SystemFileRef",
10350
+ "type": "object"
10351
+ },
10156
10352
  "TokensInfo": {
10157
10353
  "additionalProperties": false,
10158
10354
  "description": "Token/cost usage, per record (one API call's counts, aggregate fields at\ntheir zero defaults) or aggregated per execution/session\n(compute_spend_from_records derives num_turns and cost_usd).\n\nStrict on purpose: this is our own persisted schema, so an unknown key is a\nwriter bug (the num_turns=0 bug shipped because a Claude Code usage dict\nvalidated leniently against this model, silently zeroing every\nnon-overlapping field). Legacy keys were dropped from persisted blobs by\nthe 2026-07-26 tokens_info migration; per-model usage lives on\n`execution.model_usage` (CC's modelUsage, verbatim).",
@@ -10223,7 +10419,7 @@
10223
10419
  "description": "A replacement definition for an automation managed through the API.",
10224
10420
  "properties": {
10225
10421
  "automation": {
10226
- "$ref": "#/components/schemas/AgentConfig",
10422
+ "$ref": "#/components/schemas/AutomationConfig",
10227
10423
  "description": "The automation's new definition. Replaces the previous one wholesale \u2014 this is not a partial update."
10228
10424
  }
10229
10425
  },
@@ -10237,7 +10433,7 @@
10237
10433
  "description": "A replacement definition for an environment managed through the API.",
10238
10434
  "properties": {
10239
10435
  "environment": {
10240
- "$ref": "#/components/schemas/EnvironmentConfig",
10436
+ "$ref": "#/components/schemas/EnvironmentDocument",
10241
10437
  "description": "The environment's new definition. Replaces the previous one wholesale \u2014 this is not a partial update."
10242
10438
  }
10243
10439
  },
@@ -12171,6 +12367,101 @@
12171
12367
  "x-ellipsis-sdk-method": "automations.link"
12172
12368
  }
12173
12369
  },
12370
+ "/v1/automations/{automation_id}/metrics": {
12371
+ "get": {
12372
+ "description": "Return an automation's session distribution and trailing spend,\nby id or by name.\n\n`samples` carries one entry per finished session (duration, cost,\ntokens) for distributions; `spend_windows` carries what the\nautomation's sessions cost over the last 1, 7, and 28 days against\nits budget for each window.",
12373
+ "operationId": "get_automation_metrics",
12374
+ "parameters": [
12375
+ {
12376
+ "in": "path",
12377
+ "name": "automation_id",
12378
+ "required": true,
12379
+ "schema": {
12380
+ "title": "Automation Id",
12381
+ "type": "string"
12382
+ }
12383
+ },
12384
+ {
12385
+ "in": "header",
12386
+ "name": "user-agent",
12387
+ "required": false,
12388
+ "schema": {
12389
+ "anyOf": [
12390
+ {
12391
+ "type": "string"
12392
+ },
12393
+ {
12394
+ "type": "null"
12395
+ }
12396
+ ],
12397
+ "title": "User-Agent"
12398
+ }
12399
+ }
12400
+ ],
12401
+ "responses": {
12402
+ "200": {
12403
+ "content": {
12404
+ "application/json": {
12405
+ "schema": {
12406
+ "$ref": "#/components/schemas/AutomationMetricsResponse"
12407
+ }
12408
+ }
12409
+ },
12410
+ "description": "Successful Response"
12411
+ },
12412
+ "401": {
12413
+ "content": {
12414
+ "application/json": {
12415
+ "schema": {
12416
+ "$ref": "#/components/schemas/ErrorResponse"
12417
+ }
12418
+ }
12419
+ },
12420
+ "description": "The bearer token is missing, invalid, or revoked."
12421
+ },
12422
+ "403": {
12423
+ "content": {
12424
+ "application/json": {
12425
+ "schema": {
12426
+ "$ref": "#/components/schemas/ErrorResponse"
12427
+ }
12428
+ }
12429
+ },
12430
+ "description": "The credential may not perform this action, or the account is blocked."
12431
+ },
12432
+ "404": {
12433
+ "content": {
12434
+ "application/json": {
12435
+ "schema": {
12436
+ "$ref": "#/components/schemas/ErrorResponse"
12437
+ }
12438
+ }
12439
+ },
12440
+ "description": "No such automation in your account."
12441
+ },
12442
+ "422": {
12443
+ "content": {
12444
+ "application/json": {
12445
+ "schema": {
12446
+ "$ref": "#/components/schemas/HTTPValidationError"
12447
+ }
12448
+ }
12449
+ },
12450
+ "description": "Validation Error"
12451
+ }
12452
+ },
12453
+ "security": [
12454
+ {
12455
+ "HTTPBearer": []
12456
+ }
12457
+ ],
12458
+ "summary": "Get Automation Metrics",
12459
+ "tags": [
12460
+ "v1"
12461
+ ],
12462
+ "x-ellipsis-sdk-method": "automations.metrics"
12463
+ }
12464
+ },
12174
12465
  "/v1/automations/{automation_id}/sessions": {
12175
12466
  "post": {
12176
12467
  "description": "Invoke an automation.\n\nRuns the automation exactly as defined \u2014 its persona, model,\nenvironment, permissions, skills, and budget bind \u2014 and returns\nthe session it started. The body carries only what a caller may\nsupply: the typed `input` its schema demands, an optional tighter\n`budget`, and `metadata`. For a different persona or environment,\nstart a raw session with POST /v1/sessions instead.",
@@ -14597,71 +14888,52 @@
14597
14888
  },
14598
14889
  "/v1/reviews": {
14599
14890
  "get": {
14600
- "description": "List code reviews, newest first.\n\n`findings` is omitted (counters only).\n\nWebhook-created reviews appear here too, so this answers \"show\nme every review on this PR\".",
14891
+ "description": "List code reviews, newest first.\n\n`findings` and `configuration` are omitted (counters only). Each\nfilter is a set: repeat `repository`, `pull_request_number`, or\n`status` to match any of several values.\n\nWebhook-created reviews appear here too, so this answers \"show\nme every review on this PR\".",
14601
14892
  "operationId": "list_reviews",
14602
14893
  "parameters": [
14603
14894
  {
14895
+ "description": "Only reviews on these repositories, each as owner/name. Repeat the parameter for several.",
14604
14896
  "in": "query",
14605
- "name": "owner",
14606
- "required": false,
14607
- "schema": {
14608
- "anyOf": [
14609
- {
14610
- "type": "string"
14611
- },
14612
- {
14613
- "type": "null"
14614
- }
14615
- ],
14616
- "title": "Owner"
14617
- }
14618
- },
14619
- {
14620
- "in": "query",
14621
- "name": "repo",
14897
+ "name": "repository",
14622
14898
  "required": false,
14623
14899
  "schema": {
14624
- "anyOf": [
14625
- {
14626
- "type": "string"
14627
- },
14628
- {
14629
- "type": "null"
14630
- }
14631
- ],
14632
- "title": "Repo"
14900
+ "default": [],
14901
+ "description": "Only reviews on these repositories, each as owner/name. Repeat the parameter for several.",
14902
+ "items": {
14903
+ "type": "string"
14904
+ },
14905
+ "title": "Repository",
14906
+ "type": "array"
14633
14907
  }
14634
14908
  },
14635
14909
  {
14910
+ "description": "Only reviews on these pull request numbers. Repeat the parameter for several.",
14636
14911
  "in": "query",
14637
14912
  "name": "pull_request_number",
14638
14913
  "required": false,
14639
14914
  "schema": {
14640
- "anyOf": [
14641
- {
14642
- "type": "integer"
14643
- },
14644
- {
14645
- "type": "null"
14646
- }
14647
- ],
14648
- "title": "Pull Request Number"
14915
+ "default": [],
14916
+ "description": "Only reviews on these pull request numbers. Repeat the parameter for several.",
14917
+ "items": {
14918
+ "type": "integer"
14919
+ },
14920
+ "title": "Pull Request Number",
14921
+ "type": "array"
14649
14922
  }
14650
14923
  },
14651
14924
  {
14925
+ "description": "Only reviews in these statuses. Repeat the parameter for several.",
14652
14926
  "in": "query",
14653
14927
  "name": "status",
14654
14928
  "required": false,
14655
14929
  "schema": {
14656
- "anyOf": [
14657
- {
14658
- "$ref": "#/components/schemas/CodeReviewRunStatus"
14659
- },
14660
- {
14661
- "type": "null"
14662
- }
14663
- ],
14664
- "title": "Status"
14930
+ "default": [],
14931
+ "description": "Only reviews in these statuses. Repeat the parameter for several.",
14932
+ "items": {
14933
+ "$ref": "#/components/schemas/CodeReviewRunStatus"
14934
+ },
14935
+ "title": "Status",
14936
+ "type": "array"
14665
14937
  }
14666
14938
  },
14667
14939
  {
@@ -14728,7 +15000,7 @@
14728
15000
  }
14729
15001
  }
14730
15002
  },
14731
- "description": "Filtering by repository requires both owner and repo (and pull_request_number requires them too)."
15003
+ "description": "A `repository` value is not of the form owner/name."
14732
15004
  },
14733
15005
  "401": {
14734
15006
  "content": {
@@ -14758,7 +15030,7 @@
14758
15030
  }
14759
15031
  }
14760
15032
  },
14761
- "description": "The repository was not found in your account."
15033
+ "description": "A `repository` was not found in your account."
14762
15034
  },
14763
15035
  "422": {
14764
15036
  "content": {
@@ -14783,7 +15055,7 @@
14783
15055
  "x-ellipsis-sdk-method": "reviews.list"
14784
15056
  },
14785
15057
  "post": {
14786
- "description": "Run a code review on demand.\n\nReviews an existing PR or a pushed branch (for a branch, the\nplatform finds or creates a draft PR for it, since a code\nreview is structurally about a PR).\n\nA review is one pipeline run over one commit range, with one\nagent session per stage: `review.id` is the run id, and\n`stages[].session_id` is where a client streams\n(/sessions/{id}/stream on a stage session), since the review\nitself is a pipeline rather than one process.",
15058
+ "description": "Run a code review on demand.\n\nReviews an open pull request. Which pipeline runs is not a\nparameter: it resolves from the repository's files exactly as\nit does for a push, so an on-demand review never disagrees with\nthe automatic one.\n\nA review is one pipeline run over one commit range, with one\nagent session per stage: `review.id` is the run id, and\n`stages[].session_id` is where a client streams\n(/sessions/{id}/stream on a stage session), since the review\nitself is a pipeline rather than one process.",
14787
15059
  "operationId": "create_review",
14788
15060
  "parameters": [
14789
15061
  {
@@ -15479,7 +15751,7 @@
15479
15751
  "x-ellipsis-sdk-method": "sessions.list"
15480
15752
  },
15481
15753
  "post": {
15482
- "description": "Start a cloud agent session.\n\nThe daily driver: a prompt, optionally where to run it\n(`environment`) and the run's own settings, in the AgentConfig\nvocabulary. Anything omitted comes from the organization's\nsettings \u2014 default model, default environment, budget \u2014 so\n`{\"prompt\": \"...\"}` alone is a complete request. `prompt` is the\nfirst message; omit it and the session starts idle, waiting for\none. 400 when `interactive` is false and there is no prompt, or\nwhen `budget` exceeds the organization's per-session ceiling. To\nrun a saved automation, use POST /v1/automations/{automation_id}/sessions.",
15754
+ "description": "Start a cloud agent session.\n\nThe daily driver: a prompt, optionally where to run it\n(`environment`) and the run's own settings, in the AutomationConfig\nvocabulary. Anything omitted comes from the organization's\nsettings \u2014 default model, default environment, budget \u2014 so\n`{\"prompt\": \"...\"}` alone is a complete request. `prompt` is the\nfirst message; omit it and the session starts idle, waiting for\none. 400 when `interactive` is false and there is no prompt, or\nwhen `budget` exceeds the organization's per-session ceiling. To\nrun a saved automation, use POST /v1/automations/{automation_id}/sessions.",
15483
15755
  "operationId": "start_agent_session",
15484
15756
  "parameters": [
15485
15757
  {
@@ -15678,6 +15950,101 @@
15678
15950
  "x-ellipsis-sdk-method": "sessions.get"
15679
15951
  }
15680
15952
  },
15953
+ "/v1/sessions/{session_id}/diff": {
15954
+ "get": {
15955
+ "description": "Return the session's uncommitted changes as a patch.\n\nOne unified-diff section per changed file, captured from the\nsandbox's working tree when the session ended. The per-file\ncounts ride on the session itself (`git.repos[].files`); this\nis the text behind them. Empty when the tree was clean. A\nsandbox token may read only its own session's diff.",
15956
+ "operationId": "get_agent_session_diff",
15957
+ "parameters": [
15958
+ {
15959
+ "in": "path",
15960
+ "name": "session_id",
15961
+ "required": true,
15962
+ "schema": {
15963
+ "title": "Session Id",
15964
+ "type": "string"
15965
+ }
15966
+ },
15967
+ {
15968
+ "in": "header",
15969
+ "name": "user-agent",
15970
+ "required": false,
15971
+ "schema": {
15972
+ "anyOf": [
15973
+ {
15974
+ "type": "string"
15975
+ },
15976
+ {
15977
+ "type": "null"
15978
+ }
15979
+ ],
15980
+ "title": "User-Agent"
15981
+ }
15982
+ }
15983
+ ],
15984
+ "responses": {
15985
+ "200": {
15986
+ "content": {
15987
+ "application/json": {
15988
+ "schema": {
15989
+ "$ref": "#/components/schemas/SessionDiffResponse"
15990
+ }
15991
+ }
15992
+ },
15993
+ "description": "Successful Response"
15994
+ },
15995
+ "401": {
15996
+ "content": {
15997
+ "application/json": {
15998
+ "schema": {
15999
+ "$ref": "#/components/schemas/ErrorResponse"
16000
+ }
16001
+ }
16002
+ },
16003
+ "description": "The bearer token is missing, invalid, or revoked."
16004
+ },
16005
+ "403": {
16006
+ "content": {
16007
+ "application/json": {
16008
+ "schema": {
16009
+ "$ref": "#/components/schemas/ErrorResponse"
16010
+ }
16011
+ }
16012
+ },
16013
+ "description": "The credential may not perform this action, or the account is blocked."
16014
+ },
16015
+ "404": {
16016
+ "content": {
16017
+ "application/json": {
16018
+ "schema": {
16019
+ "$ref": "#/components/schemas/ErrorResponse"
16020
+ }
16021
+ }
16022
+ },
16023
+ "description": "No such session in your account."
16024
+ },
16025
+ "422": {
16026
+ "content": {
16027
+ "application/json": {
16028
+ "schema": {
16029
+ "$ref": "#/components/schemas/HTTPValidationError"
16030
+ }
16031
+ }
16032
+ },
16033
+ "description": "Validation Error"
16034
+ }
16035
+ },
16036
+ "security": [
16037
+ {
16038
+ "HTTPBearer": []
16039
+ }
16040
+ ],
16041
+ "summary": "Get Agent Session Diff",
16042
+ "tags": [
16043
+ "v1"
16044
+ ],
16045
+ "x-ellipsis-sdk-method": "sessions.diff"
16046
+ }
16047
+ },
15681
16048
  "/v1/sessions/{session_id}/export": {
15682
16049
  "get": {
15683
16050
  "description": "Export the complete session history.\n\nThe complete, ordered history of the session (agent output, tool calls, thinking,\nlifecycle events, sandbox output, message events) as an ordered\nmanifest of presigned segment URLs.\n\nSegments are gzip members: download in order and concatenate\nfor one file. The JSON API never carries the bytes (same\ntwo-step as files). /records is the paged live view of the\nsame data.",