Agents, sessions, sandboxes and trust tiers#
Four nouns describe where an agent's code runs. They map to Kubernetes resources in the maqpna.com/v1alpha1 API group.
| Term | Kind | Scope | In one sentence |
|---|---|---|---|
| agent | Agent |
Namespaced | The definition: image, trust tier, tools, model, policy, scopes, budget |
| session | AgentSession (short name asess) |
Namespaced | One run of an agent for one user, with its own sandbox, identity and token |
| sandbox | upstream Sandbox or SandboxClaim |
Namespaced | The isolated environment one session runs in |
| trust tier | TrustTier (short name tier) |
Cluster | The isolation level: RuntimeClass, jurisdiction, egress mode, maximum TTL |
flowchart LR
TT["TrustTier tier-1-microvm<br/>runtimeClassName: kata-fc<br/>jurisdiction: EU-DE"]
A["Agent team-a/coder<br/>image · tools · model<br/>policyRef · scopes"]
S1["AgentSession fix-4821<br/>user alice@acme.eu"]
S2["AgentSession fix-4822<br/>user bob@acme.eu"]
SB1["Sandbox fix-4821<br/>(Kata microVM)"]
SB2["Sandbox fix-4822<br/>(Kata microVM)"]
A -- "spec.tier" --> TT
S1 -- "spec.agentRef" --> A
S2 -- "spec.agentRef" --> A
S1 -- owns --> SB1
S2 -- owns --> SB2
Agent#
An agent is an AI program that uses tools. MAQPNA does not care how it is written; it needs an Agent resource that says:
image(and optionallycommand,args,env): what to run;tier: the name of aTrustTier;tools[]: the MCP servers it may call, each byserverRefto anMCPServer(or the deprecatedupstreamURL);model: an OpenAI-compatible endpoint, reached only through the gateway's model route;policyRef: theToolPolicyin its namespace;scopes: what its sessions may request (defaulttools:<name>for each tool);budget,maxConcurrentSessions,idleTimeout(default 15 minutes),maxSessionTTL;profile:default,browserorcodeInterpreter, which adds sidecars to the sandbox.
The agent is only a definition. Nothing runs until a session is created.
Session#
A session is one run of an agent, from start to result, acting for one person (spec.user). Every governed call belongs to exactly one session. A session has:
- its own sandbox, owned by the
AgentSessionand deleted with it; - its own identity: a SPIFFE-style ID
spiffe://<trust-domain>/ns/<ns>/agent/<agent>/session/<session>; - its own token, minted by the identity broker with the session's scopes, which must be a subset of the agent's (
ScopeEscalationotherwise); - a TTL:
min(spec.ttl or the 1-hour default, tier maxSessionTTL, agent maxSessionTTL).
A session moves through these phases (status.phase):
stateDiagram-v2
[*] --> Pending
Pending --> Provisioning: admitted (quota free)
Pending --> Failed: AgentNotFound, TierNotFound,<br/>ScopeEscalation, SovereigntyViolation
Provisioning --> Running: sandbox Ready<br/>(claim mode: pod bootstrapped)
Provisioning --> Failed: AttestationFailed, InputInvalid,<br/>PrincipalUnverified, Revoked
Running --> Suspended: spec.suspend, idle timeout,<br/>revocation with action suspend
Suspended --> Running: resume or new activity
Running --> Completed: sandbox Finished or TTL reached
Suspended --> Completed: TTL reached
Running --> Failed: revocation with action terminate
Completed --> [*]
Failed --> [*]
When a session ends, the operator records a result in status.outcome.result: Succeeded, Failed, Expired, Revoked or Cancelled. Phase and result are separate: an agent that exits with code 1 ends in phase Completed with result Failed. The full reconcile is in session lifecycle.
Sandbox#
The sandbox is the isolated environment one session runs in. MAQPNA does not build its own: it creates an upstream Sandbox (or, for warm pools, a SandboxClaim) from the kubernetes-sigs/agent-sandbox project, unstructured so MAQPNA is not tied to one agent-sandbox release (--sandbox-api-version, default v1beta1).
Every sandbox pod the operator builds is hardened the same way:
runtimeClassNamefrom the trust tier, so agent code never runs under plainrunc;- non-root (UID and GID 65532), seccomp
RuntimeDefault, read-only root filesystem, all capabilities dropped; automountServiceAccountToken: falseandenableServiceLinks: false: the agent gets no Kubernetes credentials;- the session token mounted read-only at
/var/run/maqpna/token; - a per-session NetworkPolicy
<session>-maqpna: ingress only from the gateway, egress only to DNS and the gateway (plus the attestation service or identity broker bootstrap port when needed).
The sandbox never learns real tool or model URLs. It gets MAQPNA_TOOL_<NAME>_URL={gateway}/mcp/<name> and MAQPNA_MODEL_ENDPOINT={gateway}/llm/<route>/v1.
Warm pools#
A trust tier with sandboxTemplateName and warmPoolSize keeps pre-started sandboxes in an upstream SandboxWarmPool named maqpna-<tier>. Sessions on that tier claim one. Because agent-sandbox only adopts warm pods for claims without environment variables, MAQPNA uses late binding: the claim carries nothing, and the adopted pod fetches its environment, task and a fresh token from the identity broker's /v1/bootstrap endpoint with a projected ServiceAccount token. No session token is ever stored in the claim, the pod spec or the session status.
Trust tier#
The trust tier is the isolation level a session runs at. The Helm chart ships three:
| Tier | Isolation | RuntimeClass | What it protects against |
|---|---|---|---|
tier-0 (gVisor) |
gvisor |
gvisor (runsc) |
Most kernel attack surface: system calls are served by a user-space kernel |
tier-1 (microVM) |
microvm |
kata-fc (Kata Containers + Firecracker) |
Host kernel exploits: each sandbox has its own guest kernel |
tier-2 (confidential VM) |
confidential |
kata-qemu-snp (Kata with AMD SEV-SNP or Intel TDX) |
The infrastructure operator reading memory: memory is encrypted and the token is released only after attestation |
A TrustTier also sets jurisdiction and allowedNodeLabels (required node affinity), egress (gateway-only or deny-all), defaultResources, maxSessionTTL and attestationRequired. The isolation field is descriptive: the operator copies runtimeClassName into the pod, and uses isolation only for attestation and sovereignty checks.
What you see#
maqpna session list prints one row per session:
NAME AGENT USER PHASE OUTCOME READY-IN AGE
fix-4790 coder bob@acme.eu Completed Succeeded 2.43s 118m
fix-4821 coder alice@acme.eu Running - 1.71s 3m
The columns are fixed in cmd/maqpna/session.go; the rows are illustrative. Rows are sorted by namespace and name, and empty values print as -. READY-IN is status.readyIn, the time from creation to first Running. See maqpna session list, maqpna session describe and maqpna tier list.
Related#
- Session lifecycle, step by step
- Operator
- CRD data model
- Identity and delegation