This is the first executable real-agent path. It is deliberately observation-only: the agent never captures packets, reads application payloads, mutates a mesh provider, or performs a host/network action.
operator enrollment token -> private Ed25519 seed + signed proof -> pending operator approval
-> approved mTLS client certificate -> signed event + private durable queue -> Core -> Third-Eye
Linux metadata + optional socket tables + optional Tailscale or Headscale observation
-> signed event -> private durable queue -> HTTPS/mTLS Core batch -> Third-Eye projections
typed finding -> admitted Nano program -> SQLite cursor -> expiring proposal -> existing consent gate
antiflock-agent enrollcreates one private Ed25519 seed and a retry-stable signed enrollment proof, then submits a pending request. It does not self-approve, fetch a certificate, or turn on telemetry.antiflock-agent --submitcollects at a fixed interval, signs each event with the enrolled Ed25519 key, writes it to a private bounded queue, and removes it only after Core gives a rejection-free acknowledgement.- Core accepts an active enrolled node through a verified mTLS client certificate; a bearer token remains only for a loopback/development path.
--include-flow-metadatareads/proc/net/tcp,tcp6,udp, andudp6only when opted in on Linux. It emits current endpoint/protocol metadata asflow.updated; it intentionally reports no payload, byte counter, start time, direction, egress interface, or process identity. Non-Linux package builds preserve the collector boundary and returnAF-COLLECTOR-FLOW-UNSUPPORTED; the CLI itself refuses non-Linux collection.--mesh-provider tailscale --submitruns onlytailscale status --jsonand sends peer/path observations through the same queue. It never invokes a Tailscale mutating command.--mesh-provider headscale --submitcalls only Headscale’sGET /api/v1/nodeusing a read-only API key from a private file. It reports only explicitly associated peers; it cannot create, move, tag, expire, rename, or delete a Headscale node.- Nano watchdog admission is a signed-audit Core record: source is compiled against the constrained profile, saved with its immutable digest/binding, and exposed at
POST /v1/watchdogs.POST /v1/watchdogs/{id}/runaccepts a typed finding and returns only expiring proposals; it cannot execute an action. Core can also run an explicit allowlist of admitted programs over current OPEN findings at a bounded configured interval. Its SQLite cursor is atomically compare-and-swap advanced before a proposal is returned, so a restart or concurrent Core request cannot refire the same scheduled finding.
Core must be reachable over HTTPS. An operator creates a short-lived agent enrollment token and writes it into a private local file; the token is never sent to the dashboard, queue, or Nano.
chmod 600 /etc/antiflock/enrollment.token
antiflock-agent enroll \\
--core-url https://core.example.test \\
--enrollment-token-file /etc/antiflock/enrollment.token \\
--state-dir /var/lib/antiflock \\
--ca-cert /etc/antiflock/node-ca.pem \\
--node-id node_laptop_01 \\
--display-name "Laptop 01"Use --ca-cert only when the Core certificate is anchored in a private CA. The first command returns a pending-operator-approval document. Retrying it reuses the same seed and request ID. An authorized Core operator must approve the request. Then rerun this exact command with the original private token file: Core returns the approved certificate on the authenticated replay, and the agent verifies it matches /var/lib/antiflock/node.seed before saving it privately at /var/lib/antiflock/node.pem. It never needs a second private key copy or a manual certificate transfer.
Set the real deployment and node IDs used during enrollment, then run one safe smoke-test cycle:
# One collection / delivery cycle. This is safe to use as a deployment smoke test.
antiflock-agent \
--node-id node_laptop_01 \
--boot-id "$(cat /proc/sys/kernel/random/boot_id)" \
--deployment-id DEPLOYMENT_ID \
--submit --once \
--core-url https://core.example.test \
--node-key-file /var/lib/antiflock/node.seed \
--queue-dir /var/lib/antiflock/queue \
--client-cert /var/lib/antiflock/node.pem \
--ca-cert /etc/antiflock/node-ca.pem \
--include-flow-metadata \
--mesh-provider tailscaleOmit the flow flag to avoid endpoint metadata. Omit the mesh flag to avoid the
provider probe. To use Headscale instead of Tailscale, save the read-only API key
in a 0600 file and pass an explicit association map. For a private Headscale certificate, pass its CA PEM with --headscale-ca-cert:
{ "headscale-provider-id": "node_laptop_01" }antiflock-agent --node-id node_laptop_01 --deployment-id DEPLOYMENT_ID --submit --once \
--core-url https://core.example.test --node-key-file /var/lib/antiflock/node.seed \
--queue-dir /var/lib/antiflock/queue --client-cert /var/lib/antiflock/node.pem \
--mesh-provider headscale \
--headscale-url https://headscale.example.test --headscale-api-key-file /etc/antiflock/headscale.token \
--headscale-associations-file /etc/antiflock/headscale-associations.jsonWithout --submit, the same binary retains its inspect-only
JSON mode. For a loopback development Core, a private --agent-token-file can be
used instead of the client certificate; it is rejected for a remote HTTP endpoint.
This local, read-only command checks only private file shape and queue metadata; it never prints the seed, certificate, token, or queued events. It works while the continuous agent owns the queue writer lock.
antiflock-agent status \\
--node-id node_laptop_01 \\
--state-dir /var/lib/antiflock \\
--queue-dir /var/lib/antiflock/queueidentity: ready means the private seed and matching certificate files are
present with private permissions. The queue report shows the last allocated
sequence and retained-event count. pending-operator-approval is expected
between the first enrollment command and operator approval.
- Core unavailable: signed events stay in the node-bound queue.
--oncereturns an error for a supervisor; continuous--submitwaits for its next interval and retries the exact signed batch. On Linux, each queue replacement syncs both the staged file and containing directory after atomic rename; an error after installation never rolls the in-memory queue back. - Agent reboot: queued telemetry is drained one boot ID at a time, so Core never receives a mixed-boot batch.
- Queue full: that collection cycle is not partially persisted and stops with an error. The agent does not discard older telemetry to make room.
- A malformed/partial Core acknowledgement: no events are removed.
- A suspended or revoked node: Core rejects its mTLS identity before event processing.
| Area | Remaining work |
|---|---|
| Agent enrollment UX | Service manager packages and a remote Core/Third-Eye status endpoint. Endpoint key generation, retry-safe pending submission, post-approval certificate retrieval, and read-only local status are wired; approval remains deliberately operator-gated. |
| Queue operations | Retention/health metrics and a tested recovery procedure for a full queue. One active process now holds a private advisory writer lock; a second process fails closed rather than risking queue corruption. |
| Flow monitor | Process attribution, bytes/duration, retention controls, non-Linux collectors, and independent privacy review. |
| Tailscale / Headscale | Roaming/partition tests and live setup/status polling. Both read-only probes are wired into the agent loop; Third-Eye has static setup cards. |
| Nano | Program disable/version lifecycle, durable proposal-audit projection, replay fixtures, and dedicated authoring UX. Audited admission, deterministic proposal-only API, and an explicit bounded Core scheduler are wired. |
| BYOK providers | Key rotation/revocation, platform-keystore references, outbound egress controls, audit records, and integration tests. The Headscale key is read only from a local private file and never sent to Core/Nano. |
No OPEN item can be enabled by a boolean. Each must gain its own least-privilege contract, tests, and security/privacy review before it affects a real system.