Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,19 @@ _Avoid_: Budget cap, kill limit
**Pinned runtime**:
The single approved agent-SDK release, together with the Claude Code CLI shipped inside it, that every model execution must run on. Pinning the SDK pins the CLI; the CLI never has a version of its own to keep in step. Provenance verification confirms at startup that the CLI about to run is exactly the one this release ships, and refuses to start otherwise.
_Avoid_: Runtime pair, SDK and CLI pins, the CLI on PATH

**Dashboard**:
A separate operator view over the managed instances on one Docker host. It observes instances and, from its second version, relays operator commands to them; it never claims issues or takes part in an implementation attempt.
_Avoid_: Control panel, monitor, fleet manager

**Managed instance**:
One agent container that a dashboard discovers and observes, serving exactly one target repository. It is identified by its container name, so recreating the container keeps the same managed instance; a container started for a one-off command is never a managed instance.
_Avoid_: Agent, worker, node

**Telemetry snapshot**:
A point-in-time, read-only report a managed instance gives about itself: its control state, the current (or last finished) implementation attempt's token, budget and context figures, and its most recent events. The agent owns and versions it; a dashboard only reads it and tolerates versions it does not fully know.
_Avoid_: Status, metrics, heartbeat

**Figure basis**:
How a figure in a telemetry snapshot was obtained: `measured` (reported by the provider), `estimated` (computed by the agent), `configured` (set by the operator), `sdk_assumed` (a default the runtime assumes for an unknown model), or `unavailable` (no trustworthy source). An unavailable figure is never shown as zero.
_Avoid_: Provenance (reserved for provenance verification of the pinned runtime), source, confidence
14 changes: 14 additions & 0 deletions docs/adr/0006-telemetry-through-agentctl-not-http.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Serve fleet telemetry through agentctl over the control socket, not an HTTP endpoint

A dashboard needs each managed instance's telemetry snapshot. We decided the agent serves it only as a read-only `telemetry` operation on the existing container-local control socket, exposed as `agentctl telemetry --json`, and the dashboard reads it by running `docker exec --user agent <container-id> /usr/local/bin/agentctl telemetry --json`. The agent publishes no port and opens no listener beyond the control socket, so "container = instance, no published control port" stays true, and the telemetry needs neither a token nor a setting to turn it on.

## Considered Options

- **An opt-in HTTP endpoint inside the agent, guarded by a token.** Rejected: it adds a network listener, a secret to provision and rotate per instance, and a second protocol to keep in step with `agentctl`, all to save the dashboard from needing Docker `exec`. The operator commands planned for the dashboard's second version would need the same endpoint to become writable, which would turn a read-only convenience into a remote control surface.
- **Status written to a shared volume or file.** Rejected: it needs a mount per instance and gives no way to tell a stalled agent from a quiet one, which a live socket reply does.

## Consequences

- The dashboard holds more Docker power than an HTTP pull would need (`exec` into the agent containers). The dashboard project contains this by running as the operator's own host process, bound to `127.0.0.1`, with one gateway module that can only list instances and run `agentctl telemetry`.
- The control server answers connections one at a time, so the `telemetry` handler must only serialise data that is already prepared. It does no network or git I/O, waits at most briefly for the control lock, and never lets an error escape into the listener.
- Every poll costs one `docker exec` and one Python start-up per instance, so dashboards poll on the order of seconds, not sub-second.
Loading