cellos-telemetry
The in-guest CellOS telemetry agent. Runs as PID 2 inside every Firecracker microVM, declares process/network/capability events to the host supervisor over vsock, and holds no signing key.
What it is
cellos-telemetry is the runner-evidence wedge of ADR-0006: the
process the host trusts to describe what is happening inside a guest,
because the channel it speaks on (a vsock CID:port the supervisor
bound before the workload existed) is the authenticity primitive — not
a signature on the payload.
Layer L2 (host runtime / isolation) — guest-side. Forked by
cellos-init as PID 2 before the
workload process (PID 3+) starts. The workload's seccomp profile
blocks kill(2), tgkill(2), and ptrace(2) against PIDs ≤ 2; the
agent is structurally unreachable from the workload.
What it isn't:
- Not the host-side receiver.
cellos-host-telemetry(separate crate) is the host-resident CBOR-over-vsock listener that host-stamps arriving frames withcell_id,run_id,host_received_at, and the ADGoutputblock. This crate produces only the guest fields. - Not a signer. The crate's
Cargo.tomlcarries a hard-coded DENY list (ring,ed25519-dalek,hmac,rustls,webpki,sha2-as-mac) enforced bycargo-denyin CI. ADR-0006 §5 — Claim 5a: the guest agent never holds a key. Dependencies arelibc+ value types fromcellos-core. A compromised guest could sign anything; signature-in-guest is theatre. The host trusts the channel, not the payload. - Not a kernel tracer. Probes are
/procdeltas, one declaredinotifywatch, and (stubbed) connect/capability surfaces — no eBPF, no kprobes, no kernel modules.
Public API surface
Crate-level constants
| Constant | Value | Meaning |
|---|---|---|
WIRE_CONTENT_VERSION_MAJOR |
1 |
CBOR wire-format major. Must match cellos_host_telemetry::WIRE_CONTENT_VERSION_MAJOR or the host rejects the frame. |
VSOCK_TELEMETRY_PORT |
9001 |
Well-known guest→host vsock port. |
VMADDR_CID_HOST |
2 |
Host CID per the AF_VSOCK ABI. |
MAX_FRAME_BODY_BYTES |
4096 |
Per-frame body cap. |
Probe identifiers (probes::*)
process.spawned,process.exited(/procdelta walker — implemented)capability.denied(stub — kernel surface not yet wired)fs.inotify_fired— declaredinotifywatchnet.connect_attempted(stub)
probes::ALL enumerates every known probe id; probes::is_known(s)
gates declaration acceptance.
Wire types
GuestTelemetryDeclaration— the agent's declared probe surface, projected fromcellos_core::DeclaredAuthoritySurfaceso the host can subset-checkdeclared ⊆ authorizedat admission (F3 admission-path prep, 2026-05-16).ProbeEvent— a single emitted event (guest fields only:probe_source,guest_pid,guest_comm,guest_monotonic_ns,content_version).WireError— decode failure reasons.
CBOR codec (src/lib.rs)
encode_event_body/decode_event_body— bare CBOR map(5) body.encode_frame/decode_frame—u32 LE length || bodyframing.
The codec is hand-rolled and minimal: definite-length map(5), uint
major (0), text major (3). No floats, no tags, no indefinite lengths.
content_version is always emitted first so the host can short-circuit
unknown majors before walking unknown probe-source strings.
Probe modules
probes::process—/procdelta walker for spawn/exit.probes::inotify— one declaredinotifywatch.probes::capability— capability-denied stub.probes::net_connect— connect-attempted stub.
The CBOR + framing core is pure-safe Rust (#![deny(unsafe_code)]).
Syscall surfaces under probes/ opt out per-module — libc::inotify_init1,
socket, connect, fork have no safe wrapper at this layer.
Architecture
The wire shape from src/lib.rs:
u32 LE length || CBOR map(5) {
"content_version" => u16 (FIRST — host short-circuits unknown major)
"probe_source" => text
"guest_pid" => u32
"guest_comm" => text
"guest_monotonic_ns" => u64
}
The agent fills only those five fields. The supervisor host-stamps
cell_id, run_id, host_received_at, spec_signature_hash, and
the ADG output block on receipt; anything the agent puts in those
fields is overwritten. That asymmetry is intentional — it is what
makes the channel the authenticity primitive.
Back-pressure (ADR-0006 §5.3): drop-with-counter. The agent
surfaces drops via the cell.observability.guest.telemetry.dropped
counter, never by blocking the workload. The workload's progress is
never coupled to the agent's I/O.
Configuration
No env vars and no config file. The agent is parameterised entirely
by what cellos-init and the supervisor put on the kernel cmdline +
the bound vsock channel. The VSOCK_TELEMETRY_PORT is a compile-time
constant; the host binds the matching (CID, port) before the workload
runs.
Examples
The agent is not invoked directly; it is forked by cellos-init. From
inside a supervisor integration test, the host-side counterpart looks
like:
// Pseudo-code — actual host receiver lives in cellos-host-telemetry.
use ;
let mut buf = ;
let n = vsock_listener.accept?;
let event = decode_frame?;
// host-stamp cell_id, run_id, host_received_at, ADG output …
Testing
Unit tests live inline. Public-surface coverage focuses on the codec round-trip and the probe-id surface:
cargo test -p cellos-telemetry
Integration tests for the in-guest agent live alongside
cellos-init and cellos-host-firecracker — the agent is exercised
end-to-end through a real (or mocked) vsock channel.
The "no signing primitive" claim is enforced at the workspace level by
cargo-deny (deny.toml): the cellos-telemetry musl target dep set
is asserted to be libc + cellos-core value types only. Session 19
ratified this; see ADR-0006 Claim 5a / Claim 7.
Related crates
cellos-init— PID-1 init that forks this agent as PID 2 before the workload starts.cellos-core—DeclaredAuthoritySurface- value types projected into
GuestTelemetryDeclaration.
- value types projected into
cellos-host-telemetry— the host-side receiver. It host-stamps arriving frames and emits the typed CloudEvents downstream.cellos-host-firecracker— binds the per-cell vsock CID and theVSOCK_TELEMETRY_PORTchannel before the workload runs.
ADRs
- ADR-0006 —
in-VM observability as the runner-evidence wedge. This crate is the
concrete implementation. Key claims this crate enforces:
- Claim 5 — no signing key in the guest; supervisor signs outbound CloudEvents using its host-side key after host-stamping.
- Claim 5a —
cellos-telemetryCargo manifest forbids any signing primitive; CI cargo-deny gate enforces. - §5.2 — agent runs as PID 2, forked by
cellos-initbefore the workload (PID 3+). - §5.3 — drop-with-counter back-pressure.
- §12 — wire-schema versioning (
content_versionfirst).
- ADR-0001 — the proprietary host backend decision that puts the guest-observation surface inside the cell.