DEV Community

Rairo Mukamuri
Rairo Mukamuri Subscriber

Posted on

One line of JSON stops the pump

How I gave a Claude Code agent ears, a seat in the plant's Discord, and a supervisor to answer to. Built for the Flip the Switch hackathon.

A pump tells you it is failing weeks before it fails. It hums at a new pitch. A bearing starts to hiss. An impeller picks up a fresh tone. The fitter who walks past it every morning sometimes hears it. Usually the plant hears it when the pump stops.

Across Southern Africa, mills, mines, cold rooms, and borehole pumps run on ear and experience. Vibration sensors cost more than the pump. Every fitter already carries a phone.

The brief for Flip the Switch was simple: let the machine speak in the chat the team already uses, and keep every decision about the machine with a person.

The room

Here is the run from the demo in the Injini Plant Discord server on 2026-11-06.

At 18:28, a recording of pump-00 lands in #plant-floor with one line: @injini pump-00.

At 18:29, Injini answers with a spectrogram and a number: +4.3σ out of baseline. The change sits between 330 and 851 Hz, with a new tone at 469 Hz.

Injini then does what a good maintenance lead does. It creates #case-pump-00-001, a new Discord channel linked to the plant floor. It writes a case-file room document with the evidence. It briefs the Foreman, a second Claude Code agent, who reads the case file, writes a work-order room document, and states the plan: impeller or blade fault likely, lock out first, 3 to 5 hours.

Then Injini asks to stop the pump. The supervisor's phone shows a card: Permission needed · Allow once / Allow for this session / Decline. The supervisor allows it. The stop is recorded at 18:33:22 with the supervisor's name.

At 18:35, an after-repair recording arrives in the case channel: −3.6σ. The pump sounds like itself again. The case closes.

The ears

Injini's ear is an acoustic model from my earlier Injini project. A frozen AudioSet-trained network (EfficientAT mn10_as) turns each second of sound into a 960-dimensional embedding. Three healthy 10-second clips enrol one machine. Leave-one-clip-out Ledoit-Wolf Mahalanobis distance measures how far a new recording sits from that machine's healthy cloud, on a sigma scale. Three sigma raises the alarm.

To explain a score, Injini uses band occlusion. It swaps each frequency band for healthy audio and watches which swap brings the score down. That band holds the change. A spectral diff finds the new peak inside it: 469 Hz.

The numbers are public and modest. On the DCASE 2020 (MIMII) pump dataset, with 3 enrolment clips per machine, Injini scores 0.83, 0.83, 0.80, and 0.59 AUC on pump IDs 00, 02, 04, and 06. On the demo pump (id_00), it flags 0 of 20 healthy clips and 7 of 20 faults. On fans, it scores 0.36 to 0.59 AUC, sitting at chance. The demo machine is a pump for that reason, and the README carries the full table.

The interlock

A factory requires a clear interlock before a machine stops.

Injini runs as a Claude Code agent inside Switch. Its home folder holds a CLAUDE.md file with its instructions and a .claude/settings.json file with its tool permissions. Scoring, enrolling, and listing machines run freely under the allow rules. One command sits in the ask rule:

"ask": ["Bash(python injini.py stop:*)"]
Enter fullscreen mode Exit fullscreen mode

That line requires Claude Code to ask before running the stop command. Switch catches that prompt and renders it as an approval card in Discord. Only people allowed to address Injini can answer it. The agent prepares the diagnosis and the paperwork. A person with authority closes the circuit.

One line of JSON puts the stop decision with the supervisor, on the floor, in the channel.

How to wire this in Switch

A first-time Switch user can replicate this multi-agent pattern in four steps:

  1. Bridge the chat: In Switch Console 0.40.1, run a server on your computer and connect Discord from the Messaging apps card on the server's Home page. Post once in #plant-floor; that first message turns the channel into a Switch room. Switch delivers each audio attachment into the agent's session as a file, and the agent posts images back with send_attachment.
  2. Create one folder per agent: Give @injini and @foreman separate local directories. Put each agent's role, tone, and workflow into its CLAUDE.md. Add both as Claude Code agents in Switch Console with their folder as the working directory, keep auto-approve off for @injini, and bring them in with /invite-agent injini and /invite-agent foreman.
  3. Coordinate with rooms, documents, and roles: Switch gives Claude Code built-in tools to manage the workspace. Instruct @injini in CLAUDE.md to spawn a child room (#case-pump-00-001) when a clip crosses 3σ, write the findings to a case-file room document, and mention @foreman. The Foreman reads case-file, writes work-order, and tags @artisan.
  4. Gate high-stakes actions with .claude/settings.json: Put safe read/score scripts in "allow" and state-changing scripts in "ask". Switch shows every "ask" prompt as an approval card in the channel.

What Switch carries

Every joint in this workflow is a Switch feature:

  • The Discord bridge moves the recording into Injini's session and sends the spectrogram back as an image.
  • Rooms created at runtime give each fault its own dedicated channel, linked to #plant-floor.
  • Room documents (case-file and work-order) hold the evidence and the repair plan in shared state.
  • Roles route the work order to whoever holds @artisan.
  • Approval cards keep the stop command with a person.

Two Claude Code agents and one acoustic model work alongside people in the chat the plant already uses.

What I would change

I first built Injini as a raw protocol client in Python that speaks Switch's event stream directly. Switch Console 0.40.1 registers agents through your own sign-in, and a raw client needs a registration key to join. Moving the model inside a Claude Code session solved this immediately, and the raw protocol client stays in the repo for servers that issue keys.

Two additions would make Switch even stronger for the plant floor: custom titles and button labels on approval cards for domain decisions ("Stop pump-00?"), and a warning to the room owner when a tagged role has an empty seat. In the demo, the @artisan seat was empty when the Foreman handed off the work order.

Try it

The code, the agent folders, the raw protocol client, and the pump clips live at github.com/rapha18th/injini-floor. Watch the two-minute film at youtu.be/d_CaMpgidnI.

Every machine gets a voice. Every decision stays human.

HowISwitch

Top comments (0)