Skip to content

Events carry no project, so one trail mixes every repo on the machine #37

Description

@blitzcrieg1

Hooks install globally, by design: hook_bootstrap.py says as much, and removes
per-project Cursor hooks because "global covers all workspaces". That is the
right default for a recorder, since an agent you forgot to instrument is the one
that matters.

But the canonical event carries nothing to say which project a tool call
belonged to. Grepping canonical.py and external.py for cwd, workspace or
project returns nothing. Every session on the machine lands in one
undifferentiated trail.

Three consequences, in rising order of seriousness.

The dashboard cannot answer the most natural question. "What did the agent
do in this repo today" is probably the first thing any developer asks a flight
recorder, and there is no way to express it. Filters offer source app, event
type, outcome, and time, but not place.

Detection noise crosses projects. A session-tool-burst or an off-hours hit
from unrelated work sits in the same queue as one from the repo you care about,
with nothing to tell them apart until you open each session and read the
commands.

Evidence packs leak. export --evidence covers a date range, so a pack
produced for a reviewer of one project includes every command, path and file
name from every other project worked on that week. For a tool sold on producing
compliance evidence, an export with no way to scope it to a subject is a real
obstacle, and the person who discovers it will be the person who least wants to.

The data is already arriving

Claude Code sends cwd in its hook payload. The client half-uses it: line 802
of scripts/agentmetry_ingest.py normalises Antigravity's Cwd into the tool
args, where it is folded into input_hash and stops being queryable. So the
value is on the wire and gets thrown away.

Proposed shape

  • Extract cwd in the hook client and put it on the event as a first-class
    field rather than inside tool.input.
  • Derive a stable project label from it, preferring the git toplevel of the
    cwd and falling back to the directory name, so worktrees and subdirectories of
    one repo group together.
  • Index it in trail_db alongside session_id and source_app.
  • Add a project filter to the dashboard, and a --project flag to
    export --evidence.

Constraints

Additive only. The canonical schema is a contract and existing trails must keep
opening: events recorded before this lands simply have no project, and the UI
should show them as unscoped rather than hiding them.

Absolute paths are more revealing than most fields already in the trail, since
they carry usernames and client names. Store the derived label as well as the
raw path, and let redaction apply to the path the way it does elsewhere.

Do not turn this into per-project opt-in capture. The recorder's value is that
it sees everything it orchestrates; this is about reading the trail, not about
narrowing what reaches it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions