AcTrail Use Cases
This document maps common operator questions to the AcTrail feature path and the example that proves it.
Use Case Matrix
| Question | Use This Path | Validate With |
|---|---|---|
| What process tree did the agent create? | eBPF process lifecycle plus viewer process/events output. | Example 01, Example 03 |
| Did one agent silently launch another agent? | actrailctl launch plus process seccomp exec context, TLS/plaintext LLM evidence, and agent.invocation semantic action. |
Example 07 |
| What LLM request and response did a real agent exchange? | Full-monitor payload capture plus HTTP/SSE and llm.request/llm.response semantic assembly. |
Example 08 |
| What LLM request and response did opencode exchange? | Bun/static-BoringSSL executable TLS payload capture plus proxy-aware HTTP semantics. | python3 tests/agent-trace/run_case.py opencode-bun |
| What outbound LLM request did a Rust/rustls agent send? | tls-sync with a rustls probe plan from finder fast, symbols, or a build-id-checked pattern. |
Example 06 |
| What outbound LLM request did a LangGraph Python agent send? | eBPF dynamic OpenSSL shared-library TLS payload capture around an OpenAI-compatible HTTPS call. | python3 tests/agent-trace/run_case.py langgraph-openai |
| What HTTP request/response did a non-TLS local service exchange? | Socket plaintext payload with HTTP sniffing and HTTP/1.x application analyzer. | Example 05 |
| Did file enforcement actually block the target? | Fanotify permission backend plus client-side stdout and Enforcement events. | Example 04 |
| What files, IPC, stdio, and resources did a workload touch? | Extended eBPF observation, stdio payload, provider labels, resource metrics. | Example 03 |
| Can I export higher-level actions to observability tooling? | actrailviewer export-otel over semantic actions. |
Example 04, Example 08 |
| What is the runtime overhead? | tests/performance/run_benchmark.py task-runtime benchmark. |
Performance README |
Agent Invocation Discovery
Goal: detect a tree-shaped call such as one process launching claude -p ..., where Claude is proven to be an agent by an outbound LLM request.
Use:
python3 docs/examples/07.xiaoo-claude-agent-invocation/run_e2e.py
Expected evidence:
- The monitored workload prints
ACTRAIL_AGENT_TREE_OK. - OTEL export contains a
process.execspan forclaude -p. - OTEL export contains an
llm.requestspan for the same Claude process. - OTEL export contains an
agent.invocationspan linking Claude's direct launcher to the child Claude command.
This use case requires payload capture for the child LLM call. A command match is only a candidate hint; it does not prove agent identity by itself.
Complete LLM Exchange Capture
Goal: retain the LLM request and response bytes, derive an llm.request action from the outbound request, and derive an llm.response action from inbound JSON or SSE response payloads.
For manual real-agent validation, start with Example 08. Use a runtime-specific capture path when narrowing a failure:
| Target Runtime | Capture Path |
|---|---|
| Dynamic OpenSSL | payload_tls_source = shared-library, payload_tls_resolver = openssl-symbols; use eBPF for Python _ssl because libssl is loaded after process startup. |
| Node/OpenSSL executable | tls-sync auto plan via payload_tls_source = auto, payload_tls_resolver = auto, and payload_tls_library = auto. |
| Bun/static-BoringSSL | tls-sync auto plan via finder fast; BoringSSL-specific static detection is an implementation detail, not an operator config value in current examples. |
| Rust/rustls | tls-sync auto plan with finder fast resolving rustls plaintext points from symbols, debuginfo, or supported build-id-checked patterns. |
Go crypto/tls |
payload_tls_source = executable, payload_tls_resolver = go-pclntab, payload_tls_library = go, payload_tls_capture_backend = bpf-copy-seccomp-fallback; captures crypto/tls.(*Conn).Write outbound and crypto/tls.(*Conn).Read inbound through the Go runtime copy path. |
| Plain HTTP endpoint/proxy | payload_socket_enabled = true, payload_socket_capture_backend = bpf-copy-seccomp-fallback, plus HTTP/1.x application parsing. |
Real agent acceptance cases:
| Case | Command | Runtime Boundary |
|---|---|---|
| Claude Code | python3 tests/agent-trace/run_case.py claude-code |
HTTPS/TLS when supported, otherwise plain HTTP socket plaintext if configured by provider/proxy. |
| opencode | python3 tests/agent-trace/run_case.py opencode-bun |
Bun/static-BoringSSL TLS writes or plain HTTP socket plaintext; model pinned to deepseek/deepseek-chat. |
| xiaoO | python3 tests/agent-trace/run_case.py xiaoo-rustls |
Rust/rustls plaintext points or plain HTTP socket plaintext. Stripped HTTPS/HTTP CONNECT binaries need a supported finder rustls plan before this payload case can pass. |
| LangGraph | LANGGRAPH_PYTHON=/path/to/python python3 tests/agent-trace/run_case.py langgraph-openai |
Python dynamic OpenSSL shared-library writes for HTTPS via eBPF; socket plaintext for HTTP API URLs. |
On hosts that require a local proxy for external network access, keep the proxy environment active for these commands. Do not assume the provider route is HTTPS: some agent configs use a plain HTTP base URL or proxy. When HTTPS is used, proxy tunnel facts such as CONNECT api.deepseek.com:443 may appear alongside decrypted TLS request rows. When plain HTTP is used, the request payload source is Syscall/socket-syscall.
For large LLM requests, set the relevant per-operation budget high enough before running the case. Rust/rustls TLS examples use tls-sync, so the runtime reports each TLS operation to the daemon instead of forcing every payload into a fixed multi-MB eBPF ringbuf record. Python OpenSSL uses eBPF shared-library probes because _ssl maps libssl lazily. Go crypto/tls capture is entry direct-copy and therefore only emits operations that fit the configured TLS segment budget. Plain HTTP socket payload can still use bpf-copy-seccomp-fallback: eBPF copies operations no larger than the inline budget, while seccomp notification is the user-space read fallback for larger socket operations.
Run TLS capture through actrailctl launch; do not use track-add for tls-sync, because the sync runtime, event socket, and probe plan must be prepared before exec.
Expected evidence:
actrailviewer payloadsshows complete outbound plaintext rows:TlsUserSpacefor HTTPS/TLS orSyscall/socket-syscallfor plain HTTP.- Operation state is
success. - Captured size equals original size for the operation being validated.
actrailviewer actionscontains a complete successfulllm.requestand anllm.responsewhen inbound JSON/SSE response payload is retained.actrailviewer export-jsoncontains payload nodes if payload export is enabled.actrailviewer export-otelcontainsllm.requestand the assembledllm.responsespan when that action exists.
Rows marked Truncated or operation state partial mean the configured capture budget is not sufficient for that request.
HTTP Semantics
Goal: inspect application protocol facts instead of only raw bytes.
Use:
- Plain HTTP: Example 05.
- HTTPS/2: Example 02 for a focused protocol case, or Example 08 for real-agent validation.
Expected evidence:
- Payload rows show the plaintext source boundary:
Syscallfor plain HTTP,TlsUserSpacefor HTTPS. Applicationevents show HTTP request/response, HTTP/2 frames, or HTTP/2 DATA facts depending on the protocol.llm.requestactions are assembled from retained outbound request payloads when the payload is complete.llm.responseactions are assembled from retained inbound JSON or SSE payloads; multiple SSE chunks on the same stream update one response action with multiple payload-segment evidence rows.
HTTP parsing consumes retained plaintext payloads. It should not depend on whether bytes came from OpenSSL, BoringSSL, rustls, or socket syscalls.
File Enforcement
Goal: prove the observed system both enforced a policy and recorded the decision.
Use:
python3 docs/examples/04.fanotify-enforcement-e2e/run_e2e.py \
--otel-output /tmp/actrail-fanotify-e2e.otlp.json
Expected evidence:
- Target-side stdout includes
allowed=ok. - Target-side stdout includes
denied=permission_denied. - Viewer output contains one allow and one deny Enforcement event.
- OTEL export contains two
enforcement.decisionspans when--otel-outputis used.
If the target prints denied=unexpected_success, the policy did not block access even if AcTrail produced events.
Broad Local Observation
Goal: validate process, file, IPC, network, stdio, provider, and resource observation on one host.
Use:
python3 docs/examples/clean.py --example extended-observation
./target/release/ebpf_probe verify-live \
--config docs/examples/03.extended-observation-e2e/observation.conf
Expected evidence includes:
process_events=exec,exit,fork
file_events=...
net_events=...
ipc_events=...
resource_events=process_tree
stdio_payloads=stderr:outbound,stdin:inbound,stdout:outbound
The fork event comes from sched/sched_process_fork; a host does not need syscalls/sys_enter_fork for this path. Default process lifecycle capture suppresses process signal events such as SIGCHLD.
OpenTelemetry Export
Goal: feed higher-level AcTrail actions into an observability pipeline.
Use:
./target/release/actrailviewer export-otel \
--config <operator.conf> \
--trace-id <TRACE_ID> \
--output /tmp/actrail-trace.otlp.json
Expected evidence:
- Top-level JSON contains
resourceSpans. - Semantic spans contain
actrail.action.kind. - Action kinds currently covered by examples include
process.exec,agent.invocation,file.read,file.write,http.message,llm.request,llm.response, andenforcement.decision.
Not every raw fact is currently an OTEL span. Validate low-level network rows, IPC rows, resource samples, provider labels, and payload rows through viewer commands or JSON graph export when no semantic span exists.
Performance Measurement
Goal: measure task runtime overhead, not one-time wrapper setup time.
Use:
python3 tests/performance/run_benchmark.py \
--case agent \
--mode baseline,observed-ebpf-core,observed-ebpf-payload,observed-seccomp-agent \
--repetitions 10 \
--output local/performance-agent.md
Read task_runtime_ms for the primary overhead question. outer_wall_ms is reported separately to show runner and actrailctl launch control-plane cost. The report uses distribution-level evidence rather than treating same-numbered iterations as paired samples.