Skip to content
New Latest article Do something cool with it: a week on Databricks Read

INaudio: agentic support triage on Claude Code

20 min down from two days, across 100+ inherited repositories

“A support ticket that might have taken 2 days can now be solved in a matter of 20 minutes.”

Rodrigo Machado VP of Engineering, INaudio

The challenge

INaudio is one of the largest audiobook distributors in the world. It was founded in 2004, when audiobooks still shipped on CDs and cassettes, was acquired by Spotify in 2021, and returned to independent ownership in 2025. Tarmac managed the technical transition out of Spotify: a migration of the entire platform into INaudio-owned infrastructure that landed on August 1st with one hour of downtime.

The migration is its own story. This one is about the day after.

What the support desk inherited on day one
  • 100+repositories
  • 120+microservices
  • 300distribution partners
  • 25Munique products
  • 700Mmonthly listeners
  • 2,000+terabytes of static files

Buying a fully formed business means you do not get the luxury of growing your knowledge alongside your user base. Tarmac took over first-line technical support the moment the cutover completed, for a platform nobody on the team had built, described by documentation that had drifted years away from the running code.

The scale of that is easier to see as a comparison. A team joining a normal engagement gets to know four or five repositories. This team had to hold the whole estate.

Repositories a support engineer has to reason across
  • This engagement 100+
  • A typical project 4 to 5

So every ticket started from zero. A finance question and a delivery question and a metadata question each sent an engineer into a different unfamiliar service, reading code to work out what the system was even supposed to do before they could work out why it had not done it. Rodrigo Machado put it plainly:

Each ticket was like starting over from scratch.

That is the real cost of an acquisition handover, and it does not show up on a migration plan. It shows up as a support desk where a ticket can burn two days, most of it orientation rather than diagnosis.

What we built

The fix was a knowledge base with an agent on top of it: a map of the world describing every repository, service, and function, and how they connect, plus a Claude Code agent that uses the map to drive a human to the exact code and the exact query that will answer a given ticket.

The important word in that sentence is drive. The agent never touches the codebase or the production data. It reads, reasons, cites, and hands work to a person. Everything below follows from that decision.

One index, two layers of knowledge

The knowledge base has exactly two kinds of committed document, and one index that both are discoverable through.

The knowledge base, and the loop that grows it
Layer 1

System docs

One per service. Data models with real table and field names, real enum values, the endpoints, the integrations, the operational scripts, and the known failure modes. Core tables get full field-level documentation, supporting tables get a name and a purpose. This is the map.

44 documents
Layer 2

Solution docs

One per resolved scenario, written symptom first. Exact error strings alongside the plain language a user would actually use, then branching diagnostics where each result routes to a different next step, then root cause, resolution, and the dead ends worth not repeating.

35 documents

Every non-trivial investigation becomes a new solution doc, and every fact verified along the way is written back into the system docs. The knowledge base compounds instead of forking: the fiftieth ticket is cheaper than the fifth.

Two design decisions in there do most of the work.

Solution docs are indexed by symptom, not by system. A support ticket arrives as a complaint, not a diagnosis. The person writing it does not know which service is at fault, so a knowledge base organised by service is unreachable from the only information the ticket contains. Each solution doc therefore carries a deliberately wide net of symptom phrasings: the literal error string from the log, the message the UI shows, and several ways a non-technical user might describe the same thing. That list is the retrieval surface.

A matching document is a hypothesis, never an answer. The agent is instructed to treat a matched solution doc as a starting point and to run its first diagnostic step to confirm the root cause applies to this case before following its resolution. Configs drift. A runbook that was right in April can be wrong in August, and a knowledge base that is trusted blindly is worse than no knowledge base at all, because it is confidently wrong at speed.

The loop

The workflow is a loop, not a pipeline, and it is explicit about which actor does what.

