8.0 KiB
RVBox v1 control plane
../protos/rvbox/v1/control.proto defines
the canonical control API. rvc uses the Control gRPC service over the local
Unix-domain socket. The server also exposes the same unary operations through
an optional JSON-RPC 2.0 HTTP adapter for local debugging and batch automation.
Endpoints
- Unix socket: enabled by default, mode
0600, owned by the server account. - HTTP JSON-RPC: disabled unless enabled; default bind
127.0.0.1:6900. It has no authentication by design. Binding it beyond loopback is an explicit deployment choice and requires external protection.
gRPC streams command history and live events through FollowCommand. JSON-RPC
remains simple: callers issue work, query command state, poll event/output pages
after an event sequence, append stdin, close stdin, or signal a command. It does
not invent a separate event-stream protocol.
The JSON-RPC method names are the lower-camel protobuf operation names:
listClients, getClient, listCommands, getCommand, runCommand,
appendStdin, closeStdin, signalCommand, getOutput, and the three storage
incident methods documented below. Parameters and results use protobuf JSON
mapping (including base64 strings for bytes and UTC RFC 3339 strings for
timestamps). Control response messages contain successful results only. gRPC
failures use canonical non-OK status codes with structured RVBox details where
needed; the JSON-RPC adapter maps the same domain errors to standard JSON-RPC
error objects. getOutput and getCommand are the polling path for what gRPC
exposes as follow streams.
rvc stat CLIENT also shows the active durable client-instance ID and the most
recent different instance rejected while that client is live. An operator may
run rvc client takeover CLIENT INSTANCE-ID; this creates a one-shot 5-minute
authorization for that exact pending claim. Its matching reconnect consumes the
authorization and fences the old session. If the old session is no longer live,
the replacement connects normally without this command. The JSON-RPC method is
authorizeClientTakeover.
Both transports enforce the same decoded field limits. A control gRPC request
may be at most 16 MiB; a JSON-RPC HTTP body may be at most 24 MiB to accommodate
base64 expansion of the 10 MiB script maximum. ExecutionSpec itself may be at
most 768 KiB, which also keeps its agent dispatch below the 1 MiB envelope cap.
CLI semantics
rvc stat maps to ListClients, GetClient, ListCommands, and GetCommand.
History pages default to 20 commands and may request at most 100. Historical
output uses opaque, byte-bounded cursors and may resume within an output event;
it is not numbered or paginated by lines. The server returns uncompressed output
slices with event sequence, byte offset, stream, observed timestamp, and server
receipt timestamp. rvc may render line-oriented human output, but line
boundaries are not storage or pagination boundaries.
rvc run always creates a durable command through unary RunCommand, which
returns the UUID. Foreground mode then calls FollowCommand with that UUID,
after_event_seq=0, and include_existing=true, streaming output until a
terminal event. --background returns immediately after RunCommand.
Interrupting the CLI, timing out its local wait, or losing the local control
connection never cancels remote work. The explicit rvc kill operation is the
only termination path. A foreground caller can resume FollowCommand after its
last received event sequence without missing durable history.
FollowCommandResponse wraps either a client-sequenced CommandEvent or a
server-created retention marker and exposes server receipt/recording time
separately from client observation time. A retention marker does not advance the
resume cursor. When retained history is incomplete, the server emits the relevant
marker before any terminal event on that stream, so a follower never stops on
terminal while believing truncated history was complete.
Mutating requests accept an optional request_id. rvc generates one per
mutation and reuses it for transport retries; --request-id lets automation
reuse it across CLI invocations. The CLI accepts that option globally and drops
it for reads. For RunCommand, the supplied request ID is the command's
issue_uuid. For stdin, close, signal, repair, and acknowledgement operations
it deduplicates that action while issue_uuid or incident_id continues to
identify the target. The server generates a request ID when omitted, preserving
simple JSON-RPC use.
The server stores the mutation kind, target, immutable request hash, and result
under that ID. An identical retry returns the original result; reuse with any
different method, target, or content returns CONFLICT. The record is owned by
the affected command or incident for quota and retention. A retry after that
owner has been reclaimed cannot repeat the action: it returns retained
tombstone information where available or NOT_FOUND.
rvc run --queue-ttl controls how long work may wait for server-confirmed
acceptance and defaults to 15 minutes; zero means indefinite. rvc stat
distinguishes terminal Expired, Expired (awaiting reconciliation), and
actual lifecycle with a late-after-expiry warning. It renders terminal
Rejected with the client's structured validation/platform reason; Failed
means the requested code actually launched.
rvc run --elevated maps directly to ExecutionSpec.elevated; omission is
false. Non-Windows clients reject true as unsupported in v1. Windows chooses
the effective context from that bit and launch-time login state: normal commands
use active-user when possible and otherwise local-service; elevated commands
with an active user try active-user-elevated, active-system, then
local-system, while logged-out machines use local-system directly. These
fallbacks finish before launch_prepared and never retry a process.
Detailed rvc stat CLIENT ISSUE_UUID output shows requested elevation, every
attempted Windows context, selection/fallback detail, effective context and
process-token SID, and target session ID/owner SID when applicable.
active-system is rendered conspicuously as SYSTEM in another user's session,
never as that user. A pre-launch rejection shows the structured final context-
selection error rather than implying requested code ran.
rvc append turns a string into StdinWrite with append_newline=true unless
the caller selects raw mode; --file supplies raw bytes; --attach streams
local standard input. CloseStdin is available separately. All stdin actions
are acknowledged and idempotent.
Query behavior
Command details expose persisted request fields, effective execution metadata,
lifecycle, terminal result, output availability/truncation, current resource
snapshot, and suspected_hung diagnostics. The latter is informational and
must not be shown as a terminal state. Pagination response cursors are stable
within their declared ordering (newest issue time for command lists; increasing
event_seq for events/output).
Control failures are never embedded in otherwise-successful response messages.
They use canonical gRPC status codes with structured RVBox details; JSON-RPC
returns the corresponding JSON-RPC error object, and rvc maps the same domain
error to a stable exit code rather than parsing text.
Storage incidents
rvc storage incidents lists unresolved storage incidents by default and can
include resolved history. rvc storage repair INCIDENT attempts only a known
safe repair. rvc storage acknowledge INCIDENT --note ... accepts documented
irrecoverable loss and clears that incident from dirty health. Both mutations
use the same optional --request-id behavior as other mutations. An
acknowledgement note is required and bounded to 4 KiB. Repair or acknowledgement
changes incident state; it does not delete history as part of that action;
resolved history later follows the independent audit/incident quota. The
JSON-RPC equivalents are listStorageIncidents,
repairStorageIncident, and acknowledgeStorageIncident.