@ellipsis-dev/sdk 0.22.0 → 0.27.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,41 +1,21 @@
1
1
  {
2
2
  "$defs": {
3
- "AgentConfig": {
3
+ "AttributionType": {
4
+ "enum": [
5
+ "github_user",
6
+ "linear_user",
7
+ "slack_user",
8
+ "api_key"
9
+ ],
10
+ "title": "AttributionType",
11
+ "type": "string"
12
+ },
13
+ "AutomationConfig": {
4
14
  "additionalProperties": false,
15
+ "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.",
5
16
  "properties": {
6
- "budget": {
7
- "$ref": "#/$defs/AgentConfigBudget",
8
- "default": {
9
- "day": null,
10
- "month": null,
11
- "session": null,
12
- "week": null
13
- }
14
- },
15
- "claude": {
16
- "$ref": "#/$defs/AgentConfigClaude",
17
- "default": {
18
- "effort": null,
19
- "fallback_model": null,
20
- "max_turns": null,
21
- "model": null,
22
- "settings": null,
23
- "system": ""
24
- }
25
- },
26
- "codex": {
27
- "anyOf": [
28
- {
29
- "$ref": "#/$defs/AgentConfigCodex"
30
- },
31
- {
32
- "type": "null"
33
- }
34
- ],
35
- "default": null
36
- },
37
17
  "ellipsis": {
38
- "$ref": "#/$defs/AgentConfigEllipsis",
18
+ "$ref": "#/$defs/AutomationIdentity",
39
19
  "default": {
40
20
  "description": null,
41
21
  "enabled": true,
@@ -47,50 +27,10 @@
47
27
  "version": "v1"
48
28
  }
49
29
  },
50
- "environment": {
51
- "anyOf": [
52
- {
53
- "type": "string"
54
- },
55
- {
56
- "$ref": "#/$defs/AgentConfigEnvironment"
57
- }
58
- ],
59
- "default": {
60
- "compute": {
61
- "cpu": null,
62
- "memory": null,
63
- "timeout": null
64
- },
65
- "hooks": {
66
- "post_clone": null,
67
- "post_start": null
68
- },
69
- "image": {
70
- "dockerfile_append": null,
71
- "setup": null
72
- },
73
- "mcp_servers": [],
74
- "repositories": [],
75
- "variables": []
76
- },
77
- "title": "Environment"
78
- },
79
30
  "input": {
80
31
  "anyOf": [
81
32
  {
82
- "$ref": "#/$defs/AgentConfigInput"
83
- },
84
- {
85
- "type": "null"
86
- }
87
- ],
88
- "default": null
89
- },
90
- "output": {
91
- "anyOf": [
92
- {
93
- "$ref": "#/$defs/AgentConfigOutput"
33
+ "$ref": "#/$defs/InputContract"
94
34
  },
95
35
  {
96
36
  "type": "null"
@@ -98,44 +38,69 @@
98
38
  ],
99
39
  "default": null
100
40
  },
101
- "permissions": {
102
- "$ref": "#/$defs/AgentConfigPermissions",
41
+ "session": {
42
+ "$ref": "#/$defs/SessionConfig",
103
43
  "default": {
104
- "ellipsis": true,
105
- "github": {
106
- "permissions": null,
107
- "repositories": null
108
- }
44
+ "budget": {
45
+ "day": null,
46
+ "month": null,
47
+ "session": null,
48
+ "week": null
49
+ },
50
+ "claude": {
51
+ "effort": null,
52
+ "fallback_model": null,
53
+ "max_turns": null,
54
+ "model": null,
55
+ "settings": null,
56
+ "system": ""
57
+ },
58
+ "codex": null,
59
+ "environment": {
60
+ "compute": {
61
+ "cpu": null,
62
+ "memory": null,
63
+ "timeout": null
64
+ },
65
+ "hooks": {
66
+ "post_clone": null,
67
+ "post_start": null
68
+ },
69
+ "image": {
70
+ "dockerfile_append": null,
71
+ "setup": null
72
+ },
73
+ "mcp_servers": [],
74
+ "repositories": [],
75
+ "variables": []
76
+ },
77
+ "output": null,
78
+ "permissions": {
79
+ "ellipsis": true,
80
+ "github": {
81
+ "permissions": null,
82
+ "repositories": null
83
+ }
84
+ },
85
+ "skills": []
109
86
  }
110
87
  },
111
- "skills": {
112
- "default": [],
113
- "items": {
114
- "$ref": "#/$defs/AgentConfigSkill"
115
- },
116
- "title": "Skills",
117
- "type": "array"
118
- },
119
88
  "trigger": {
120
89
  "anyOf": [
121
90
  {
122
91
  "discriminator": {
123
92
  "mapping": {
124
- "cron": "#/$defs/AgentConfigCronTrigger",
125
- "mention": "#/$defs/AgentConfigMentionTrigger",
126
- "react": "#/$defs/AgentConfigReactTrigger"
93
+ "cron": "#/$defs/CronTrigger",
94
+ "react": "#/$defs/ReactTrigger"
127
95
  },
128
96
  "propertyName": "type"
129
97
  },
130
98
  "oneOf": [
131
99
  {
132
- "$ref": "#/$defs/AgentConfigCronTrigger"
133
- },
134
- {
135
- "$ref": "#/$defs/AgentConfigReactTrigger"
100
+ "$ref": "#/$defs/CronTrigger"
136
101
  },
137
102
  {
138
- "$ref": "#/$defs/AgentConfigMentionTrigger"
103
+ "$ref": "#/$defs/ReactTrigger"
139
104
  }
140
105
  ]
141
106
  },
@@ -148,21 +113,71 @@
148
113
  }
149
114
  },
150
115
  "required": [
151
- "budget",
152
- "claude",
153
- "codex",
154
116
  "ellipsis",
155
- "environment",
156
117
  "input",
157
- "output",
158
- "permissions",
159
- "skills",
118
+ "session",
160
119
  "trigger"
161
120
  ],
162
- "title": "AgentConfig",
121
+ "title": "AutomationConfig",
122
+ "type": "object"
123
+ },
124
+ "AutomationIdentity": {
125
+ "additionalProperties": false,
126
+ "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.",
127
+ "properties": {
128
+ "description": {
129
+ "anyOf": [
130
+ {
131
+ "type": "string"
132
+ },
133
+ {
134
+ "type": "null"
135
+ }
136
+ ],
137
+ "default": null,
138
+ "title": "Description"
139
+ },
140
+ "enabled": {
141
+ "default": true,
142
+ "title": "Enabled",
143
+ "type": "boolean"
144
+ },
145
+ "metadata": {
146
+ "$ref": "#/$defs/ConfigMetadata",
147
+ "default": {
148
+ "annotations": {},
149
+ "labels": []
150
+ }
151
+ },
152
+ "name": {
153
+ "anyOf": [
154
+ {
155
+ "type": "string"
156
+ },
157
+ {
158
+ "type": "null"
159
+ }
160
+ ],
161
+ "default": null,
162
+ "title": "Name"
163
+ },
164
+ "version": {
165
+ "default": "v1",
166
+ "title": "Version",
167
+ "type": "string"
168
+ }
169
+ },
170
+ "required": [
171
+ "description",
172
+ "enabled",
173
+ "metadata",
174
+ "name",
175
+ "version"
176
+ ],
177
+ "title": "AutomationIdentity",
163
178
  "type": "object"
164
179
  },
165
- "AgentConfigBudget": {
180
+ "BudgetConfig": {
166
181
  "additionalProperties": false,
167
182
  "properties": {
168
183
  "day": {
@@ -220,10 +235,21 @@
220
235
  "session",
221
236
  "week"
222
237
  ],
223
- "title": "AgentConfigBudget",
238
+ "title": "BudgetConfig",
224
239
  "type": "object"
225
240
  },
226
- "AgentConfigClaude": {
241
+ "BudgetSource": {
242
+ "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.",
243
+ "enum": [
244
+ "system",
245
+ "account",
246
+ "config",
247
+ "run"
248
+ ],
249
+ "title": "BudgetSource",
250
+ "type": "string"
251
+ },
252
+ "ClaudeConfig": {
227
253
  "additionalProperties": false,
228
254
  "properties": {
229
255
  "effort": {
@@ -277,7 +303,7 @@
277
303
  "settings": {
278
304
  "anyOf": [
279
305
  {
280
- "$ref": "#/$defs/AgentConfigSettingsRef"
306
+ "$ref": "#/$defs/SettingsRef"
281
307
  },
282
308
  {
283
309
  "type": "null"
@@ -291,7 +317,7 @@
291
317
  "type": "string"
292
318
  },
293
319
  {
294
- "$ref": "#/$defs/AgentConfigSystemFileRef"
320
+ "$ref": "#/$defs/SystemFileRef"
295
321
  },
296
322
  {
297
323
  "items": {
@@ -300,7 +326,7 @@
300
326
  "type": "string"
301
327
  },
302
328
  {
303
- "$ref": "#/$defs/AgentConfigSystemFileRef"
329
+ "$ref": "#/$defs/SystemFileRef"
304
330
  }
305
331
  ]
306
332
  },
@@ -319,1060 +345,68 @@
319
345
  "settings",
320
346
  "system"
321
347
  ],
322
- "title": "AgentConfigClaude",
348
+ "title": "ClaudeConfig",
323
349
  "type": "object"
324
350
  },
325
- "AgentConfigCodex": {
326
- "additionalProperties": false,
327
- "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.",
351
+ "ClaudeSessionRecord": {
352
+ "description": "A native transcript record of a Claude session (source=claude_code).",
328
353
  "properties": {
329
- "model": {
330
- "default": "gpt-5.6-terra",
331
- "title": "Model",
332
- "type": "string"
333
- },
334
- "system": {
354
+ "agent_turn_id": {
335
355
  "anyOf": [
336
356
  {
337
357
  "type": "string"
338
358
  },
339
359
  {
340
- "$ref": "#/$defs/AgentConfigSystemFileRef"
341
- },
342
- {
343
- "items": {
344
- "anyOf": [
345
- {
346
- "type": "string"
347
- },
348
- {
349
- "$ref": "#/$defs/AgentConfigSystemFileRef"
350
- }
351
- ]
352
- },
353
- "type": "array"
360
+ "type": "null"
354
361
  }
355
362
  ],
356
- "default": "",
357
- "title": "System"
358
- }
359
- },
360
- "required": [
361
- "model",
362
- "system"
363
- ],
364
- "title": "AgentConfigCodex",
365
- "type": "object"
366
- },
367
- "AgentConfigCompute": {
368
- "additionalProperties": false,
369
- "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.",
370
- "properties": {
371
- "cpu": {
363
+ "default": null,
364
+ "description": "Identifier of the turn the record belongs to, if any.",
365
+ "title": "Agent Turn Id"
366
+ },
367
+ "cost": {
372
368
  "anyOf": [
373
369
  {
374
- "maximum": 16,
375
- "minimum": 0.125,
376
- "type": "number"
370
+ "type": "integer"
377
371
  },
378
372
  {
379
373
  "type": "null"
380
374
  }
381
375
  ],
382
376
  "default": null,
383
- "title": "Cpu"
377
+ "description": "Cost attributed to this record, if any.",
378
+ "title": "Cost"
384
379
  },
385
- "memory": {
380
+ "created_at": {
381
+ "description": "When the record was created.",
382
+ "format": "date-time",
383
+ "title": "Created At",
384
+ "type": "string"
385
+ },
386
+ "duration": {
386
387
  "anyOf": [
387
388
  {
388
- "type": "string"
389
- },
390
- {
391
- "$ref": "#/$defs/AgentConfigMemorySize"
389
+ "type": "integer"
392
390
  },
393
391
  {
394
392
  "type": "null"
395
393
  }
396
394
  ],
397
395
  "default": null,
398
- "title": "Memory"
396
+ "description": "Duration attributed to this record, if any.",
397
+ "title": "Duration"
399
398
  },
400
- "timeout": {
401
- "anyOf": [
402
- {
403
- "type": "string"
404
- },
405
- {
406
- "$ref": "#/$defs/AgentConfigDuration"
407
- },
408
- {
409
- "type": "null"
410
- }
411
- ],
412
- "default": null,
413
- "title": "Timeout"
414
- }
415
- },
416
- "required": [
417
- "cpu",
418
- "memory",
419
- "timeout"
420
- ],
421
- "title": "AgentConfigCompute",
422
- "type": "object"
423
- },
424
- "AgentConfigCronTrigger": {
425
- "additionalProperties": false,
426
- "properties": {
427
- "schedule": {
428
- "title": "Schedule",
429
- "type": "string"
430
- },
431
- "type": {
432
- "const": "cron",
433
- "default": "cron",
434
- "title": "Type",
435
- "type": "string"
436
- }
437
- },
438
- "required": [
439
- "schedule",
440
- "type"
441
- ],
442
- "title": "AgentConfigCronTrigger",
443
- "type": "object"
444
- },
445
- "AgentConfigDuration": {
446
- "additionalProperties": false,
447
- "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.",
448
- "properties": {
449
- "hours": {
450
- "anyOf": [
451
- {
452
- "minimum": 0,
453
- "type": "integer"
454
- },
455
- {
456
- "type": "null"
457
- }
458
- ],
459
- "default": null,
460
- "title": "Hours"
461
- },
462
- "minutes": {
463
- "anyOf": [
464
- {
465
- "minimum": 0,
466
- "type": "integer"
467
- },
468
- {
469
- "type": "null"
470
- }
471
- ],
472
- "default": null,
473
- "title": "Minutes"
474
- },
475
- "seconds": {
476
- "anyOf": [
477
- {
478
- "minimum": 0,
479
- "type": "integer"
480
- },
481
- {
482
- "type": "null"
483
- }
484
- ],
485
- "default": null,
486
- "title": "Seconds"
487
- }
488
- },
489
- "required": [
490
- "hours",
491
- "minutes",
492
- "seconds"
493
- ],
494
- "title": "AgentConfigDuration",
495
- "type": "object"
496
- },
497
- "AgentConfigEllipsis": {
498
- "additionalProperties": false,
499
- "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.",
500
- "properties": {
501
- "description": {
502
- "anyOf": [
503
- {
504
- "type": "string"
505
- },
506
- {
507
- "type": "null"
508
- }
509
- ],
510
- "default": null,
511
- "title": "Description"
512
- },
513
- "enabled": {
514
- "default": true,
515
- "title": "Enabled",
516
- "type": "boolean"
517
- },
518
- "metadata": {
519
- "$ref": "#/$defs/AgentConfigMetadata",
520
- "default": {
521
- "annotations": {},
522
- "labels": []
523
- }
524
- },
525
- "name": {
526
- "anyOf": [
527
- {
528
- "type": "string"
529
- },
530
- {
531
- "type": "null"
532
- }
533
- ],
534
- "default": null,
535
- "title": "Name"
536
- },
537
- "version": {
538
- "default": "v1",
539
- "title": "Version",
540
- "type": "string"
541
- }
542
- },
543
- "required": [
544
- "description",
545
- "enabled",
546
- "metadata",
547
- "name",
548
- "version"
549
- ],
550
- "title": "AgentConfigEllipsis",
551
- "type": "object"
552
- },
553
- "AgentConfigEllipsisPermissions": {
554
- "additionalProperties": {
555
- "anyOf": [
556
- {
557
- "$ref": "#/$defs/Level"
558
- },
559
- {
560
- "$ref": "#/$defs/EllipsisGrant"
561
- },
562
- {
563
- "items": {
564
- "anyOf": [
565
- {
566
- "$ref": "#/$defs/Level"
567
- },
568
- {
569
- "$ref": "#/$defs/EllipsisGrant"
570
- }
571
- ]
572
- },
573
- "type": "array"
574
- }
575
- ]
576
- },
577
- "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.",
578
- "propertyNames": {
579
- "$ref": "#/$defs/Resource"
580
- },
581
- "title": "AgentConfigEllipsisPermissions",
582
- "type": "object"
583
- },
584
- "AgentConfigEnvironment": {
585
- "additionalProperties": false,
586
- "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.",
587
- "properties": {
588
- "compute": {
589
- "$ref": "#/$defs/AgentConfigCompute",
590
- "default": {
591
- "cpu": null,
592
- "memory": null,
593
- "timeout": null
594
- }
595
- },
596
- "hooks": {
597
- "$ref": "#/$defs/AgentConfigEnvironmentHooks",
598
- "default": {
599
- "post_clone": null,
600
- "post_start": null
601
- }
602
- },
603
- "image": {
604
- "$ref": "#/$defs/AgentConfigEnvironmentImage",
605
- "default": {
606
- "dockerfile_append": null,
607
- "setup": null
608
- }
609
- },
610
- "mcp_servers": {
611
- "default": [],
612
- "items": {
613
- "anyOf": [
614
- {
615
- "type": "string"
616
- },
617
- {
618
- "$ref": "#/$defs/AgentConfigMcpServer"
619
- },
620
- {
621
- "$ref": "#/$defs/AgentConfigMcpStdioServer"
622
- },
623
- {
624
- "$ref": "#/$defs/AgentConfigMcpRemoteServer"
625
- }
626
- ]
627
- },
628
- "title": "Mcp Servers",
629
- "type": "array"
630
- },
631
- "repositories": {
632
- "default": [],
633
- "items": {
634
- "$ref": "#/$defs/AgentConfigRepository"
635
- },
636
- "title": "Repositories",
637
- "type": "array"
638
- },
639
- "variables": {
640
- "default": [],
641
- "items": {
642
- "$ref": "#/$defs/AgentConfigEnvironmentVariable"
643
- },
644
- "title": "Variables",
645
- "type": "array"
646
- }
647
- },
648
- "required": [
649
- "compute",
650
- "hooks",
651
- "image",
652
- "mcp_servers",
653
- "repositories",
654
- "variables"
655
- ],
656
- "title": "AgentConfigEnvironment",
657
- "type": "object"
658
- },
659
- "AgentConfigEnvironmentHooks": {
660
- "additionalProperties": false,
661
- "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.",
662
- "properties": {
663
- "post_clone": {
664
- "anyOf": [
665
- {
666
- "type": "string"
667
- },
668
- {
669
- "type": "null"
670
- }
671
- ],
672
- "default": null,
673
- "title": "Post Clone"
674
- },
675
- "post_start": {
676
- "anyOf": [
677
- {
678
- "type": "string"
679
- },
680
- {
681
- "type": "null"
682
- }
683
- ],
684
- "default": null,
685
- "title": "Post Start"
686
- }
687
- },
688
- "required": [
689
- "post_clone",
690
- "post_start"
691
- ],
692
- "title": "AgentConfigEnvironmentHooks",
693
- "type": "object"
694
- },
695
- "AgentConfigEnvironmentImage": {
696
- "additionalProperties": false,
697
- "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`.",
698
- "properties": {
699
- "dockerfile_append": {
700
- "anyOf": [
701
- {
702
- "type": "string"
703
- },
704
- {
705
- "type": "null"
706
- }
707
- ],
708
- "default": null,
709
- "title": "Dockerfile Append"
710
- },
711
- "setup": {
712
- "anyOf": [
713
- {
714
- "type": "string"
715
- },
716
- {
717
- "type": "null"
718
- }
719
- ],
720
- "default": null,
721
- "title": "Setup"
722
- }
723
- },
724
- "required": [
725
- "dockerfile_append",
726
- "setup"
727
- ],
728
- "title": "AgentConfigEnvironmentImage",
729
- "type": "object"
730
- },
731
- "AgentConfigEnvironmentVariable": {
732
- "additionalProperties": false,
733
- "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.",
734
- "properties": {
735
- "name": {
736
- "title": "Name",
737
- "type": "string"
738
- },
739
- "value": {
740
- "anyOf": [
741
- {
742
- "type": "string"
743
- },
744
- {
745
- "type": "null"
746
- }
747
- ],
748
- "default": null,
749
- "title": "Value"
750
- }
751
- },
752
- "required": [
753
- "name",
754
- "value"
755
- ],
756
- "title": "AgentConfigEnvironmentVariable",
757
- "type": "object"
758
- },
759
- "AgentConfigGithubPermissions": {
760
- "additionalProperties": false,
761
- "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.",
762
- "properties": {
763
- "permissions": {
764
- "anyOf": [
765
- {
766
- "const": "read_only",
767
- "type": "string"
768
- },
769
- {
770
- "additionalProperties": {
771
- "type": "string"
772
- },
773
- "type": "object"
774
- },
775
- {
776
- "type": "null"
777
- }
778
- ],
779
- "default": null,
780
- "title": "Permissions"
781
- },
782
- "repositories": {
783
- "anyOf": [
784
- {
785
- "items": {
786
- "type": "string"
787
- },
788
- "type": "array"
789
- },
790
- {
791
- "type": "null"
792
- }
793
- ],
794
- "default": null,
795
- "title": "Repositories"
796
- }
797
- },
798
- "required": [
799
- "permissions",
800
- "repositories"
801
- ],
802
- "title": "AgentConfigGithubPermissions",
803
- "type": "object"
804
- },
805
- "AgentConfigInput": {
806
- "additionalProperties": false,
807
- "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`).",
808
- "properties": {
809
- "json_schema": {
810
- "anyOf": [
811
- {
812
- "additionalProperties": true,
813
- "type": "object"
814
- },
815
- {
816
- "type": "null"
817
- }
818
- ],
819
- "default": null,
820
- "title": "Json Schema"
821
- },
822
- "message": {
823
- "anyOf": [
824
- {
825
- "type": "string"
826
- },
827
- {
828
- "type": "null"
829
- }
830
- ],
831
- "default": null,
832
- "title": "Message"
833
- }
834
- },
835
- "required": [
836
- "json_schema",
837
- "message"
838
- ],
839
- "title": "AgentConfigInput",
840
- "type": "object"
841
- },
842
- "AgentConfigMcpRemoteServer": {
843
- "additionalProperties": false,
844
- "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.",
845
- "properties": {
846
- "headers": {
847
- "additionalProperties": {
848
- "type": "string"
849
- },
850
- "default": {},
851
- "title": "Headers",
852
- "type": "object"
853
- },
854
- "name": {
855
- "title": "Name",
856
- "type": "string"
857
- },
858
- "url": {
859
- "title": "Url",
860
- "type": "string"
861
- }
862
- },
863
- "required": [
864
- "headers",
865
- "name",
866
- "url"
867
- ],
868
- "title": "AgentConfigMcpRemoteServer",
869
- "type": "object"
870
- },
871
- "AgentConfigMcpServer": {
872
- "additionalProperties": false,
873
- "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`).",
874
- "properties": {
875
- "name": {
876
- "title": "Name",
877
- "type": "string"
878
- }
879
- },
880
- "required": [
881
- "name"
882
- ],
883
- "title": "AgentConfigMcpServer",
884
- "type": "object"
885
- },
886
- "AgentConfigMcpStdioServer": {
887
- "additionalProperties": false,
888
- "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.",
889
- "properties": {
890
- "args": {
891
- "default": [],
892
- "items": {
893
- "type": "string"
894
- },
895
- "title": "Args",
896
- "type": "array"
897
- },
898
- "command": {
899
- "title": "Command",
900
- "type": "string"
901
- },
902
- "env": {
903
- "additionalProperties": {
904
- "type": "string"
905
- },
906
- "default": {},
907
- "title": "Env",
908
- "type": "object"
909
- },
910
- "name": {
911
- "title": "Name",
912
- "type": "string"
913
- }
914
- },
915
- "required": [
916
- "args",
917
- "command",
918
- "env",
919
- "name"
920
- ],
921
- "title": "AgentConfigMcpStdioServer",
922
- "type": "object"
923
- },
924
- "AgentConfigMemorySize": {
925
- "additionalProperties": false,
926
- "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.",
927
- "properties": {
928
- "gb": {
929
- "anyOf": [
930
- {
931
- "minimum": 0,
932
- "type": "integer"
933
- },
934
- {
935
- "type": "null"
936
- }
937
- ],
938
- "default": null,
939
- "title": "Gb"
940
- },
941
- "mb": {
942
- "anyOf": [
943
- {
944
- "minimum": 0,
945
- "type": "integer"
946
- },
947
- {
948
- "type": "null"
949
- }
950
- ],
951
- "default": null,
952
- "title": "Mb"
953
- }
954
- },
955
- "required": [
956
- "gb",
957
- "mb"
958
- ],
959
- "title": "AgentConfigMemorySize",
960
- "type": "object"
961
- },
962
- "AgentConfigMentionPlatform": {
963
- "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.",
964
- "enum": [
965
- "github",
966
- "linear"
967
- ],
968
- "title": "AgentConfigMentionPlatform",
969
- "type": "string"
970
- },
971
- "AgentConfigMentionTrigger": {
972
- "additionalProperties": false,
973
- "properties": {
974
- "platforms": {
975
- "default": [],
976
- "items": {
977
- "$ref": "#/$defs/AgentConfigMentionPlatform"
978
- },
979
- "title": "Platforms",
980
- "type": "array"
981
- },
982
- "type": {
983
- "const": "mention",
984
- "default": "mention",
985
- "title": "Type",
986
- "type": "string"
987
- }
988
- },
989
- "required": [
990
- "platforms",
991
- "type"
992
- ],
993
- "title": "AgentConfigMentionTrigger",
994
- "type": "object"
995
- },
996
- "AgentConfigMetadata": {
997
- "additionalProperties": false,
998
- "properties": {
999
- "annotations": {
1000
- "additionalProperties": {
1001
- "type": "string"
1002
- },
1003
- "default": {},
1004
- "title": "Annotations",
1005
- "type": "object"
1006
- },
1007
- "labels": {
1008
- "default": [],
1009
- "items": {
1010
- "type": "string"
1011
- },
1012
- "title": "Labels",
1013
- "type": "array"
1014
- }
1015
- },
1016
- "required": [
1017
- "annotations",
1018
- "labels"
1019
- ],
1020
- "title": "AgentConfigMetadata",
1021
- "type": "object"
1022
- },
1023
- "AgentConfigOutput": {
1024
- "additionalProperties": false,
1025
- "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.",
1026
- "properties": {
1027
- "json_schema": {
1028
- "additionalProperties": true,
1029
- "title": "Json Schema",
1030
- "type": "object"
1031
- }
1032
- },
1033
- "required": [
1034
- "json_schema"
1035
- ],
1036
- "title": "AgentConfigOutput",
1037
- "type": "object"
1038
- },
1039
- "AgentConfigPermissions": {
1040
- "additionalProperties": false,
1041
- "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.",
1042
- "properties": {
1043
- "ellipsis": {
1044
- "anyOf": [
1045
- {
1046
- "enum": [
1047
- true,
1048
- "all"
1049
- ]
1050
- },
1051
- {
1052
- "$ref": "#/$defs/AgentConfigEllipsisPermissions"
1053
- }
1054
- ],
1055
- "default": true,
1056
- "title": "Ellipsis"
1057
- },
1058
- "github": {
1059
- "$ref": "#/$defs/AgentConfigGithubPermissions",
1060
- "default": {
1061
- "permissions": null,
1062
- "repositories": null
1063
- }
1064
- }
1065
- },
1066
- "required": [
1067
- "ellipsis",
1068
- "github"
1069
- ],
1070
- "title": "AgentConfigPermissions",
1071
- "type": "object"
1072
- },
1073
- "AgentConfigReactTrigger": {
1074
- "additionalProperties": false,
1075
- "properties": {
1076
- "issue": {
1077
- "anyOf": [
1078
- {
1079
- "$ref": "#/$defs/ReactIssue"
1080
- },
1081
- {
1082
- "type": "null"
1083
- }
1084
- ],
1085
- "default": null
1086
- },
1087
- "linear_issue": {
1088
- "anyOf": [
1089
- {
1090
- "$ref": "#/$defs/ReactLinearIssue"
1091
- },
1092
- {
1093
- "type": "null"
1094
- }
1095
- ],
1096
- "default": null
1097
- },
1098
- "pull_request": {
1099
- "anyOf": [
1100
- {
1101
- "$ref": "#/$defs/ReactPullRequest"
1102
- },
1103
- {
1104
- "type": "null"
1105
- }
1106
- ],
1107
- "default": null
1108
- },
1109
- "push": {
1110
- "anyOf": [
1111
- {
1112
- "$ref": "#/$defs/ReactPush"
1113
- },
1114
- {
1115
- "type": "null"
1116
- }
1117
- ],
1118
- "default": null
1119
- },
1120
- "sentry": {
1121
- "anyOf": [
1122
- {
1123
- "$ref": "#/$defs/ReactSentry"
1124
- },
1125
- {
1126
- "type": "null"
1127
- }
1128
- ],
1129
- "default": null
1130
- },
1131
- "slack_channel": {
1132
- "anyOf": [
1133
- {
1134
- "$ref": "#/$defs/ReactSlackChannel"
1135
- },
1136
- {
1137
- "type": "null"
1138
- }
1139
- ],
1140
- "default": null
1141
- },
1142
- "type": {
1143
- "const": "react",
1144
- "default": "react",
1145
- "title": "Type",
1146
- "type": "string"
1147
- }
1148
- },
1149
- "required": [
1150
- "issue",
1151
- "linear_issue",
1152
- "pull_request",
1153
- "push",
1154
- "sentry",
1155
- "slack_channel",
1156
- "type"
1157
- ],
1158
- "title": "AgentConfigReactTrigger",
1159
- "type": "object"
1160
- },
1161
- "AgentConfigRepository": {
1162
- "additionalProperties": false,
1163
- "properties": {
1164
- "name": {
1165
- "title": "Name",
1166
- "type": "string"
1167
- },
1168
- "owner": {
1169
- "anyOf": [
1170
- {
1171
- "type": "string"
1172
- },
1173
- {
1174
- "type": "null"
1175
- }
1176
- ],
1177
- "default": null,
1178
- "title": "Owner"
1179
- },
1180
- "ref": {
1181
- "anyOf": [
1182
- {
1183
- "type": "string"
1184
- },
1185
- {
1186
- "type": "null"
1187
- }
1188
- ],
1189
- "default": null,
1190
- "title": "Ref"
1191
- }
1192
- },
1193
- "required": [
1194
- "name",
1195
- "owner",
1196
- "ref"
1197
- ],
1198
- "title": "AgentConfigRepository",
1199
- "type": "object"
1200
- },
1201
- "AgentConfigSettingsRef": {
1202
- "additionalProperties": false,
1203
- "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.",
1204
- "properties": {
1205
- "path": {
1206
- "title": "Path",
1207
- "type": "string"
1208
- },
1209
- "repository": {
1210
- "anyOf": [
1211
- {
1212
- "$ref": "#/$defs/AgentConfigRepository"
1213
- },
1214
- {
1215
- "type": "null"
1216
- }
1217
- ],
1218
- "default": null
1219
- }
1220
- },
1221
- "required": [
1222
- "path",
1223
- "repository"
1224
- ],
1225
- "title": "AgentConfigSettingsRef",
1226
- "type": "object"
1227
- },
1228
- "AgentConfigSkill": {
1229
- "additionalProperties": false,
1230
- "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.",
1231
- "properties": {
1232
- "path": {
1233
- "title": "Path",
1234
- "type": "string"
1235
- },
1236
- "repository": {
1237
- "anyOf": [
1238
- {
1239
- "$ref": "#/$defs/AgentConfigRepository"
1240
- },
1241
- {
1242
- "type": "null"
1243
- }
1244
- ],
1245
- "default": null
1246
- }
1247
- },
1248
- "required": [
1249
- "path",
1250
- "repository"
1251
- ],
1252
- "title": "AgentConfigSkill",
1253
- "type": "object"
1254
- },
1255
- "AgentConfigSource": {
1256
- "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.",
1257
- "enum": [
1258
- "explicit",
1259
- "inline",
1260
- "template",
1261
- "repo_default",
1262
- "account_default",
1263
- "platform_default",
1264
- "trigger",
1265
- "builtin"
1266
- ],
1267
- "title": "AgentConfigSource",
1268
- "type": "string"
1269
- },
1270
- "AgentConfigSystemFileRef": {
1271
- "additionalProperties": false,
1272
- "properties": {
1273
- "file": {
1274
- "title": "File",
1275
- "type": "string"
1276
- },
1277
- "repository": {
1278
- "anyOf": [
1279
- {
1280
- "$ref": "#/$defs/AgentConfigRepository"
1281
- },
1282
- {
1283
- "type": "null"
1284
- }
1285
- ],
1286
- "default": null
1287
- }
1288
- },
1289
- "required": [
1290
- "file",
1291
- "repository"
1292
- ],
1293
- "title": "AgentConfigSystemFileRef",
1294
- "type": "object"
1295
- },
1296
- "AttributionType": {
1297
- "enum": [
1298
- "github_user",
1299
- "linear_user",
1300
- "slack_user",
1301
- "api_key"
1302
- ],
1303
- "title": "AttributionType",
1304
- "type": "string"
1305
- },
1306
- "BudgetSource": {
1307
- "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.",
1308
- "enum": [
1309
- "system",
1310
- "account",
1311
- "config",
1312
- "run"
1313
- ],
1314
- "title": "BudgetSource",
1315
- "type": "string"
1316
- },
1317
- "ClaudeSessionRecord": {
1318
- "description": "A native transcript record of a Claude session (source=claude_code).",
1319
- "properties": {
1320
- "agent_turn_id": {
1321
- "anyOf": [
1322
- {
1323
- "type": "string"
1324
- },
1325
- {
1326
- "type": "null"
1327
- }
1328
- ],
1329
- "default": null,
1330
- "description": "Identifier of the turn the record belongs to, if any.",
1331
- "title": "Agent Turn Id"
1332
- },
1333
- "cost": {
1334
- "anyOf": [
1335
- {
1336
- "type": "integer"
1337
- },
1338
- {
1339
- "type": "null"
1340
- }
1341
- ],
1342
- "default": null,
1343
- "description": "Cost attributed to this record, if any.",
1344
- "title": "Cost"
1345
- },
1346
- "created_at": {
1347
- "description": "When the record was created.",
1348
- "format": "date-time",
1349
- "title": "Created At",
1350
- "type": "string"
1351
- },
1352
- "duration": {
1353
- "anyOf": [
1354
- {
1355
- "type": "integer"
1356
- },
1357
- {
1358
- "type": "null"
1359
- }
1360
- ],
1361
- "default": null,
1362
- "description": "Duration attributed to this record, if any.",
1363
- "title": "Duration"
1364
- },
1365
- "feed_seq": {
1366
- "description": "The record's position in the session's ordered feed \u2014 the resume cursor for the stream and the records endpoints.",
1367
- "title": "Feed Seq",
1368
- "type": "integer"
1369
- },
1370
- "id": {
1371
- "description": "Unique identifier of the record.",
1372
- "title": "Id",
1373
- "type": "string"
1374
- },
1375
- "model": {
399
+ "feed_seq": {
400
+ "description": "The record's position in the session's ordered feed \u2014 the resume cursor for the stream and the records endpoints.",
401
+ "title": "Feed Seq",
402
+ "type": "integer"
403
+ },
404
+ "id": {
405
+ "description": "Unique identifier of the record.",
406
+ "title": "Id",
407
+ "type": "string"
408
+ },
409
+ "model": {
1376
410
  "anyOf": [
1377
411
  {
1378
412
  "type": "string"
@@ -1614,6 +648,48 @@
1614
648
  "title": "CodexCommandExecutionItem",
1615
649
  "type": "object"
1616
650
  },
651
+ "CodexConfig": {
652
+ "additionalProperties": false,
653
+ "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.",
654
+ "properties": {
655
+ "model": {
656
+ "default": "gpt-5.6-terra",
657
+ "title": "Model",
658
+ "type": "string"
659
+ },
660
+ "system": {
661
+ "anyOf": [
662
+ {
663
+ "type": "string"
664
+ },
665
+ {
666
+ "$ref": "#/$defs/SystemFileRef"
667
+ },
668
+ {
669
+ "items": {
670
+ "anyOf": [
671
+ {
672
+ "type": "string"
673
+ },
674
+ {
675
+ "$ref": "#/$defs/SystemFileRef"
676
+ }
677
+ ]
678
+ },
679
+ "type": "array"
680
+ }
681
+ ],
682
+ "default": "",
683
+ "title": "System"
684
+ }
685
+ },
686
+ "required": [
687
+ "model",
688
+ "system"
689
+ ],
690
+ "title": "CodexConfig",
691
+ "type": "object"
692
+ },
1617
693
  "CodexErrorEvent": {
1618
694
  "additionalProperties": true,
1619
695
  "properties": {
@@ -2436,55 +1512,160 @@
2436
1512
  }
2437
1513
  },
2438
1514
  "required": [
2439
- "cache_write_input_tokens",
2440
- "cached_input_tokens",
2441
- "input_tokens",
2442
- "output_tokens",
2443
- "reasoning_output_tokens"
1515
+ "cache_write_input_tokens",
1516
+ "cached_input_tokens",
1517
+ "input_tokens",
1518
+ "output_tokens",
1519
+ "reasoning_output_tokens"
1520
+ ],
1521
+ "title": "CodexUsage",
1522
+ "type": "object"
1523
+ },
1524
+ "CodexWebSearchItem": {
1525
+ "additionalProperties": true,
1526
+ "properties": {
1527
+ "id": {
1528
+ "anyOf": [
1529
+ {
1530
+ "type": "string"
1531
+ },
1532
+ {
1533
+ "type": "null"
1534
+ }
1535
+ ],
1536
+ "default": null,
1537
+ "title": "Id"
1538
+ },
1539
+ "query": {
1540
+ "anyOf": [
1541
+ {
1542
+ "type": "string"
1543
+ },
1544
+ {
1545
+ "type": "null"
1546
+ }
1547
+ ],
1548
+ "default": null,
1549
+ "title": "Query"
1550
+ },
1551
+ "type": {
1552
+ "const": "web_search",
1553
+ "default": "web_search",
1554
+ "title": "Type",
1555
+ "type": "string"
1556
+ }
1557
+ },
1558
+ "required": [
1559
+ "id",
1560
+ "query",
1561
+ "type"
1562
+ ],
1563
+ "title": "CodexWebSearchItem",
1564
+ "type": "object"
1565
+ },
1566
+ "ComputeConfig": {
1567
+ "additionalProperties": false,
1568
+ "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.",
1569
+ "properties": {
1570
+ "cpu": {
1571
+ "anyOf": [
1572
+ {
1573
+ "maximum": 16,
1574
+ "minimum": 0.125,
1575
+ "type": "number"
1576
+ },
1577
+ {
1578
+ "type": "null"
1579
+ }
1580
+ ],
1581
+ "default": null,
1582
+ "title": "Cpu"
1583
+ },
1584
+ "memory": {
1585
+ "anyOf": [
1586
+ {
1587
+ "type": "string"
1588
+ },
1589
+ {
1590
+ "$ref": "#/$defs/MemorySize"
1591
+ },
1592
+ {
1593
+ "type": "null"
1594
+ }
1595
+ ],
1596
+ "default": null,
1597
+ "title": "Memory"
1598
+ },
1599
+ "timeout": {
1600
+ "anyOf": [
1601
+ {
1602
+ "type": "string"
1603
+ },
1604
+ {
1605
+ "$ref": "#/$defs/Duration"
1606
+ },
1607
+ {
1608
+ "type": "null"
1609
+ }
1610
+ ],
1611
+ "default": null,
1612
+ "title": "Timeout"
1613
+ }
1614
+ },
1615
+ "required": [
1616
+ "cpu",
1617
+ "memory",
1618
+ "timeout"
1619
+ ],
1620
+ "title": "ComputeConfig",
1621
+ "type": "object"
1622
+ },
1623
+ "ConfigMetadata": {
1624
+ "additionalProperties": false,
1625
+ "properties": {
1626
+ "annotations": {
1627
+ "additionalProperties": {
1628
+ "type": "string"
1629
+ },
1630
+ "default": {},
1631
+ "title": "Annotations",
1632
+ "type": "object"
1633
+ },
1634
+ "labels": {
1635
+ "default": [],
1636
+ "items": {
1637
+ "type": "string"
1638
+ },
1639
+ "title": "Labels",
1640
+ "type": "array"
1641
+ }
1642
+ },
1643
+ "required": [
1644
+ "annotations",
1645
+ "labels"
2444
1646
  ],
2445
- "title": "CodexUsage",
1647
+ "title": "ConfigMetadata",
2446
1648
  "type": "object"
2447
1649
  },
2448
- "CodexWebSearchItem": {
2449
- "additionalProperties": true,
1650
+ "CronTrigger": {
1651
+ "additionalProperties": false,
2450
1652
  "properties": {
2451
- "id": {
2452
- "anyOf": [
2453
- {
2454
- "type": "string"
2455
- },
2456
- {
2457
- "type": "null"
2458
- }
2459
- ],
2460
- "default": null,
2461
- "title": "Id"
2462
- },
2463
- "query": {
2464
- "anyOf": [
2465
- {
2466
- "type": "string"
2467
- },
2468
- {
2469
- "type": "null"
2470
- }
2471
- ],
2472
- "default": null,
2473
- "title": "Query"
1653
+ "schedule": {
1654
+ "title": "Schedule",
1655
+ "type": "string"
2474
1656
  },
2475
1657
  "type": {
2476
- "const": "web_search",
2477
- "default": "web_search",
1658
+ "const": "cron",
1659
+ "default": "cron",
2478
1660
  "title": "Type",
2479
1661
  "type": "string"
2480
1662
  }
2481
1663
  },
2482
1664
  "required": [
2483
- "id",
2484
- "query",
1665
+ "schedule",
2485
1666
  "type"
2486
1667
  ],
2487
- "title": "CodexWebSearchItem",
1668
+ "title": "CronTrigger",
2488
1669
  "type": "object"
2489
1670
  },
2490
1671
  "DeltaFrame": {
@@ -2566,6 +1747,58 @@
2566
1747
  "title": "DoneFrame",
2567
1748
  "type": "object"
2568
1749
  },
1750
+ "Duration": {
1751
+ "additionalProperties": false,
1752
+ "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.",
1753
+ "properties": {
1754
+ "hours": {
1755
+ "anyOf": [
1756
+ {
1757
+ "minimum": 0,
1758
+ "type": "integer"
1759
+ },
1760
+ {
1761
+ "type": "null"
1762
+ }
1763
+ ],
1764
+ "default": null,
1765
+ "title": "Hours"
1766
+ },
1767
+ "minutes": {
1768
+ "anyOf": [
1769
+ {
1770
+ "minimum": 0,
1771
+ "type": "integer"
1772
+ },
1773
+ {
1774
+ "type": "null"
1775
+ }
1776
+ ],
1777
+ "default": null,
1778
+ "title": "Minutes"
1779
+ },
1780
+ "seconds": {
1781
+ "anyOf": [
1782
+ {
1783
+ "minimum": 0,
1784
+ "type": "integer"
1785
+ },
1786
+ {
1787
+ "type": "null"
1788
+ }
1789
+ ],
1790
+ "default": null,
1791
+ "title": "Seconds"
1792
+ }
1793
+ },
1794
+ "required": [
1795
+ "hours",
1796
+ "minutes",
1797
+ "seconds"
1798
+ ],
1799
+ "title": "Duration",
1800
+ "type": "object"
1801
+ },
2569
1802
  "EffortLevel": {
2570
1803
  "enum": [
2571
1804
  "low",
@@ -2581,30 +1814,208 @@
2581
1814
  "additionalProperties": false,
2582
1815
  "description": "One grant entry: a level, optionally narrowed to instances whose\nnatural key (a file's name, a memory's path, a secret's name, a config's\nname, a session's id) matches any of the `match` globs.",
2583
1816
  "properties": {
2584
- "level": {
2585
- "$ref": "#/$defs/Level"
1817
+ "level": {
1818
+ "$ref": "#/$defs/Level"
1819
+ },
1820
+ "match": {
1821
+ "anyOf": [
1822
+ {
1823
+ "items": {
1824
+ "type": "string"
1825
+ },
1826
+ "type": "array"
1827
+ },
1828
+ {
1829
+ "type": "null"
1830
+ }
1831
+ ],
1832
+ "default": null,
1833
+ "title": "Match"
1834
+ }
1835
+ },
1836
+ "required": [
1837
+ "level",
1838
+ "match"
1839
+ ],
1840
+ "title": "EllipsisGrant",
1841
+ "type": "object"
1842
+ },
1843
+ "EllipsisPermissions": {
1844
+ "additionalProperties": {
1845
+ "anyOf": [
1846
+ {
1847
+ "$ref": "#/$defs/Level"
1848
+ },
1849
+ {
1850
+ "$ref": "#/$defs/EllipsisGrant"
1851
+ },
1852
+ {
1853
+ "items": {
1854
+ "anyOf": [
1855
+ {
1856
+ "$ref": "#/$defs/Level"
1857
+ },
1858
+ {
1859
+ "$ref": "#/$defs/EllipsisGrant"
1860
+ }
1861
+ ]
1862
+ },
1863
+ "type": "array"
1864
+ }
1865
+ ]
1866
+ },
1867
+ "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.",
1868
+ "propertyNames": {
1869
+ "$ref": "#/$defs/Resource"
1870
+ },
1871
+ "title": "EllipsisPermissions",
1872
+ "type": "object"
1873
+ },
1874
+ "EnvironmentConfig": {
1875
+ "additionalProperties": false,
1876
+ "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.",
1877
+ "properties": {
1878
+ "compute": {
1879
+ "$ref": "#/$defs/ComputeConfig",
1880
+ "default": {
1881
+ "cpu": null,
1882
+ "memory": null,
1883
+ "timeout": null
1884
+ }
1885
+ },
1886
+ "hooks": {
1887
+ "$ref": "#/$defs/EnvironmentHooks",
1888
+ "default": {
1889
+ "post_clone": null,
1890
+ "post_start": null
1891
+ }
1892
+ },
1893
+ "image": {
1894
+ "$ref": "#/$defs/EnvironmentImage",
1895
+ "default": {
1896
+ "dockerfile_append": null,
1897
+ "setup": null
1898
+ }
1899
+ },
1900
+ "mcp_servers": {
1901
+ "default": [],
1902
+ "items": {
1903
+ "anyOf": [
1904
+ {
1905
+ "type": "string"
1906
+ },
1907
+ {
1908
+ "$ref": "#/$defs/McpServerRef"
1909
+ },
1910
+ {
1911
+ "$ref": "#/$defs/McpStdioServer"
1912
+ },
1913
+ {
1914
+ "$ref": "#/$defs/McpRemoteServer"
1915
+ }
1916
+ ]
1917
+ },
1918
+ "title": "Mcp Servers",
1919
+ "type": "array"
1920
+ },
1921
+ "repositories": {
1922
+ "default": [],
1923
+ "items": {
1924
+ "$ref": "#/$defs/RepositoryRef"
1925
+ },
1926
+ "title": "Repositories",
1927
+ "type": "array"
1928
+ },
1929
+ "variables": {
1930
+ "default": [],
1931
+ "items": {
1932
+ "$ref": "#/$defs/EnvironmentVariable"
1933
+ },
1934
+ "title": "Variables",
1935
+ "type": "array"
1936
+ }
1937
+ },
1938
+ "required": [
1939
+ "compute",
1940
+ "hooks",
1941
+ "image",
1942
+ "mcp_servers",
1943
+ "repositories",
1944
+ "variables"
1945
+ ],
1946
+ "title": "EnvironmentConfig",
1947
+ "type": "object"
1948
+ },
1949
+ "EnvironmentHooks": {
1950
+ "additionalProperties": false,
1951
+ "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.",
1952
+ "properties": {
1953
+ "post_clone": {
1954
+ "anyOf": [
1955
+ {
1956
+ "type": "string"
1957
+ },
1958
+ {
1959
+ "type": "null"
1960
+ }
1961
+ ],
1962
+ "default": null,
1963
+ "title": "Post Clone"
1964
+ },
1965
+ "post_start": {
1966
+ "anyOf": [
1967
+ {
1968
+ "type": "string"
1969
+ },
1970
+ {
1971
+ "type": "null"
1972
+ }
1973
+ ],
1974
+ "default": null,
1975
+ "title": "Post Start"
1976
+ }
1977
+ },
1978
+ "required": [
1979
+ "post_clone",
1980
+ "post_start"
1981
+ ],
1982
+ "title": "EnvironmentHooks",
1983
+ "type": "object"
1984
+ },
1985
+ "EnvironmentImage": {
1986
+ "additionalProperties": false,
1987
+ "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`.",
1988
+ "properties": {
1989
+ "dockerfile_append": {
1990
+ "anyOf": [
1991
+ {
1992
+ "type": "string"
1993
+ },
1994
+ {
1995
+ "type": "null"
1996
+ }
1997
+ ],
1998
+ "default": null,
1999
+ "title": "Dockerfile Append"
2586
2000
  },
2587
- "match": {
2001
+ "setup": {
2588
2002
  "anyOf": [
2589
2003
  {
2590
- "items": {
2591
- "type": "string"
2592
- },
2593
- "type": "array"
2004
+ "type": "string"
2594
2005
  },
2595
2006
  {
2596
2007
  "type": "null"
2597
2008
  }
2598
2009
  ],
2599
2010
  "default": null,
2600
- "title": "Match"
2011
+ "title": "Setup"
2601
2012
  }
2602
2013
  },
2603
2014
  "required": [
2604
- "level",
2605
- "match"
2015
+ "dockerfile_append",
2016
+ "setup"
2606
2017
  ],
2607
- "title": "EllipsisGrant",
2018
+ "title": "EnvironmentImage",
2608
2019
  "type": "object"
2609
2020
  },
2610
2021
  "EnvironmentSource": {
@@ -2619,6 +2030,34 @@
2619
2030
  "title": "EnvironmentSource",
2620
2031
  "type": "string"
2621
2032
  },
2033
+ "EnvironmentVariable": {
2034
+ "additionalProperties": false,
2035
+ "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.",
2036
+ "properties": {
2037
+ "name": {
2038
+ "title": "Name",
2039
+ "type": "string"
2040
+ },
2041
+ "value": {
2042
+ "anyOf": [
2043
+ {
2044
+ "type": "string"
2045
+ },
2046
+ {
2047
+ "type": "null"
2048
+ }
2049
+ ],
2050
+ "default": null,
2051
+ "title": "Value"
2052
+ }
2053
+ },
2054
+ "required": [
2055
+ "name",
2056
+ "value"
2057
+ ],
2058
+ "title": "EnvironmentVariable",
2059
+ "type": "object"
2060
+ },
2622
2061
  "ErrorFrame": {
2623
2062
  "description": "Terminal error marker, sent before the server closes with code 1011.",
2624
2063
  "properties": {
@@ -2741,6 +2180,52 @@
2741
2180
  "title": "GithubAccountType",
2742
2181
  "type": "string"
2743
2182
  },
2183
+ "GithubPermissions": {
2184
+ "additionalProperties": false,
2185
+ "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.",
2186
+ "properties": {
2187
+ "permissions": {
2188
+ "anyOf": [
2189
+ {
2190
+ "const": "read_only",
2191
+ "type": "string"
2192
+ },
2193
+ {
2194
+ "additionalProperties": {
2195
+ "type": "string"
2196
+ },
2197
+ "type": "object"
2198
+ },
2199
+ {
2200
+ "type": "null"
2201
+ }
2202
+ ],
2203
+ "default": null,
2204
+ "title": "Permissions"
2205
+ },
2206
+ "repositories": {
2207
+ "anyOf": [
2208
+ {
2209
+ "items": {
2210
+ "type": "string"
2211
+ },
2212
+ "type": "array"
2213
+ },
2214
+ {
2215
+ "type": "null"
2216
+ }
2217
+ ],
2218
+ "default": null,
2219
+ "title": "Repositories"
2220
+ }
2221
+ },
2222
+ "required": [
2223
+ "permissions",
2224
+ "repositories"
2225
+ ],
2226
+ "title": "GithubPermissions",
2227
+ "type": "object"
2228
+ },
2744
2229
  "Harness": {
2745
2230
  "enum": [
2746
2231
  "claude_code",
@@ -2772,6 +2257,43 @@
2772
2257
  "title": "HeartbeatFrame",
2773
2258
  "type": "object"
2774
2259
  },
2260
+ "InputContract": {
2261
+ "additionalProperties": false,
2262
+ "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`).",
2263
+ "properties": {
2264
+ "json_schema": {
2265
+ "anyOf": [
2266
+ {
2267
+ "additionalProperties": true,
2268
+ "type": "object"
2269
+ },
2270
+ {
2271
+ "type": "null"
2272
+ }
2273
+ ],
2274
+ "default": null,
2275
+ "title": "Json Schema"
2276
+ },
2277
+ "message": {
2278
+ "anyOf": [
2279
+ {
2280
+ "type": "string"
2281
+ },
2282
+ {
2283
+ "type": "null"
2284
+ }
2285
+ ],
2286
+ "default": null,
2287
+ "title": "Message"
2288
+ }
2289
+ },
2290
+ "required": [
2291
+ "json_schema",
2292
+ "message"
2293
+ ],
2294
+ "title": "InputContract",
2295
+ "type": "object"
2296
+ },
2775
2297
  "IssueAction": {
2776
2298
  "enum": [
2777
2299
  "opened",
@@ -2879,89 +2401,225 @@
2879
2401
  "title": "Record Type",
2880
2402
  "type": "string"
2881
2403
  },
2882
- "session_id": {
2883
- "description": "Identifier of the session the record belongs to.",
2884
- "title": "Session Id",
2404
+ "session_id": {
2405
+ "description": "Identifier of the session the record belongs to.",
2406
+ "title": "Session Id",
2407
+ "type": "string"
2408
+ },
2409
+ "session_message_id": {
2410
+ "anyOf": [
2411
+ {
2412
+ "type": "string"
2413
+ },
2414
+ {
2415
+ "type": "null"
2416
+ }
2417
+ ],
2418
+ "default": null,
2419
+ "description": "Correlates a user-echo record back to the session message it echoes, so clients can retire queued messages by id.",
2420
+ "title": "Session Message Id"
2421
+ },
2422
+ "source": {
2423
+ "description": "Who wrote the record. Open vocabulary: ignore records with unknown sources.",
2424
+ "type": "string"
2425
+ },
2426
+ "stream_seq": {
2427
+ "description": "The record's position within its execution's stream.",
2428
+ "title": "Stream Seq",
2429
+ "type": "integer"
2430
+ },
2431
+ "tokens_info": {
2432
+ "anyOf": [
2433
+ {
2434
+ "$ref": "#/$defs/TokensInfo"
2435
+ },
2436
+ {
2437
+ "type": "null"
2438
+ }
2439
+ ],
2440
+ "default": null,
2441
+ "description": "Token usage reported for this record, if any."
2442
+ },
2443
+ "tools": {
2444
+ "anyOf": [
2445
+ {
2446
+ "items": {
2447
+ "type": "string"
2448
+ },
2449
+ "type": "array"
2450
+ },
2451
+ {
2452
+ "type": "null"
2453
+ }
2454
+ ],
2455
+ "default": null,
2456
+ "description": "Names of the tools used in this record, if any.",
2457
+ "title": "Tools"
2458
+ }
2459
+ },
2460
+ "required": [
2461
+ "agent_turn_id",
2462
+ "cost",
2463
+ "created_at",
2464
+ "duration",
2465
+ "feed_seq",
2466
+ "id",
2467
+ "model",
2468
+ "payload",
2469
+ "record_format",
2470
+ "record_type",
2471
+ "session_id",
2472
+ "session_message_id",
2473
+ "source",
2474
+ "stream_seq",
2475
+ "tokens_info",
2476
+ "tools"
2477
+ ],
2478
+ "title": "LifecycleSessionRecord",
2479
+ "type": "object"
2480
+ },
2481
+ "LinearIssueAction": {
2482
+ "enum": [
2483
+ "opened"
2484
+ ],
2485
+ "title": "LinearIssueAction",
2486
+ "type": "string"
2487
+ },
2488
+ "McpRemoteServer": {
2489
+ "additionalProperties": false,
2490
+ "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.",
2491
+ "properties": {
2492
+ "headers": {
2493
+ "additionalProperties": {
2494
+ "type": "string"
2495
+ },
2496
+ "default": {},
2497
+ "title": "Headers",
2498
+ "type": "object"
2499
+ },
2500
+ "name": {
2501
+ "title": "Name",
2502
+ "type": "string"
2503
+ },
2504
+ "url": {
2505
+ "title": "Url",
2506
+ "type": "string"
2507
+ }
2508
+ },
2509
+ "required": [
2510
+ "headers",
2511
+ "name",
2512
+ "url"
2513
+ ],
2514
+ "title": "McpRemoteServer",
2515
+ "type": "object"
2516
+ },
2517
+ "McpServerRef": {
2518
+ "additionalProperties": false,
2519
+ "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`).",
2520
+ "properties": {
2521
+ "name": {
2522
+ "title": "Name",
2523
+ "type": "string"
2524
+ }
2525
+ },
2526
+ "required": [
2527
+ "name"
2528
+ ],
2529
+ "title": "McpServerRef",
2530
+ "type": "object"
2531
+ },
2532
+ "McpStdioServer": {
2533
+ "additionalProperties": false,
2534
+ "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.",
2535
+ "properties": {
2536
+ "args": {
2537
+ "default": [],
2538
+ "items": {
2539
+ "type": "string"
2540
+ },
2541
+ "title": "Args",
2542
+ "type": "array"
2543
+ },
2544
+ "command": {
2545
+ "title": "Command",
2885
2546
  "type": "string"
2886
2547
  },
2887
- "session_message_id": {
2888
- "anyOf": [
2889
- {
2890
- "type": "string"
2891
- },
2892
- {
2893
- "type": "null"
2894
- }
2895
- ],
2896
- "default": null,
2897
- "description": "Correlates a user-echo record back to the session message it echoes, so clients can retire queued messages by id.",
2898
- "title": "Session Message Id"
2548
+ "env": {
2549
+ "additionalProperties": {
2550
+ "type": "string"
2551
+ },
2552
+ "default": {},
2553
+ "title": "Env",
2554
+ "type": "object"
2899
2555
  },
2900
- "source": {
2901
- "description": "Who wrote the record. Open vocabulary: ignore records with unknown sources.",
2556
+ "name": {
2557
+ "title": "Name",
2902
2558
  "type": "string"
2903
- },
2904
- "stream_seq": {
2905
- "description": "The record's position within its execution's stream.",
2906
- "title": "Stream Seq",
2907
- "type": "integer"
2908
- },
2909
- "tokens_info": {
2559
+ }
2560
+ },
2561
+ "required": [
2562
+ "args",
2563
+ "command",
2564
+ "env",
2565
+ "name"
2566
+ ],
2567
+ "title": "McpStdioServer",
2568
+ "type": "object"
2569
+ },
2570
+ "MemorySize": {
2571
+ "additionalProperties": false,
2572
+ "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.",
2573
+ "properties": {
2574
+ "gb": {
2910
2575
  "anyOf": [
2911
2576
  {
2912
- "$ref": "#/$defs/TokensInfo"
2577
+ "minimum": 0,
2578
+ "type": "integer"
2913
2579
  },
2914
2580
  {
2915
2581
  "type": "null"
2916
2582
  }
2917
2583
  ],
2918
2584
  "default": null,
2919
- "description": "Token usage reported for this record, if any."
2585
+ "title": "Gb"
2920
2586
  },
2921
- "tools": {
2587
+ "mb": {
2922
2588
  "anyOf": [
2923
2589
  {
2924
- "items": {
2925
- "type": "string"
2926
- },
2927
- "type": "array"
2590
+ "minimum": 0,
2591
+ "type": "integer"
2928
2592
  },
2929
2593
  {
2930
2594
  "type": "null"
2931
2595
  }
2932
2596
  ],
2933
2597
  "default": null,
2934
- "description": "Names of the tools used in this record, if any.",
2935
- "title": "Tools"
2598
+ "title": "Mb"
2936
2599
  }
2937
2600
  },
2938
2601
  "required": [
2939
- "agent_turn_id",
2940
- "cost",
2941
- "created_at",
2942
- "duration",
2943
- "feed_seq",
2944
- "id",
2945
- "model",
2946
- "payload",
2947
- "record_format",
2948
- "record_type",
2949
- "session_id",
2950
- "session_message_id",
2951
- "source",
2952
- "stream_seq",
2953
- "tokens_info",
2954
- "tools"
2602
+ "gb",
2603
+ "mb"
2955
2604
  ],
2956
- "title": "LifecycleSessionRecord",
2605
+ "title": "MemorySize",
2957
2606
  "type": "object"
2958
2607
  },
2959
- "LinearIssueAction": {
2960
- "enum": [
2961
- "opened"
2608
+ "OutputConfig": {
2609
+ "additionalProperties": false,
2610
+ "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.",
2611
+ "properties": {
2612
+ "json_schema": {
2613
+ "additionalProperties": true,
2614
+ "title": "Json Schema",
2615
+ "type": "object"
2616
+ }
2617
+ },
2618
+ "required": [
2619
+ "json_schema"
2962
2620
  ],
2963
- "title": "LinearIssueAction",
2964
- "type": "string"
2621
+ "title": "OutputConfig",
2622
+ "type": "object"
2965
2623
  },
2966
2624
  "ParentKind": {
2967
2625
  "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).",
@@ -2972,6 +2630,40 @@
2972
2630
  "title": "ParentKind",
2973
2631
  "type": "string"
2974
2632
  },
2633
+ "PermissionsConfig": {
2634
+ "additionalProperties": false,
2635
+ "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.",
2636
+ "properties": {
2637
+ "ellipsis": {
2638
+ "anyOf": [
2639
+ {
2640
+ "enum": [
2641
+ true,
2642
+ "all"
2643
+ ]
2644
+ },
2645
+ {
2646
+ "$ref": "#/$defs/EllipsisPermissions"
2647
+ }
2648
+ ],
2649
+ "default": true,
2650
+ "title": "Ellipsis"
2651
+ },
2652
+ "github": {
2653
+ "$ref": "#/$defs/GithubPermissions",
2654
+ "default": {
2655
+ "permissions": null,
2656
+ "repositories": null
2657
+ }
2658
+ }
2659
+ },
2660
+ "required": [
2661
+ "ellipsis",
2662
+ "github"
2663
+ ],
2664
+ "title": "PermissionsConfig",
2665
+ "type": "object"
2666
+ },
2975
2667
  "PromptBlockedReason": {
2976
2668
  "description": "Why direct prompting is refused. Absent when prompting is allowed.",
2977
2669
  "enum": [
@@ -3195,6 +2887,94 @@
3195
2887
  "title": "ReactSlackChannel",
3196
2888
  "type": "object"
3197
2889
  },
2890
+ "ReactTrigger": {
2891
+ "additionalProperties": false,
2892
+ "properties": {
2893
+ "issue": {
2894
+ "anyOf": [
2895
+ {
2896
+ "$ref": "#/$defs/ReactIssue"
2897
+ },
2898
+ {
2899
+ "type": "null"
2900
+ }
2901
+ ],
2902
+ "default": null
2903
+ },
2904
+ "linear_issue": {
2905
+ "anyOf": [
2906
+ {
2907
+ "$ref": "#/$defs/ReactLinearIssue"
2908
+ },
2909
+ {
2910
+ "type": "null"
2911
+ }
2912
+ ],
2913
+ "default": null
2914
+ },
2915
+ "pull_request": {
2916
+ "anyOf": [
2917
+ {
2918
+ "$ref": "#/$defs/ReactPullRequest"
2919
+ },
2920
+ {
2921
+ "type": "null"
2922
+ }
2923
+ ],
2924
+ "default": null
2925
+ },
2926
+ "push": {
2927
+ "anyOf": [
2928
+ {
2929
+ "$ref": "#/$defs/ReactPush"
2930
+ },
2931
+ {
2932
+ "type": "null"
2933
+ }
2934
+ ],
2935
+ "default": null
2936
+ },
2937
+ "sentry": {
2938
+ "anyOf": [
2939
+ {
2940
+ "$ref": "#/$defs/ReactSentry"
2941
+ },
2942
+ {
2943
+ "type": "null"
2944
+ }
2945
+ ],
2946
+ "default": null
2947
+ },
2948
+ "slack_channel": {
2949
+ "anyOf": [
2950
+ {
2951
+ "$ref": "#/$defs/ReactSlackChannel"
2952
+ },
2953
+ {
2954
+ "type": "null"
2955
+ }
2956
+ ],
2957
+ "default": null
2958
+ },
2959
+ "type": {
2960
+ "const": "react",
2961
+ "default": "react",
2962
+ "title": "Type",
2963
+ "type": "string"
2964
+ }
2965
+ },
2966
+ "required": [
2967
+ "issue",
2968
+ "linear_issue",
2969
+ "pull_request",
2970
+ "push",
2971
+ "sentry",
2972
+ "slack_channel",
2973
+ "type"
2974
+ ],
2975
+ "title": "ReactTrigger",
2976
+ "type": "object"
2977
+ },
3198
2978
  "RecordsAppendFrame": {
3199
2979
  "description": "Cursored append-only delivery of session records, ordered by feed_seq,\nfrom all sources. Every record in the frame advances the resume cursor \u2014\nincluding ones a client renders as nothing.",
3200
2980
  "properties": {
@@ -3273,6 +3053,46 @@
3273
3053
  }
3274
3054
  ]
3275
3055
  },
3056
+ "RepositoryRef": {
3057
+ "additionalProperties": false,
3058
+ "properties": {
3059
+ "name": {
3060
+ "title": "Name",
3061
+ "type": "string"
3062
+ },
3063
+ "owner": {
3064
+ "anyOf": [
3065
+ {
3066
+ "type": "string"
3067
+ },
3068
+ {
3069
+ "type": "null"
3070
+ }
3071
+ ],
3072
+ "default": null,
3073
+ "title": "Owner"
3074
+ },
3075
+ "ref": {
3076
+ "anyOf": [
3077
+ {
3078
+ "type": "string"
3079
+ },
3080
+ {
3081
+ "type": "null"
3082
+ }
3083
+ ],
3084
+ "default": null,
3085
+ "title": "Ref"
3086
+ }
3087
+ },
3088
+ "required": [
3089
+ "name",
3090
+ "owner",
3091
+ "ref"
3092
+ ],
3093
+ "title": "RepositoryRef",
3094
+ "type": "object"
3095
+ },
3276
3096
  "Resource": {
3277
3097
  "description": "Everything a credential can be granted access to, one value per /v1\nresource family. `TOKENS` is reserved for the future token-management\nroutes; nothing maps to it yet.",
3278
3098
  "enum": [
@@ -4083,18 +3903,30 @@
4083
3903
  "Session": {
4084
3904
  "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.",
4085
3905
  "properties": {
4086
- "agent": {
4087
- "$ref": "#/$defs/SessionAgent",
4088
- "description": "The agent that ran: the config the session executed, where that config came from, and any override merged into it."
4089
- },
4090
3906
  "attribution": {
4091
3907
  "$ref": "#/$defs/SessionAttribution",
4092
3908
  "description": "The principal this session is attributed to."
4093
3909
  },
3910
+ "automation": {
3911
+ "anyOf": [
3912
+ {
3913
+ "$ref": "#/$defs/SessionAutomation"
3914
+ },
3915
+ {
3916
+ "type": "null"
3917
+ }
3918
+ ],
3919
+ "default": null,
3920
+ "description": "The automation the session was started from, or null for a raw session started with POST /v1/sessions."
3921
+ },
4094
3922
  "budget": {
4095
3923
  "$ref": "#/$defs/SessionBudget",
4096
3924
  "description": "The spend budget enforced for this session."
4097
3925
  },
3926
+ "config": {
3927
+ "$ref": "#/$defs/SessionConfig",
3928
+ "description": "What the session ran on, frozen when it was created: the harness block, the resolved environment, permissions, skills, output contract, and budget."
3929
+ },
4098
3930
  "context_repository": {
4099
3931
  "anyOf": [
4100
3932
  {
@@ -4120,7 +3952,7 @@
4120
3952
  },
4121
3953
  "environment": {
4122
3954
  "$ref": "#/$defs/SessionEnvironment",
4123
- "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."
3955
+ "description": "The environment the session resolved: the saved environment's id and how it was chosen. The environment's frozen body is `config.environment`."
4124
3956
  },
4125
3957
  "exit_status": {
4126
3958
  "anyOf": [
@@ -4227,7 +4059,7 @@
4227
4059
  },
4228
4060
  "source": {
4229
4061
  "$ref": "#/$defs/SessionSource",
4230
- "description": "Where the session came from (e.g. react, manual, api, cli, mention, cron)."
4062
+ "description": "Where the session came from (e.g. react, web, api, cli, mention, cron)."
4231
4063
  },
4232
4064
  "status": {
4233
4065
  "$ref": "#/$defs/SessionStatus",
@@ -4278,9 +4110,10 @@
4278
4110
  }
4279
4111
  },
4280
4112
  "required": [
4281
- "agent",
4282
4113
  "attribution",
4114
+ "automation",
4283
4115
  "budget",
4116
+ "config",
4284
4117
  "context_repository",
4285
4118
  "cost",
4286
4119
  "created_at",
@@ -4308,54 +4141,6 @@
4308
4141
  "title": "Session",
4309
4142
  "type": "object"
4310
4143
  },
4311
- "SessionAgent": {
4312
- "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.",
4313
- "properties": {
4314
- "automation_id": {
4315
- "anyOf": [
4316
- {
4317
- "type": "string"
4318
- },
4319
- {
4320
- "type": "null"
4321
- }
4322
- ],
4323
- "default": null,
4324
- "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.",
4325
- "title": "Automation Id"
4326
- },
4327
- "config": {
4328
- "$ref": "#/$defs/AgentConfig",
4329
- "description": "The agent definition the session actually ran, frozen when the session was created."
4330
- },
4331
- "override": {
4332
- "anyOf": [
4333
- {
4334
- "additionalProperties": true,
4335
- "type": "object"
4336
- },
4337
- {
4338
- "type": "null"
4339
- }
4340
- ],
4341
- "default": null,
4342
- "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.",
4343
- "title": "Override"
4344
- },
4345
- "source": {
4346
- "$ref": "#/$defs/AgentConfigSource",
4347
- "description": "How this session's config was chosen."
4348
- }
4349
- },
4350
- "required": [
4351
- "automation_id",
4352
- "config",
4353
- "override",
4354
- "source"
4355
- ],
4356
- "title": "SessionAgent",
4357
- "type": "object"
4358
- },
4359
4144
  "SessionAttribution": {
4360
4145
  "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.",
4361
4146
  "properties": {
@@ -4405,6 +4190,34 @@
4405
4190
  "title": "SessionAttribution",
4406
4191
  "type": "object"
4407
4192
  },
4193
+ "SessionAutomation": {
4194
+ "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.",
4195
+ "properties": {
4196
+ "config": {
4197
+ "$ref": "#/$defs/AutomationConfig",
4198
+ "description": "The automation definition the session was started from, frozen when the session was created."
4199
+ },
4200
+ "id": {
4201
+ "anyOf": [
4202
+ {
4203
+ "type": "string"
4204
+ },
4205
+ {
4206
+ "type": "null"
4207
+ }
4208
+ ],
4209
+ "default": null,
4210
+ "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.",
4211
+ "title": "Id"
4212
+ }
4213
+ },
4214
+ "required": [
4215
+ "config",
4216
+ "id"
4217
+ ],
4218
+ "title": "SessionAutomation",
4219
+ "type": "object"
4220
+ },
4408
4221
  "SessionBudget": {
4409
4222
  "description": "The spend budget actually enforced for this session, and which layer of\nthe cascade set it.",
4410
4223
  "properties": {
@@ -4427,6 +4240,112 @@
4427
4240
  "title": "SessionBudget",
4428
4241
  "type": "object"
4429
4242
  },
4243
+ "SessionConfig": {
4244
+ "additionalProperties": false,
4245
+ "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.",
4246
+ "properties": {
4247
+ "budget": {
4248
+ "$ref": "#/$defs/BudgetConfig",
4249
+ "default": {
4250
+ "day": null,
4251
+ "month": null,
4252
+ "session": null,
4253
+ "week": null
4254
+ }
4255
+ },
4256
+ "claude": {
4257
+ "$ref": "#/$defs/ClaudeConfig",
4258
+ "default": {
4259
+ "effort": null,
4260
+ "fallback_model": null,
4261
+ "max_turns": null,
4262
+ "model": null,
4263
+ "settings": null,
4264
+ "system": ""
4265
+ }
4266
+ },
4267
+ "codex": {
4268
+ "anyOf": [
4269
+ {
4270
+ "$ref": "#/$defs/CodexConfig"
4271
+ },
4272
+ {
4273
+ "type": "null"
4274
+ }
4275
+ ],
4276
+ "default": null
4277
+ },
4278
+ "environment": {
4279
+ "anyOf": [
4280
+ {
4281
+ "type": "string"
4282
+ },
4283
+ {
4284
+ "$ref": "#/$defs/EnvironmentConfig"
4285
+ }
4286
+ ],
4287
+ "default": {
4288
+ "compute": {
4289
+ "cpu": null,
4290
+ "memory": null,
4291
+ "timeout": null
4292
+ },
4293
+ "hooks": {
4294
+ "post_clone": null,
4295
+ "post_start": null
4296
+ },
4297
+ "image": {
4298
+ "dockerfile_append": null,
4299
+ "setup": null
4300
+ },
4301
+ "mcp_servers": [],
4302
+ "repositories": [],
4303
+ "variables": []
4304
+ },
4305
+ "title": "Environment"
4306
+ },
4307
+ "output": {
4308
+ "anyOf": [
4309
+ {
4310
+ "$ref": "#/$defs/OutputConfig"
4311
+ },
4312
+ {
4313
+ "type": "null"
4314
+ }
4315
+ ],
4316
+ "default": null
4317
+ },
4318
+ "permissions": {
4319
+ "$ref": "#/$defs/PermissionsConfig",
4320
+ "default": {
4321
+ "ellipsis": true,
4322
+ "github": {
4323
+ "permissions": null,
4324
+ "repositories": null
4325
+ }
4326
+ }
4327
+ },
4328
+ "skills": {
4329
+ "default": [],
4330
+ "items": {
4331
+ "$ref": "#/$defs/SkillRef"
4332
+ },
4333
+ "title": "Skills",
4334
+ "type": "array"
4335
+ }
4336
+ },
4337
+ "required": [
4338
+ "budget",
4339
+ "claude",
4340
+ "codex",
4341
+ "environment",
4342
+ "output",
4343
+ "permissions",
4344
+ "skills"
4345
+ ],
4346
+ "title": "SessionConfig",
4347
+ "type": "object"
4348
+ },
4430
4349
  "SessionCost": {
4431
4350
  "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\".",
4432
4351
  "properties": {
@@ -4472,7 +4391,7 @@
4472
4391
  "type": "object"
4473
4392
  },
4474
4393
  "SessionEnvironment": {
4475
- "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.",
4394
+ "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.",
4476
4395
  "properties": {
4477
4396
  "environment_id": {
4478
4397
  "anyOf": [
@@ -4497,7 +4416,7 @@
4497
4416
  }
4498
4417
  ],
4499
4418
  "default": null,
4500
- "description": "How the environment was chosen (request, agent_config, repo_default, account_default, platform_default). Null when the config carried its own inline environment."
4419
+ "description": "How the environment was chosen (request, agent_config, platform_default; repo_default and account_default on sessions from before those ladders were removed). Null when the config carried its own inline environment."
4501
4420
  }
4502
4421
  },
4503
4422
  "required": [
@@ -4784,7 +4703,7 @@
4784
4703
  "title": "Author"
4785
4704
  },
4786
4705
  "body": {
4787
- "description": "The message text.",
4706
+ "description": "The message text, with one `[Image #N]` placeholder per attached image.",
4788
4707
  "title": "Body",
4789
4708
  "type": "string"
4790
4709
  },
@@ -4839,6 +4758,14 @@
4839
4758
  "title": "Id",
4840
4759
  "type": "string"
4841
4760
  },
4761
+ "images": {
4762
+ "description": "Images attached to the message, metadata only: index, media type, size. The bytes go to the model, never over the stream.",
4763
+ "items": {
4764
+ "$ref": "#/$defs/SessionMessageImage"
4765
+ },
4766
+ "title": "Images",
4767
+ "type": "array"
4768
+ },
4842
4769
  "sender_attribution_id": {
4843
4770
  "anyOf": [
4844
4771
  {
@@ -4882,6 +4809,7 @@
4882
4809
  "delivered_turn_id",
4883
4810
  "feed_seq",
4884
4811
  "id",
4812
+ "images",
4885
4813
  "sender_attribution_id",
4886
4814
  "sender_attribution_type",
4887
4815
  "session_id",
@@ -4890,6 +4818,33 @@
4890
4818
  "title": "SessionMessage",
4891
4819
  "type": "object"
4892
4820
  },
4821
+ "SessionMessageImage": {
4822
+ "description": "One image on a message, metadata only. `index` is the N in the\n`[Image #N]` placeholder in the message body.",
4823
+ "properties": {
4824
+ "index": {
4825
+ "description": "1-based position: the N in `[Image #N]`.",
4826
+ "title": "Index",
4827
+ "type": "integer"
4828
+ },
4829
+ "media_type": {
4830
+ "description": "The image's MIME type.",
4831
+ "title": "Media Type",
4832
+ "type": "string"
4833
+ },
4834
+ "size_bytes": {
4835
+ "description": "Size of the decoded image, in bytes.",
4836
+ "title": "Size Bytes",
4837
+ "type": "integer"
4838
+ }
4839
+ },
4840
+ "required": [
4841
+ "index",
4842
+ "media_type",
4843
+ "size_bytes"
4844
+ ],
4845
+ "title": "SessionMessageImage",
4846
+ "type": "object"
4847
+ },
4893
4848
  "SessionMessageStatus": {
4894
4849
  "enum": [
4895
4850
  "pending",
@@ -5001,9 +4956,10 @@
5001
4956
  "type": "object"
5002
4957
  },
5003
4958
  "SessionSource": {
4959
+ "description": "Where a session came from: the credential that started it (web app,\nAPI key, CLI) or the trigger that fired (react, mention, cron). Never\ntaken from a request body.",
5004
4960
  "enum": [
5005
4961
  "react",
5006
- "manual",
4962
+ "web",
5007
4963
  "api",
5008
4964
  "cli",
5009
4965
  "mention",
@@ -5211,6 +5167,60 @@
5211
5167
  "title": "SessionTokens",
5212
5168
  "type": "object"
5213
5169
  },
5170
+ "SettingsRef": {
5171
+ "additionalProperties": false,
5172
+ "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.",
5173
+ "properties": {
5174
+ "path": {
5175
+ "title": "Path",
5176
+ "type": "string"
5177
+ },
5178
+ "repository": {
5179
+ "anyOf": [
5180
+ {
5181
+ "$ref": "#/$defs/RepositoryRef"
5182
+ },
5183
+ {
5184
+ "type": "null"
5185
+ }
5186
+ ],
5187
+ "default": null
5188
+ }
5189
+ },
5190
+ "required": [
5191
+ "path",
5192
+ "repository"
5193
+ ],
5194
+ "title": "SettingsRef",
5195
+ "type": "object"
5196
+ },
5197
+ "SkillRef": {
5198
+ "additionalProperties": false,
5199
+ "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.",
5200
+ "properties": {
5201
+ "path": {
5202
+ "title": "Path",
5203
+ "type": "string"
5204
+ },
5205
+ "repository": {
5206
+ "anyOf": [
5207
+ {
5208
+ "$ref": "#/$defs/RepositoryRef"
5209
+ },
5210
+ {
5211
+ "type": "null"
5212
+ }
5213
+ ],
5214
+ "default": null
5215
+ }
5216
+ },
5217
+ "required": [
5218
+ "path",
5219
+ "repository"
5220
+ ],
5221
+ "title": "SkillRef",
5222
+ "type": "object"
5223
+ },
5214
5224
  "SnapshotFrame": {
5215
5225
  "description": "The first frame after the stream connects: the session plus its open\ninbox. Records always arrive separately via records_append frames.",
5216
5226
  "properties": {
@@ -5261,6 +5271,32 @@
5261
5271
  "title": "SnapshotFrame",
5262
5272
  "type": "object"
5263
5273
  },
5274
+ "SystemFileRef": {
5275
+ "additionalProperties": false,
5276
+ "properties": {
5277
+ "file": {
5278
+ "title": "File",
5279
+ "type": "string"
5280
+ },
5281
+ "repository": {
5282
+ "anyOf": [
5283
+ {
5284
+ "$ref": "#/$defs/RepositoryRef"
5285
+ },
5286
+ {
5287
+ "type": "null"
5288
+ }
5289
+ ],
5290
+ "default": null
5291
+ }
5292
+ },
5293
+ "required": [
5294
+ "file",
5295
+ "repository"
5296
+ ],
5297
+ "title": "SystemFileRef",
5298
+ "type": "object"
5299
+ },
5264
5300
  "TokensInfo": {
5265
5301
  "additionalProperties": false,
5266
5302
  "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).",