How a ticket moves. Only one step touches a live system.
  1. Human

    1. The ticket arrives

    Symptoms, error text, and the specific entity IDs involved. The agent asks for the IDs up front, because a diagnosis that cannot be run against a real case is not a diagnosis.

  2. Agent

    2. Orient on the map

    Read the index, identify every system that could be involved rather than committing to one, and check whether a solution doc already matches these symptoms. Most real issues span several services, so the agent is told not to narrow early.

  3. Agent

    3. Verify against code

    Form two or three explicit hypotheses, then go read the source that would confirm or kill each one. Not the documentation. The code. Every claim comes back cited to a file and a line number.

  4. Human

    4. Run the queries

    The agent hands over one or two queries chosen to split the surviving hypotheses, with the table and column names already verified against the schema and a note on what each possible result would mean. A person runs them. This is the only step that reaches a live system.

  5. Loop

    Repeat until conclusive

    The agent states which hypotheses the results support and which they eliminate, and what is still open. If the answer is inconclusive it goes back to step 3 and generates the next step rather than guessing.

  6. Agent

    5. Root cause, then resolution

    Root cause stated with evidence, code cited by path and line, data cited as the query and its dated result. Only then does it propose a fix, pointing at the specific code, config, or record that needs to change. A human makes the change.

Evidence, not recall

An agent that sounds confident is easy. An agent a support desk will actually trust took a specific set of rules, and they are the part of this build we would carry to any other client.

  • Docs are hypotheses, code is truth. When a system doc and the source disagree, the source wins and the discrepancy gets flagged and fixed. The knowledge base is a starting position, not an authority.
  • Never propose a root cause from docs alone. No cause, design, fix, or diagnostic query goes out before the relevant source has been read. If the agent lacks access to a repository it has to say which repository and which specific file or logic it needs, rather than reasoning around the gap.
  • The agent reads code, the human runs queries. A clean division of labour that also happens to be the safety property.
  • Cite everything. Code as a path and line number. Data as the exact query and its dated result. Not “I believe X” but “I confirmed in this file at this line that X.”
  • Verify even the expected answer. A matching runbook or a familiar-looking config is a hypothesis. A thirty second check is cheaper than a wrong conclusion delivered to a client.
  • Verify every table and column name before writing a query. Never inferred from naming convention. The agent checks the system doc, then the model definition, then any column-name override on the field, and asks rather than guessing if it still cannot find the source. Guessed schema is the fastest way to burn a support desk’s trust in a tool.

That last rule looks pedantic written down. It exists because an ORM field name and the actual database column can diverge silently through an override, and a query built on the assumed name fails in a way that looks like a data problem rather than a tooling problem. The team lost time to exactly that before the rule existed.

Guardrails that are structural, not advisory

Diagnosis in this environment routinely means checking live cloud state, and that is the point where a helpful agent becomes a dangerous one. The posture is layered, deliberately.

The real guarantee is an identity with a read-only policy and no write or delete permissions at all. Everything the agent does in the cloud goes through that principal. On top of it sits a written skill telling the agent to use only that profile and to surface any required change rather than make it, and underneath that a pre-execution hook that inspects every shell command before it runs and hard-blocks anything that would either use the wrong credentials or mutate state, across the cloud CLI and every infrastructure tool in the stack.

The hook is written to fail open on purpose. It runs on every command in the session, so it only ever blocks when it positively identifies a violation, and it is documented as defence in depth rather than as the security boundary. The permissions are the boundary. This is the difference between a guardrail a team can rely on and one that quietly stops working the first time it gets in someone’s way.

The whole workflow is Claude Code, checked into a repository

