Agent? Fetch sharkmagic.si/docs/llms.txt or this page as markdown
Limits#
What the hosted node enforces at launch. Your account's live values are authoritative: GET /v1/quotas (your
quotas with current use) and GET /v1/capabilities (the node's limits and features, no auth). Do not hard-code the
numbers below in an agent; read them.
curl -sS https://hel1.sharkmagic.si/v1/capabilities
shark quotas --json # or GET /v1/quotas on the node with a node token (api.md, "Auth")
Every limit below answers with a stable error code when you hit it (errors.md); none is a silent cap.
Your account#
The account service sets per-account caps; the node enforces them and GET /v1/quotas shows each as a row with
limit and used (scope: tenant): spaces (held, awake or hibernated), awake_spaces, concurrent_leases. The
same answer names your account's class (limits_class) and how to raise a limit (raise). Defaults at launch, by
class (an account can be given others; your rows are the truth):
| cap | new account (first 7 days) | running on promotional credit only | standard | partner | when exceeded |
|---|---|---|---|---|---|
| Spaces held | 20 | 10 | 50 | 200 | 429 quota_exceeded, details.quota: spaces: delete one |
| Spaces awake at once | 7 | 7 | 7 | 100 | 429 quota_exceeded, details.quota: awake on create, fork or wake: hibernate one (shark hibernate, or shark space set <space> --idle 30m so idle ones sleep by themselves) |
| commands running at once | 4 | 2 | 6 | 12 | queued, then 429 lease_cap_reached (retryable, the command did not start) |
| exposed processes awake at once | 2 | 1 | 3 | 20 | refused with quota_exceeded: stop or sleep one |
| CPU per command | 4 CPUs | 2 CPUs | the VM's 8 vCPU | the VM's 8 vCPU | none: the command runs slower |
A Space does not hibernate by itself unless it, or the node, has an idle setting: hibernate the ones you are not using.
Every 429 quota_exceeded names the cap (details.quota, limit, used), your details.limits_class and
details.raise: how to get more (write to support@sharkmagic.si; design partners and SDK platforms get the
partner limits). Prices are the same in every class.
shark quotas --json # {"limits_class": "partner", "raise": "...", "data": [{"name": "awake_spaces", "scope": "tenant", "limit": 100, "used": 12}, ...]}
curl -sS -H "Authorization: Bearer $SHARK_API_KEY" https://api.sharkmagic.si/v1/limits # class, caps, label caps (no use)
Partner limits#
For design partners and SDK platforms whose own end users each get Spaces: the partner class, set by Shark (ask
us; an operator turns it on with one command and it reaches the nodes within seconds). Its numbers are sized to what
one node serves: 200 Spaces is the node's per-account ceiling, 100 awake is a quarter of the node's 400 live
Spaces. The node's own protections still apply on top of any class: 50 GiB of disk per account, and its admission
(503 out_of_capacity while memory or CPU is short, retryable).
Per-label limits#
A platform can cap each of its own end users by a label of their Spaces (Spaces take labels at create, fork and
PATCH). A selector key caps each value of that label on its own; key=value caps that one value and wins
over key for it. Two counts: awake (Spaces awake at once) and spaces (held). A Space without the label is not
capped by it. They only tighten: the account's caps above still apply.
shark quotas labels set end_user --awake 3 --spaces 20 # every end user: 3 awake, 20 held
shark quotas labels set end_user=acme --awake 10 # acme gets 10 awake
shark quotas labels --json # {"class": ..., "label_caps": {"end_user": {"awake": 3, "spaces": 20}, ...}}
shark quotas labels rm end_user=acme
# HTTP (account service): PATCH /v1/limits/labels {"labels": {"end_user": {"awake": 3}}} (null removes a selector)
# PUT /v1/limits/labels {"labels": {...}} (replaces all; null clears)
| limit | value | when exceeded |
|---|---|---|
| selectors per account | 32; key [A-Za-z0-9._/-]{1,63}, value 1–255 chars |
400 invalid_request, details.field |
| a value's Spaces awake / held | what you set (integer 0–1,000,000; 0 = none allowed) | 429 quota_exceeded, details.quota: label_awake or label_spaces, details.label (end_user=alice), details.selector, limit, used; on create, fork, wake and on a PATCH that moves a Space into a full value |
GET /v1/quotas shows one row per selector and count (scope: label): for key=value its use; for key the
fullest value (label, used) and how many values you use (values). A change reaches the nodes within one poll of
the account service (about 2 s).
Commands#
| limit | value | when exceeded |
|---|---|---|
| lease shape (each command's microVM) | 8 vCPU, 4 GiB | — |
timeout_s, sync exec (JSON when it ends) |
default 120 s, max 900 s | 400 invalid_request, details.max_s: 900 |
timeout_s, streaming (Accept: text/event-stream) or async ("wait": false) |
default 30 min, max 7,200 s (2 h) | 400 invalid_request, details.max_s: 7200 |
output returned by a sync exec |
last 1 MiB of each stream (stdout_truncated: true) |
the full output stays in the op log |
| op log (stored output per op) | 32 MiB per stream, then truncated |
|
| op retention (result and output) | 7 days | 410 op_expired; the commit stays in audit |
cmd |
1 B – 256 KiB | 400 |
stdin |
1 MiB | 413 payload_too_large |
env per request |
128 names, 16 KiB per value | 400 |
op_id |
1–64 of [A-Za-z0-9_.:-] |
400 invalid_op_id |
| commands running at once, per account | your account's cap (above; then a queue; too long a wait gives 429 lease_cap_reached before the command starts) |
429, retryable |
| node admission (memory and CPU) | the node refuses new commands, Spaces and wakes while its memory is short or its CPUs are saturated; live state: the node_admission row of GET /v1/quotas |
503 out_of_capacity with Retry-After (details.reason), retryable; nothing started |
stdin streaming into a running command (stdin_stream) |
not served yet | 422 unsupported |
Spaces and files#
| limit | value | when exceeded |
|---|---|---|
| Spaces per account (live and hibernated) | your account's cap (above) | 429 quota_exceeded |
| disk per account on the node | 50 GiB (51,200 MiB) | 507 insufficient_storage, scope: tenant |
| live Spaces per node (hibernated ones do not count) | 400 | 429 space_limit_reached, retryable |
| forks per call | 1–50 | 400 |
| labels per Space | 32; key [A-Za-z0-9._/-]{1,63}, value ≤ 255 chars |
400 |
| name | [A-Za-z0-9._-]{1,63}, unique per account |
400 / 409 conflict |
| JSON request body | 1 MiB | 413 |
single file upload (PUT /v1/spaces/{id}/files) |
512 MiB, streamed | 413 |
archive upload (POST /v1/spaces/{id}/files/archive) |
2 GiB | 413 |
Idempotency-Key |
1–255 chars, kept 24 h |
Secrets, network, terminals#
| limit | value |
|---|---|
| secrets per Space | 64 |
| secret value size | 16 KiB |
egress allow entries |
256 |
terminals per Space (shark connect) |
8 (429 too_many_terminals) |
| one-time preview login link | 60 s, one use |
| exposed process idle before it sleeps | idle_s, default 30 s |
API#
| limit | value |
|---|---|
| request rate per credential | 100/s, burst 500 (429 rate_limited with Retry-After) |
| failed authentications per address | limited (429 auth_rate_limited) |
| transport | HTTPS only (plain HTTP is refused except on loopback) |
Not available (today)#
GPUs; non-Linux guests; process memory carried across commands; the services, snapshots, restore, connectors,
model-gateway, events and webhooks routes (422 unsupported); stdin streaming; E2B SDK compatibility. shark connect is coming on the hosted node (exposed processes and preview URLs are live:
concepts.md).
<sub>Values: cmd/sharkfs (api_v1*.go, node*.go), internal/apiv1, internal/secrets, and the hosted node's
configuration (deploy/v1/shark-api.service) as of 2026-11-05; the account defaults from the account service
(control-plane/src/config.ts, DEFAULT_CAPS) as of 2026-11-07. Account quotas can differ per account; GET /v1/quotas tells you yours.</sub>
