feat(sight): blood lineage tree with AGENT_MODE detection#661
Open
jfeng18 wants to merge 5 commits into
Open
Conversation
6ccd232 to
e4c79a5
Compare
0f14dfc to
f50ad4d
Compare
This was referenced May 29, 2026
f50ad4d to
3c04313
Compare
This was referenced Jun 2, 2026
d669b83 to
04f8738
Compare
Contributor
Author
a3c6b9f to
6e3f294
Compare
Introduce a userspace blood lineage tree that tracks Agent process families (Agent -> SubAgent -> Tool / Skill). Nodes carry pid/ppid, process type, AGENT_MODE flag, comm and an optional agent name, and maintain parent->child links on insert/remove. classify() assigns a type from the process's ancestry and environment: a child of an Agent/SubAgent becomes SubAgent (if it matches an agent pattern) or Tool; a parentless process with AGENT_MODE=1 becomes an Agent root; everything else stays Unknown. subtree()/roots() expose the forest for queries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wire the lineage tree into the event loop. proctrace exec/exit events maintain the tree (insert+classify on exec, remove on exit), inferring AGENT_MODE and agent-pattern matches from the pid->agent-name cache to avoid redundant /proc reads. Add scanner helpers read_ppid() and has_agent_mode() that read /proc/<pid>/stat and /proc/<pid>/environ, used by the procmon path to auto-detect AGENT_MODE=1 roots. ensure_lineage_node() closes a race: proctrace does not emit an exec event for an AGENT_MODE root (it was not yet in traced_processes when it execed), so the procmon detection path inserts and classifies the node directly, making detection order-independent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Five correctness fixes from an adversarial review of the as-pushed branch: 1. **PID-reuse phantom child** — LineageTree::insert did not detach the pid from its old parent's children list when re-parenting (e.g. PID reuse where the old Exit was missed under ringbuf pressure). Detach- then-attach in insert. 2. **AGENT_MODE gate routed via stringly-typed name prefix** — the "agent-mode-" prefix on the cached agent display name was reused as a state-machine input, conflating naming with state. Read the LINEAGE_FLAG_AGENT_MODE bit on the lineage tree node (set by procmon's earlier ensure_lineage_node call) instead. 3. **AGENT_MODE precedence rule untested** — added two discriminating tests pinning that AGENT_MODE on a child of Agent/SubAgent stays Tool (reordering match arms in classify() would now fail). 4. **ProcessType::Skill forward-declared but undocumented** — added a doc comment marking it as forward-declared for the follow-up scoring task, plus a test pinning that classify() never produces Skill under any current input combination. 5. **Commit subject lengths** — the two existing commits on this branch exceeded the 50-char rule (73 and 63). Reworded during this rebase to 49 and 45. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
B1: procmon.bpf.c used get_task_ns_pid() for event->pid but host tgid for ppid — inconsistent in containers. Use host tgid (from bpf_get_current_pid_tgid()) for both, matching proctrace convention. B2: root agent exit only triggered ProcMonEvent::Exit (not proctrace VariableEvent::Exit), so lineage tree was never cleaned. Add lineage_tree.remove() in ProcMonEvent::Exit handler. I1: LineageTree::remove() now reparents children to grandparent instead of orphaning them (mirrors kernel subreaper behavior). Found via workflow kernel-code cross-reference review against cloud-kernel 6.6 branch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…roots Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6e3f294 to
4556654
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the blood lineage tree for AI agent process tracking — a userspace mirror of process parent-child relationships, enriched with type classification (Agent / SubAgent / Tool, with Skill forward-declared for a follow-up scoring task).
The classifier is built from two complementary signals already produced by AgentSight:
proctraceexec/exit events feed the tree's parent-child links.procmon+/proc/[pid]/environdetect theAGENT_MODE=1environment variable that marks a top-level Agent root.Update (audit fixes folded in, commit
fix(sight): lineage correctness + AGENT_MODE gate)A self-review of the as-pushed branch caught five issues:
LineageTree::insert— re-parenting did not detach the pid from the old parent's children list (PID reuse where the old Exit was missed). Detach-then-attach in insert.update_lineage_from_procinferred AGENT_MODE from a"agent-mode-"prefix on the cached agent display name. Replaced with a direct read of the lineage tree node'sLINEAGE_FLAG_AGENT_MODEbit (set by procmon's earlierensure_lineage_nodecall).Tool(reordering match arms inclassify()would now fail).ProcessType::Skillforward-declared but undocumented — added a doc comment marking it as forward-declared for the follow-up scoring task, plus a test pinning thatclassify()never produces Skill under any current input.Testing
cargo test --lib lineage)Independent of #662–#668.