Files
cairnobs/proto
jcoffey-dev 93c160ec51 Add agent restart lifecycle command
Extends the existing CheckIn RPC with a one-shot AgentCommand
(restart only -- stop/uninstall need real per-platform OS
service-manager integration and stay deliberately out of scope),
delivered at-most-once: cleared the instant it's handed to the agent
in a response, since a restarting agent's process is gone before it
could ever confirm receipt. On restart, the agent flushes whatever's
buffered, aborts its source task, and exits cleanly, relying entirely
on the host's own service manager to bring it back up.

Issuing a command is gated at RoleAdmin (stricter than config
editing's RoleEditor) and logged into the same audit_log table Phase
7's AI interactions use, via a new agent_command event type.

A real bug was found and fixed during live verification: the first
implementation tried to atomically read-and-clear pending_command in
a single INSERT...ON CONFLICT statement using a sibling CTE
referenced only from RETURNING, on the assumption that Postgres
evaluates every part of a WITH query against one pre-statement
snapshot. That's wrong specifically for FOR UPDATE, which always
reads the latest row version including one written earlier in the
same statement -- confirmed empirically (a restart command was
always coming back empty even when genuinely pending, so the agent
never received it). Fixed by splitting into two real, ordered
statements inside one explicit transaction.

See /docs/agent-management-design.md's "Lifecycle commands" section.
2026-08-16 20:30:07 -07:00
..

proto

Shared .proto contracts. Source of truth for the agent↔ingest gRPC service; each language generates its own bindings from these files rather than sharing generated code across languages.

  • sentry/logs/v1/logs.protoLogIngest.PushBatch, the data-plane RPC an agent calls to ship log records.
  • sentry/agent/v1/agent_control.protoAgentControl.CheckIn, the control-plane RPC an agent calls (on its own heartbeat ticker, same push-not-pull posture) to report its config and fetch any remote override -- see /docs/agent-management-design.md. Same mTLS connection/listener as LogIngest, a second service on it rather than a second protocol.

Go bindings

Go is the one language here with pre-generated, checked-in bindings (sentry/logs/v1/logs.pb.go, logs_grpc.pb.go), living in this directory as its own module (github.com/sentry/sentry/proto) that /ingest and /api depend on via a local replace directive in their go.mod. Rust (/agent) instead generates its bindings at build time via tonic-build (see agent/sentry-agent/build.rs) — no checked-in Rust output.

To regenerate the Go bindings after changing either .proto file:

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

cd proto
protoc --go_out=. --go_opt=paths=source_relative \
       --go-grpc_out=. --go-grpc_opt=paths=source_relative \
       sentry/logs/v1/logs.proto sentry/agent/v1/agent_control.proto
go build ./...