4.9 KiB
Grid-agent control plane v1
The grid agent exposes one transport-neutral request/response and event API.
Integrated clients receive an InProcessControlClient; split clients use the
same ControlRequestEnvelope, ControlResponseEnvelope, and ControlEvent
types over TCP. No terminal, Unix socket, named-pipe, permission-bit, or
platform-specific type appears in the core API.
Transport and negotiation
TCP frames are a four-byte unsigned big-endian length followed by one UTF-8 JSON value. Empty, partial, malformed, idle, and oversized frames close the connection within configured deadlines. The first frame must be:
{"frame":"hello","body":{"version":1,"token":"separate-operator-capability"}}
The server answers with a hello containing version 1, the authenticated
operator or observer role, or a typed error. Every later client frame is a
request; server frames are response or event. Request IDs contain at most
96 ASCII identifier bytes and cannot be replayed on a connection. A caller can
cancel an active request by its ID. Responses and events can arrive in either
order, so clients correlate responses by request ID.
Plain TCP binds only to IPv4 or IPv6 loopback. Remote control is off by default and a non-loopback address is rejected unless both DER certificate and private key paths are explicitly configured. Remote mode uses Rustls before the hello exchange and emits an operator warning at startup. The TLS client API requires the embedding client to supply its certificate roots and server-name policy. Every split connection must still authenticate with a dedicated control token; observer and operator tokens must differ and configuration rejects reuse of an LLM API key or grid password. Tokens are absent from protocol errors, audit, serialization traits, and diagnostics.
Remote service configuration uses the JSON fields
control.remote_tls_certificate_der and
control.remote_tls_private_key_der together with a non-loopback
control.listen value. Both files are bounded, non-symlink DER files. Omitting
either field, or selecting a non-loopback address without both, fails
configuration before a listener is created.
Requests
The JSON request envelope is stable and versioned. For example:
{"version":1,"request_id":"health-1","request":{"method":"health"}}
Observers can call health, metrics, runtime, list_sessions,
list_scheduled_jobs, list_pending_approvals, list_audit_events,
list_observability_events, and subscribe_events. Operators can additionally
call cancel_request, pause_autonomy, resume_autonomy, cancel_action,
decide_approval, force_reconnect, expire_conversation, set_roaming_job,
inject_operator_message, and graceful_shutdown. Cancellation is a mutation
and is operator-only. List requests use an opaque numeric cursor and a page
size of 1 through 100.
Runtime projections contain lifecycle/readiness, session generation, safe
region and pose fields when known, behavior mode, control-queue utilization,
and aggregate budget use. Conversation responses contain metadata only. Audit
and approval responses exclude arguments, prompt contents, credentials,
authorization headers, capability URLs, model reasoning, and filesystem data.
Unified events use pseudonymous correlation IDs and fixed-cardinality metrics;
their schema, journal, redaction, and replay rules are documented in
grid-agent-observability.md.
cancel_action binds to the exact bounded action ID carried by behavior audit
observations; it can cancel a queued or executing embodied action without
preempting unrelated work. The built-in roaming job ID is default-roaming.
Errors are typed as authentication_failed, version_mismatch,
permission_denied, invalid_request, replay, not_found, conflict,
cancelled, timed_out, busy, backpressure, frame_too_large,
idle_timeout, transport_closed, or internal, with a bounded safe message
and a retryable flag.
Events, bounds, and reconnect
Events carry monotonically increasing sequence numbers. A subscription can
resume after its last observed sequence. If retained history no longer covers
that point, its first item is an explicit gap with first_available and
last_missed, followed by retained events. Mutation events record the
authenticated role/connection principal, operation name, and completed or
rejected outcome, never request contents.
Connections, unauthenticated handshakes, in-flight request tasks, subscriptions, command/event queues, replay history, event history, event bytes, event rate, frames, pages, idle time, request time, and writes all have validated hard bounds. A full event or writer queue disconnects the slow consumer instead of blocking the headless service. With zero clients, event publication retains only the configured history and creates no background work. Server shutdown cancels and joins all listener, connection, request, and writer tasks within its deadline.