Platform Services

Diminuendo is a pure gateway. It does not execute agent code, does not invoke tools, and does not call language models. Those responsibilities belong to three upstream platform services — Podium, Chronicle, and Ensemble — each accessed through an Effect service with circuit-breaker resilience, exponential retry, and health probing. The gateway’s role is to mediate: it translates between the client-facing wire protocol and the platform services’ internal APIs, maps events from one vocabulary to another, and ensures that transient failures in any upstream service degrade gracefully rather than cascading into the client connection.

Podium: Agent Orchestration

Podium is the agent orchestration platform that manages compute instances, agent lifecycles, and message routing. Diminuendo connects to Podium as an upstream service — creating compute instances for coding agents, establishing WebSocket connections to stream events, and proxying file operations to agent workspaces.

PodiumClient

The PodiumClient is an Effect service (Context.Tag) that encapsulates all communication with the Podium coordinator. It provides five core operations:
export class PodiumClient extends Context.Tag("PodiumClient")<PodiumClient, {
  readonly createInstance: (params: {
    agentType: string
    agentId?: string
    secrets?: Record<string, string>
    environment?: Record<string, string>
  }) => Effect.Effect<{ instanceId: string; deploymentId: string }, PodiumConnectionError>

  readonly connect: (instanceId: string) =>
    Effect.Effect<PodiumConnection, PodiumConnectionError>

  readonly isAlive: (instanceId: string) => Effect.Effect<boolean>

  readonly stopInstance: (instanceId: string) =>
    Effect.Effect<void, PodiumConnectionError>

  readonly listFiles: (instanceId: string, path?: string, depth?: number) =>
    Effect.Effect<FileEntry[], PodiumConnectionError>
  readonly readFile: (instanceId: string, path: string) =>
    Effect.Effect<FileContent, PodiumConnectionError>
  readonly fileHistory: (instanceId: string, path: string) =>
    Effect.Effect<IterationMeta[], PodiumConnectionError>
  readonly fileAtIteration: (instanceId: string, path: string, iteration: number) =>
    Effect.Effect<FileContent, PodiumConnectionError>
}>() {}
The PodiumClientLive layer reads PODIUM_URL and PODIUM_API_KEY from the application config and provides the concrete implementation.

Instance Lifecycle

The lifecycle of an agent instance follows a predictable four-phase pattern:
1

Create Instance

When a user starts a session or an inactive session is reactivated, the gateway calls createInstance with the agent type, deployment descriptor, secrets, and environment variables.
POST /api/v1/instances
{
  "deployment_id": "coding-agent:1.0.0@local",
  "agent_id": "optional-agent-id",
  "secrets": { ... },
  "environment": { ... }
}
--> { "instance_id": "inst-abc123", "deployment_id": "..." }
The deployment ID is constructed as {agentType}:1.0.0@local from the session’s agent type.
2

Connect via WebSocket

After instance creation, the gateway establishes a WebSocket connection to the instance’s event stream:
ws://{PODIUM_URL}/api/v1/instances/{instanceId}/connect
This returns a PodiumConnection object with methods to send messages, access the event stream, and close the connection.
3

Stream Events and Send Messages

The connection remains open for the duration of the session. Messages from the user are sent via sendMessage(content). Events from the agent arrive through the events stream (Stream.Stream<PodiumEvent>).
4

Stop Instance

When a session is deactivated or the gateway shuts down, the instance is stopped:
DELETE /api/v1/instances/{instanceId}
A 404 response is treated as success — the instance may have already been reclaimed by Podium.

PodiumConnection

The PodiumConnection interface represents an active WebSocket connection to a Podium instance:
export interface PodiumConnection {
  readonly instanceId: string
  readonly sendMessage: (content: string, metadata?: Record<string, unknown>) =>
    Effect.Effect<void, PodiumConnectionError>
  readonly sendRaw: (data: string) =>
    Effect.Effect<void, PodiumConnectionError>
  readonly events: Stream.Stream<PodiumEvent, PodiumConnectionError>
  readonly close: Effect.Effect<void>
}
Messages are sent as JSON with a process_message envelope:
{
  "type": "process_message",
  "content": {
    "text": "Fix the authentication bug in auth.ts",
    ...metadata
  }
}

PodiumEvent and Event Mapping

