Platform limits
This is the whole platform's limits table in one page: how big a request can be, what you may name things, what a new project is allowed to run, how long things wait before giving up, and how long credentials live. Every number here comes from the code that enforces it.
Two things to know before you read on:
- Most limits are defaults, not laws. Where a limit is backed by a setting (shown in the last column), the operator running your platform can change it. Where a limit is a hard rule of the API, it says so.
- Check your own project's live limits with
GET /v1/projects/{projectID}/quotaor the console's Quota page — that reads the cluster's own enforcement rather than this table. See Quotas and audit.
Request body and upload sizes
Exceeding these returns 400, or the request is refused before it is read. Two paths answer 413 instead: a direct POST to a deployed function (the language shims) and an upload through the console's proxy.
| What | Limit | Notes |
|---|---|---|
Most core API JSON bodies (agent-engine-api) | 8 KiB | Users, orgs, projects, members, invitations, keys, service accounts |
| Agent or function code upload | 100 MiB | Plus 1 MiB of slack for the form fields. Setting: MAX_UPLOAD_BYTES |
| Stored source file (browser editor) | 1 MiB per file | 200 files per agent; an uploaded archive may expand to at most 64 MiB |
| Agent invoke request | 1 MiB | Applies to invoke, streaming invoke, and memorize |
| Agent invoke upstream response | 32 MiB | A larger response from the agent becomes a 502 |
| Function event body (the runtime shim) | 8 MiB | The cap on a direct POST to a deployed function |
| Per-agent secrets body | 1 MiB | PUT and PATCH on /v1/agents/{name}/secrets |
| Project secret create body | 128 KiB | The value itself is capped separately, below |
| Project secret value | 65536 bytes (64 KiB) | 400 — secret value is N bytes, limit is 65536 |
| Secret binding body | 8 KiB | PUT on a secret map |
| MCP server create body | 4 KiB | Only name and expose are read |
| MCP tool publish body | 1 MiB | It carries Python source |
| Serverless API body | 256 KiB | Every route on serverless-api |
| VectorDB body | 32 MiB | Setting: MAX_BODY_BYTES |
| VectorDB query filter | 64 KiB | 400 — filter is too large |
| MemoryStore create body | 16 KiB | — |
| Pub/Sub publish body | 4 MiB | Every other Pub/Sub body is capped at 1 MiB |
| Sandboxed tool call body | 1 MiB | The tool's own response is capped at 8 MiB |
Pagination and batch sizes
| What | Default | Maximum | Notes |
|---|---|---|---|
page_size on every list endpoint | 50 | 200 | limit is accepted as an alias. A larger value is rejected with 400 — page_size must be between 1 and 200 — never clamped |
page_token | — | — | Opaque, tamper-evident, and bound to the list that issued it. A token from another list is 400 — page_token is invalid or was issued for a different list; start from the first page |
| VectorDB points per upsert | — | 1000 | All-or-nothing: one bad point rejects the whole batch. Setting: MAX_POINTS_PER_REQUEST |
VectorDB top_k per query | 10 | 1000 | Setting: MAX_TOP_K |
| VectorDB scroll page | 50 | 1000 | The point browser |
| VectorDB ids per delete-points call | — | 1000 | — |
| VectorDB collections listed in a direct-access credential | — | 256 | Beyond that the response sets truncated: true |
| Pub/Sub messages per publish | — | 100 | 400 — a publish carries at most 100 messages (got N) |
| Pub/Sub messages per pull | 10 | 100 | Over-asks are silently capped, not rejected |
| Pub/Sub acknowledgement ids per call | — | 1000 | — |
| Agent log history lines | 500 | — | The limit query parameter on the history endpoint |
| Serverless log tail lines | 500 | 10000 | The tail query parameter; minimum 1. Setting: LOG_TAIL_LINES |
Name rules
Names are chosen once and cannot be changed — renaming would move the address other things depend on.
| Resource | Rule | Length |
|---|---|---|
| Agent or function | ^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$ — a lowercase DNS label | ≤ 63 |
| Serverless service | ^[a-z]([-a-z0-9]{0,50}[a-z0-9])?$ | 1–52 (shorter than 63 because revision names append -00001) |
| MCP server | ^[a-z]([a-z0-9-]{0,38}[a-z0-9])?$ | ≤ 40 |
| MCP tool | ^[a-z][a-z0-9_]{0,62}$ — a lowercase identifier, no leading underscore | ≤ 63 |
| VectorDB index | [a-z0-9]([a-z0-9-]*[a-z0-9])? — no uppercase, no underscore | ≤ 48 |
| MemoryStore instance | ^[a-z]([-a-z0-9]*[a-z0-9])?$ | 1–40 |
| Pub/Sub topic and subscription | ^[a-z]([a-z0-9-]*[a-z0-9])?$ | ≤ 63 |
| Project secret | ^[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}$ | 1–63 |
| Environment variable / secret key | ^[A-Za-z_][A-Za-z0-9_]*$ | — |
| Service account | A lowercase DNS label. Reserved permanently, even after deletion, so a new principal can never inherit an old one's grants | — |
session_id | ^[A-Za-z0-9_.-]{1,128}$ | ≤ 128 |
user_id | ^[A-Za-z0-9_.:@-]{1,128}$ | ≤ 128 |
| A session id you choose yourself while unauthenticated | Must be at least 24 characters of unguessable randomness — or omit it and the platform generates one | ≥ 24 |
| Password | Minimum 12 characters | ≥ 12 |
Agents and functions share one flat name space per project: a function cannot take a name an agent already holds.
crusoe-cloud-credential is a reserved secret name. Nineteen environment variable names are reserved and cannot be bound to a secret — they are listed in the Secrets API.
Default project quotas
Written into every new project at creation. A hard value of 0 means that resource is unlimited. Nothing in the API raises a cap — ask your platform operator.
| Resource | Default | Shown in the console as |
|---|---|---|
| Running instances (pods) | 50 | Running instances |
| Kubernetes Services | 30 | Services |
| CPU reserved (requests) | 10 | CPU (reserved) |
| Memory reserved (requests) | 20 GiB | Memory (reserved) |
| CPU maximum (limits) | 20 | CPU (max) |
| Memory maximum (limits) | 40 GiB | Memory (max) |
| Pub/Sub backlog storage | 1 GiB per project | (Pub/Sub quota page) |
| Pub/Sub topics | 100 per project | — |
| Pub/Sub producers and consumers | 100 each, per topic | — |
Per-container defaults are applied when you do not set your own: a limit of 2 CPU / 4 GiB and a request of 100m CPU / 256 MiB.
Every serverless revision permanently holds two Kubernetes Services (one public, one private), and every deploy or spec edit creates a revision. Once the Services quota is full, new revisions across the whole project stop becoming ready until you delete services you no longer need.
Pub/Sub budget is spent by claim, not by use. A topic reserves its max_bytes the moment it exists, so four empty 16 MiB topics have already spent 64 MiB. Consuming messages does not give budget back — delete a topic or lower its max_bytes.
If some older material quotes 60 Kubernetes Services, that is a fallback value used only when a project is created without the field; projects created by the platform's own control plane get 30. Your live number is always in GET /v1/projects/{projectID}/quota.
Timeouts
| What | Default | Maximum | Setting |
|---|---|---|---|
| Agent invoke (control plane waits this long for the agent) | 60 s | — | INVOKE_TIMEOUT_SECONDS |
| Serverless request timeout | 300 s | 3600 s | timeout_seconds, mirrored into the container as CRUSOE_REQUEST_TIMEOUT_SECONDS |
| MCP server request timeout | 300 s | — | — |
run_python sandbox execution | 20 s | 60 s | timeout_s on the execute call; 400 — timeout_s must be between 1 and 60 |
| Sandboxed tool call | 30 s | 120 s | timeout_s; 400 — timeout_s must be between 1 and 120 |
| Waiting for a warm sandbox pod | 30 s | — | Then 503 — no warm sandbox pod available, try again shortly |
| A tool sandbox becoming ready | 110 s | — | Tool calls have no warm pool, so they pay pod scheduling and image pull |
| Pub/Sub pull long-poll wait | 2000 ms | 20000 ms | timeout_ms |
| Pub/Sub acknowledgement deadline | 30 s | 600 s (minimum 1 s) | ack_deadline_seconds. On a push subscription this doubles as the per-request timeout — leave room for a cold start |
| MemoryStore API request | 30 s | — | REQUEST_TIMEOUT_SECONDS |
| MemoryStore live stats read | 3 s | — | — |
| Scale to zero after idle | about 90 s | — | Poll for zero instances with a generous timeout rather than sleeping a fixed time |
| A stale build claim is reclaimable after | 30 min | — | Until then a second deploy gets 409 — a build is already in progress for agent <name> |
platformctl deploy waiting for ready | polls every 2 s, up to 5 min | — | — |
platformctl invoke client timeout | 5 min | — | — |
Retention and history
| What | Retention | Notes |
|---|---|---|
| Persisted agent logs | 14 days | Survives scale-to-zero and revision rollouts. Setting: LOG_RETENTION |
| Live agent and serverless logs | none | Streamed from the newest running instance only; an idle, scaled-to-zero workload has no live logs (you get 200 and an explanation, not an error) |
| Audit log | kept, but with no export, no retention policy, and no date-range filter yet | Alpha. See Break-glass and audit |
| Metrics history | none | The platform reports live instance counts and readiness; there are no historical charts, because no time-series database is deployed |
| Stored agent source | latest version only | No history, no version control — copy anything you want to keep |
| Pub/Sub messages | only while some subscription still owes an acknowledgement | Create subscriptions before publishing, or the message is reclaimed |
| VectorDB and MemoryStore data | until you delete it | No snapshots, no backups, no restore. Deleting an index or an instance is irreversible |
Credentials, tokens, and sign-in
| What | Value | Notes |
|---|---|---|
| Session token lifetime | 12 hours | HMAC-signed and stateless, so it is not revocable before it expires |
| API key expiry | 0 (never expires) or 1–3650 days | 400 — expires_in_days must be between 1 and 3650, or 0 for a key that does not expire |
| API key secret visibility | shown exactly once, at creation | Only a hash is stored. Lost it? Revoke the key and create another |
| Sign-in throttle | 10 attempts per IP and 50 per account, per 15 minutes | 429 with a Retry-After header |
| Password minimum | 12 characters | Same rule for new accounts, changes, and invitation acceptance |
| Break-glass grant | 4 hours by default, 24 hours maximum | Reason required, at least 8 characters, shown verbatim to the project's members |
Secret read token (:issue-token) | 300 s by default | Clamped to 3600 s. The store's own maximum lease may clamp it further — trust the returned ttl_seconds |
| Pub/Sub direct broker token | never expires | Revoking one means rotating the platform signing key for everyone |
| VectorDB direct-access token | non-expiring by default | Setting: QDRANT_JWT_TTL. Scoped to the exact collections that existed when it was minted, so refetch after creating an index |
| MCP server bearer token | minted once, reused across redeploys | Format: cai_mcp_ plus 64 hexadecimal characters |
| Invitation token | shown exactly once, and expires | Send the accept link immediately — it cannot be retrieved later |
Rate limits
| API | Limit | What you see |
|---|---|---|
agent-engine-api | Per-principal token bucket, tuned by the operator (RATELIMIT_RPS / RATELIMIT_BURST); anonymous callers are limited per IP | 429 |
serverless-api | 100 requests/second, burst 200, per principal per API replica; /healthz is exempt | 429 |
| VectorDB, MemoryStore, Pub/Sub | Per-principal token bucket on every route except health checks | 429 |
Service defaults worth knowing
These are not caps — they are what you get when you do not say otherwise.
| Service | Default |
|---|---|
| Serverless scaling | minimum 0 instances, maximum 10, 80 concurrent requests per instance |
| Serverless resources | 250m CPU / 512 MiB requested, 1 CPU / 512 MiB limit — applied only when you send no resources at all |
| Serverless port | 8080; exactly one port, named http1 or h2c |
| Serverless maximum instances | Sending max_scale: 0 on a serverless service behaves as 10, not unlimited. On an agent's config, max_scale: 0 does mean unbounded |
| Agent invoke authentication | open to anonymous callers; the operator can close it. Writing to an agent's memory bank always requires a credential |
| Code sandbox warm pool | 3 pods kept ready; each pod runs one snippet and is destroyed. Execution pods are limited to 1 CPU / 512 MiB (requesting 50m / 128 MiB) |
| Sandboxed tool pods | 2 CPU / 1 GiB limit, 100m / 256 MiB request; no warm pool |
| VectorDB index | 1536 dimensions, cosine distance, 1 shard, 1 replica, no quantization. Dimensions accept 1–65536 and replicas 1–8; only replicas and payload placement can be changed later |
| MemoryStore size classes | small 256 MiB container / 192 MiB usable, medium 1 GiB / 768 MiB, large 4 GiB / 3 GiB — usable memory is 75% of the container, on purpose |
| MemoryStore persistence | on, with a 2 GiB volume; eviction policy noeviction (writes fail at the limit rather than dropping keys) |
| Pub/Sub topic | 16 MiB max_bytes, no age limit, discard: old |
| Pub/Sub subscription | type shared, 30 s acknowledgement deadline, 5 delivery attempts, 1000 unacknowledged messages in flight, start_from: all, pull delivery |
Related pages
- API overview — pagination, error envelope, and rate limits in detail
- Quotas and audit — reading your project's live usage
- Core concepts — what a project, revision, and quota actually are
- Known issues — where alpha limits bite today
- Secrets API · MCP servers API · Platform API