<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lachie James</title>
    <description>The latest articles on DEV Community by Lachie James (@lachiejames).</description>
    <link>https://dev.to/lachiejames</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3830450%2Fd385909f-3d24-4c9e-a1a4-cac6582d7673.jpg</url>
      <title>DEV Community: Lachie James</title>
      <link>https://dev.to/lachiejames</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lachiejames"/>
    <language>en</language>
    <item>
      <title>I added voice mode to my AI work tool using ElevenLabs as the speech layer</title>
      <dc:creator>Lachie James</dc:creator>
      <pubDate>Wed, 08 Apr 2026 08:02:13 +0000</pubDate>
      <link>https://dev.to/lachiejames/i-added-voice-mode-to-my-ai-work-tool-using-elevenlabs-as-the-speech-layer-1pfk</link>
      <guid>https://dev.to/lachiejames/i-added-voice-mode-to-my-ai-work-tool-using-elevenlabs-as-the-speech-layer-1pfk</guid>
      <description>&lt;p&gt;SlopWeaver is a desktop app that connects your work tools (Gmail, Slack, Linear, Google Docs, and more) and uses AI to handle busywork. It already had a text-based AI chat with full tool access: workspace search, task creation, cross-platform context. Adding voice meant giving the same capabilities a speech interface.&lt;/p&gt;

&lt;p&gt;The architecture:&lt;/p&gt;

&lt;p&gt;ElevenLabs Conversational AI handles the speech side. It manages the WebSocket connection, speech-to-text, text-to-speech, turn detection, and interruption handling. SlopWeaver is registered as a custom LLM provider. When you speak, ElevenLabs transcribes it and sends the text to SlopWeaver's API in OpenAI Chat Completions format. SlopWeaver processes it through the same Claude chat pipeline as text (tool calls, context retrieval, generation), then streams the response back as SSE chunks. ElevenLabs begins speaking the chunks as they arrive, so TTS starts before the full response is generated.&lt;/p&gt;

&lt;p&gt;In practice, the voice conversation has the same tool access as text. You can ask it to search your messages, create tasks, summarize threads, pull context from connected platforms. Voice is an input modality, not a separate product.&lt;/p&gt;

&lt;p&gt;In this demo I used voice mode to work through some product issues. Asked the AI to explain a Sentry error on screen, told it to create a task for broken Gmail email rendering, then accepted a proposed fix from the tasks page. One task created by voice, one existing proposal accepted.&lt;/p&gt;

&lt;p&gt;Three problems I ran into that might save you time if you're building something similar:&lt;/p&gt;

&lt;p&gt;ElevenLabs uses Whisper for transcription, and it misheard domain-specific words constantly. "Slack" became "stack", "Jira" became "gyra", "SlopWeaver" became anything. I built a per-user vocabulary correction service that runs post-transcription. It's a simple find-and-replace pass but it made a big difference in downstream AI comprehension.&lt;/p&gt;

&lt;p&gt;The AI's text responses contain markdown, code blocks, URLs, and embedded content. None of that works when spoken aloud. Added a sanitization layer between the chat pipeline output and the SSE stream that strips non-voice-safe content. The AI generates one response, and the rendering layer decides what's appropriate for voice vs text display.&lt;/p&gt;

&lt;p&gt;The round trip is: speech capture, ElevenLabs transcription, network to SlopWeaver API, Claude generation (sometimes with tool calls that hit external APIs), network back to ElevenLabs, text-to-speech, audio playback. Each step adds latency, and tool calls add more. Two things helped most: using ElevenLabs' lowest-latency TTS model (eleven_flash_v2_5) and streaming response chunks so TTS can start speaking before generation finishes. The target is under 800ms for the first spoken token on non-tool-call turns.&lt;/p&gt;

&lt;p&gt;Each voice conversation turn is a billable action. Preflight affordability check runs when the session starts, actual cost deduction happens after the webhook completes. Sessions are Redis-backed with a 30-minute TTL, which also prevents race conditions between overlapping turns.&lt;/p&gt;

&lt;p&gt;Stack: NestJS, React 19, Tauri v2 (desktop), Claude (Anthropic SDK with prompt caching), ElevenLabs Conversational AI (WebSocket + custom LLM webhook), Supabase + pgvector, BullMQ.&lt;/p&gt;

&lt;p&gt;Building in public. Previous demos showed the review queue and the cross-platform AI chat. This one adds voice as a third interaction mode.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>productivity</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Fan-out auditing: making AI coding agents actually read your entire codebase</title>
      <dc:creator>Lachie James</dc:creator>
      <pubDate>Wed, 25 Mar 2026 13:36:09 +0000</pubDate>
      <link>https://dev.to/lachiejames/fan-out-auditing-making-ai-coding-agents-actually-read-your-entire-codebase-31ba</link>
      <guid>https://dev.to/lachiejames/fan-out-auditing-making-ai-coding-agents-actually-read-your-entire-codebase-31ba</guid>
      <description>&lt;p&gt;AI coding agents can't fit a large codebase in context. When you ask one to audit 800 files, it reads some and skips the rest. I've tried Claude, ChatGPT, Deep Research for refactoring, type safety, architecture audits. Decent answers every time, but I could always find things they missed just by reading the code myself.&lt;/p&gt;

&lt;p&gt;Fan-out auditing trades parallelism for thoroughness.&lt;/p&gt;

&lt;h3&gt;
  
  
  The idea
&lt;/h3&gt;

&lt;p&gt;Instead of one agent doing a shallow pass on 500 files, you launch 200 agents each doing a deep pass on 5-8 files. AI gets worse at larger batches. An agent reading 5 files will catch things an agent reading 500 won't.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;The prompt is a Claude Code slash command (~300 lines of markdown). The orchestrator:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Runs one grep to find relevant files&lt;/li&gt;
&lt;li&gt;Groups files into slices of 5-8, keeping same-directory files together&lt;/li&gt;
&lt;li&gt;Shows the slice plan and waits for confirmation&lt;/li&gt;
&lt;li&gt;Launches agents in batches of 10, each writing findings to its own &lt;code&gt;.md&lt;/code&gt; file in the repo&lt;/li&gt;
&lt;li&gt;After all phase 1 agents complete, launches phase 2 agents that read ~12 phase 1 files each and identify cross-cutting patterns&lt;/li&gt;
&lt;li&gt;Writes a final synthesis from the phase 1 and phase 2 files&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why small batches matter
&lt;/h3&gt;

&lt;p&gt;This is the core insight. AI performance degrades with input size. Give an agent 5 files and it reads every line, considers each one against the criteria, and produces specific findings with line numbers. Give it 50 files and it starts pattern-matching on file names, skipping files that "look fine," and producing vague observations.&lt;/p&gt;

&lt;p&gt;The fan-out pattern forces thoroughness by keeping each agent's scope small enough that it has no excuse to skim.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why every agent writes to a file
&lt;/h3&gt;

&lt;p&gt;The first version of this used agents that returned findings in their response, and the orchestrator summarized them. That's lossy. An agent finds 8 specific issues with line numbers, the orchestrator compresses them to "several type safety issues found," and the detail is gone.&lt;/p&gt;

&lt;p&gt;When every agent writes to its own .md file in the repo, nothing gets lost. The orchestrator synthesizes from files, not from compressed return values in context. You can also watch the files appear in real time in your editor, which is useful for long runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: cross-cutting patterns
&lt;/h3&gt;

&lt;p&gt;Individual agents can only see their slice. If 9 different slices all have the same issue, no single agent knows that. Phase 2 agents each read ~12 phase 1 output files and look for patterns that span multiple slices. This is where findings like "this same function is reimplemented in 8 modules" emerge.&lt;/p&gt;

&lt;p&gt;Phase 1 runs on Sonnet (file reading is straightforward). Phase 2 runs on Opus (reasoning across 12 reports to spot non-obvious patterns is harder).&lt;/p&gt;

&lt;h3&gt;
  
  
  What it's good for
&lt;/h3&gt;

&lt;p&gt;I've used the same pattern for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy audits: checking user-facing text against a style guide or tropes list&lt;/li&gt;
&lt;li&gt;Refactoring: finding duplicated logic, consolidation opportunities, dead code&lt;/li&gt;
&lt;li&gt;Selling point discovery: reading every file to find features worth marketing&lt;/li&gt;
&lt;li&gt;Architecture audits: checking module boundaries, dependency violations, pattern compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You swap the reference document and the pre-filter grep. The fan-out mechanics stay the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it doesn't fix
&lt;/h3&gt;

&lt;p&gt;A human who knows the codebase inside out will still catch things this misses. The AI still can't reason about high-level architecture decisions or understand business context that isn't in the code. But the difference between "AI read some files and gave vague observations" and "AI read every file and gave findings with line numbers" is worth the 29 minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The test run
&lt;/h3&gt;

&lt;p&gt;I used it to check all user-facing text in my product (SlopWeaver, ~800 source files) against tropes.fyi (a catalog of AI writing tells).&lt;/p&gt;

&lt;p&gt;Results: 201 slices, 809 files inspected, 220 output files, 180+ findings.&lt;/p&gt;

&lt;p&gt;It scales to any repo size. A repo with 10,000 files would produce more slices and take longer, but the same prompt works.&lt;/p&gt;

&lt;p&gt;Stack: Claude Code, Claude Sonnet 4.6 (phase 1), Claude Opus 4.6 (phase 2).&lt;/p&gt;