Events arriving from Podium carry a messageType field and an optional content object:
export interface PodiumEvent {
  readonly messageType: string
  readonly content?: Record<string, unknown>
  readonly agentId?: string
}
The PodiumEventMapper (src/domain/PodiumEventMapper.ts) is a pure function that translates Podium’s 30+ message types into Diminuendo’s 51-event wire protocol. Each Podium event is transformed into one or more client events with session-scoped sequence numbers and timestamps.

Turn Lifecycle

Podium MessageClient EventDescription
created / stream_startturn_startedAgent begins processing
update / stream_updatetext_deltaIncremental text output
complete / stream_end / stream_completeturn_completeAgent finishes processing
errorturn_errorAgent encountered an error

Tool Events

Podium MessageClient EventDescription
tool.call_starttool_call_startTool invocation begins
tool.call_deltatool_call_deltaStreaming tool arguments
tool.calltool_callComplete tool invocation with args
tool.resulttool_resultTool execution result
tool.errortool_errorTool execution failed

Interactive Events

Podium MessageClient EventDescription
tool.question_requestedquestion_requestedAgent needs user input
tool.permission_requestedpermission_requestedAgent needs action permission
tool.approval_resolvedapproval_resolvedPermission request resolved

Thinking Events

Podium MessageClient EventDescription
thinking.startthinking_startAgent begins reasoning
thinking.progress / thinking_updatethinking_progressIncremental thinking text
thinking.completethinking_completeReasoning phase complete

Terminal Events

Podium MessageClient EventDescription
terminal.streamterminal_streamTerminal output data
terminal.completeterminal_completeCommand finished (with exit code)

Sandbox Events

Podium MessageClient EventDescription
sandbox.provisioningsandbox_provisioningSandbox environment being set up
sandbox.initsandbox_readySandbox ready for use
sandbox.removedsandbox_removedSandbox torn down

Session Lifecycle

Podium MessageClient EventDescription
terminatingsession_state (state: terminated)Agent shutting down
terminatedsession_state (state: terminated)Agent process exited

Usage Events

Podium MessageClient EventDescription
usage / usage.updateusage_updateToken counts, model, cost per turn
context / usage.contextusage_contextTotal token usage and context window
Any Podium event that does not match a known message type but contains text content is treated as a text_delta fallback. Events with no matching type and no content are silently dropped (mapped to an empty array).

File Operations Proxy

File access messages from clients are proxied through to Podium’s REST file API:
Client MessagePodium API
list_filesGET /api/v1/instances/{id}/files?path={path}&depth={depth}
read_fileGET /api/v1/instances/{id}/files/{path}
file_historyGET /api/v1/instances/{id}/files/{path}/history
file_at_iterationGET /api/v1/instances/{id}/files/{path}/at/{iteration}
All file API calls use a 15-second timeout and propagate PodiumConnectionError on failure. File operations require an active Podium instance for the session — if the session is inactive, the gateway must first activate it before file operations can proceed.

Resilience

Circuit Breaker

The createInstance method is protected by a circuit breaker:
ParameterValue
Failure threshold5 consecutive failures
Cooldown period30 seconds
Reset behaviorHalf-open after cooldown; first success closes the breaker
When the circuit breaker is open, createInstance calls fail immediately with a PodiumConnectionError rather than attempting the HTTP request.

Exponential Retry

Failed requests are retried with exponential backoff and jitter:
ParameterValue
Initial delay500ms
Backoff schedule500ms, 1s, 2s, 4s
Max retries3
JitterApplied to each delay

Connection Deduplication

The gateway prevents parallel createInstance calls for the same session. If a session is already in the activating state (meaning a createInstance call is in flight), a second activation request for the same session will wait for the first call to complete rather than issuing a duplicate request to Podium.

Health Probe

The isAlive(instanceId) method checks whether a Podium instance is still running via a 5-second timeout HTTP probe:
isAlive: (instanceId) => Effect.tryPromise({
  try: async () => {
    const res = await fetch(`${podiumUrl}/api/v1/instances/${instanceId}`, {
      headers: authHeaders,
      signal: AbortSignal.timeout(5000),
    })
    return res.ok
  },
  catch: () => false,
})
This probe is used by the /health endpoint to assess Podium availability, and by the stale session recovery mechanism to determine whether a session’s Podium instance survived a gateway restart (it never does — Podium connections do not survive process death).