How hosting works
read as.mdThis page explains the machine underneath your deployed app: what actually runs, what it guarantees, and what happens at the edges — pod replacement, saturation, an expired trial, a runtime update. For the how-to — deploy commands, guuey.json, MCP flavors — see Hosting & runtime.
One pod per app, not per conversation
Section titled “One pod per app, not per conversation”Deploying an app creates one dedicated, long-running pod for it, in its own Kubernetes namespace. The unit is the app — never the conversation, the user, or the request. All of an app’s conversations share its pod (or pods, once it scales), and the process serving the first message of the day is the same one that served the last message of yesterday. There is no cold start to absorb, and nothing to warm up: an idle agent is still a running agent.
This is deliberate asymmetry: MCP servers you host on Guuey scale to zero when idle and wake on the next call, because a stateless tool server can afford a wake-up. Your agent can’t — so it never sleeps while its plan or trial is active.
Isolation and sandboxing
Section titled “Isolation and sandboxing”Each app’s pod lives in its own namespace behind a default-deny network: nothing else in the cluster can connect to it, and it can reach the public internet but not other tenants, in-cluster services, or the cloud provider’s credential endpoints.
Workloads that run your code — a code-mode agent’s image, an MCP server you host — run under gVisor. What that means concretely: the workload’s system calls are handled by a user-space kernel instead of the host’s, so the classic container-escape surface (a shared host kernel reachable by any syscall) is structurally reduced. That is the property that lets Guuey host arbitrary compute — code execution, binaries, headless browsers — as ordinary workloads. A no-code agent’s pod runs Guuey’s own runtime image and is not a gVisor workload today; its isolation is the same namespace and default-deny network plus the jail around the worker that executes agent turns — a bubblewrap sandbox per session with a cleared, allowlisted environment that never contains a managed model key.
The full isolation model — network posture, credential custody, what Guuey structurally cannot reach — is on Security & isolation.
Sizes are reservations, not hints
Section titled “Sizes are reservations, not hints”A pod size (xs–xl) is a fixed CPU and memory allocation, reserved and capped at the same value. In Kubernetes terms the pod runs in the Guaranteed quality-of-service class: a noisy neighbor cannot starve your pod, and your pod cannot burst into anyone else’s. When you pick md, you have 1 vCPU and 1 GiB — not “up to”, not “shared”.
Each size also carries a bounded pod-local scratch allowance for working files — separate from durable per-user storage, which is its own primitive (State & memory). The size table, billing units, and which sizes each plan may use are on Plans & billing.
Replicas and per-user pinning
Section titled “Replicas and per-user pinning”maxPods is a live knob: raise it and the platform converges to the new replica count within about five minutes, with no redeploy and no restart of existing pods. The ceiling comes from the app’s plan; asking past it is refused with the ceiling named, never silently clamped.
Scaling out does not change what any single user experiences, because each user’s traffic is pinned to one pod: requests are routed by a consistent hash of the credential each request carries — the same one that identifies the user — so every request and every conversation from one user lands on the same replica for as long as that credential is in use. Pinning is per user, not per conversation: two chats from the same person share a pod on purpose, because pod-local working files are kept per user.
When a pinned pod goes away — a scale-down, a runtime update, a node replacement — that user’s next request re-pins to a live pod. A refreshed sign-in token re-pins the user the same way. Conversation history is unaffected (it lives off-pod, see below); pod-local scratch starts fresh on the new pod, and agents are expected to treat it as working space, not a store.
What failure looks like
Section titled “What failure looks like”The failure modes have designed answers, not accidents:
- Pod replacement is drain-aware. A pod being retired finishes its in-flight turns first — including multi-step tool loops mid-flight — before it exits. New requests arriving during the drain get a structured
503and land on a live pod on retry. Deploys and runtime updates roll with a surge replica, so a replacement is ready before the old pod is asked to go. - Saturation is refused, not absorbed. Each pod caps how many turns it runs concurrently for its size. Past the cap, excess requests get a structured
503 POD_SATURATEDwith aRetry-Afterhint; Guuey’s chat surfaces show a high-demand notice and retry automatically. A burst therefore degrades into structured refusals the client can retry, instead of the pod taking on more turns than its size can hold. - A failed deploy never takes down what’s serving. Rollouts keep the previous pod running until the new build is ready, so a build that can’t come up leaves the old version serving. An app with no healthy build at all is parked at zero rather than left crash-looping; the next deploy is what revives it.
Pause, resume, and lapse
Section titled “Pause, resume, and lapse”An app’s runtime posture follows its billing state, and every transition has a documented way back:
- Trial end. Every app gets a 7-day trial from its first successful deploy — the clock is stamped once and never restarts. If the trial ends with no plan, the app pauses: replicas go to zero, the public chat surface says the agent is paused, and a redeploy is refused. Nothing is deleted — history, settings, and domains are kept. Choosing a plan resumes the app automatically within a few minutes, no redeploy needed. Details, the one-trial-at-a-time rule, and warning emails: Plans & billing.
- Payment failure. The app keeps serving, clamped to one pod, while the payment is retried — see Plans & billing.
- Plan lapse. When a plan stops being honored — canceled or unpaid, as opposed to a payment merely being retried — the app becomes plan-less, and the same 7-day clock decides what happens next. Past that window (which is every app older than a week) it pauses exactly like a trial end — pod to zero, history/settings/domains kept, redeploy refused — and resumes automatically once a plan is on it again. Inside the window it keeps serving on the free tier’s posture (one
xspod) until the window ends. Nothing is resized on a transient billing hiccup: a retrying payment still honors the plan (see Payment failure above).
Runtime updates
Section titled “Runtime updates”Every agent pod runs on Guuey’s runtime image, and the platform ships improvements to it continuously. The default is auto-update: when a new runtime is released, the platform rolls each app to it one at a time, with the same drain-aware, surge-first mechanics as a deploy — in-flight turns complete, and a ready replacement exists before the old pod exits. You never redeploy to receive a runtime update.
If you’d rather control the moment, --runtime-auto-update off (on guuey deploy or guuey agent config) pins the app to the exact runtime captured at its last deploy; each subsequent deploy captures the then-current runtime. Pinning is a scheduling preference, not a security exemption: a runtime with a serious vulnerability is rolled everywhere, pinned or not.
Code-mode apps are the one exception to hands-off updates: your image bakes the runtime in at build time, so runtime improvements reach a code-mode app on its next deploy — the platform never rebuilds your image behind your back.
The live stream and the durable record
Section titled “The live stream and the durable record”Two separate systems carry a conversation, and they fail independently:
- The live stream is transport. Responses stream over Server-Sent Events directly from the pod running your agent — the client connects straight to the app’s always-on address, with no relay in between. A stream is transient by design: it exists for the duration of a response.
- The durable record is storage. The transcript is persisted to the platform’s history store (DynamoDB) as the conversation happens, off-pod and independent of any open stream. Clients read history from the platform, not from the pod.
The split is what makes the lifecycle above safe: history survives pod replacement, scale-to-zero, pause, redeploy, and runtime updates, because the pod was never where it lived. A user can close the tab mid-conversation, come back after the app has been paused and resumed, and pick up the thread.
Where to go next
Section titled “Where to go next”- Hosting & runtime — deploy an app, declare MCP servers, pick sizes.
- Plans & billing — size table, pod pricing, plan ceilings.
- Security & isolation — the isolation model in depth.
- State & memory — durable per-user storage, and which environments have it enabled.
- API & contract stability — what you can build against today.