Runtime

Runtime

Application workers

Connect tool handlers to the Phrony runtime over the Work gRPC stream.

Overview

Application workers are long-lived processes that:

  1. Open a bidirectional Work gRPC stream to the runtime — one persistent connection both sides can send messages over, so the runtime can push jobs and the worker can push results without reconnecting each time.
  2. Register the tool@version handlers they implement (with capacity and contract metadata) — "here's what I can do and how many at once."
  3. Receive invoke messages, run handler code, and send result (the answer) or nack ("I can't take this one").
  4. Send heartbeats to renew their lease — a periodic "still alive" ping so the runtime knows the worker hasn't died mid-job.

The runtime routes model-emitted calls to registered workers. Workers do not call the model; they only execute tools.

Concept examples

Register (first message on the Work stream):

YAML
worker_id: worker-7
handlers:
  - tool: weather.get-forecast
    version: "1.0.0"
    max_concurrency: 4

Invoke → result → ack:

Text
Runtime → invoke(call_id=c1, tool=weather.get-forecast, args={ city: "Oslo" })
Worker  → result(call_id=c1, payload={ temp_c: 12 })
Runtime → result_ack(call_id=c1)    # worker may drop local state now

Heartbeat (keeps the lease alive):

Text
every ~TTL/2 seconds: worker → heartbeat
lease expired + no heartbeat → runtime treats worker as gone

Connect and register

Use the generated client for phrony.runtime.v1.Runtime / Work:

Text
Runtime.Work(stream WorkClientMsg) returns (stream WorkServerMsg)

First client message: register with:

FieldDescription
worker_id
Stable id for this process instance
workload_identity
Workload identity (for example SPIFFE ID, mTLS subject, or deployment label) checked against the tool allowlist when configured
image_digest
OCI image digest of the running worker image
handlers
List of tool, version, contract_version, descriptor_hash, max_concurrency
in_flight
Optional call_ids still executing or holding a result awaiting runtime ack (reconnect resync)

The runtime responds with registered and a lease TTL. Send heartbeat before the lease expires (typically at half the TTL interval).

Invocation lifecycle

sequenceDiagram
  participant R as Runtime
  participant W as Worker
  R->>W: invoke (call_id, tool, version, args, deadline)
  W->>W: Run handler
  W->>R: result (payload or error)
  R->>R: Persist outcome
  R->>W: result_ack (call_id)
Server → workerMeaning
invoke
Run one call; includes call_id, session_id, args, side_effect_class, deadline
cancel
Session cancelled; stop work for call_id
result_ack
Durable result recorded; worker may drop local state for call_id
Worker → serverMeaning
result
Success (payload) or handler error (error code + message)
nack
Worker refuses or cannot run the call (routing-level)

Hold results until result_ack. On reconnect, re-advertise in-flight call_ids in register so the runtime can dedupe and resume.

Handler advertisement

Each handler advertises a routing key tool@version that must match the manifest binding ref and version (not necessarily the wire name shown to the model).

Example manifest binding:

YAML
spec:
  tools:
    - ref: weather.get-forecast
      version: "1.0.0"
      side_effect_class: read_only

The worker registers tool: weather.get-forecast, version: 1.0.0, plus contract_version and max_concurrency.

Environment variables

Typical worker configuration:

VariableDescription
PHRONY_RUNTIME_ADDR
Runtime gRPC address (default 127.0.0.1:7777)
WORKER_ID
Instance id
WORKER_WORKLOAD_IDENTITY
Identity for allowlist checks
WORKER_IMAGE_DIGEST
Image digest for allowlist checks

Example worker

The tool-worker-playground repository is a minimal Go worker that registers a weather handler and connects to a local runtime. Use it as a reference implementation for stream handling, heartbeats, and dispatch.

Interactive sessions

When a session runs with attach/streaming, clients receive tool_call and tool_result events on the interactive stream, and approval_required when HITL blocks a call. Approvals use a separate client message on the interactive RPC.

Up next

Tool dispatch

Loop, failure modes, and session behavior.

Integrity and allowlist

Approve workers before dispatch.