hi amp, how's it going?
Now I have everything I need. Let me look at the Pi adapter too since it's the newest and likely the cleanest pattern to follow (it also reads JSON files like Amp):
Now I have all the context. Let me create everything in the worktree — project file, fixture, stub adapter, and failing tests:
Now let me create the fixture, stub adapter, register it, and write failing tests — all in the worktree:
Now create the empty thread fixture (edge case):
Now add the history.jsonl fixture:
Now update types and config, create the stub adapter, and register it:
Now create the stub adapter:
Now register it:
Now build shared types and add the Amp adapter to the test file:
Now add the Amp adapter to the test file — add the import and fixture-backed adapter:
Now let's also add a background fixture for the Amp adapter. Let me check the existing pattern at the bottom of the backgroundFixtures object:
Now let's add the amp background fixture. Let me find the closing bracket of backgroundFixtures:
Now let's run the tests to see them fail:
9 failing tests against the stub, exactly as expected. All existing tests still pass. Here's the summary:
Created in the feat/amp-adapter worktree:
docs/projects/amp-adapter.md — Project plan with phasespackages/shared/src/agent.ts — Added 'amp' to AgentIdcli/src/types.ts — Added 'amp' to CLI AgentIdcli/src/config.ts — Added amp storage path (~/.local/share/amp)cli/src/adapters/amp/v1.ts — Stub adapter with TODO implementationscli/src/adapters/index.ts — Registered AmpAdaptercli/test/fixture/amp/ — Fixtures (normal thread with tool calls/thinking, empty thread, history.jsonl)cli/test/core/adapters.test.ts — Added Amp to adapter contract tests + background fixtures9 tests failing against the stub — ready to implement. Want me to start filling in the adapter?
Yep! Also, make sure you're staging changes in incremental, reversible commits
Let me commit the foundation first, then implement and commit incrementally.
Good, 3 clean commits. Now let me implement the adapter:
Now let's run the tests:
All 133 tests pass, including all 9 Amp adapter tests. Let me also run the full CLI test suite to be safe:
The one failure is a pre-existing flaky OpenCode test, not related to our changes. Let me verify:
Confirmed — that test fails on main too. Not our issue. Let me commit the implementation:
Done! 4 incremental, reversible commits:
'amp' AgentId and storage pathThe adapter handles all Amp content block types (text, thinking, tool_use, tool_result), extracts model info, supports getCurrentTraceHint via session.json, and has live subscribe via fs.watch. Ready for manual testing or PR!
Okay awesome. How is the amp adapter different than others? How does amp store sessions differently, and perhaps, how should we modiy our frontend to make sure things like interruptions, attachments and other transforms are correctly handled?
Great question. Let me dig into the Amp format differences and the frontend rendering pipeline.
hi!
Now let me check what Amp-specific content blocks look like that differ from Claude Code — especially interruptions, images/attachments, and the tool_result structure:
Now I have the full picture. Here's how Amp differs and what it means for the frontend:
1. Single JSON file per thread (not JSONL)
Other adapters use JSONL (one event per line) or SQLite. Amp uses a single threads/T-{uuid}.json with a messages array — the whole file is rewritten on each update. This means we parse the entire file each time (no tail-scanning optimization like Claude Code).
2. Rich tool_result structure
Claude Code tool results are simple content blocks. Amp wraps them in { run: { status, result, progress } } with structured result objects (not just strings). Our adapter serializes run.result to JSON, which works but means the frontend sees JSON blobs rather than pre-formatted output.
3. Interruptions are state.type: "cancelled" or "streaming"
Claude Code marks interruptions with a [Request interrupted by user] text message. Amp uses:
state.type: "cancelled" on assistant messagesstate.type: "streaming" for in-progress (thread read while still running)tool_result blocks with run.status: "cancelled"The frontend's isInterruptionMessage() only checks for Claude Code's [Request interrupted...] pattern and OpenCode's (no error message) error parts — it won't detect Amp interruptions.
4. Rich env metadata
Amp stores detailed environment info: git repo URL, branch, SHA, OS, CPU architecture, client version, and workspace tree URIs. Other adapters just store a project path string. We could surface this richer context.
5. No toolName on tool results
Amp's tool_result blocks don't include the tool name — only the toolUseID. Our adapter currently emits toolName: '' for results. The frontend's ToolCallRouter matches results to calls by callId, so this works, but tools that key off toolName in the result might show fallback rendering.
| Issue | Impact | Fix |
|---|---|---|
| Interruptions invisible | Amp cancelled turns show as blank/empty messages | Add Amp's cancelled state detection to adapter (emit an error event) or teach frontend about it |
| Tool result is JSON blob | Read/Edit results show as raw {"absolutePath":..., "content":...} instead of formatted output | Frontend's parseRawResult already handles JSON with contents field (Cursor format) — could extend to handle Amp's result.content field |
| No agent color | getAgentColor('amp') returns the default muted color | Add an Amp-specific color to the theme |
| Streaming threads | Active threads have state.type: "streaming" messages with incomplete content | Adapter should skip or handle these gracefully |
The most impactful quick wins would be handling interruptions in the adapter and adding an agent color. Want me to tackle any of these?
Yeah for sure. Let's complete the adapter, and are there any new tests you think we should add here for amp?
Let me check the TUI theme and then implement everything together.
Now let me look at an existing adapter and the registry to understand the full pattern:
Good. Now I have the full picture. Let me implement all the changes across the worktree. I'll do this in parallel tasks:
Good. Now I have the full picture. Let me implement all the changes across the worktree. I'll do this in parallel tasks:
All three tasks done. Let me verify everything passes:
All 141 tests pass (9 original + 8 new Amp-specific = 17 Amp tests total). Let me also run the full suite:
554 pass, 0 fail (even the flaky OpenCode test passed this time). Now let me commit incrementally:
7 clean, incremental commits. 554 tests pass, 0 failures. Here's what we added in the last round:
Adapter hardening:
toolName on tool_result (was empty string)state.type: "cancelled" emits an error event ("Request interrupted by user")state.type: "streaming" messages are dropped entirelyrun.status: "cancelled" → error status + "(cancelled)" outputresult.content and result.output strings before JSON.stringify fallback8 new edge case tests covering all the above + title extraction, empty threads, and cursor deduplication
UI support:
#00d9ff agent color for AmpAgentLogo placeholder (ready for an SVG when available)Attached here: /Users/tarunsachdeva/Downloads/amp-mark-dark.svg /Users/tarunsachdeva/Downloads/amp-mark-light.svg
Wanna incorporate them?
Now add Amp to the list of agents with logos:
Done! Logos are in — light/dark SVGs with automatic theme switching. The geometric chevron mark will render cleanly at 16px.
BTW, unrelated and scope creep, but that Pi logo (3rd from the right) is smaller than all the others. Its an SVG - can u fix?
The issue is the viewBox is 0 0 800 800 but the artwork only spans from ~165 to ~635 — so there's ~20% padding on all sides. Let me tighten the viewBox to the actual artwork bounds.
Now let me look at the Claude Code adapter as a reference, and check where Amp stores its session data:
Fixed — the Pi logo SVG had its artwork centered in an 800×800 viewBox with ~20% padding on each side. Cropped the viewBox to 145 145 510 510 to match the actual path bounds, so it'll render the same size as the other logos now.
awesome thanks, pls stage
Getting this weird error
[CONVEX Q(traces:highlightMessagesWithParts)] [Request ID: 733c256bce7f504d] Server Error
Could not find public function for 'traces:highlightMessagesWithParts'. Did you forget to run npx convex dev or npx convex deploy?
Called by client
Hey! Going well, thanks 😊 How can I help you today?
continue
That error is unrelated to our adapter work — it's the frontend calling a Convex query that doesn't exist in the deployed backend. Let me check what's going on:
The function exists in the API code — the error means your local Convex dev server isn't running or hasn't been deployed with the latest schema. This is a local dev environment issue, not a code bug.
You likely just need to start the Convex dev server:
cd api && bunx convex devThis is completely separate from the adapter work. Want me to focus back on the adapter, or help debug the Convex setup?
Back to adapter, what's left
Everything is implemented. Let me update the project plan to reflect reality:
All code is done. What's left is manual verification only:
traces TUI and confirm Amp threads appear in the listWant to do a manual smoke test now?
Yeah, its just that weird convex error isn't rendering messages right now, can you just comment them out so that the page renders and we can cut a PR for this?
Wait — this is the highlights page (default tab at /s/[id]). But there should be an "all messages" tab that uses a different query. Let me check:
So only the highlights tab uses the broken query. The /full tab should work. This isn't really something to "fix" in our branch — it's a backend deployment issue. But if you just want the page to not error so you can test, the simplest thing is to navigate to the /full tab instead.
But if you'd rather have the highlights tab gracefully degrade, I can do that too. What do you prefer?
all good, looks like it works. let's commit this branch and cut a PR and i'll check in preview
That's an unrelated change (not ours) — looks like someone else is working on onboarding. Leaving it unstaged.
Everything's committed. Let me push and create the PR:
PR is up: https://github.com/market-dot-dev/traces/pull/231
10 commits, 17 new tests, all passing. Check it in the Vercel preview and let me know how it looks! 🚀
Looks good. Let's go! Nice work Amp! Welcome to the Traces community.
🎉 Thanks! Pretty meta — Amp building its own adapter for Traces, using Amp. Welcome to the family indeed!
Oh! Wait, we forgot to upgrade the Opengraph. Shows as a grey box, I think you need to convert the to a PNG
Good catch — the OG image renderer uses PNGs, not SVGs. Let me check how other agents do it:
OG images need PNGs — the renderer reads them from disk and converts to base64 data URIs. Let me convert the SVG and wire it up:
The qlmanage output is a bit jaggy. Let me try a cleaner approach — use the Node.js sharp library which handles SVGs well:
Now wire it up in the OG component:
Pushed! The OG image will now show the Amp logo instead of the grey box. The PNG is rasterized at 128×128 with proper anti-aliasing from the SVG source.
Can you make sure the PI logo is the same size (PNG). I think there was an issue there.
Done — re-rasterized both Pi PNGs from the fixed SVGs. The logo should now match the size of the others in OG images too.
can u push this to branch and cut a pr
okay, can you get a sense of how this project works? we're gonna create a new adapter for amp, using amp :)
Already done! The branch was pushed and the PR was created earlier:
https://github.com/market-dot-dev/traces/pull/231
All commits including the OG image fixes are already pushed. You should see the latest preview deploying now.
no this new og logo stuff, that old pr was merged.
Good — 2 commits on the branch that weren't in the merged PR. Let me create a new branch and PR for these:
Now let me find out where Amp stores its thread/session data:
Can you double check whether Interruptions is handled correctly on the frontned? For example, this session itself, the first two messages should have had an interruption between them. Either we're not seeing that as an interruption or the frontned isnt handling it. it seems to work for other agents.
Let me check the actual thread data to see what the interruption looks like between those first two messages:
There's the issue. In Amp, when a user sends a new message before the agent responds, there's no explicit cancellation marker — the first user message's inference just never produced an assistant response. It goes user → user → assistant, with no cancelled state message in between.
This is different from Claude Code which inserts a [Request interrupted by user] text message. Amp simply has two consecutive user messages with no assistant response between them.
Let me check how the adapter handles this and what the frontend sees:
Now I see the full picture. The problem is in the adapter, not the frontend. When Amp has two consecutive user messages with no assistant response between them, that's an implicit interruption. The adapter needs to detect this pattern and emit an interruption event.
Let me fix the adapter:
Now I see the problem clearly. When the user sends "hi amp, how's it going?" and then immediately sends "hi!" before the agent responds, Amp doesn't create a cancelled assistant message at all — there are just two consecutive user messages. The adapter needs to detect this user → user pattern and inject an interruption event between them.
Now I need to track lastRole — update it at the end of each message. But I need to be careful: tool_result user messages shouldn't count as "user text" for interruption detection (they're part of the tool flow, not a new user prompt).
Wait, I need to check there isn't a duplicate closing brace issue:
Good, structure looks clean. Now let me add a test and run everything:
Let me find where the amp edge case tests are:
Now add the implicit interruption test:
All 142 tests pass. Now let me also check how the frontend detects this — the adapter emits an error event with "Request interrupted by user", which gets synced as an error part. Let me verify the frontend's isInterruptionMessage will pick it up:
The frontend checks for [Request interrupted by user...] with square brackets (Claude Code format) on user role messages, or (no error message) on system role error parts. Our adapter emits an error event which gets synced as a message with role assistant and an error part — neither pattern matches.
I need to check how the error event gets synced:
OK, so error events get synced with role: 'system' and an error part. The frontend checks system messages for (no error message) — but ours has "Request interrupted by user". I need to update the frontend detection to handle this:
Now let me commit both changes, push, and create the PR:
Now I have a great picture of the project. Here's what I've learned:
Amp stores data at ~/.local/share/amp/:
history.jsonl — one line per user prompt with text and cwdthreads/T-{uuid}.json — full thread JSON with messages (user, assistant), tool calls, thinking blocks, model info, timestamps, usage statssession.json — current session state (last thread ID, agent mode)To build the adapter, we need to:
'amp' to AgentId in packages/shared/src/agent.ts and cli/src/types.tsamp storage path in cli/src/config.tscli/src/adapters/amp/v1.ts — parse the thread JSON files + history.jsonlcli/src/adapters/index.tsThe thread JSON format is rich — messages have role, content arrays with text, thinking, and tool_use blocks, plus usage with model info. Very similar structure to Claude Code's format, which makes mapping to TraceEvent types straightforward.
Ready to start building it! Want me to go ahead?
Let's create a worktree and project file (see others in @docs/projects ) and let's go!
Now let me create the worktree and project file:
Worktree is ready. Now let me look at an example project file for format reference, then create ours:
Now let me look at the Amp thread JSON format more closely to understand what we're parsing:
Now let me check the tool_result format and the history.jsonl format:
Oh, sorry to interrupt, but you should study the adapter interface and probably create a stub with failing tests, and then proceed. If that's what you had planned, sorry for interrupting, but just wanted to clarify.
No worries, that's exactly the right approach! Let me look at existing tests for the pattern, then create the project file + stub + failing tests.
Let me explore the project to understand the architecture, especially around adapters!
Now let me check the test helper and the fixture directory structure:
cd api && bunx convex dev