Documentation Index
Fetch the complete documentation index at: https://quintsecurity.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Sub-Agent Detection
Quint detects when AI agents spawn child agents — even without explicit instrumentation. The system combines passive detection (traffic analysis heuristics) with active detection (pattern matching, spawn tickets, and trace propagation) to build high-confidence parent-child attribution.In-Process Task Dispatch
Claude Code (and some other agent frameworks) can spawn child tasks inside the same process and the same CONNECT tunnel — no new TCP connection, no new model, no new PID. The passive detection layers below assume the child shows up as a distinct tunnel, so they miss this case. Quint handles it inforwardproxy.SubagentDetector.
Mechanism
For every POST with a JSON body, the detector:- Hashes the top-level
systemprompt with FNV-1a - Tracks per-tunnel state:
{parentHash, currentHash, msgCount, currentSession} - Compares the incoming hash and
messages.lengthto previous turns
Transition Rules
| State change | Trigger | Emits |
|---|---|---|
subagent_start | prompt hash changes AND messages.length <= 2 | {parentSession}:sub:{N} |
parent_resume | prompt hash reverts to parentHash AND messages.length > 2 | back to parentSession |
| no-op | hash changes but msgCount > 2 | (mid-session prompt rewrite — MCP connect, CLAUDE.md edit) |
Child Session IDs
Child session IDs are deterministic and human-readable::sub:1, :sub:2, :sub:3. Each child carries ParentSessionID pointing at the root, which is written to audit_log.parent_session_id at capture time. The local viewer renders nested rows with a purple left border and a sub badge.
Why Not Just Use Tunnel State
The in-process path deliberately avoids relying on CONNECT tunnel boundaries:- Subagents share the parent’s keep-alive connection — no new tunnel
- The process tree is identical — no new PID to bind to
- The request model is often unchanged — no Layer 1 divergence signal
Passive Detection
Passive detection works via traffic analysis in the forward proxy, using three independent layers that feed signals into a correlation engine.Detection Layers
Layer 1: Model Divergence
When an agent uses a different model than previously seen in the same tunnel, Quint infers a sub-agent spawn. The first model seen becomes the parent model; subsequent different models trigger a split. Known divergence patterns:| Parent Model | Child Model | Provider |
|---|---|---|
*opus* / *sonnet* | *haiku* | Anthropic |
*gpt-4o | *gpt-4o-mini* | OpenAI |
*pro* | *flash* |
Layer 2: Concurrency Spike
Quint tracks CONNECT tunnel counts per IP address. During the first 10 seconds (stabilization window), it learns the baseline concurrency. After that, if active tunnels exceedbaseline + 2, a sub-agent is detected.
Layer 3: Temporal Gap
When time between CONNECT requests from the same IP exceeds the burst window (2000ms default), Quint evaluates:- Has parent trace (
X-Quint-Traceheader) → confirmed child (source:child_detect) - No trace, active tunnels exist → inferred child (source:
inferred_child) - No trace, no active tunnels → new peer agent
Configuration
Passive detection is enabled by default in forward proxy mode. Tuning parameters:| Parameter | Default | Description |
|---|---|---|
| Burst window | 2000ms | Time gap threshold for temporal detection |
| Stabilization window | 10s | Time to learn baseline concurrency |
| Spike threshold | baseline + 2 | Tunnel count increase to trigger detection |
| Max body preview | 8192 bytes | How much of POST body to read for model extraction |
Active Detection
Active detection identifies agent creation in MCP tool calls and propagates trace context through the agent hierarchy.Spawn Patterns
Quint ships with 8 built-in patterns that match tool calls indicating agent creation:| ID | Description | Tool Pattern | Confidence | Spawn Type |
|---|---|---|---|---|
openai-handoff | OpenAI Agents SDK transfer | *transfer_to_* | 0.90 | delegation |
generic-create-agent | Generic agent creation | *create*agent* | 0.85 | direct |
a2a-delegation | Agent-to-Agent protocol | *send_task* | 0.85 | delegation |
run-agent | Running another agent | *run*agent* | 0.85 | direct |
invoke-assistant | Invoking an assistant | *invoke*assistant* | 0.80 | direct |
delegation-flag | Delegation keywords in args | * (any tool) | 0.75 | delegation |
shell-agent-spawn | Shell exec launching agents | *exec* | 0.70 | fork |
subtask-spawn | Task decomposition | *task* | 0.65 | delegation |
Argument Scanning
Some patterns also check tool call arguments for keywords:- delegation-flag:
delegate,handoff,transfer,spawn_agent - shell-agent-spawn:
agent,assistant,claude,gpt,llm - subtask-spawn:
subtask,sub_task,child_task,delegate_task - generic-create-agent:
agent,assistant,model
Child Hint Extraction
When a spawn is detected, Quint extracts the child agent’s identity hint from:- Tool name patterns (e.g.,
transfer_to_research_bot→research_bot) - Argument fields:
agent,agent_name,agent_id,assistant,assistant_id,target_agent,delegate_to
Trace Propagation
Quint propagates trace context through two mechanisms:HTTP Header: X-Quint-Trace
X-Quint-Trace: a1b2c3d4-e5f6-7890.2
The trace ID is a UUID generated at the root agent. Depth increments at each spawn. This header is used in the forward proxy to link CONNECT tunnels to parent agents.
In-Band Field: _quint
For MCP stdio transport (where HTTP headers aren’t available), trace context is embedded in JSON-RPC params:
_quint field is stripped before forwarding to the actual MCP server.
In-Band Auth
The_quint field in MCP initialize params can also carry authentication:
Spawn Tickets
For cryptographically verified parent-child links, Quint issues HMAC-SHA256 spawn tickets when a spawn is detected.Ticket Format
Claims
| Field | Description |
|---|---|
pid | Parent agent ID |
pname | Parent agent name |
child | Child hint (extracted from tool call) |
d | Depth in agent hierarchy |
sc | Narrowed scopes for child |
tid | Trace ID for correlation |
st | Spawn type: direct, delegation, fork |
exp | Expiration (default: 5 minutes from creation) |
n | Random nonce (replay protection) |
Correlation Engine
Detection signals from both passive and active layers merge in the correlation engine, which maintains a relationship graph with confidence scores.Signal Types
| Signal | Constant | Base Confidence |
|---|---|---|
| Spawn pattern match | spawn | ~0.85 |
| Trace context header | context | ~0.95 |
| Temporal correlation | temporal | ~0.50 |
| HMAC-verified ticket | signature | 1.0 |
Confidence Merging
Multiple signals for the same parent-child pair are merged using diminishing returns:Relationship Graph
The engine tracks:quint.relationships.{org_id} NATS subject for downstream consumption.
Signal Flow
When a spawn is detected, the following happens:Pattern Match
The tool call matches a spawn pattern. A
SpawnEvent is emitted with the pattern ID, confidence, and child hint.Ticket Generation
An HMAC-SHA256 spawn ticket is created with the parent’s identity, narrowed scopes, and a 5-minute TTL.
Ticket Injection
The ticket is injected into the tool call’s
_quint field (MCP) or made available via X-Quint-Trace (HTTP).Child Verification
When the child agent connects, it presents the ticket. Quint verifies the HMAC signature and establishes the relationship with 1.0 confidence.
Correlation
The spawn signal is sent to the correlation engine, which merges it with any other signals (temporal, context, model divergence).
Dashboard Visualization
The dashboard renders parent-child trees from the correlation engine data. Each node shows:- Agent name and provider
- Model in use
- Confidence score for the parent-child link
- Signal types that contributed to detection