Amplifier Case Study

Cross-Repo
Bug Hunting

Following a bug across 3 repositories, 2 languages,
and a Python-to-Rust FFI boundary

Active Investigation
Based on developer-reported debugging sessions
The Symptom

501 Not Implemented

A voice feature in amplifier-chat started failing. Model downloads were broken. The error message was unhelpful.

What broke

Voice model downloads in amplifier-chat returned a 501 Not Implemented error. The feature that had been working simply… stopped.

The question

Nothing in amplifier-chat had changed. The code was the same. So where was the bug? And why was a download returning "Not Implemented"?

This is the kind of bug that makes engineers groan. The symptom is in one repo, but the cause could be anywhere in the dependency chain.

The Territory

Three repos. Two languages. One bug.

amplifier-chat
Python / TypeScript
Frontend application where the voice feature lives. This is where the symptom appeared — model downloads failing with a 501 error.
Surface Layer
amplifier-distro
Build System / Packaging
Distribution and dependency management. The amplifier-chat[voice] optional dependency pattern wasn't packaging voice dependencies correctly.
Middle Layer
amplifierd
Rust / PyO3
The daemon process with Rust code exposed to Python via PyO3 bindings. An async cancellation bug lurked at the FFI boundary.
Root Cause
Layer 1 · amplifier-chat

Starting at the surface

Observation
Voice downloads fail with 501
The voice model download endpoint returns "Not Implemented." But the endpoint exists, and the code to handle it hasn't changed.
Investigation
Check the dependency chain
The voice feature uses optional dependencies — amplifier-chat[voice]. If these aren't installed, voice features fall back to "not implemented." Could the dependencies be missing?
Finding
Dependencies aren't resolving
The optional dependency pattern is broken. Amplifier traces the issue upstream — something changed in how the distribution builds voice packages.
Layer 2 · amplifier-distro

Into the build system

The packaging problem

Changes in amplifier-distro altered how voice dependencies are bundled. The [voice] extras pattern that pip uses to install optional features was no longer resolving correctly.

Why it's tricky

Build system changes are invisible to application code. amplifier-chat didn't change — but the packages it received at install time did. Classic "works on my machine" territory.

But that wasn't the whole story

Fixing the dependency resolution would restore voice downloads. But in a separate Amplifier session investigating a related issue, a deeper bug was found — one that had been silently corrupting async operations at the Rust/Python boundary.

Layer 3 · amplifierd

The root cause:
async across an FFI boundary

In a separate Amplifier debugging session, a confirmed async cancellation bug was found in the Rust daemon (amplifierd), exposed through PyO3 bindings.

# The bug: calling an async method synchronously # coordinator.request_cancel() is defined in Rust via PyO3 # It returns a coroutine — an async operation that needs to be awaited # ❌ What the code was doing: coordinator.request_cancel() # Returns a coroutine object, doesn't execute it # ✅ What it should have been doing: await coordinator.request_cancel() # Actually executes the cancellation

The Rust function request_cancel() was exposed to Python as an async method via PyO3. But the calling code treated it as synchronous — creating a coroutine that was immediately discarded, never awaited, never executed.

The Challenge

Why async + FFI bugs are notoriously hard

Silent failure

Calling an async function without await doesn't throw an error. It silently creates a coroutine object that gets garbage collected. The operation simply never happens.

Cross-language boundary

The async nature of the function is defined in Rust, but the calling mistake happens in Python. No single-language linter catches this — it lives at the PyO3 FFI seam.

Intermittent symptoms

Cancellation bugs manifest as operations that "sometimes work" — they complete when they happen to finish before the cancel was needed, and fail silently when they don't.

A human debugger would need to: understand Python async semantics, understand Rust async semantics, understand how PyO3 bridges them, and know to look for unawaited coroutines at the boundary. Amplifier followed this thread across all three layers.

The Payoff

"Two changes needed."

After tracing the full call chain across three repositories, Amplifier immediately identified both required fixes — the dependency resolution in amplifier-distro and the async cancellation in amplifierd.

The Fix

Diagnose → Fix → Test → Merge

Step 1
Diagnose
Trace bug across repos
Step 2
Git Worktree
Isolate the fix branch
Step 3
Fix Rust Code
Correct the async call
Step 4
Run Tests
Verify the fix works
Step 5
Squash Merge
Clean commit history

Git worktrees for isolation

The developer created a git worktree to isolate the Rust fix from other work in progress. Amplifier guided the fix, the developer ran tests, and the change was squash-merged — a clean, auditable commit.

Cross-session coordination

The developer offered to "prompt amplifier-distro" from another session to make necessary build changes. Multiple Amplifier sessions working in parallel on coordinated fixes across repos.

The Pattern

Sessions coordinating with sessions

This debugging journey revealed a workflow pattern: a developer running multiple Amplifier sessions, each focused on a different repo, sharing context through the developer.

Session A

amplifier-chat — Identifies the 501 error, traces it to a dependency issue, reports finding to developer.

Session B

amplifierd — Finds the async cancellation bug in Rust/PyO3 code, fixes it, runs tests, merges.

Session C

amplifier-distro — Developer offers to "prompt amplifier-distro" to make coordinated build-system changes.

The developer acts as the coordinator, carrying context between focused sessions. Each session maintains deep context about its repo — the developer connects the dots between them.

Why This Matters

What this demonstrates about AI-assisted debugging

Following the thread

Amplifier didn't stop at the first plausible explanation. It traced the symptom (501 error) through the dependency layer (build system) to the root cause (async FFI bug) — across repo and language boundaries.

Polyglot fluency

The debugging required understanding Python async semantics, Rust async semantics, PyO3 FFI bindings, and how they interact. No single-language tool handles this. Amplifier operates across the full stack.

Instant diagnosis

After tracing the full call chain, Amplifier identified "two changes needed" immediately — no trial-and-error, no bisecting commits, no printf debugging. Trace the chain, find the cause, state the fix.

End-to-end workflow

Not just diagnosis — Amplifier participated in the full cycle: diagnose, create worktree, fix code, run tests, squash-merge. From symptom to shipped fix in a single workflow.

Reality Check

Without AI, this bug is a multi-day investigation.

Cross-repo async FFI bugs combine three of the hardest debugging challenges: distributed systems, language boundaries, and concurrency. Engineers who've chased these bugs know the cost.

By The Numbers

Investigation scope

3
Repositories traversed
2
Languages (Python + Rust)
1
FFI boundary (PyO3)
2
Fixes identified instantly

Workflow: Diagnose → Git Worktree → Fix → Test → Squash Merge — all within Amplifier sessions, with cross-session coordination between repos.

Sources

Sources & Methodology

Data as of: March 2026

Feature status: Active — cross-repo debugging is a core Amplifier capability used in ongoing development

Story source:

Repositories involved:

Gaps & limitations:

Attribution: Story reflects a real debugging workflow described by the developer who participated in the sessions

Try It

Your bugs don't
stay in one repo.

Neither should your debugging tools.

Amplifier traces bugs across repository boundaries, language boundaries, and FFI layers — following the thread wherever it leads.

More Amplifier Stories