Voice AI and backend engineer. I work on the frameworks voice agents run on, and on the failures that only show up on a real phone call.
Twelve fixes merged upstream — eight into livekit/agents, plus pipecat, jambonz and drachtio.
📍 Chennai, India · 2026 CS graduate · open to a first engineering role 🔗 Portfolio · LinkedIn
In the framework itself
- livekit/agents#7139 —
ConnectionPool.invalidate()closed sockets that were still streaming, and a handshake in flight escaped invalidation entirely and stayed reusable with stale settings. Eleven plugins call it fromupdate_options, so one change to the primitive repaired all of them. Reviewed line by line by a maintainer. - #7054 — found a whole bug class, fixed all fifteen instances across library, examples and tests, and got ruff's
RUF006enabled in their CI so dangling tasks cannot come back.
Provider plugins — the same stale-handshake bug, found by grepping siblings for the shape
- #7132 asyncai · #7133 neuphonic · #7140 cartesia, where the API version was also sent in a header that disagreed with the body it was built for
Lifecycle and cleanup
- #7023 — an STT connection pool that stayed open after shutdown
- #7012 — per-stream HTTP sessions leaking through a
WeakSet - #7050 — a discarded prewarm task rebuilding a pool after close
- pipecat#5464 — a TTS service wrote model, voice and language only into its websocket init message, so a runtime change was stored, warned about, and silently never sent
SIP and telephony
- jambonz#1585 — a TTS
stream_resumedevent sent to a different hook path than the one it resumed - jambonz#1584 — a call transferred between feature servers re-sent trying, ringing and in-progress statuses the application had already received
- drachtio-srf#240 — proxied responses built their header strip list from the request option, so the wrong headers were stripped and forwarded
Open PRs across livekit/agents, pipecat, litellm and drizzle-orm.
Take a bug fixed in one place, then grep every sibling for the same shape — it is almost never alone. Then verify by mutation: revert the fix and confirm the new test fails. A test that passes both ways has told me nothing.
Most of it started with debugging real calls on my own voice agent: audio arriving out of order, sessions torn down mid-sentence, a connection quietly serving the wrong voice after a settings change.
Atlas — an outbound voice agent on Twilio Media Streams and Deepgram. Barge-in, a call-session state machine, outcome classification, dialling constrained to legal calling hours, and SMS/WhatsApp on one session model. ~31,000 lines, solo.
InvoiceCheck.in — GST invoice verification, live. An 11-point compliance check run before marketplaces reject an invoice, OCR auto-fill, Razorpay pay-per-check.
Python asyncio pytest · LiveKit Agents Pipecat jambonz drachtio · Twilio Programmable Voice & Media Streams SIP WebRTC Deepgram · TypeScript NestJS Next.js · Postgres Prisma Redis BullMQ · Docker CI/CD



