@aexhq/sdk 0.40.6 → 0.40.7

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,88 +1,88 @@
1
- ---
2
- title: Subagents
3
- description: Delegate bounded sub-tasks to child agent runs with the subagent tool.
4
- icon: GitFork
5
- ---
6
-
7
- A run can delegate bounded sub-tasks to **child agent runs** with the built-in
8
- `subagent` tool. Delegation is agent-driven: the model decides to fan work out,
9
- each child is a real run with its own record, and the parent collects results
10
- as the children finish. There is no client-side parent/child API — lineage is
11
- session-internal.
12
-
13
- ## How the tool works
14
-
15
- The agent calls `subagent` with a `prompt` and a `model` (both required), plus
16
- optional `system`, `provider`, `runtimeSize`, `timeout`,
17
- `includeBuiltinTools`, `tools` (builtin-tool names for the child), `skills`,
18
- and `files`. The call is **always async**: on a successful spawn it returns
19
- immediately with the child run id, and the parent keeps working while the child
20
- runs. When a child settles, the parent is notified in its loop, and it reads
21
- the child's status and captured outputs on demand with the companion
22
- `subagent_result` tool.
23
-
24
- Children inherit the parent's vaulted BYOK provider keys server-side — the
25
- child submission carries no secrets. Include a provider key for every provider
26
- your subagents may use when you open the parent session (a parent holding no
27
- key for the child's provider gets a clear `parent_missing_provider_key` tool
28
- error). See [Credentials](../credentials.md).
29
-
30
- ## Depth and breadth limits
31
-
32
- Delegation is bounded by two server-enforced lineage limits:
33
-
34
- | Limit | Value | Behavior at the limit |
35
- | --- | --- | --- |
36
- | Max depth | **5** — the root run is depth 0 and may spawn down to depth 5; a depth-5 run may not spawn further | The spawn is rejected with a `depth_exceeded` tool error (the parent keeps running). |
37
- | Concurrent children per lineage root | **1000** live (non-terminal) descendants by default; hard platform ceiling **4096** | Further spawns are refused until a child settles. |
38
-
39
- The whole descendant subtree of one root shares a single depth and breadth
40
- budget, enforced server-side at every level — a grandchild spawn counts against
41
- the same root budget as a direct child. Values are mirrored in
42
- [Limits & quotas](../limits-and-quotas.md).
43
-
44
- ## Where children run: `in-process` vs `container`
45
-
46
- By default a child runs **in-process**: it executes as a sibling agent process
47
- inside the parent's own machine, sharing the parent's CPU, memory, and
48
- lifetime. This is the platform default shipped today.
49
-
50
- - **No extra runtime cost.** The parent's machine is the billable unit, so
51
- in-process children bill **$0 of additional runtime** — fan-out is priced by
52
- the parent box, however many children it hosts. (Model-token spend is still
53
- whatever each child's provider calls cost on your BYOK key.)
54
- - **Shared capacity.** N children share the parent's fixed CPU/memory. For
55
- large fan-outs, size the parent up (`runtime`) rather than assuming each
56
- child gets its own machine.
57
- - **Joined lifecycle.** The parent's terminal waits for its in-process children,
58
- and their results are folded into the parent's per-child accounting. Platform
59
- recovery re-spawns in-process children exactly once if the parent's machine
60
- is replaced mid-run — settled children are never re-run.
61
-
62
- The escape valve is `host: "container"`: the child is dispatched to its **own
63
- isolated machine** with its own runtime size and its own runtime billing, and
64
- the parent does not host it. Use it when a child needs guaranteed capacity,
65
- isolation from the parent's filesystem/CPU, or a different machine size than
66
- the parent can share.
67
-
68
- ## Lineage and observability
69
-
70
- Every child — in-process or container — is a first-class run record:
71
-
72
- - The parent's transcript logs each spawn with the child's run id.
73
- - Each child has its own status, typed event timeline, and captured outputs.
74
- The child's events and outputs are readable by id
75
- (`aex.sessions.outputs(id)` in the SDK, or the CLI's `aex events` /
76
- `aex outputs`). Child runs are not served by the session read surface
77
- today — `aex.sessions.get(id)` / `aex sessions` / the CLI's `aex status`
78
- answer `not_found` for a child id.
79
- - The child's outputs are handed back to the parent via `subagent_result`, and
80
- they remain independently downloadable after the lineage finishes.
81
-
82
- ## Bounding delegation
83
-
84
- - Turn delegation off for a run by cherry-picking builtins without `subagent`
85
- (see [Agent tools](agent-tools.md)) or setting `includeBuiltinTools: false`.
86
- - A per-session spend cap (`overrides.maxSpendUsd`) bounds the parent's spend.
87
- - The depth/breadth limits above are platform defaults and are not settable
88
- per-session today.
1
+ ---
2
+ title: Subagents
3
+ description: Delegate bounded sub-tasks to child agent runs with the subagent tool.
4
+ icon: GitFork
5
+ ---
6
+
7
+ A run can delegate bounded sub-tasks to **child agent runs** with the built-in
8
+ `subagent` tool. Delegation is agent-driven: the model decides to fan work out,
9
+ each child is a real run with its own record, and the parent collects results
10
+ as the children finish. There is no client-side parent/child API — lineage is
11
+ session-internal.
12
+
13
+ ## How the tool works
14
+
15
+ The agent calls `subagent` with a `prompt` and a `model` (both required), plus
16
+ optional `system`, `provider`, `runtimeSize`, `timeout`,
17
+ `includeBuiltinTools`, `tools` (builtin-tool names for the child), `skills`,
18
+ and `files`. The call is **always async**: on a successful spawn it returns
19
+ immediately with the child run id, and the parent keeps working while the child
20
+ runs. When a child settles, the parent is notified in its loop, and it reads
21
+ the child's status and captured outputs on demand with the companion
22
+ `subagent_result` tool.
23
+
24
+ Children inherit the parent's vaulted BYOK provider keys server-side — the
25
+ child submission carries no secrets. Include a provider key for every provider
26
+ your subagents may use when you open the parent session (a parent holding no
27
+ key for the child's provider gets a clear `parent_missing_provider_key` tool
28
+ error). See [Credentials](../credentials.md).
29
+
30
+ ## Depth and breadth limits
31
+
32
+ Delegation is bounded by two server-enforced lineage limits:
33
+
34
+ | Limit | Value | Behavior at the limit |
35
+ | --- | --- | --- |
36
+ | Max depth | **5** — the root run is depth 0 and may spawn down to depth 5; a depth-5 run may not spawn further | The spawn is rejected with a `depth_exceeded` tool error (the parent keeps running). |
37
+ | Concurrent children per lineage root | **1000** live (non-terminal) descendants by default; hard platform ceiling **4096** | Further spawns are refused until a child settles. |
38
+
39
+ The whole descendant subtree of one root shares a single depth and breadth
40
+ budget, enforced server-side at every level — a grandchild spawn counts against
41
+ the same root budget as a direct child. Values are mirrored in
42
+ [Limits & quotas](../limits-and-quotas.md).
43
+
44
+ ## Where children run: `in-process` vs `container`
45
+
46
+ By default a child runs **in-process**: it executes as a sibling agent process
47
+ inside the parent's own machine, sharing the parent's CPU, memory, and
48
+ lifetime. This is the platform default shipped today.
49
+
50
+ - **No extra runtime cost.** The parent's machine is the billable unit, so
51
+ in-process children bill **$0 of additional runtime** — fan-out is priced by
52
+ the parent box, however many children it hosts. (Model-token spend is still
53
+ whatever each child's provider calls cost on your BYOK key.)
54
+ - **Shared capacity.** N children share the parent's fixed CPU/memory. For
55
+ large fan-outs, size the parent up (`runtime`) rather than assuming each
56
+ child gets its own machine.
57
+ - **Joined lifecycle.** The parent's terminal waits for its in-process children,
58
+ and their results are folded into the parent's per-child accounting. Platform
59
+ recovery re-spawns in-process children exactly once if the parent's machine
60
+ is replaced mid-run — settled children are never re-run.
61
+
62
+ The escape valve is `host: "container"`: the child is dispatched to its **own
63
+ isolated machine** with its own runtime size and its own runtime billing, and
64
+ the parent does not host it. Use it when a child needs guaranteed capacity,
65
+ isolation from the parent's filesystem/CPU, or a different machine size than
66
+ the parent can share.
67
+
68
+ ## Lineage and observability
69
+
70
+ Every child — in-process or container — is a first-class run record:
71
+
72
+ - The parent's transcript logs each spawn with the child's run id.
73
+ - Each child has its own status, typed event timeline, and captured outputs.
74
+ The child's events and outputs are readable by id
75
+ (`aex.sessions.outputs(id)` in the SDK, or the CLI's `aex events` /
76
+ `aex outputs`). Child runs are not served by the session read surface
77
+ today — `aex.sessions.get(id)` / `aex sessions` / the CLI's `aex status`
78
+ answer `not_found` for a child id.
79
+ - The child's outputs are handed back to the parent via `subagent_result`, and
80
+ they remain independently downloadable after the lineage finishes.
81
+
82
+ ## Bounding delegation
83
+
84
+ - Turn delegation off for a run by cherry-picking builtins without `subagent`
85
+ (see [Agent tools](agent-tools.md)) or setting `includeBuiltinTools: false`.
86
+ - A per-session spend cap (`overrides.maxSpendUsd`) bounds the parent's spend.
87
+ - The depth/breadth limits above are platform defaults and are not settable
88
+ per-session today.
@@ -1,125 +1,125 @@
1
- ---
2
- title: Credentials
3
- ---
4
-
5
- # Credentials
6
-
7
- aex uses explicit, per-session credentials:
8
-
9
- - `AEX_API_KEY` authenticates the SDK or CLI to aex.
10
- - `apiKeys` carries BYOK provider keys for the model provider.
11
- - `McpServer.remote(..., { headers })` carries MCP auth when a remote MCP server needs it.
12
- - `environment.secrets` carries runtime secrets for your own code.
13
-
14
- Secrets never belong in reusable run config, files, prompts, or examples.
15
-
16
- ## The client credential
17
-
18
- Pass your aex API key directly to the constructor — `new Aex(apiKey)` — or as
19
- the `apiKey` option:
20
-
21
- ```ts
22
- import { Aex } from "@aexhq/sdk";
23
-
24
- const aex = new Aex(process.env.AEX_API_KEY!); // preferred shorthand
25
- // equivalently:
26
- // const aex = new Aex({ apiKey: process.env.AEX_API_KEY! });
27
- ```
28
-
29
- See [Authentication](authentication.md) for how keys are scoped, rotated, and
30
- issued during the beta.
31
-
32
- ## Provider keys
33
-
34
- A session selects one upstream provider and must carry a BYOK key for it. Include
35
- additional provider keys only when subagents may use those providers.
36
-
37
- ```ts
38
- const result = await aex.run({
39
- model: Models.CLAUDE_HAIKU_4_5,
40
- message: "Write a short report and save it as a file.",
41
- apiKeys: {
42
- anthropic: process.env.ANTHROPIC_API_KEY!
43
- }
44
- });
45
- ```
46
-
47
- Provider keys are used by the managed runtime for model calls. They are not saved
48
- as client defaults.
49
-
50
- ## Runtime secrets
51
-
52
- Use `environment.secrets` for credentials your code needs at runtime. The value
53
- can be ephemeral with `Secret.value(...)` or a workspace secret reference with
54
- `Secret.ref(...)`.
55
-
56
- ```ts
57
- import { Aex, Models, Secret } from "@aexhq/sdk";
58
-
59
- const aex = new Aex({ apiKey: process.env.AEX_API_KEY! });
60
-
61
- await aex.run({
62
- model: Models.CLAUDE_HAIKU_4_5,
63
- message: "Call https://api.example.com/v1/status with INTERNAL_API_TOKEN and summarize it.",
64
- environment: {
65
- secrets: {
66
- INTERNAL_API_TOKEN: Secret.value(process.env.INTERNAL_API_TOKEN!)
67
- },
68
- networking: {
69
- mode: "limited",
70
- allowedHosts: ["api.example.com"]
71
- }
72
- },
73
- apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
74
- });
75
- ```
76
-
77
- Inside the run, use normal HTTP code for the service:
78
-
79
- ```bash
80
- curl -sS \
81
- -H "Authorization: Bearer $INTERNAL_API_TOKEN" \
82
- https://api.example.com/v1/status
83
- ```
84
-
85
- ## Workspace secrets
86
-
87
- > **Availability note:** workspace-secret `Secret.ref(...)` injection requires
88
- > the next platform deploy — on the current hosted plane the referenced
89
- > variable can resolve empty inside the run. Per-run `Secret.value(...)`
90
- > secrets are unaffected.
91
-
92
- Store reusable values once, then reference them by name:
93
-
94
- ```ts
95
- await aex.secrets.set({
96
- name: "internal-api-token",
97
- value: process.env.INTERNAL_API_TOKEN!
98
- });
99
-
100
- await aex.run({
101
- model: Models.CLAUDE_HAIKU_4_5,
102
- message: "Use INTERNAL_API_TOKEN for the status request.",
103
- environment: {
104
- secrets: {
105
- INTERNAL_API_TOKEN: Secret.ref("internal-api-token")
106
- }
107
- },
108
- apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
109
- });
110
- ```
111
-
112
- Secret reads return metadata only; they never return the stored value.
113
-
114
- ## Networking
115
-
116
- Networking is open by default within the platform's managed egress ceiling. Use
117
- `environment.networking.mode: "limited"` with `allowedHosts` when you want a
118
- run's own code to reach only named hosts. See [Networking](networking.md) for
119
- the two-layer enforcement model.
120
-
121
- ## Explicit call-site rule
122
-
123
- There is no `defaultSecrets` and no client-held secret state. Each
124
- `openSession(...)` or `run(...)` call should show the provider keys, MCP auth, and
125
- runtime secrets needed for that call.
1
+ ---
2
+ title: Credentials
3
+ ---
4
+
5
+ # Credentials
6
+
7
+ aex uses explicit, per-session credentials:
8
+
9
+ - `AEX_API_KEY` authenticates the SDK or CLI to aex.
10
+ - `apiKeys` carries BYOK provider keys for the model provider.
11
+ - `McpServer.remote(..., { headers })` carries MCP auth when a remote MCP server needs it.
12
+ - `environment.secrets` carries runtime secrets for your own code.
13
+
14
+ Secrets never belong in reusable run config, files, prompts, or examples.
15
+
16
+ ## The client credential
17
+
18
+ Pass your aex API key directly to the constructor — `new Aex(apiKey)` — or as
19
+ the `apiKey` option:
20
+
21
+ ```ts
22
+ import { Aex } from "@aexhq/sdk";
23
+
24
+ const aex = new Aex(process.env.AEX_API_KEY!); // preferred shorthand
25
+ // equivalently:
26
+ // const aex = new Aex({ apiKey: process.env.AEX_API_KEY! });
27
+ ```
28
+
29
+ See [Authentication](authentication.md) for how keys are scoped, rotated, and
30
+ issued during the beta.
31
+
32
+ ## Provider keys
33
+
34
+ A session selects one upstream provider and must carry a BYOK key for it. Include
35
+ additional provider keys only when subagents may use those providers.
36
+
37
+ ```ts
38
+ const result = await aex.run({
39
+ model: Models.CLAUDE_HAIKU_4_5,
40
+ message: "Write a short report and save it as a file.",
41
+ apiKeys: {
42
+ anthropic: process.env.ANTHROPIC_API_KEY!
43
+ }
44
+ });
45
+ ```
46
+
47
+ Provider keys are used by the managed runtime for model calls. They are not saved
48
+ as client defaults.
49
+
50
+ ## Runtime secrets
51
+
52
+ Use `environment.secrets` for credentials your code needs at runtime. The value
53
+ can be ephemeral with `Secret.value(...)` or a workspace secret reference with
54
+ `Secret.ref(...)`.
55
+
56
+ ```ts
57
+ import { Aex, Models, Secret } from "@aexhq/sdk";
58
+
59
+ const aex = new Aex({ apiKey: process.env.AEX_API_KEY! });
60
+
61
+ await aex.run({
62
+ model: Models.CLAUDE_HAIKU_4_5,
63
+ message: "Call https://api.example.com/v1/status with INTERNAL_API_TOKEN and summarize it.",
64
+ environment: {
65
+ secrets: {
66
+ INTERNAL_API_TOKEN: Secret.value(process.env.INTERNAL_API_TOKEN!)
67
+ },
68
+ networking: {
69
+ mode: "limited",
70
+ allowedHosts: ["api.example.com"]
71
+ }
72
+ },
73
+ apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
74
+ });
75
+ ```
76
+
77
+ Inside the run, use normal HTTP code for the service:
78
+
79
+ ```bash
80
+ curl -sS \
81
+ -H "Authorization: Bearer $INTERNAL_API_TOKEN" \
82
+ https://api.example.com/v1/status
83
+ ```
84
+
85
+ ## Workspace secrets
86
+
87
+ > **Availability note:** workspace-secret `Secret.ref(...)` injection requires
88
+ > the next platform deploy — on the current hosted plane the referenced
89
+ > variable can resolve empty inside the run. Per-run `Secret.value(...)`
90
+ > secrets are unaffected.
91
+
92
+ Store reusable values once, then reference them by name:
93
+
94
+ ```ts
95
+ await aex.secrets.set({
96
+ name: "internal-api-token",
97
+ value: process.env.INTERNAL_API_TOKEN!
98
+ });
99
+
100
+ await aex.run({
101
+ model: Models.CLAUDE_HAIKU_4_5,
102
+ message: "Use INTERNAL_API_TOKEN for the status request.",
103
+ environment: {
104
+ secrets: {
105
+ INTERNAL_API_TOKEN: Secret.ref("internal-api-token")
106
+ }
107
+ },
108
+ apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
109
+ });
110
+ ```
111
+
112
+ Secret reads return metadata only; they never return the stored value.
113
+
114
+ ## Networking
115
+
116
+ Networking is open by default within the platform's managed egress ceiling. Use
117
+ `environment.networking.mode: "limited"` with `allowedHosts` when you want a
118
+ run's own code to reach only named hosts. See [Networking](networking.md) for
119
+ the two-layer enforcement model.
120
+
121
+ ## Explicit call-site rule
122
+
123
+ There is no `defaultSecrets` and no client-held secret state. Each
124
+ `openSession(...)` or `run(...)` call should show the provider keys, MCP auth, and
125
+ runtime secrets needed for that call.
package/docs/defaults.md CHANGED
@@ -1,64 +1,64 @@
1
- ---
2
- title: Defaults
3
- ---
4
-
5
- # Defaults
6
-
7
- These are the values aex applies when you **omit** the corresponding option on a
8
- run. Every value is mirrored from a single source-of-truth constant in the
9
- platform's limits module; this page is hand-maintained against those constants.
10
- If a value here ever disagrees with the constant, the constant wins.
11
-
12
- Each value below is named by its source-of-truth constant. The runtime-size
13
- presets are defined in the public
14
- [`packages/contracts/src/runtime-sizes.ts`](https://github.com/aexhq/aex/blob/main/packages/contracts/src/runtime-sizes.ts).
15
- For the hard ceilings and who can raise them, see
16
- [Limits & quotas](limits-and-quotas.md). For policy boundaries, see
17
- [Limits](limits.md).
18
-
19
- ## Run
20
-
21
- | Option | Default | How to override | Source |
22
- | --- | --- | --- | --- |
23
- | `timeout` (run deadline) | 8 hours (also the ceiling) | Per-session via `overrides.timeout` (e.g. `"30m"`, `"2h"`). Values outside the run-timeout floor (1 minute) / ceiling (8 hours) are rejected with `RunConfigValidationError` before submission. | `RUN_DEFAULT_TIMEOUT_MS` |
24
- | `runtime` (machine size) | `shared-0.25x-1gb` — 0.25 vCPU, 1 GB | Per-session via `runtime` (use `Sizes.*` in TypeScript). | `RUN_DEFAULT_RUNTIME_SIZE` |
25
- | `overrides.maxSpendUsd` (per-session spend cap) | None — no spend cap (the session is still bounded by its `timeout` and any workspace-level cap) | Per-session via `overrides.maxSpendUsd` (a positive USD amount); the session is stopped once its spend would exceed the cap. | — |
26
- | `overrides.maxTurns` (agent iterations per run) | 20 (ceiling 200) | Per-session via `overrides.maxTurns` (a positive integer, clamped to the ceiling). | `RUN_DEFAULT_MAX_TURNS` |
27
-
28
- ## Tools
29
-
30
- | Option | Default | How to override | Source |
31
- | --- | --- | --- | --- |
32
- | Per-call exec timeout | 30 minutes | Per-call via the tool call's `timeoutMs`. | `RUN_DEFAULT_EXEC_TIMEOUT_MS` |
33
- | `web_fetch` returned body | 500 KB (UTF-8) | Per-call via the tool's `max_bytes` argument. | `REQUEST_WEB_FETCH_DEFAULT_MAX_BYTES` |
34
-
35
- ## MCP
36
-
37
- | Option | Default | How to override | Source |
38
- | --- | --- | --- | --- |
39
- | MCP connect timeout (register + initialize + discover) | 30 seconds | Per-port via `connectTimeoutMs`. | `RUN_DEFAULT_MCP_CONNECT_TIMEOUT_MS` |
40
- | MCP `tools/call` timeout | 30 minutes | Per-port via `callTimeoutMs`. | `RUN_DEFAULT_MCP_CALL_TIMEOUT_MS` |
41
-
42
- ## Links (signed URLs and tickets)
43
-
44
- | Option | Default | How to override | Source |
45
- | --- | --- | --- | --- |
46
- | Output link / signed-URL TTL | 300 seconds (5 minutes) at the storage layer; `session.outputs().link(...)` defaults to `"1h"` | Per-call via `expiresSeconds` (storage) or `expiresIn` on `session.outputs().link` / `session.outputs().fetch`. | `REQUEST_PRESIGN_URL_DEFAULT_TTL_SECONDS` |
47
- | Event-stream connection ticket TTL | 60 seconds | Per-mint via the `ttlMs` argument. | `REQUEST_TICKET_DEFAULT_TTL_MS` |
48
-
49
- ## Subagents
50
-
51
- | Option | Default | How to override | Source |
52
- | --- | --- | --- | --- |
53
- | Concurrent child runs per lineage root | 1000 (live, non-terminal child runs) | Platform default (subagents run in-process; no public per-run override). Hard ceiling 4096. | `RUN_DEFAULT_MAX_CONCURRENT_CHILD_RUNS` |
54
- | Max subagent depth | 5 | Platform default (subagents run in-process; no public per-run override). | `RUN_MAX_PUBLIC_SUBAGENT_DEPTH` |
55
-
56
- ## Workspace
57
-
58
- | Option | Default | How to override | Source |
59
- | --- | --- | --- | --- |
60
- | Run submit rate (per minute) | 120 (`0` = disabled); past it `POST /runs` fails with `429 workspace_submit_rate_exceeded` | Per-plane via env `AEX_WORKSPACE_SUBMIT_RATE_PER_MIN`; per-workspace via support. | — |
61
- | Max concurrent runs | Plan-based: 5 live root runs (free), 50 (Pro), 200 (Team); hard ceiling 200 | Per-plan (upgrade) or per-workspace override via support, clamped to the ceiling. | `PLANS[planKey].maxConcurrentRuns` |
62
- | Monthly spend cap | $250 per UTC calendar month (`0` = unlimited) | Per-workspace override via support. | `WORKSPACE_DEFAULT_SPEND_CAP_USD` |
63
- | Per-workspace mutation rate limits (per minute) | run cancel 30, run delete 30, signed link 120, API key create 10, API key delete 30 | Per-plane via the matching `AEX_RATE_LIMIT_<ACTION>_PER_MINUTE` env var. | `WORKSPACE_RATE_LIMIT_DEFAULTS` |
64
- | Workspace storage cap | 500 GB (decimal) | Per-plane via env `AEX_WORKSPACE_STORAGE_CAP_BYTES`; admin workspaces are uncapped (not a customer entitlement). | `WORKSPACE_DEFAULT_STORAGE_CAP_BYTES` |
1
+ ---
2
+ title: Defaults
3
+ ---
4
+
5
+ # Defaults
6
+
7
+ These are the values aex applies when you **omit** the corresponding option on a
8
+ run. Every value is mirrored from a single source-of-truth constant in the
9
+ platform's limits module; this page is hand-maintained against those constants.
10
+ If a value here ever disagrees with the constant, the constant wins.
11
+
12
+ Each value below is named by its source-of-truth constant. The runtime-size
13
+ presets are defined in the public
14
+ [`packages/contracts/src/runtime-sizes.ts`](https://github.com/aexhq/aex/blob/main/packages/contracts/src/runtime-sizes.ts).
15
+ For the hard ceilings and who can raise them, see
16
+ [Limits & quotas](limits-and-quotas.md). For policy boundaries, see
17
+ [Limits](limits.md).
18
+
19
+ ## Run
20
+
21
+ | Option | Default | How to override | Source |
22
+ | --- | --- | --- | --- |
23
+ | `timeout` (run deadline) | 8 hours (also the ceiling) | Per-session via `overrides.timeout` (e.g. `"30m"`, `"2h"`). Values outside the run-timeout floor (1 minute) / ceiling (8 hours) are rejected with `RunConfigValidationError` before submission. | `RUN_DEFAULT_TIMEOUT_MS` |
24
+ | `runtime` (machine size) | `shared-0.25x-1gb` — 0.25 vCPU, 1 GB | Per-session via `runtime` (use `Sizes.*` in TypeScript). | `RUN_DEFAULT_RUNTIME_SIZE` |
25
+ | `overrides.maxSpendUsd` (per-session spend cap) | None — no spend cap (the session is still bounded by its `timeout` and any workspace-level cap) | Per-session via `overrides.maxSpendUsd` (a positive USD amount); the session is stopped once its spend would exceed the cap. | — |
26
+ | `overrides.maxTurns` (agent iterations per run) | 20 (ceiling 200) | Per-session via `overrides.maxTurns` (a positive integer, clamped to the ceiling). | `RUN_DEFAULT_MAX_TURNS` |
27
+
28
+ ## Tools
29
+
30
+ | Option | Default | How to override | Source |
31
+ | --- | --- | --- | --- |
32
+ | Per-call exec timeout | 30 minutes | Per-call via the tool call's `timeoutMs`. | `RUN_DEFAULT_EXEC_TIMEOUT_MS` |
33
+ | `web_fetch` returned body | 500 KB (UTF-8) | Per-call via the tool's `max_bytes` argument. | `REQUEST_WEB_FETCH_DEFAULT_MAX_BYTES` |
34
+
35
+ ## MCP
36
+
37
+ | Option | Default | How to override | Source |
38
+ | --- | --- | --- | --- |
39
+ | MCP connect timeout (register + initialize + discover) | 30 seconds | Per-port via `connectTimeoutMs`. | `RUN_DEFAULT_MCP_CONNECT_TIMEOUT_MS` |
40
+ | MCP `tools/call` timeout | 30 minutes | Per-port via `callTimeoutMs`. | `RUN_DEFAULT_MCP_CALL_TIMEOUT_MS` |
41
+
42
+ ## Links (signed URLs and tickets)
43
+
44
+ | Option | Default | How to override | Source |
45
+ | --- | --- | --- | --- |
46
+ | Output link / signed-URL TTL | 300 seconds (5 minutes) at the storage layer; `session.outputs().link(...)` defaults to `"1h"` | Per-call via `expiresSeconds` (storage) or `expiresIn` on `session.outputs().link` / `session.outputs().fetch`. | `REQUEST_PRESIGN_URL_DEFAULT_TTL_SECONDS` |
47
+ | Event-stream connection ticket TTL | 60 seconds | Per-mint via the `ttlMs` argument. | `REQUEST_TICKET_DEFAULT_TTL_MS` |
48
+
49
+ ## Subagents
50
+
51
+ | Option | Default | How to override | Source |
52
+ | --- | --- | --- | --- |
53
+ | Concurrent child runs per lineage root | 1000 (live, non-terminal child runs) | Platform default (subagents run in-process; no public per-run override). Hard ceiling 4096. | `RUN_DEFAULT_MAX_CONCURRENT_CHILD_RUNS` |
54
+ | Max subagent depth | 5 | Platform default (subagents run in-process; no public per-run override). | `RUN_MAX_PUBLIC_SUBAGENT_DEPTH` |
55
+
56
+ ## Workspace
57
+
58
+ | Option | Default | How to override | Source |
59
+ | --- | --- | --- | --- |
60
+ | Run submit rate (per minute) | 120 (`0` = disabled); past it `POST /runs` fails with `429 workspace_submit_rate_exceeded` | Per-plane via env `AEX_WORKSPACE_SUBMIT_RATE_PER_MIN`; per-workspace via support. | — |
61
+ | Max concurrent runs | Plan-based: 5 live root runs (free), 50 (Pro), 200 (Team); hard ceiling 200 | Per-plan (upgrade) or per-workspace override via support, clamped to the ceiling. | `PLANS[planKey].maxConcurrentRuns` |
62
+ | Monthly spend cap | $250 per UTC calendar month (`0` = unlimited) | Per-workspace override via support. | `WORKSPACE_DEFAULT_SPEND_CAP_USD` |
63
+ | Per-workspace mutation rate limits (per minute) | run cancel 30, run delete 30, signed link 120, API key create 10, API key delete 30 | Per-plane via the matching `AEX_RATE_LIMIT_<ACTION>_PER_MINUTE` env var. | `WORKSPACE_RATE_LIMIT_DEFAULTS` |
64
+ | Workspace storage cap | 500 GB (decimal) | Per-plane via env `AEX_WORKSPACE_STORAGE_CAP_BYTES`; admin workspaces are uncapped (not a customer entitlement). | `WORKSPACE_DEFAULT_STORAGE_CAP_BYTES` |