Everything described above is a Claude Code project, and that is what makes it a system rather than a set of habits. The rules are not typed into a chat window at the start of a session and lost at the end of it. They are files, versioned in git, reviewed by pull request, and shipped with the knowledge base.

  • CLAUDE.md is the operating contract. Claude Code reads it automatically when a session opens. It picks the mode from what the developer brings, ticket triage or the project pipeline, and it carries the verification discipline. Every rule in the “evidence, not recall” section above lives in that file, which means the standard is reviewable, arguable in a pull request, and identical for every engineer.
  • The cloud posture ships as a Skill. The read-only rules are a Claude Code Skill with a trigger description covering the cloud CLI, the SDKs, and the phrasings a developer actually uses, so it loads exactly when a session reaches for live infrastructure and costs nothing in context when it does not.
  • The guardrail is a hook, not a request. A PreToolUse hook is registered in the project settings, matched to shell commands, and resolved through the project directory variable so it works in every clone rather than on one laptop. It inspects the command and blocks at the tool boundary, before execution. Claude Code will not run a project hook until a person approves it on first use, so the safety net is opt-in by design.
  • The document generators are agent guides. Writing a new system doc, capturing a solution doc, and running the staged project pipeline are each a written playbook the agent follows, so two engineers on different tickets produce documents in the same shape.
  • MCP handles publishing. Stage documents reach the team’s workspace over MCP, and only when a developer asks. The agent is explicitly forbidden from browsing or searching that workspace for evidence.

The practical effect is that onboarding is a clone. A new engineer gets the map, the runbooks, the operating contract, the skill, the guardrail, and the playbooks in one command, already configured, and starts working tickets the same way as everyone else. Building the workflow on Claude Code rather than around it is what turned a good internal habit into something a fourteen person team could share.

The results

The measured effect is on the clock, and it is large.

Time to resolve a non-trivial support ticket
  • Before about 2 days
  • After about 20 minutes

Roughly 15 hours and 40 minutes of senior engineer time returned on every ticket in that band, against a two day baseline of sixteen working hours.

What that means for the people running the desk is worth being precise about, because the headline number is easy to misread. The agent did not make anyone type faster. It removed the orientation phase.

The expensive part of a support ticket was never the fix. It was the hours before the fix: working out which of a hundred repositories to open, reading enough of an unfamiliar service to understand its intended behaviour, and only then starting to diagnose. That phase is now a few minutes of the agent reading the map and handing back two queries.

Triage stopped depending on who is available. Before, a ticket touching the finance ledger effectively had to wait for whoever had last been inside the finance ledger. The map is the same map for everyone, so the work routes on capacity rather than on who happens to hold the context.

A whole class of ticket stopped being an investigation at all. Thirty five recurring scenarios are now written down as symptom-first runbooks with copy-paste diagnostics. When a ticket matches one, the desk is confirming a known root cause rather than discovering it, and the cost drops to running a single verification step.

The work compounds instead of evaporating. Every non-trivial investigation ends by capturing what was learned, and every fact verified along the way is written back into the map with a freshness date. In roughly four months the two layers grew to about 107,000 words of verified, code-checked documentation, built as a byproduct of doing the support work rather than as a documentation project nobody had budget for.

Where it goes next

The same map that explains why something broke also explains what a change would touch, so the knowledge base is being extended into solution design: given a proposed feature, the agent runs a staged pipeline from technical analysis through design and plan to executable tickets, under the same evidence rules. Analysis is explicitly forbidden from proposing a solution, design has to name the alternatives it rejected, and rollback has to be stated as concrete commands rather than “revert the change.”

Facts verified during that work flow back into the same system docs the support desk reads. One map, two uses, and every ticket and every project makes it better.

This was one of three workstreams running out of the same handover. The other two were the migration itself, which landed in one hour of downtime, and the cost work that took more than $500,000 a year out of the cloud bill.

There is no vendor relationship to describe at the end of this one. Tarmac is INaudio’s technical team, from the engineers working the support queue to the VP of Engineering quoted above. The agentic workflow in this case study was not built for a client and handed over. It is how the team works, because we are the team.

Tech stack

  • Claude Code
  • Claude Code Skills
  • Claude Code Hooks
  • MCP
  • Python
  • AWS
  • Git

Let’s build something worth taking off.

Tell us what you’re building. We’ll assemble the senior team to ship it.