Skip to main content

Edge Daemon

The Quint edge daemon is a Go binary that runs as a LaunchDaemon on macOS. It operates the HTTPS forward proxy, MCP stdio relay, MCP multi-server gateway, and unified session tracker. It receives OS-level events from the EndpointSecurity system extension over a Unix socket and merges them with proxy content data into a unified session model.

Installation

Distributed as a signed .pkg installer that sets up both the Go daemon and the QuintAgent.app (ES extension):
The installer registers:
  • LaunchDaemon at /Library/LaunchDaemons/dev.quintai.agent.plist
  • QuintAgent.app in /Applications/ (hosts the ES system extension)
  • Configuration at /etc/quint/config.yaml
The same config.yaml format is used in both development and production. The daemon reads it on startup — no separate dev/prod config mechanism.

Three Event Sources

The daemon ingests events from three independent sources, all feeding into the unified session tracker:

Source 1: EndpointSecurity Extension

The ES extension (Swift) detects AI agent processes via code signing and monitors 9 event types. Events arrive over a Unix socket with auth handshake. See ES Extension for full details.

Source 2: Forward Proxy

MITM TLS interception via HTTP_PROXY / HTTPS_PROXY environment variables. Parses 7 LLM API formats to extract tool calls with arguments. See Forward Proxy for full details.

Source 3: Process Scanner

Runs every 5 seconds, scanning the process table for AI agents using 21 platform signatures. Uses ps etime to recover real start times. This fills the gap for agents that were already running when the daemon started (the ES extension only sees new process launches).

Two Operation Modes

Full production mode: LaunchDaemon with ES extension, forward proxy, process scanner, cloud forwarder, and session lifecycle management.
This is the default mode when installed via .pkg.

Unified Session Tracker

The session tracker (internal/unisession/) is the core data model. It merges all three event sources into a single session per agent invocation.

Session Identity

Each session has a stable ID: {rootPID}-{startUnixMs}. This survives PID reuse — if a PID is recycled, the millisecond timestamp differentiates the sessions.

What Each Source Contributes

Session Fields

PID Liveness Reaper

Every 10 seconds, the tracker checks if each active session’s root PID is still alive (via kill(pid, 0)). Dead sessions transition to ended and a session_end event is sent to the cloud.

Audit Log & Session Attribution

Every intercepted request, response, and tool call is persisted to a local SQLite audit database (~/.quint/quint.db, table audit_log). Each row is signed with Ed25519 and chained to the previous row via prev_hash — the audit log is tamper-evident even before it reaches the cloud.

Schema (subset)

How session_id is populated

At every MITM log site (request, response, tool call), the daemon calls SessionLookup(pid) — a callback wired to unisession.Tracker.SessionByPID. If the PID is tracked (i.e. belongs to a detected AI agent process or one of its children), we stamp the row with that session’s ID and PID. If not tracked, the fields are left null. This makes the audit log natively join-able by session without reconstructing attribution after the fact:
Two simultaneous Claude Code terminals produce two distinct session_id values — no bleed between invocations.

Decoded Timeline API

The raw response_json for streaming LLM calls is a thick stack of wrappers: AWS eventstream binary framing → JSON with base64-encoded "bytes" → Anthropic SSE events → content block deltas. To let downstream consumers avoid re-implementing the decode stack, the daemon exposes:
Returns a flat array of TimelineEvent objects — request, assistant_text, tool_call (with reconstructed JSON input), and response_raw fallback. This is what the local viewer uses to render a readable session drill-down.

Historical sessions

audit_log outlives the in-memory unisession.Tracker (reaped ~10s after the root PID exits). The /api/es/sessions endpoint merges live tracker state with audit.DB.HistoricalSessions(limit) — distinct (session_id, process_pid) groupings seen in audit, ordered by MAX(timestamp) — so reaped sessions remain discoverable.

Cloud Forwarder

The daemon pushes events and sessions to api.quintai.dev via HTTPS: Source: proxy/internal/cloud/forwarder.go. Session lifecycle events (session_start, session_resume, session_end) go through a separate ingest endpoint (/v1/sessions/ingest). Each QuintEvent enqueued for the cloud forwarder also carries session_id, so the cloud actions table can be joined to the cloud sessions table by the same key the local audit log uses.

LLM Conversation Parsing

Seven dedicated parsers extract structured data from HTTP request/response bodies: Detection priority: path-based (Responses, Gemini, Bedrock) -> host-based (Anthropic, OpenAI, Azure, Google, Mistral) -> body sniff -> generic fallback.

Agent Platform Detection

The daemon identifies AI agent platforms through 21 signatures using a multi-layer approach:
  1. Code signing (via ES extension) — team ID + signing ID, cryptographically verified
  2. Process name — case-insensitive exact match on binary name
  3. Path patterns — substring match in binary path
  4. Parent cascade — child inherits parent’s agent status
See ES Extension for the rest of the detection cascade.

Security Hardening

Data Classification

Stays on Machine

  • Source code content
  • Credentials and secrets
  • Full request/response bodies
  • Private signing keys
  • CA private key

Sent to Cloud

  • Structured metadata (action type, tool name, risk score)
  • Agent identity and platform
  • Session lifecycle (start, resume, end)
  • Timestamps and session IDs
  • File paths (for file operation events)
Source code, credentials, and secrets never leave the machine. The cloud receives only structured metadata sufficient for fleet-wide visibility and compliance reporting.