Resources
CPU, memory, disk, and GPU requirements for Scrydon deployments
Use these requirements to size the cluster before running helm install. They
are derived from what the chart's defaults actually reserve, listed service by
service below. A chart test renders the defaults and fails when these tables
stop matching them, so a release that grows a service updates this page too.
Minimum (evaluation / small teams)
| Resource | Requirement |
|---|---|
| CPU | 8 vCPU |
| RAM | 40 GB |
| Disk | 160 GB for persistent volumes, plus room for images on every node |
| Nodes | 2 or more |
| GPU | Not required |
Where the numbers come from: the default stack's services request about 24 GiB of memory between them, and each of the 14 Dapr sidecars adds 128 MiB and 50m CPU — roughly 26 GiB and 4.4 vCPU the scheduler must place before anything starts. A first install needs a little more for a few minutes. The 6 schema-bootstrap Jobs request 0.5 vCPU and 1.25 GiB between them, and they run while the workloads start, so the peak is about 4.8 vCPU and 27.5 GiB. Add about 30% for kube-system, the Dapr control plane, Traefik, the kubelet's own reservation and rollout surges, and 8 vCPU and 40 GB of node memory are the floor that schedules cleanly. The persistent volumes claim 125 GiB by default (table below).
Note: Size for the first-install peak, not for the steady state. If the nodes cannot hold the workloads and the bootstrap Jobs at once, the scheduler places whichever pods it reaches first. When
dbis the one left waiting, the Jobs that need it reach their 10-minute deadline and the install does not converge. Troubleshooting covers the recovery.
These numbers assume the full default stack. To run smaller, turn off the components you do not need — see Helm → Trimming for low-resource installs.
Recommended (production)
| Resource | Requirement |
|---|---|
| CPU | 16 vCPU |
| RAM | 64 GB |
| Disk | 250 GB SSD |
| Nodes | 3 or more |
| GPU | Optional. Required only for local AI model inference, such as running Ollama in-cluster. |
Note: GPU resources are contractually licensed (your license JWT reflects your entitlement), but Scrydon does not runtime-enforce GPU limits. GPU nodes are only needed if you plan to run local inference models inside your cluster.
Per-service memory
The chart sets a memory request and limit on every Scrydon workload. The request is what the scheduler reserves, so the sum of requests (times replicas) is your floor: pods do not schedule until the node pool can hold it. The limit is the burst ceiling before a pod is OOM-killed.
| Workload | Replicas | Memory request | Memory limit | Notes |
|---|---|---|---|---|
platform | 1 | 1 GiB | 2 GiB | Platform UI: SSR shell and control-plane routes |
api-platform | 1 | 2 GiB | 4 GiB | Auth, platform API and the AI Gateway |
agentic | 1 | 1 GiB | 2 GiB | Workflow UI |
api-agentic | 1 | 3 GiB | 4 GiB | Headless workflow runtime (Dapr Workflow). Heaviest app |
agentic-realtime | 1 | 256 MiB | 512 MiB | WebSocket fan-out |
horizon | 1 | 256 MiB | 1 GiB | Operator home UI |
analytics | 2 | 1.5 GiB | 2 GiB | SSR and chart rendering |
cortex | 1 | 1 GiB | 3 GiB | Chat UI and LLM streaming proxy |
api-ontology | 1 | 256 MiB | 512 MiB | Ontology API |
api-table | 1 | 512 MiB | 2 GiB | Managed Tables. The limit covers the Iceberg maintenance sweep's peak |
api-ingestion | 2 | 256 MiB | 1 GiB | Where every data source that fetches or receives data runs. Stream and push also need the ingest buffer |
marimo-document | 1 | 128 MiB | 512 MiB | Stateless notebook document renderer |
managed-execution-actor-host | 2 | 512 MiB | 4 GiB | Managed-process execution backend. executionFabric.managedProcess.enabled: false removes it |
db | 1 | 3 GiB | 6 GiB | Bundled PostgreSQL 18 + pgvector. infra.db.enabled: false for managed Postgres |
starrocks-fe | 1 | 5 GiB | 8 GiB | Single-pod StarRocks behind Managed Tables. infra.starrocks.enabled: false removes it |
seaweedfs | 1 | 1.5 GiB | 3 GiB | Bundled S3-compatible object storage |
lakekeeper | 1 | 512 MiB | 1 GiB | Iceberg REST catalog |
scrydon-opa | 2 | 128 MiB | 512 MiB | Policy decision point |
event-backbone-valkey | 1 | 128 MiB | 512 MiB | Event backbone stream |
Every Scrydon app pod also carries a Dapr sidecar requesting 128 MiB and 50m CPU. The Dapr control plane and Traefik set no requests of their own; the 30% headroom above covers them.
api-platform includes the local ONNX embedding model. Its model and tokenizer
total about 23 MiB (about 48 MiB with ONNX WASM runtime assets), but inference uses much more resident memory:
an isolated compiled Linux arm64 benchmark reached 866 MiB after a 100-text batch.
The existing 2 GiB request and 4 GiB limit leave room for this model alongside
the platform API; measure peak RSS under your own embedding and gateway traffic.
Isolated notebook compute is additional and schedules in runtimePlane.workloadNamespace.
Each active interactive runtime reserves 4 GiB for Marimo plus 1 GiB for source control,
512 MiB for its broker, and 128 MiB for the egress enforcer (5.625 GiB total). A notebook job
reserves 4 GiB for its runner plus 128 MiB each for its broker and enforcer (4.25 GiB total).
Size the Kata/KVM node pool for expected concurrent sessions and jobs; opening documents does
not consume this capacity. A warm exec pool (runtimePlane.execPool, off by default) adds a
standing reservation: 1.1 CPU and 2.125 GiB per pooled Agent pod and 1.35 CPU and 1.375 GiB per
pooled Function pod, each plus the Kata RuntimeClass overhead, whether or not they are used.
Persistent volumes
Every volume is ReadWriteOnce and uses global.storageClass, or the
cluster's default StorageClass when that is empty.
| Volume | Size | Set with |
|---|---|---|
seaweedfs-data | 50 GiB | infra.seaweedfs.storage.size |
starrocks-data | 20 GiB | infra.starrocks.storage.size |
db-pvc | 5 GiB | infra.db.storage.size |
event-backbone-valkey | 2 GiB | eventBackbone.valkey.storage.size |
dapr-scheduler-server | 3 × 16 GiB | dapr.dapr_scheduler.cluster.storageSize (Dapr's default, one volume per scheduler replica) |
That is 125 GiB in total. The Postgres volume is sized for evaluation;
raise infra.db.storage.size before production data lands on it.
AI Gateway
The AI Gateway runs inside the api-platform pod, so its
cost lands on that Deployment's CPU rather than on a service of its own. The
chart ships auth.resources at a 500m request and a 2000m limit. That default
carries the control-plane traffic api-platform already serves; router traffic is
additional, and is the one workload on this page that scales with how your
people work rather than with how many services you enabled.
What one turn costs
A turn's CPU cost is a small fixed part plus a part that scales with the number of streamed events, not with the number of bytes. Your DLP posture changes the per-event term, so there are three curves rather than one:
| DLP mode | CPU per turn |
|---|---|
disabled | 0.017 vCPU-s + 0.14 ms × events |
audit | 0.025 vCPU-s + 0.18 ms × events |
enforce | 0.026 vCPU-s + 0.20 ms × events |
The event term is the one that matters. A coding agent streams roughly one event per generated token, so a turn that writes 600 tokens costs about five times a turn that writes 100 — even though both are small responses. Note that DLP is almost entirely a per-event cost, not a fixed one: it inspects the stream as it passes, so a longer answer pays more.
| Response length | Streamed events | disabled | audit | enforce |
|---|---|---|---|---|
| ~200 tokens (short answer, tool call) | ~200 | 0.05 vCPU-s | 0.06 vCPU-s | 0.07 vCPU-s |
| ~600 tokens (typical agent turn) | ~600 | 0.10 vCPU-s | 0.13 vCPU-s | 0.15 vCPU-s |
| ~1 000 tokens | ~1 000 | 0.16 vCPU-s | 0.20 vCPU-s | 0.23 vCPU-s |
| ~2 000 tokens (long code write) | ~2 000 | 0.30 vCPU-s | 0.38 vCPU-s | 0.43 vCPU-s |
Prompt size is close to free by comparison: a 150 KB prompt costs about the same as a 16 KB one, because the router parses a request once and does not re-read it.
enforce also adds a consistent ~11 ms to time-to-first-token — it releases
the stream in governed 512-character windows and holds back a 256-character tail
so a finding straddling a boundary is still caught. That cost is flat: it does
not grow with the length of the answer. audit adds no measurable TTFT, because
it inspects without holding anything back.
Sizing for a developer population
Size from turns per second, not from how many developers hold an account. A developer with an agent open is not streaming continuously — they read, edit, and think between turns. The fraction of time their tool is actually streaming is the duty cycle, and it is the number that decides your CPU.
For 1 000 developers issuing typical 600-token turns of roughly 15 seconds each:
Provisioned vCPU below is at a 65 % utilisation target, for all three DLP modes:
| Duty cycle | Concurrent streams | Turns/s | disabled | audit | enforce | Replicas |
|---|---|---|---|---|---|---|
| 10 % — occasional use | 100 | 6.7 | 1.1 vCPU | 1.3 vCPU | 1.5 vCPU | 2 |
| 25 % — steady coding-agent use | 250 | 16.7 | 2.6 vCPU | 3.3 vCPU | 3.8 vCPU | 4 |
| 50 % — heavy, agent-driven | 500 | 33.3 | 5.3 vCPU | 6.7 vCPU | 7.5 vCPU | 8 |
| 100 % — every developer streaming at once | 1 000 | 66.7 | 10.5 vCPU | 13.4 vCPU | 15.1 vCPU | 16 |
Turning DLP on costs roughly 25 % more CPU per turn in audit and 50 % in
enforce, on a typical agent turn. That is a real cost but rarely the deciding
one — the replica count below moves first.
The replica count is usually the binding number, not the vCPU total. Each
pod accepts auth.maxInFlight open calls (default 64; router turns, platform
API calls and MCP tool calls share it — the older auth.llmRouter.maxInFlight
still works as a fallback), so the
minimum replica count is concurrent streams ÷ 64 regardless of how much CPU
headroom a pod has. At 250 concurrent streams that is 4 replicas holding about
3.5 vCPU between them — well under the 2000m limit each one is allowed. Raise
maxInFlight and the CPU limit together, or add replicas; do not raise one
alone.
Validating your own numbers
The figures above are a starting point, not a substitute for measuring your own traffic. Turn length, DLP posture, and how agent-heavy your developers are all move the result by more than the modelling error. Once traffic is real, the metrics on the AI Gateway capacity section tell you where you actually are:
scrydon_llm_router_streams_in_flightagainst yourmaxInFlight— how close a pod is to shedding.scrydon_llm_router_admission_rejections_total— sustained non-zero at steady state means add a replica, not client retries.scrydon_llm_router_overhead_msversusscrydon_llm_router_provider_ttfb_ms— separates time your platform spent from time the provider spent, so you can tell a capacity problem from a slow model.
A single organisation has a second ceiling, independent of CPU. Each turn
writes hash-chained audit evidence, and that evidence is ordered per
organisation — so one tenant's sustained turn rate is bounded by how fast its
audit chain commits, and adding replicas does not move it. Two audit writes per
turn, or four when DLP runs in enforce.
Our capacity suite measures that commit at 3-10 ms, which puts one organisation
somewhere between roughly 100 and 380 audit writes per second — comfortably
above every row in the table above except the last one under enforce. If you
are placing all 1 000 developers in one organisation and running DLP in
enforce and expecting them to stream simultaneously, validate that
combination before committing to it. Traffic spread across several
organisations does not share the ordering and is not affected.