# Kundan Thonda https://kundan.fyi/about ## About I'm a software engineer at Copart, on the Member Mobile team in Dallas, TX. I work across mobile, backend and platform. On the client that means React Native and TypeScript. On the server it means Node.js, Redis and CI. I owned over-the-air updates, reCAPTCHA Enterprise and the UK identity-verification migration end to end, and shipped each one behind staged rollouts. I also build tools that Copart engineers use every day, including a launcher for Claude Code. ## Right now - I'm building [Pitwall](/work/pitwall), a Mac app that keeps terminals and Claude Code sessions in one window. - I'm building [Local Voice Dictation](/work#local-voice-dictation), a private, on-device alternative to Wispr Flow, in Swift. - I'm adding routing to the [code assistant](/work/read-only-agents) that chooses how to answer based on confidence. - I'm building [Kai](/work/kai-v2), the chat on this site. It answers from what is published here and shows the source behind each answer. ## How I work The same four habits show up across what I have built. - **Ship in stages.** [Over-the-air updates](/work/ota-updates) roll out in stages. The [reCAPTCHA rollout](/work/recaptcha-enterprise) went market by market behind flags. The [UK and Ireland identity launches](/work/identity-migration) ran separately. - **Keep a way back.** The app recovers from reCAPTCHA SDK failures without blocking sign-in. The identity migration kept a legacy-flow fallback. The [content service](/work/content-service) keeps serving cached alerts during CMS outages. - **Check before trusting.** Over-the-air bundles are code-signed and verified end to end, and a CI gate rejects any bundle that needs a store release. [Kai](/work/kai-v2) checks every source number against the passages it supplied. - **Give assistants read access, not write access.** The [code assistant](/work/read-only-agents) answers questions but cannot change code. Fixes go through a separate, human-approved service that opens draft pull requests. ## Working with AI tools At Copart I build the tooling around Claude Code. The [launcher](/work/claude-code-launcher) sends sessions through the company’s gateway, with model switching and live spend and quota tracking, and 500+ engineers use it. I also rolled out shared team skills for tickets, PR review, releases and TestFlight, automatic pull-request review in CI, and usage cost controls. ## Experience ### Software Engineer, Copart (Member Mobile), Sept 2025 to present - Designed and built over-the-air updates across the app and the Node.js server. Bundles are code-signed, rollout is staged, and a CI gate rejects any bundle that needs a store release. - Integrated reCAPTCHA Enterprise on client and server across login, registration and bidding. It protected 3.7M+ sessions in two months. Per-market flags controlled the rollout. - Built the mobile registration flow for buyers in 10+ countries and 10 languages: payment with 3DS, ID verification, OCR document scan and business documents. - Led the migration from LexisNexis to Veriff for UK identity verification, finished before the contract expired. Separate UK and Ireland launches ran behind per-market flags, with retry limits and a legacy-flow fallback. - Built an in-app content service. Payload CMS publishes to Redis, so the API keeps serving cached alerts during CMS outages. The business publishes alerts and banners without an app release. - Built the Claude Code launcher used by 500+ Copart engineers. It sends sessions through the company’s gateway, with model switching and live spend and quota tracking. I also rolled out shared team skills for tickets, PR review, releases and TestFlight, automatic pull-request review in CI, and usage cost controls. - Built an internal assistant on Google ADK and Gemini that answers questions about code, Datadog and Crashlytics. It has no write access. Fixes go through a separate human-approved service that opens draft pull requests. ### Software Development & Service Management Intern, Provalus (Optomi), Feb 2025 to May 2025 - Connected ServiceNow workflow automation to REST APIs and C#/.NET services. Scheduled jobs and business rules removed manual operations work. - Built system health and incident dashboards that the operations team adopted for weekly reporting. ### IT Help Desk Technician (part-time), SFA, Jun 2024 to Aug 2025 - Troubleshot access, account and device issues for a campus of 10,000+ students. ## Skills - **Languages:** TypeScript, JavaScript, Python, C#, SQL, Bash - **Mobile:** React Native, iOS (Xcode, TestFlight), Android (Gradle), Fastlane, OTA (expo-updates), MobX - **Web and backend:** React, Next.js, Node.js, Express, Payload CMS, REST - **Assistants and search:** Claude Code (skills, hooks, subagents), MCP servers, Google ADK, Gemini on Vertex AI, vector search and embeddings, Graphify, Obsidian (notes the assistants read), usage cost tracking - **Data and cloud:** PostgreSQL, Redis, SQLite, GCP (Cloud Run, Cloud SQL), Amazon S3 - **Observability:** Firebase Crashlytics, FullStory, Datadog, Unleash feature flags - **Identity and security:** reCAPTCHA Enterprise, Veriff - **Tools and testing:** Git, GitHub Actions, Docker, Jest, Maestro ## Education B.S. Computer Science, Stephen F. Austin State University. Graduated Aug 2025, GPA 3.6. ## Certification ServiceNow Certified System Administrator (CSA), 2025. ## Off the clock Away from the keyboard, I enjoy the night sky, Formula 1, and trying a new recipe. I make time for films, music, and travel, too. --- # Over-the-air updates https://kundan.fyi/work/ota-updates ## Problem The Copart Member Mobile app needed a way to ship JavaScript fixes without waiting for an app store release. An update had to be trusted before it ran, and changes that needed native code had to stay on the store-release path. ## What I built I built the over-the-air path on both sides: expo-updates in the React Native app, and the Node.js server behind it. Bundles are code-signed and roll out in stages. A CI gate rejects any bundle that needs a store release. Each release runs end-to-end signature checks and unit tests. ## Result JavaScript fixes for the Copart app now reach users in minutes. --- # reCAPTCHA Enterprise rollout https://kundan.fyi/work/recaptcha-enterprise ## Problem The reCAPTCHA Enterprise rollout had to protect login, registration and bidding without locking out a real buyer. Sign-in still had to work when the SDK failed. ## What I built I integrated reCAPTCHA Enterprise on the client and server. Per-market flags controlled the staged rollout, and the app recovers from SDK failures without blocking sign-in. I added Account Defender for login and registration, plus outcome feedback for risk assessment. ## Result The reCAPTCHA Enterprise rollout protected 3.7M+ sessions in two months. --- # A code assistant with no write access https://kundan.fyi/work/read-only-agents ## Problem The code assistant at Copart needed a firm boundary between answering questions and changing code. It must have no write access. ## What I built I built the internal assistant on Google ADK and Gemini. It directs questions to the codebase, Datadog or Crashlytics, using search and a code graph built with Graphify. Other tools can read it through MCP servers, a standard way for assistants to read data. Fixes go through a separate, human-approved service that opens draft pull requests. ## Result The code assistant can answer engineers’ questions without changing any of its sources. I’m now adding routing that chooses how to answer based on confidence. --- # Claude Code launcher https://kundan.fyi/work/claude-code-launcher ## Problem The Claude Code launcher brings session access, usage costs and quotas into one place for Copart engineers. ## What I built I built the Claude Code launcher to send sessions through the company’s gateway, with model switching and live spend and quota tracking. I also rolled out shared team skills for tickets, pull-request review, releases and TestFlight, automatic pull-request review in CI, and usage cost controls. ## Result The Claude Code launcher is used by 500+ Copart engineers. --- # Mobile registration flow https://kundan.fyi/work/registration-flow ## Problem The Copart registration flow has to serve buyers across countries and languages. Not every buyer needs the same steps. ## What I built I built the mobile registration flow in React Native and TypeScript. It covers payment with 3DS, ID verification, an OCR document scan and business documents. ## Result One registration flow now serves buyers in 10+ countries and 10 languages. --- # UK identity verification migration https://kundan.fyi/work/identity-migration ## Problem The UK identity verification migration had a fixed deadline: the LexisNexis contract was expiring. The UK and Ireland needed separate launches. ## What I built I led the move from LexisNexis to Veriff. Per-market flags controlled the UK and Ireland launches, with retry limits and a legacy-flow fallback. ## Result The UK identity verification migration finished before the LexisNexis contract expired. --- # In-app content service https://kundan.fyi/work/content-service ## Problem The Copart in-app content service had to keep alerts available during a CMS outage. ## What I built I built the in-app content service on Payload CMS. It publishes to Redis, and the API serves cached alerts. The database is continuously backed up to Amazon S3. ## Result The business can publish alerts and banners to the Copart app without an app release. --- # Pitwall https://kundan.fyi/work/pitwall ## Problem Pitwall has to track Claude Code sessions across separate shells. ## What I built I’m building Pitwall alone in TypeScript as a macOS app. Each project has a live board of its terminals and Claude Code sessions. --- # Kai, the chat on this site https://kundan.fyi/work/kai-v2 ## Problem The first Kai was my resume pasted into a chatbot. The new one has to answer from my own pages, show where each fact came from, run on low-cost services, and stay safe to leave open to anyone. ## What I built Kai searches my pages before it writes anything, matching both keywords and meaning. Every answer carries numbered sources. The server checks each number against the passages it supplied; an answer without a valid source becomes “I don’t know that one.” A backup service can answer if the first fails. Per-visitor limits and a daily cap bound cost. The chat and the read-only address for other assistants share one set of tools. ## Hard part Free services differ in how reliably they use a search tool. So Kai’s server searches first, using the visitor’s last two messages, and supplies the five best passages, numbered. Kai does not depend on the chatbot choosing to search. If meaning-based search is slow or fails, keyword search still works. I keep meaning-based scores from different search services separate, because they cannot be compared reliably. ## Result My goal for Kai was at least 36 of 40 test questions answered correctly with a source. The latest run passed 39 of 40 (October 21, 2026). The 40 questions cover facts, projects, traps, unknowns, job fit and prompt injection, and the full results are on the [evals page](/evals). --- # Local Voice Dictation https://kundan.fyi/work#local-voice-dictation Local Voice Dictation is a private, on-device alternative to Wispr Flow. It is written in Swift and built on the open-source FluidVoice. --- # Reactotron fork https://kundan.fyi/work#reactotron-fork This Reactotron fork extends the React Native debugger with Swagger-style API docs and request inspection. It is written in TypeScript, and the mobile team uses it. --- # ccswitch https://kundan.fyi/work#ccswitch ccswitch is a per-command LLM-gateway launcher for Claude Code. The code is at github.com/kundan0907/ccswitch. It picks the gateway for each command. --- # Voice-Assisted Receiving App https://kundan.fyi/work#voice-assisted-receiving The Voice-Assisted Receiving App turns spoken warehouse input into structured records. It was my senior design project, built with React and Python on Azure, and it uses Azure Speech-to-Text. --- # Why Kai searches before it answers https://kundan.fyi/notes/why-kai-searches-first Kai is the chat on this site. It answers questions about my work and cites where each answer comes from. The first version of Kai was a chatbot with my resume pasted into the prompt. This one searches my content first. ## Why search comes first A chatbot can have a search tool and still answer without using it. Kai runs on low-cost services, and models vary in how reliably they look up facts. I don’t want the quality of an answer to depend on whether the chatbot chose to search. ## What runs instead Before Kai writes anything, the server searches my pages. It uses the visitor’s latest message and the one before it, so a follow-up like “and what about the second one?” still has context. It supplies the five best passages as numbered sources, S1 to S5. Kai writes an answer with those numbers. The server checks each one against the passages it supplied. It drops any number that does not match. An answer left without a valid source becomes “I don’t know that one.” Most answers need one request to the chat service. Kai can ask for up to two extra searches, but the first search never depends on it doing so. ## How the search works I build the search index from this site’s pages before deployment. Each passage is a section of a page, with a header like “Case study: Over-the-air updates › Result”, so it makes sense alone. Two searches rank the passages, one by keywords and one by meaning. I merge the two ranked lists. When a question has at least three distinct terms and the best keyword match contains all of them, the server skips meaning-based search. That saves a network request. If meaning-based search fails or takes more than two seconds, keyword search works alone. I avoid mixing meaning-based scores from different search services, because those scores cannot be compared reliably. ## How to check a source You don't have to take the citations on faith. Each citation in an answer is a numbered chip. Open it and the passage it points to appears under the answer, with a link to the full page. If an answer is wrong, the passages show why. Either the right passage never came back, or it came back and the model misread it. Those are different bugs, and the passages tell me which one I have. ## What I haven't measured yet I haven't published test results. The plan is a set of 40 questions that checks required facts, forbidden facts and citations, including trap questions about things I don't share. The scores will go on a public page when they exist.