Skip to content

Commit 63a36fd

Browse files
joahgampagent
andcommitted
feat(parsers): add agent-trace.dev v1 sidecar parser
Adds support for the open, vendor-neutral agent-trace.dev v1 spec (https://agent-trace.dev/) as a third parser alongside the existing Claude Code and Codex/Copilot native log parsers. Why --- ai-blame previously had to grow one bespoke parser per agent. The agent-trace.dev v1 spec is an open, agent-agnostic JSON sidecar format designed exactly for this attribution use case, and any producer of the spec (first-party emitter or third-party exporter from native logs) is unlocked at once. What ---- - New `src/parsers/agent_trace.rs` reads `.agent-trace/*.json` records conforming to the v1 schema and emits one `EditRecord` per `files[].conversations[].ranges[]` entry. - Registered in `ParserRegistry::new()` first so the unambiguous `.json` + spec-shaped discriminator wins before the `.jsonl` parsers see the file. - `get_agent_trace_dirs()` discovers `<cwd>/.agent-trace/` and `~/.agent-trace/` automatically and feeds them into `get_all_trace_dirs()`. - Smoke-tested end-to-end against 21 real spec records: 126 edits across 41 files extracted via `ai-blame stats` / `report`. Limitations ----------- agent-trace.dev records carry attribution ranges + `content_hash` (spec §6.3) rather than raw `old_string` / `new_string` patches, so `stats` / `timeline` / `report` / `transcript` work fully but `blame` / `annotate` cannot perform the same patch-walk reconstruction as the native parsers. Documented in the parser module docstring and in the README. Tests ----- 7 new unit tests in `parsers::agent_trace::tests` covering parse, filter, fallback, can_parse acceptance/rejection, and `collect_trace_files` extension filtering. Full `cargo test` is green (22 passing); `cargo fmt --check` and `cargo clippy` clean. Amp-Thread-ID: https://ampcode.com/threads/T-019e0ee7-99b6-72e7-a9eb-e71bba013ceb Co-authored-by: Amp <amp@ampcode.com>
1 parent 3892e20 commit 63a36fd

4 files changed

Lines changed: 537 additions & 5 deletions

File tree

README.md

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,30 @@ rules:
215215
216216
## Supported Agents
217217
218-
| Agent | Status |
219-
|-------|--------|
220-
| Claude Code | ✅ Supported |
221-
| OpenAI Codex / GitHub Copilot | ✅ Supported |
222-
| Others | PRs welcome! |
218+
| Agent | Status | Format |
219+
|-------|--------|--------|
220+
| Claude Code | ✅ Supported | Native `.jsonl` traces under `~/.claude/` |
221+
| OpenAI Codex / GitHub Copilot | ✅ Supported | Native `.jsonl` traces (incl. CLI ghost snapshots) |
222+
| Amp, Cursor, Goose, Cline, Kimi, … | ✅ Supported via [agent-trace.dev](https://agent-trace.dev/) | `.agent-trace/*.json` v1 sidecars (any producer) |
223+
| Others | PRs welcome! | |
224+
225+
### agent-trace.dev v1
226+
227+
ai-blame reads the open, vendor-neutral
228+
[agent-trace.dev v1 spec](https://agent-trace.dev/) from
229+
`<repo>/.agent-trace/*.json` (and `~/.agent-trace/`). Any tool that
230+
emits the spec — whether as a first-party feature or via a third-party
231+
exporter that converts an agent's native logs — is automatically
232+
supported.
233+
234+
> agent-trace.dev records carry attribution ranges + `content_hash`
235+
> rather than raw `old_string` / `new_string` patches, so the `stats`,
236+
> `timeline`, `report`, and `transcript` commands work fully against
237+
> them; `blame` / `annotate` will mark touched lines with metadata but
238+
> cannot perform the same patch-walk reconstruction as the native Claude
239+
> / Codex parsers. See
240+
> [`src/parsers/agent_trace.rs`](src/parsers/agent_trace.rs) for the
241+
> mapping details.
223242

224243
## Differences from Python Version
225244

src/extractor.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,33 @@ pub fn get_codex_trace_dirs() -> Vec<PathBuf> {
155155
dirs
156156
}
157157

158+
/// Locate agent-trace.dev v1 sidecar directories. The spec is storage-agnostic
159+
/// but the conventional layout is `<repo>/.agent-trace/*.json`, so we look in
160+
/// the project root and the user's home as fallbacks.
161+
pub fn get_agent_trace_dirs() -> Vec<PathBuf> {
162+
let mut dirs = Vec::new();
163+
164+
if let Ok(cwd) = std::env::current_dir() {
165+
let local = cwd.join(".agent-trace");
166+
if local.exists() {
167+
dirs.push(local);
168+
}
169+
}
170+
171+
if let Some(home) = dirs::home_dir() {
172+
let user_dir = home.join(".agent-trace");
173+
if user_dir.exists() {
174+
dirs.push(user_dir);
175+
}
176+
}
177+
178+
dirs
179+
}
180+
158181
pub fn get_all_trace_dirs(claude_dir: &Path) -> Vec<PathBuf> {
159182
let mut dirs = vec![claude_dir.to_path_buf()];
160183
dirs.extend(get_codex_trace_dirs());
184+
dirs.extend(get_agent_trace_dirs());
161185
dirs
162186
}
163187

0 commit comments

Comments
 (0)