[APIE-1370][APIE-1606] New agentdetect package - #3472
[APIE-1370][APIE-1606] New agentdetect package#3472Noel Cothren (noeldevelops) wants to merge 15 commits into
agentdetect package#3472Conversation
Remove references to internal-only artifacts (friction logs, ticket IDs like FF-9295, the signals-comparison memo, "proof of concept" framing, LaunchDarkly, and capture dates) from comments and test descriptions, and neutralize the agentdetect-poc fixture string. Purely comment/description changes plus one non-asserted test fixture value; no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The " helper" suffix is an Electron packaging convention, not an editor one, so classifyEditorHelper previously tagged any Electron app's helper (Slack, Discord, Hyper — itself a terminal) as kindIDEHost with an empty vendor, polluting the IDEHost signal. Gate classification on the product matching a known kindIDEHost row; unrecognized Electron apps now fall through to kindUnknown. Trades away recognizing an unseen VS Code fork purely from its helper (theoretical, since its main basename would be unknown too) for not misclassifying non-editor Electron apps. Splits the fork-generalization test into known-editor and non-editor-Electron cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A helper-matched IDE host previously resolved to an empty key, so its
identity was dropped from the wire (optional("") is nil) even though the
editor was known — a VS Code chain whose nearest editor process is a
"code helper (plugin)" emitted ide_host: nil. Resolve the helper to its
editor's table key ("code helper (plugin)" -> "code"), the same way the
version-suffix rule resolves "python3.13" -> "python", so ide_host now
carries the editor while still only ever recording table vocabulary,
never the observed helper basename.
Applies to the Electron editors (code, cursor, windsurf); zed and
JetBrains have no helper subprocesses and were already keyed directly.
Also tightens surrounding comments.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
🎉 All Contributor License Agreements have been signed. Ready to merge. |
There was a problem hiding this comment.
Pull request overview
Adds a new pkg/agentdetect Go package that detects “agentic” execution context (AI agents / IDE-hosted environments) via env var fingerprints and best-effort process ancestry inspection, with a privacy-preserving telemetry projection intended for later wiring into usage events.
Changes:
- Introduces core detection logic (
Detect), fingerprint tables (env/proc/cmdline), and a constrained wire-format projection (Attributes) designed to avoid leaking raw process/argv data. - Adds a gopsutil-backed
ProcSourceimplementation plus extensive synthetic + live-process tests to validate detection behavior, bounds/guards, and privacy constraints. - Updates module dependencies to include
github.com/shirou/gopsutil/v4and related indirect deps; adds a gitignore entry for local manual-testing binaries.
Reviewed changes
Copilot reviewed 13 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/agentdetect/doc.go | Package-level documentation for agent detection goals, signals, and privacy guarantees |
| pkg/agentdetect/proc.go | Defines ProcInfo and ProcSource abstraction for process ancestry walking |
| pkg/agentdetect/proc_gopsutil.go | Implements real process lookup via gopsutil with per-read timeout guards |
| pkg/agentdetect/detect.go | Core detection logic: env/CI/TTY signals, bounded ancestry walk, redaction helpers |
| pkg/agentdetect/fingerprints.go | Env/proc/cmdline fingerprint tables and name/path resolution rules |
| pkg/agentdetect/attributes.go | Wire-format Attributes projection for attaching to usage events |
| pkg/agentdetect/scenarios_test.go | Synthetic scenario fixtures used to validate documented failure modes |
| pkg/agentdetect/detect_test.go | Comprehensive unit tests for detection behavior, guards, and privacy constraints |
| pkg/agentdetect/ide_surfaces_test.go | Tests for IDE-host surface classification and in-editor agent attribution limits |
| pkg/agentdetect/attributes_test.go | Tests that enforce wire-format constraints and schema discipline |
| pkg/agentdetect/proc_gopsutil_test.go | Live-process tests ensuring gopsutil source works and doesn’t serialize raw observations |
| pkg/agentdetect/field_probe_test.go | Opt-in manual probe test for capturing real-world process tree shapes |
| go.mod | Adds github.com/shirou/gopsutil/v4 dependency |
| go.sum | Updates sums for gopsutil and transitive dependencies |
| .gitignore | Ignores locally built agentdetect manual-testing binaries |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Code review of the agentdetect package found the privacy invariant (only fixed-table keys, never raw process text, reach AncestorMatch/WrapperMatch) was enforced only by discipline and a runtime test. Introduce fpKey, a private string type returned only by the fingerprint resolvers, so a future assignment of raw process data into one of these fields is a compile error. Also close a gap where walk()'s own budget check is cooperative and never runs while a single ProcSource.Info call is blocked — on darwin several gopsutil calls ignore their context, so a slow syscall could stall past the configured budget. boundedWalk now enforces a hard wall-clock ceiling above that budget and gives up on the walk if it's exceeded. Also clarifies the maxIdentityArgs doc comment and notes the follow-up-PR export need on vendorForProcKey/vendorForArgvPattern.
childStart, the walk's pid-reuse baseline, was only ever set from a descendant already walked, so depth 1 (StartPid) had no prior read to compare against and went unchecked — a recycled pid one hop above the CLI could fabricate an ancestor undetected. Add Options.SelfPid (defaulting to os.Getpid()) to seed childStart with the CLI's own start time before the walk begins; a lookup failure just disables the depth-1 check, same as any other unreadable start time.
ChainShape doc claimed a completed walk always ends in 'n' or 'r', but a walk that reaches PID 1 without an init/remote ancestor produces a valid shape like "sit" — drop the false claim. Also fixes "Detect method" (it's a function) and the field-probe test's file header, which said it's outside the automated suite even though go test discovers and skips it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
agentdetect packageagentdetect package




⭐ No user-facing changes yet. This PR does not "hook up" the package to any existing code; it will be done in a follow-up after updating the cc usage service.
Closes APIE-1606
Release Notes
Checklist
Whatsection below whether this PR applies to Confluent Cloud, Confluent Platform, or both.Test & Reviewsection below.Blast Radiussection below.What
Problem: We would like to improve the usability of our CLI tool for human and AI Agent users. As a first step, we'd like to know more.
Solution: This package adds logic to collect AI agent signals from a list of known env vars & process names to send with our telemetry and indicate whether users are in Agentic environment. We're adding the data to existing usage telemetry sent on command invocation, so we will also learn more about the commands' usage & error rates as they relate to environment and agent use cases.
Key Technical Details
pkg/agentdetectwith no call sites; no existing behavior changes. Wiring into telemetry is coming in a follow-up PR after updating the shared usage-service schema.Detection Logic Design
Initially I thought just checking env vars, or just inspecting the process tree for names like "claude" or "codex" could tell us definitively "this is an agent", but in field testing with a proof of concept I found many gaps in both those approaches depending on things like OS, install method, and IDE host environment.
The final logic steps through several layers of checks and will send all definite signals found. Downstream we will infer agent usage from the patterns gathered (see internal docs for more details on metrics design).
The package contains a buildable debug binary that can be used going forward to troubleshoot or add more surface to our fingerprint tables.
Privacy
fpKey, a private string type returned only by the fingerprint resolvers, so raw process text can never be assigned into fields in future updates either.Blast Radius
At this time there are no user-facing changes or code paths, so this PR has zero blast radius.
Once connected to the usage events, there are multiple guards (depth cap, wall-clock deadline, cycle guard, pid-reuse guard), each able to stop data collection if something goes wrong. A key part of the design was to insure a failure in this package does not cascade to the user's original task.
References
Internal Docs
1-Pager with Eng Design
Wiki with initial research notes and questions
Jira issue
Claude-generated diagram of the Detect logic
Test & Review
TestLiveResultSerializesNoRawObservationsruns the actualgopsutilwalk against the live process tree and asserts no raw process names leak into JSON.How to Field Test
Build the debug binary from the root directory
go build -o agentdetect-debug ./cmd/agentdetect-debugRun the debugger yourself from a terminal, or ask an agent to run it to see what it detects
You can copy the binary to another machine and run it under different OSes and agent CLIs there too, since it has no dependency on the CLI's other state.