&lt;p&gt;The prompt is open source: &lt;a href="https://github.com/lachiejames/fan-out-audit" rel="noopener noreferrer"&gt;github.com/lachiejames/fan-out-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One markdown file, drop it into &lt;code&gt;.claude/commands/&lt;/code&gt;. The repo includes the full output from this audit (all 220 files) so you can browse what it produces before running it.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>codereview</category>
    </item>
    <item>
      <title>I built an AI chat that searches your work tools and cites its sources</title>
      <dc:creator>Lachie James</dc:creator>
      <pubDate>Mon, 23 Mar 2026 04:24:17 +0000</pubDate>
      <link>https://dev.to/lachiejames/i-built-an-ai-chat-that-searches-your-work-tools-and-cites-its-sources-1gf2</link>
      <guid>https://dev.to/lachiejames/i-built-an-ai-chat-that-searches-your-work-tools-and-cites-its-sources-1gf2</guid>
      <description>&lt;p&gt;Every AI assistant I've tried needs you to manually provide context from your other tools.&lt;/p&gt;

&lt;p&gt;SlopWeaver's AI chat skips that. It's connected to your work tools (Gmail, Slack, Linear, Google Docs, and more) and searches across them when you ask a question. Every source is cited inline with platform-colored chips. Hover to preview, click to navigate to the original.&lt;/p&gt;

&lt;p&gt;This demo shows the flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a security assessment report in the inbox&lt;/li&gt;
&lt;li&gt;Ask the AI "what's this about?" and get a quick summary&lt;/li&gt;
&lt;li&gt;Ask for a deep analysis: the AI triggers workspace search, knowledge lookup, and extended reasoning&lt;/li&gt;
&lt;li&gt;Get a structured report: findings with CVSS scores, per-finding remediation status from Linear tickets, a supply chain incident timeline from Slack, stakeholder responsibilities, and your personal action items with deadlines&lt;/li&gt;
&lt;li&gt;33 sources cited inline from Gmail, Slack, Linear, and knowledge sources&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The search layer is hybrid: keyword + semantic (Voyage AI embeddings, 1024 dimensions) + reranking (Voyage rerank-2.5). Entity resolution connects "Daniel Frost" across platforms into one identity. Claude generates the response with extended reasoning and numbered citations pointing back to specific source documents.&lt;/p&gt;

&lt;p&gt;The citation UX was the hardest part to get right. Each citation chip is color-coded to its platform (Gmail orange, Slack purple, Linear blue). Hovering shows a preview card with the original subject, sender, timestamp, and excerpt. Clicking navigates to the source in the inbox or opens it externally.&lt;/p&gt;

&lt;p&gt;Stack: Tauri v2 (desktop), NestJS, React 19, Claude (Anthropic SDK with prompt caching), Supabase + pgvector, BullMQ, Voyage AI.&lt;/p&gt;

&lt;p&gt;Building in public. The previous demo showed the approval queue (AI drafts, you review before anything sends). This one shows the intelligence layer behind it. Together they tell the story: AI that can see across your tools AND still waits for you to act.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>rag</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built an AI inbox that can't send emails (and that's the whole point)</title>
      <dc:creator>Lachie James</dc:creator>
      <pubDate>Wed, 18 Mar 2026 05:40:50 +0000</pubDate>
      <link>https://dev.to/lachiejames/i-built-an-ai-inbox-that-cant-send-emails-and-thats-the-whole-point-3007</link>
      <guid>https://dev.to/lachiejames/i-built-an-ai-inbox-that-cant-send-emails-and-thats-the-whole-point-3007</guid>
      <description>&lt;p&gt;

  &lt;/p&gt;
&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/NeRBoiR_bxU"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;




&lt;p&gt;Every AI productivity tool seems to promise the same thing: "AI handles your email/messages/tasks automatically!"&lt;/p&gt;

&lt;p&gt;And every time I try one, the first thing I do is turn off the auto-send because I don't trust it to email my coworkers unsupervised.&lt;/p&gt;

&lt;p&gt;So I built the opposite. SlopWeaver is a desktop AI work inbox where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI pulls context from your connected tools (Gmail, Slack, Linear, etc.)&lt;/li&gt;
&lt;li&gt;AI drafts replies and stages actions&lt;/li&gt;
&lt;li&gt;Everything lands in a review queue&lt;/li&gt;
&lt;li&gt;Nothing sends without you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The short demo shows this queue workflow in action. One message comes in, context gets pulled automatically, draft is ready.&lt;/p&gt;

&lt;p&gt;The "nothing auto-sends" constraint has been the best architectural decision in the project. It simplifies trust, UX, and error handling all at once.&lt;/p&gt;

&lt;p&gt;Stack: Tauri v2, NestJS, React 19, Claude (Anthropic SDK), Supabase + pgvector, BullMQ.&lt;/p&gt;

&lt;p&gt;Building in public. Would love feedback from anyone who's tried to solve the "too many tools, not enough context" problem.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
