<?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>Forem: Laurent Charignon</title>
    <description>The latest articles on Forem by Laurent Charignon (@laurent_charignon).</description>
    <link>https://forem.com/laurent_charignon</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%2F3570041%2F0a45385f-2d9e-4b0f-987f-cdeede2b6b4a.jpg</url>
      <title>Forem: Laurent Charignon</title>
      <link>https://forem.com/laurent_charignon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/laurent_charignon"/>
    <language>en</language>
    <item>
      <title>Building with LLMs at Scale: Part 5 - Learning and Knowledge Accumulation</title>
      <dc:creator>Laurent Charignon</dc:creator>
      <pubDate>Fri, 17 Oct 2025 03:14:50 +0000</pubDate>
      <link>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-5-learning-and-knowledge-accumulation-6ml</link>
      <guid>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-5-learning-and-knowledge-accumulation-6ml</guid>
      <description>&lt;p&gt;This is the final article in my series on working with LLMs at scale. &lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part1-pain-points"&gt;Part 1&lt;/a&gt; through &lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part4-experiments"&gt;Part 4&lt;/a&gt; focused on &lt;em&gt;building&lt;/em&gt; with LLMs—managing sessions, ensuring quality, coordinating parallel work.&lt;/p&gt;

&lt;p&gt;This article is about something different: using LLMs as &lt;strong&gt;learning tools&lt;/strong&gt;. Not just to write code, but to help you understand complex systems, internalize patterns, and build lasting knowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Learning Problem
&lt;/h2&gt;

&lt;p&gt;As a developer, you're constantly learning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New frameworks and libraries&lt;/li&gt;
&lt;li&gt;Complex algorithms&lt;/li&gt;
&lt;li&gt;System architecture patterns&lt;/li&gt;
&lt;li&gt;Domain-specific knowledge&lt;/li&gt;
&lt;li&gt;Best practices and anti-patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Traditional learning methods are slow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading documentation takes hours&lt;/li&gt;
&lt;li&gt;Watching tutorials is passive&lt;/li&gt;
&lt;li&gt;Trial-and-error is inefficient&lt;/li&gt;
&lt;li&gt;Taking notes manually is tedious&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What if LLMs could accelerate this? Not by just answering questions, but by creating personalized learning materials tailored to how &lt;em&gt;you&lt;/em&gt; learn best?&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 1: Heavily-Annotated Code (Worksheets)
&lt;/h2&gt;

&lt;p&gt;When learning a new codebase or pattern, I ask Claude to generate &lt;strong&gt;worksheets&lt;/strong&gt;—code with extensive inline comments explaining every decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Understanding React Hooks
&lt;/h3&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Explain React hooks to me
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate a complete React component using hooks, but add inline comments
explaining:
- Why this hook is needed
- What problems it solves
- Common mistakes to avoid
- How it compares to class components
- Performance implications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// useState: Manages local component state&lt;/span&gt;
  &lt;span class="c1"&gt;// Why: We need to track user data that changes over time&lt;/span&gt;
  &lt;span class="c1"&gt;// Replaces: this.state in class components&lt;/span&gt;
  &lt;span class="c1"&gt;// Common mistake: Forgetting state updates are asynchronous&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// useEffect: Handles side effects (API calls, subscriptions)&lt;/span&gt;
  &lt;span class="c1"&gt;// Why: We need to fetch data after component mounts&lt;/span&gt;
  &lt;span class="c1"&gt;// Dependencies: [userId] means "re-run when userId changes"&lt;/span&gt;
  &lt;span class="c1"&gt;// Common mistake: Missing dependencies causes stale closures&lt;/span&gt;
  &lt;span class="c1"&gt;// Performance: Cleanup function prevents memory leaks&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Start loading&lt;/span&gt;
    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Fetch user data&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Cleanup: Cancel fetch if component unmounts&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// In production, you'd actually cancel the fetch here&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Dependency array: re-run when userId changes&lt;/span&gt;

  &lt;span class="c1"&gt;// useMemo: Memoizes expensive computations&lt;/span&gt;
  &lt;span class="c1"&gt;// Why: Prevents recalculating on every render&lt;/span&gt;
  &lt;span class="c1"&gt;// Only recalculates when 'user' changes&lt;/span&gt;
  &lt;span class="c1"&gt;// Common mistake: Overusing for cheap operations (adds overhead)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;displayName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Expensive operation example (yours might be more complex)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// useCallback: Memoizes function references&lt;/span&gt;
  &lt;span class="c1"&gt;// Why: Prevents child components from re-rendering unnecessarily&lt;/span&gt;
  &lt;span class="c1"&gt;// Without this: New function created on every render&lt;/span&gt;
  &lt;span class="c1"&gt;// Performance: Only useful if passed to optimized child components&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRefresh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Refresh logic here&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleRefresh&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Refresh&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't just code—it's a &lt;strong&gt;learning artifact&lt;/strong&gt;. I can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read it top to bottom to understand the flow&lt;/li&gt;
&lt;li&gt;See why each decision was made&lt;/li&gt;
&lt;li&gt;Learn common mistakes to avoid&lt;/li&gt;
&lt;li&gt;Understand performance implications&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Prompt Pattern
&lt;/h3&gt;

&lt;p&gt;The key is being specific about what you want explained:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate [concept] code with inline comments explaining:
- Why this approach (vs alternatives)
- Common mistakes
- Performance considerations
- When to use / not use
- How it connects to [related concept]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've used this pattern to learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rust's ownership system&lt;/li&gt;
&lt;li&gt;Clojure's transducers&lt;/li&gt;
&lt;li&gt;Kubernetes operators&lt;/li&gt;
&lt;li&gt;Distributed system patterns&lt;/li&gt;
&lt;li&gt;Database indexing strategies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pattern 2: Flashcards for Spaced Repetition
&lt;/h2&gt;

&lt;p&gt;Reading annotated code helps understanding, but doesn't ensure &lt;em&gt;retention&lt;/em&gt;. For that, I use &lt;strong&gt;flashcards&lt;/strong&gt; with spaced repetition.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Flashcard System
&lt;/h3&gt;

&lt;p&gt;I built a flashcard CLI (see &lt;a href="https://github.com/charignon/flashcards" rel="noopener noreferrer"&gt;github.com/charignon/flashcards&lt;/a&gt;) that implements spaced repetition algorithms (SM-2, Leitner boxes).&lt;/p&gt;

&lt;p&gt;But manually creating flashcards is tedious. So I ask Claude to generate them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Learning System Design
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate flashcards for distributed systems concepts. Format as JSON.
Focus on: CAP theorem, consensus algorithms, partitioning strategies.

Each card should have:
- A precise question
- A complete answer
- Tags for organization
- Notes with additional context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude generates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"In the CAP theorem, what does 'Partition Tolerance' actually mean?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"answer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The system continues to operate despite network partitions (messages between nodes being lost or delayed). You must choose: consistency (all nodes see same data) or availability (all requests get responses) during a partition."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"cap-theorem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"distributed-systems"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fundamentals"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"notes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Common misconception: You can't 'give up' partition tolerance—network partitions will happen. You choose between CP (consistent but not available during partition) or AP (available but inconsistent during partition)."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What is the key difference between Raft and Paxos consensus algorithms?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"answer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Raft uses leader election + log replication (simpler to understand). Paxos uses proposal numbers + acceptors (more flexible but complex). Raft is easier to implement correctly."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"consensus"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"raft"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"paxos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"algorithms"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"notes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Raft was explicitly designed to be more understandable than Paxos. In practice, most systems use Raft (etcd, Consul) or Raft-like algorithms (Zab in ZooKeeper)."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"When should you use hash-based partitioning vs range-based partitioning?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"answer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hash partitioning: Uniform distribution, good for random access. Range partitioning: Preserves ordering, good for range queries. Choose based on your query patterns."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"partitioning"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sharding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"database"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"notes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Real example: User IDs → hash partition (uniform load). Timestamps → range partition (range queries like 'last 24 hours'). Hybrid approaches exist (compound keys)."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I import these directly into my flashcard system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;system_design_cards.json | ./flashcards bulk-create &lt;span class="nt"&gt;--project&lt;/span&gt; system-design
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I can quiz myself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./flashcards quiz &lt;span class="nt"&gt;--project&lt;/span&gt; system-design &lt;span class="nt"&gt;--limit&lt;/span&gt; 5

Question 1/5: In the CAP theorem, what does &lt;span class="s1"&gt;'Partition Tolerance'&lt;/span&gt; actually mean?

&lt;span class="o"&gt;[&lt;/span&gt;Show answer? y/n]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Spaced Repetition Loop
&lt;/h3&gt;

&lt;p&gt;Here's how the system works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Generate flashcards&lt;/strong&gt; from concept (Claude)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Import into flashcard CLI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quiz yourself&lt;/strong&gt; (spaced repetition schedules reviews)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate confidence&lt;/strong&gt; (1-5): Low = see again soon, High = see much later&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeat&lt;/strong&gt; over days/weeks until internalized&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The beauty: I can generate flashcards for &lt;em&gt;any&lt;/em&gt; technical topic in minutes. No manual card creation. No finding existing decks that don't quite match my needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Topics I've Created Flashcard Decks For
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Algorithms&lt;/strong&gt;: Time complexity, specific algorithm details, when to use what&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System design&lt;/strong&gt;: Distributed systems patterns, scalability techniques&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Languages&lt;/strong&gt;: Rust ownership, Clojure idioms, Python async/await&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Databases&lt;/strong&gt;: Indexing strategies, transaction isolation levels, CAP tradeoffs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes&lt;/strong&gt;: Resource types, networking concepts, operator patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interview prep&lt;/strong&gt;: LeetCode patterns, behavioral question frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Meta-Pattern: AI as a Learning Compiler
&lt;/h2&gt;

&lt;p&gt;These patterns share a common insight:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LLMs can transform any learning goal into a personalized learning artifact.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You provide a concept to learn, your preferred style (flashcards, annotated code), and your knowledge gaps. Claude generates materials tailored to you—at the right complexity, in the format you learn best from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Workflow
&lt;/h2&gt;

&lt;p&gt;My typical learning workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Generate annotated code&lt;/strong&gt;: Complete implementation with explanatory comments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract flashcards&lt;/strong&gt;: Key concepts become cards for spaced repetition&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quiz over time&lt;/strong&gt;: Spaced repetition embeds knowledge long-term&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This takes 30-60 minutes to generate materials, then ongoing review. Traditional learning (reading papers, watching videos, manual note-taking) would take hours or days to achieve the same depth.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Flashcard System Details
&lt;/h2&gt;

&lt;p&gt;Since I mentioned my flashcard system, here's how it works:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple spaced repetition algorithms (SM-2, Leitner, fixed intervals)&lt;/li&gt;
&lt;li&gt;Project organization (tag by topic)&lt;/li&gt;
&lt;li&gt;Adaptive quiz sessions (repeat failed items immediately)&lt;/li&gt;
&lt;li&gt;JSON import/export (easy to generate with LLMs)&lt;/li&gt;
&lt;li&gt;CLI for terminal-based studying&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create from Claude-generated JSON&lt;/span&gt;
flashcards bulk-create &lt;span class="nt"&gt;--file&lt;/span&gt; cards.json &lt;span class="nt"&gt;--project&lt;/span&gt; rust

&lt;span class="c"&gt;# Start adaptive quiz session&lt;/span&gt;
flashcards quiz &lt;span class="nt"&gt;--project&lt;/span&gt; rust &lt;span class="nt"&gt;--limit&lt;/span&gt; 10

&lt;span class="c"&gt;# Review a specific card&lt;/span&gt;
flashcards review &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;--confidence&lt;/span&gt; 4

&lt;span class="c"&gt;# See statistics&lt;/span&gt;
flashcards stats &lt;span class="nt"&gt;--project&lt;/span&gt; rust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The adaptive sessions are key: if you get a card wrong (confidence &amp;lt; 3), it immediately re-queues it. You practice until you get it right, then spaced repetition takes over for long-term retention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Learnings
&lt;/h2&gt;

&lt;p&gt;After a year of using LLMs for learning:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Annotated code beats plain code.&lt;/strong&gt; The "why" matters more than the "what."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flashcards with spaced repetition work.&lt;/strong&gt; Generate hundreds of cards in minutes, internalize them over weeks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Active learning beats passive.&lt;/strong&gt; Quizzing yourself is more effective than rereading notes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Beyond Code Generation
&lt;/h2&gt;

&lt;p&gt;This series has been about working with LLMs at scale—managing multiple sessions, ensuring quality, building coordination patterns. But it's also been about a fundamental shift in how we work with code and knowledge.&lt;/p&gt;

&lt;p&gt;LLMs aren't just code generators. They're:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Productivity multipliers (Part 2)&lt;/li&gt;
&lt;li&gt;Quality enforcers (Part 3)&lt;/li&gt;
&lt;li&gt;Coordination layers (Part 3)&lt;/li&gt;
&lt;li&gt;Learning accelerators (Part 5)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The developers who thrive in this new world won't be the ones who use LLMs as fancy autocomplete. They'll be the ones who build workflows, tooling, and patterns that let them work at 10x their previous speed while maintaining quality and continuously learning.&lt;/p&gt;

&lt;p&gt;My system—tmux integration, telemetry, memento, smoke tests, code review workflows, flashcards—is just one approach. Yours will look different based on your needs, your style, your projects.&lt;/p&gt;

&lt;p&gt;But the core principles apply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make the invisible visible (ergonomics, telemetry)&lt;/li&gt;
&lt;li&gt;Enforce quality automatically (smoke tests)&lt;/li&gt;
&lt;li&gt;Share context between sessions (memento)&lt;/li&gt;
&lt;li&gt;Learn continuously (flashcards, annotated code)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The future of software development is human-AI collaboration. Not humans being replaced, but humans being amplified. The question isn't whether to use LLMs—it's how to use them most effectively.&lt;/p&gt;

&lt;p&gt;I hope this series has given you ideas, tools, and patterns you can adapt to your own workflow.&lt;/p&gt;

&lt;p&gt;Now go build something amazing.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;All tools mentioned are open source:&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- &lt;a href="https://github.com/charignon/memento" rel="noopener noreferrer"&gt;Memento&lt;/a&gt; - Note system for LLM context&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- &lt;a href="https://github.com/charignon/flashcards" rel="noopener noreferrer"&gt;Flashcards&lt;/a&gt; - Spaced repetition CLI&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- &lt;a href="https://github.com/charignon/dotfiles" rel="noopener noreferrer"&gt;Dotfiles&lt;/a&gt; - Tmux scripts and config&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- &lt;a href="https://github.com/charignon/appdaemon" rel="noopener noreferrer"&gt;AppDaemon&lt;/a&gt; - Home automation examples&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Find me on &lt;a href="https://github.com/charignon" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; or read more on my &lt;a href="https://charignon.github.io/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>llm</category>
      <category>learning</category>
    </item>
    <item>
      <title>Building with LLMs at Scale: Part 4 - Experiments and Works-in-Progress</title>
      <dc:creator>Laurent Charignon</dc:creator>
      <pubDate>Fri, 17 Oct 2025 03:06:48 +0000</pubDate>
      <link>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-4-experiments-and-works-in-progress-40mp</link>
      <guid>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-4-experiments-and-works-in-progress-40mp</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part1-pain-points"&gt;Part 1&lt;/a&gt;, &lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part2-ergonomics"&gt;Part 2&lt;/a&gt;, and &lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part3-abstractions"&gt;Part 3&lt;/a&gt;, I covered pain points and solutions that work reliably. This article is different—it's about &lt;strong&gt;experiments&lt;/strong&gt;, &lt;strong&gt;works-in-progress&lt;/strong&gt;, and &lt;strong&gt;lessons from things that didn't quite pan out&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not every tool needs to be polished. Some are scaffolding for better ideas. Some solve problems that disappear with faster models. And some teach valuable lessons even when they fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Project Explorer: Solving Yesterday's Problem
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Original Problem
&lt;/h3&gt;

&lt;p&gt;Before Sonnet 4.5, exploring a codebase with Claude was slow. Reading 20 files meant 20 sequential API calls, token limits to manage, and 10+ minutes of setup time.&lt;/p&gt;

&lt;p&gt;Workarounds emerged: naming key files with an &lt;code&gt;@&lt;/code&gt; prefix (&lt;code&gt;@README.md&lt;/code&gt;, &lt;code&gt;@main.go&lt;/code&gt;) so they'd appear first in directory listings, making them easier for Claude to discover. Some users created special "guide" files that aggregated important context.&lt;/p&gt;

&lt;p&gt;I built &lt;code&gt;project-ingest&lt;/code&gt; (inspired by &lt;a href="https://gitingest.com" rel="noopener noreferrer"&gt;gitingest.com&lt;/a&gt;) to solve this. The tool would output a single markdown document with the project structure, key file contents, and dependency graph. Claude could ingest this in one shot instead of reading files incrementally.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Changed
&lt;/h3&gt;

&lt;p&gt;Sonnet 4.5 changed the game, though I'm not entirely sure &lt;em&gt;how&lt;/em&gt;. Is it just faster at reading files? Does it batch requests differently? Does it handle context more efficiently? Whatever the implementation, the result is clear: &lt;strong&gt;it's fast enough that project ingestion overhead feels worse than just reading files directly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (Sonnet 3.5):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;project-ingest&lt;/code&gt; → 15 seconds&lt;/li&gt;
&lt;li&gt;Claude reads summary → 5 seconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total:&lt;/strong&gt; 20 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;After (Sonnet 4.5):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude reads 20 files directly → 8 seconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total:&lt;/strong&gt; 8 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ingester became slower than the problem it solved.&lt;/p&gt;

&lt;h3&gt;
  
  
  When It's Still Useful
&lt;/h3&gt;

&lt;p&gt;I haven't deleted &lt;code&gt;project-ingest&lt;/code&gt; because it remains valuable for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Very large codebases&lt;/strong&gt; (100+ files): Still faster to get a high-level view&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project snapshots&lt;/strong&gt;: Capturing codebase state at a point in time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation generation&lt;/strong&gt;: Creating an overview for human readers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-project analysis&lt;/strong&gt;: Comparing architecture across multiple projects&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But for everyday "help me understand this project" tasks? Obsolete.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Lesson
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Build for today's constraints, not tomorrow's.&lt;/strong&gt; The tool was perfect for its time, but model improvements made it obsolete. That's okay. The investment taught me patterns I applied elsewhere (like how to efficiently traverse project structures).&lt;/p&gt;

&lt;p&gt;When a tool becomes unnecessary because the problem disappeared, that's a success, not a failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Review in Emacs: Closing the Loop
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Review Problem
&lt;/h3&gt;

&lt;p&gt;I'm browsing through a codebase—maybe one I wrote months ago, maybe one Claude just generated, maybe something I'm casually exploring. I spot issues: a function that could be clearer, error handling that's too generic, a repeated pattern that should be abstracted.&lt;/p&gt;

&lt;p&gt;The problem: &lt;strong&gt;I'm in discovery mode, not fix mode.&lt;/strong&gt; I don't want to stop and fix each issue immediately. I want to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mark the issue at the exact line&lt;/strong&gt; while I'm looking at it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep browsing&lt;/strong&gt; without losing flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Later, batch all issues together&lt;/strong&gt; and have an LLM fix them all at once&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where the Code Review Logger comes in. It decouples discovery from fixing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Emacs Integration
&lt;/h3&gt;

&lt;p&gt;I built an Emacs mode (&lt;code&gt;code-review-logger.el&lt;/code&gt;) that tracks review comments in an org-mode file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="c1"&gt;;; While reviewing code in Emacs:&lt;/span&gt;
&lt;span class="c1"&gt;;; SPC r c - Log comment at current line&lt;/span&gt;
&lt;span class="c1"&gt;;; SPC r r - Log comment for selected region&lt;/span&gt;
&lt;span class="c1"&gt;;; SPC r o - Open review log&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;code-review-log-comment&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s"&gt;"Log a review comment with file/line tracking"&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;buffer-file-name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;line&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;line-number-at-pos&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;code-review-format-entry&lt;/span&gt; &lt;span class="nv"&gt;comment&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt; &lt;span class="nv"&gt;line&lt;/span&gt; &lt;span class="s"&gt;"TODO"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates entries in &lt;code&gt;~/code_review.org&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;** TODO [[file:~/repos/memento/src/cli.py::127][cli.py:127]]
   :PROPERTIES:
   :PROJECT: memento
   :TIMESTAMP: [2025-09-30 Mon 14:23]
   :END:
   This error handling is too generic - catch specific exceptions

** TODO [[file:~/repos/memento/src/search.py::89][search.py:89]]
   :PROPERTIES:
   :PROJECT: memento
   :TIMESTAMP: [2025-09-30 Mon 14:25]
   :END:
   Add caching here - search is called repeatedly with same query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Review code in Emacs&lt;/strong&gt; (with syntax highlighting, jump-to-def, all IDE features)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mark issues as I find them&lt;/strong&gt; (SPC r c for quick comment)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger the automated fix process&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Read code-review-llm-prompt-template and follow it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Claude automatically&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Reads &lt;code&gt;~/code_review.org&lt;/code&gt; for all TODO items&lt;/li&gt;
&lt;li&gt;Fixes each issue in the actual code&lt;/li&gt;
&lt;li&gt;Runs &lt;code&gt;make test&lt;/code&gt; after every change&lt;/li&gt;
&lt;li&gt;Marks items as DONE only when tests pass&lt;/li&gt;
&lt;li&gt;Provides a summary of what was fixed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The entire workflow is encoded in a memento note (&lt;code&gt;code-review-llm-prompt-template&lt;/code&gt;) that Claude reads. This note contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The review format specification&lt;/li&gt;
&lt;li&gt;Priority order (correctness → architecture → security → performance)&lt;/li&gt;
&lt;li&gt;Testing requirements (always run &lt;code&gt;make test&lt;/code&gt;, never leave tests failing)&lt;/li&gt;
&lt;li&gt;Guidelines for what makes a good vs. bad review&lt;/li&gt;
&lt;li&gt;The complete fix-and-verify process&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why This Works
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Batch processing&lt;/strong&gt; is more efficient than interactive fixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude sees all issues at once and can plan holistically&lt;/li&gt;
&lt;li&gt;No back-and-forth during fixing&lt;/li&gt;
&lt;li&gt;Tests run after every change (not just at the end)&lt;/li&gt;
&lt;li&gt;Clear audit trail of what was fixed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Emacs integration&lt;/strong&gt; solves the "review without IDE" problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm in my editor with all my tools&lt;/li&gt;
&lt;li&gt;Jump to definitions, search references, check blame&lt;/li&gt;
&lt;li&gt;Clicking org links takes me directly to the code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Structured format&lt;/strong&gt; means Claude gets precise instructions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exact file paths (clickable org-mode links)&lt;/li&gt;
&lt;li&gt;Exact line numbers&lt;/li&gt;
&lt;li&gt;Context about the issue&lt;/li&gt;
&lt;li&gt;Project name for multi-repo workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Current State: Automated Fix Process
&lt;/h3&gt;

&lt;p&gt;The system is fully automated for the fix workflow. When I have pending reviews, I simply say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read code-review-llm-prompt-template and follow it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads the standardized prompt from memento&lt;/li&gt;
&lt;li&gt;Processes all TODO items from &lt;code&gt;~/code_review.org&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Fixes issues, runs tests, marks items DONE&lt;/li&gt;
&lt;li&gt;Never leaves the codebase with failing tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight: &lt;strong&gt;encoding the entire workflow in a memento note makes it repeatable and consistent&lt;/strong&gt;. I don't need to remember the exact prompt or process—it's all documented and ready to execute.&lt;/p&gt;

&lt;p&gt;Future improvements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Auto-trigger on commit&lt;/strong&gt;: Git hook that checks for pending reviews before allowing commits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proactive review suggestions&lt;/strong&gt;: Claude analyzing code during normal sessions and adding items to the review log&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review metrics&lt;/strong&gt;: Track what types of issues are most common to improve coding patterns&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Diff Workflow: Bringing Changes Back to Emacs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Claude makes changes in the terminal. I want to review them in Emacs. How do I bridge that gap?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Current Solution
&lt;/h3&gt;

&lt;p&gt;Simple but effective:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Claude generates changes, I run:&lt;/span&gt;
git diff &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/review.diff

&lt;span class="c"&gt;# In Emacs:&lt;/span&gt;
&lt;span class="c"&gt;# Open the diff file&lt;/span&gt;
&lt;span class="c"&gt;# Use Emacs diff-mode for navigation&lt;/span&gt;
&lt;span class="c"&gt;# Apply/reject hunks interactively&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works but feels clunky. I'm copying diffs manually, opening files, navigating around.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I Want
&lt;/h3&gt;

&lt;p&gt;A tighter integration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Claude signals "I made changes"&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emacs automatically shows the diff&lt;/strong&gt; in a split window&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I review with full IDE context&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I approve/reject&lt;/strong&gt; specific changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude sees my feedback&lt;/strong&gt; and adjusts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP server for Emacs communication&lt;/li&gt;
&lt;li&gt;Claude code that can signal "review needed"&lt;/li&gt;
&lt;li&gt;Emacs mode that listens for review requests&lt;/li&gt;
&lt;li&gt;Two-way communication (Claude → Emacs → Claude)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've prototyped pieces of this but nothing production-ready yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Barrier
&lt;/h3&gt;

&lt;p&gt;Building reliable two-way communication between Claude and Emacs is hard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emacs server needs to be always-on&lt;/li&gt;
&lt;li&gt;Need protocol for structured messages&lt;/li&gt;
&lt;li&gt;Need to handle failures gracefully&lt;/li&gt;
&lt;li&gt;Race conditions when multiple Claudes talk to one Emacs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm experimenting with using memento as the message bus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude writes "review-needed" note&lt;/li&gt;
&lt;li&gt;Emacs polls memento for new reviews&lt;/li&gt;
&lt;li&gt;Emacs writes feedback to memento&lt;/li&gt;
&lt;li&gt;Claude reads feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clunky but doesn't require real-time communication.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Didn't Work: Session Auto-Resume
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Idea
&lt;/h3&gt;

&lt;p&gt;When I restart my computer, I lose all tmux sessions. What if Claude could auto-resume?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before shutdown, save session state:&lt;/span&gt;
tmux-save-sessions  &lt;span class="c"&gt;# Captures all window/pane layouts&lt;/span&gt;

&lt;span class="c"&gt;# After restart:&lt;/span&gt;
tmux-restore-sessions  &lt;span class="c"&gt;# Recreates everything&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each session would:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restore to the correct directory&lt;/li&gt;
&lt;li&gt;Read the last prompt from history&lt;/li&gt;
&lt;li&gt;Show a summary: "You were working on memento refactoring"&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why It Failed
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context loss is too severe.&lt;/strong&gt; Even if I restore the directory and prompt, Claude doesn't remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What code was already written&lt;/li&gt;
&lt;li&gt;What decisions were made&lt;/li&gt;
&lt;li&gt;What tests were run&lt;/li&gt;
&lt;li&gt;What bugs were found&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd need to capture and replay the entire conversation, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Huge token usage (replaying thousands of tokens)&lt;/li&gt;
&lt;li&gt;Slow startup (processing all that history)&lt;/li&gt;
&lt;li&gt;Potential for Claude to make different decisions on replay&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Lesson
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Session continuity requires more than just state restoration.&lt;/strong&gt; You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicit checkpoints (memento notes with "current status")&lt;/li&gt;
&lt;li&gt;Clear handoff documents ("Session ended here, next steps are...")&lt;/li&gt;
&lt;li&gt;Project-specific context (not just conversation history)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of auto-resume, I now use &lt;strong&gt;explicit handoff notes&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Session Checkpoint: 2025-09-30 14:30&lt;/span&gt;

&lt;span class="gu"&gt;## What We Did&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Refactored CLI argument parsing to use argparse
&lt;span class="p"&gt;-&lt;/span&gt; All tests pass
&lt;span class="p"&gt;-&lt;/span&gt; Committed changes: git log -1

&lt;span class="gu"&gt;## What's Next&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Add JSON output support to all commands
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Update documentation
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Add integration tests

&lt;span class="gu"&gt;## Key Decisions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Using argparse instead of manual parsing for consistency
&lt;span class="p"&gt;-&lt;/span&gt; All commands must support --json flag

&lt;span class="gu"&gt;## Files Modified&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; src/cli.py (lines 1-89, 127-145)
&lt;span class="p"&gt;-&lt;/span&gt; src/parser.py (new file)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next session reads this note and picks up where we left off. Works better than trying to resume the conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiments in Progress
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. MCP Coordination Server
&lt;/h3&gt;

&lt;p&gt;Building an MCP server specifically for coordinating parallel LLM sessions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Hypothetical API
&lt;/span&gt;&lt;span class="n"&gt;coordinator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;claim_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/parser.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;coordinator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_barrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refactor-complete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;coordinator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for_barrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refactor-complete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;coordinator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_session_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# → "in_progress" | "blocked" | "completed"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would solve the "stepping on each other" problem when running parallel sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Telemetry Mining
&lt;/h3&gt;

&lt;p&gt;I have months of telemetry data (see Part 2). Now I want to mine it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Which prompts lead to longest sessions?
# Which projects have the most rework?
# When do I context-switch most?
# Correlation between session length and memory usage?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal: optimize my workflow based on data, not intuition.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. LLM-Generated Architecture Docs
&lt;/h3&gt;

&lt;p&gt;After a major refactor, can Claude generate architecture documentation automatically?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read all files in src/. Generate an architecture document explaining:
- Key components and their responsibilities
- Data flow through the system
- API boundaries
- Design decisions and trade-offs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Early experiments are promising. The docs aren't perfect but are good starting points.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Learnings
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Embrace obsolescence.&lt;/strong&gt; If a tool becomes unnecessary, that's progress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Perfect is the enemy of done.&lt;/strong&gt; The code review logger works even though it's not fully automated. Ship it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tight integration is hard.&lt;/strong&gt; Two-way communication between tools (Claude ↔ Emacs) requires careful design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explicit beats implicit.&lt;/strong&gt; Session handoff notes work better than trying to auto-resume from history.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data reveals patterns.&lt;/strong&gt; Telemetry showed me I context-switch too often—now I batch similar tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Part 5&lt;/strong&gt; (final article) covers using Claude as a learning tool: generating flashcards, creating annotated worksheets, and building a spaced-repetition system for technical concepts.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The code review logger is in the &lt;a href="https://github.com/charignon/memento/tree/main/emacs-config" rel="noopener noreferrer"&gt;memento repo&lt;/a&gt;. The project ingester is at &lt;code&gt;~/bin/project-ingest&lt;/code&gt;. The tmux session tools are in my &lt;a href="https://github.com/charignon/dotfiles" rel="noopener noreferrer"&gt;dotfiles&lt;/a&gt;. All MIT licensed—use freely.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>learning</category>
      <category>llm</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Building with LLMs at Scale: Part 3 - Higher-Level Abstractions</title>
      <dc:creator>Laurent Charignon</dc:creator>
      <pubDate>Fri, 17 Oct 2025 03:06:40 +0000</pubDate>
      <link>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-3-higher-level-abstractions-2c67</link>
      <guid>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-3-higher-level-abstractions-2c67</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part1-pain-points"&gt;Part 1&lt;/a&gt; I described the pain points of working with multiple LLM sessions. &lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part2-ergonomics"&gt;Part 2&lt;/a&gt; covered the ergonomics layer that made individual sessions manageable.&lt;/p&gt;

&lt;p&gt;But ergonomics alone isn't enough when you're running 5-10 parallel Claude sessions. You need &lt;strong&gt;coordination&lt;/strong&gt;, &lt;strong&gt;quality enforcement&lt;/strong&gt;, and &lt;strong&gt;shared context&lt;/strong&gt;. This article covers the higher-level abstractions that make LLM teams actually work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Smoke Test Paradigm: Designing Software for Rapid Iteration
&lt;/h2&gt;

&lt;p&gt;Here's the key insight: &lt;strong&gt;software design principles that help human developers also help LLMs&lt;/strong&gt;. The same things that trip up human coders—complex interfaces, tight coupling, unclear contracts—trip up LLMs too.&lt;/p&gt;

&lt;p&gt;When building software that LLMs will write and modify, the classic principles still apply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modular code&lt;/strong&gt;: Small, well-defined components&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple interfaces&lt;/strong&gt;: Clear inputs and outputs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loose coupling&lt;/strong&gt;: Changes in one area don't cascade&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast feedback&lt;/strong&gt;: Know immediately when something breaks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference is velocity. LLMs can iterate 10x faster than humans—but only if the feedback loop is tight. That's where &lt;strong&gt;smoke tests&lt;/strong&gt; become critical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Smoke Tests Over Unit Tests?
&lt;/h3&gt;

&lt;p&gt;I tried comprehensive unit test suites. They worked, but the overhead was crushing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing tests took longer than writing features&lt;/li&gt;
&lt;li&gt;Tests became brittle as code evolved&lt;/li&gt;
&lt;li&gt;Mocking and fixtures added complexity&lt;/li&gt;
&lt;li&gt;False positives made me ignore failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem: unit tests are designed for human-paced development. When Claude can refactor an entire module in 30 seconds, waiting 5 minutes for a full test suite kills momentum.&lt;/p&gt;

&lt;p&gt;Instead, I adopted &lt;strong&gt;smoke tests&lt;/strong&gt;: simple, end-to-end checks that verify the system works. Run in seconds. Clear pass/fail. No ambiguity.&lt;/p&gt;

&lt;p&gt;Example from my flashcards project (&lt;code&gt;test/smoke_test.sh&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# Smoke test: Does the basic workflow work?&lt;/span&gt;

&lt;span class="c"&gt;# Create a flashcard&lt;/span&gt;
./flashcards create &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--question&lt;/span&gt; &lt;span class="s2"&gt;"What is 2+2?"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--answer&lt;/span&gt; &lt;span class="s2"&gt;"4"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="s2"&gt;"math"&lt;/span&gt;

&lt;span class="c"&gt;# Get quiz items&lt;/span&gt;
./flashcards quiz &lt;span class="nt"&gt;--limit&lt;/span&gt; 1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"What is 2+2?"&lt;/span&gt;

&lt;span class="c"&gt;# Review it&lt;/span&gt;
./flashcards review &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;--confidence&lt;/span&gt; 5

&lt;span class="c"&gt;# Check it's in the list&lt;/span&gt;
./flashcards list | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"What is 2+2?"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Smoke test passed!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No mocking. No fixtures. No complex assertions. Just: &lt;strong&gt;Does it work end-to-end?&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Make Test Convention
&lt;/h3&gt;

&lt;p&gt;Every project has a &lt;code&gt;Makefile&lt;/code&gt; with a &lt;code&gt;test&lt;/code&gt; target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running smoke tests..."&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;./test/smoke_test.sh
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ All tests passed"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude knows this convention. After every code change, it automatically runs &lt;code&gt;make test&lt;/code&gt;. If tests fail, Claude must fix them before continuing.&lt;/p&gt;

&lt;p&gt;This simple pattern has caught hundreds of regressions. Claude refactors a function? Tests catch it. Claude renames a variable? Tests catch it. Claude adds a feature? Tests verify it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Works
&lt;/h3&gt;

&lt;p&gt;Smoke tests have unique advantages for LLM workflows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fast&lt;/strong&gt;: Run in seconds, not minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear failures&lt;/strong&gt;: "Command failed" is unambiguous&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-documenting&lt;/strong&gt;: Reading the test shows how the system should work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to maintain&lt;/strong&gt;: When features change, tests are obvious to update&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catches real issues&lt;/strong&gt;: Integration problems that unit tests miss&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The trade-off: you don't get fine-grained coverage. But in my experience, that's fine. I'd rather have 90% confidence in 5 seconds than 99% confidence after 5 minutes of test runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memento: Shared Context Between Sessions
&lt;/h2&gt;

&lt;p&gt;The core challenge of parallel LLM sessions: they don't know about each other.&lt;/p&gt;

&lt;p&gt;Session A refactors the authentication system. Session B adds a new feature that uses authentication. Session A's changes break Session B's code—but Session B has no idea until tests fail.&lt;/p&gt;

&lt;p&gt;I needed a shared knowledge base. Enter &lt;strong&gt;memento&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Is Memento?
&lt;/h3&gt;

&lt;p&gt;Memento is my note-taking system built on &lt;a href="https://www.orgroam.com/" rel="noopener noreferrer"&gt;org-roam&lt;/a&gt;, which implements the &lt;a href="https://zettelkasten.de/introduction/" rel="noopener noreferrer"&gt;Zettelkasten method&lt;/a&gt; for networked thought. I expose it to Claude via MCP (Model Context Protocol).&lt;/p&gt;

&lt;p&gt;Think of it as a shared brain for all Claude sessions—a personal knowledge graph where notes link to each other, concepts build on each other, and every LLM session can read and contribute to the collective knowledge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33dp1vw340ov47fc80cp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33dp1vw340ov47fc80cp.png" alt="Memento note system showing interconnected knowledge graph" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public notes&lt;/strong&gt; tagged with &lt;code&gt;PUBLIC&lt;/code&gt; are accessible via MCP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Searchable&lt;/strong&gt; with full-text search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured&lt;/strong&gt; with org-mode properties and tags&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version controlled&lt;/strong&gt; in git&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent&lt;/strong&gt; across sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Global Context Pattern
&lt;/h3&gt;

&lt;p&gt;Every Claude session starts by reading the &lt;code&gt;claude-global-context&lt;/code&gt; note:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="c1"&gt;;; Automatically loaded by Claude at session start&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;mcp__memento__note_get&lt;/span&gt; &lt;span class="ss"&gt;:note_id&lt;/span&gt; &lt;span class="s"&gt;"claude-global-context"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This note contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My coding preferences&lt;/li&gt;
&lt;li&gt;Project structure&lt;/li&gt;
&lt;li&gt;Common pitfalls&lt;/li&gt;
&lt;li&gt;Tools available (memento, MCP servers, custom scripts)&lt;/li&gt;
&lt;li&gt;Reminders (never access &lt;code&gt;~/.roam&lt;/code&gt; directly, always use MCP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I discover patterns, I add them to this note. Every future Claude session gets that knowledge automatically.&lt;/p&gt;

&lt;p&gt;Example from my global context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## 🧪 Testing Approach:&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Write tests for new features
&lt;span class="p"&gt;-&lt;/span&gt; Rely on smoke tests for projects (trigger with &lt;span class="sb"&gt;`make test`&lt;/span&gt;)
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Whenever all tests pass after a change, make a commit with a descriptive message**&lt;/span&gt;

&lt;span class="gu"&gt;## 🔧 ELISP DEVELOPMENT WITH DOOMSCRIPT:&lt;/span&gt;
See the note tagged &lt;span class="sb"&gt;`elisp`&lt;/span&gt; for patterns and testing approaches
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Session-Specific Context
&lt;/h3&gt;

&lt;p&gt;For complex projects, I create dedicated notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;memento-clojure-patterns&lt;/code&gt;: Clojure idioms and anti-patterns&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;appdaemon-testing-guide&lt;/code&gt;: How to test Home Assistant automations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mcp-server-patterns&lt;/code&gt;: How to build reliable MCP servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When Claude works on these projects, I explicitly reference the notes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read the note `mcp-server-patterns` and apply those patterns
to this new server implementation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude reads the note, absorbs the context, and applies it. The next Claude session working on the same project does the same thing—they're building on shared knowledge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coordination Patterns (Experimental)
&lt;/h3&gt;

&lt;p&gt;I'm experimenting with explicit coordination notes for parallel sessions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# working-on-memento-refactor&lt;/span&gt;

&lt;span class="gu"&gt;## Current State&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Session A: Refactoring CLI argument parsing (IN PROGRESS)
&lt;span class="p"&gt;-&lt;/span&gt; Session B: Adding new &lt;span class="sb"&gt;`bulk-update`&lt;/span&gt; command (WAITING)
&lt;span class="p"&gt;-&lt;/span&gt; Session C: Updating tests (COMPLETED)

&lt;span class="gu"&gt;## Decisions Made&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use argparse instead of manual parsing (Session A, 2025-09-28)
&lt;span class="p"&gt;-&lt;/span&gt; All commands must support JSON output (Session B, 2025-09-27)

&lt;span class="gu"&gt;## Upcoming Work&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Migrate all commands to new arg structure
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Add integration tests
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Update documentation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each session reads this note before starting work. Session A updates its status when done. Session B sees that and can proceed safely.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;informal&lt;/strong&gt; right now—I'm still exploring better patterns. Some ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Barrier functionality&lt;/strong&gt;: Session B blocks until Session A completes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lock mechanism&lt;/strong&gt;: Only one session can modify a file at once&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency tracking&lt;/strong&gt;: Session C depends on Session A and Session B&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm considering building an MCP server specifically for project coordination. Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Hypothetical coordination MCP server
&lt;/span&gt;&lt;span class="n"&gt;mcp_coordinator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;claim_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/parser.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Other sessions get an error if they try to edit it
&lt;/span&gt;&lt;span class="n"&gt;mcp_coordinator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_barrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refactor-complete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required_sessions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;mcp_coordinator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for_barrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refactor-complete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Blocks until A and B finish
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Supervisor Pattern: Orchestrating LLM Teams
&lt;/h2&gt;

&lt;p&gt;When I need major changes, I run multiple Claude sessions in parallel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session A&lt;/strong&gt;: Implements feature X&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session B&lt;/strong&gt;: Writes tests for feature X&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session C&lt;/strong&gt;: Updates documentation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session D&lt;/strong&gt;: Reviews changes from A, B, and C&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the &lt;strong&gt;supervisor pattern&lt;/strong&gt;—but instead of manually coordinating, I use &lt;strong&gt;an LLM to generate prompts for other LLMs&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Meta-LLM Approach
&lt;/h3&gt;

&lt;p&gt;Here's the key insight: planning parallel work is itself an LLM task. So I have Claude generate the work breakdown and individual prompts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;I describe the goal&lt;/strong&gt; to a planning session: "Implement feature X with tests and docs"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The planner LLM creates&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;A work plan broken into phases (represented as a DAG)&lt;/li&gt;
&lt;li&gt;Individual prompt files for each parallel task&lt;/li&gt;
&lt;li&gt;Memento-based coordination scheme&lt;/li&gt;
&lt;li&gt;A supervisor prompt for monitoring progress&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I review and launch&lt;/strong&gt; using my automation tools&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This meta-approach scales much better than manual coordination. The planner understands dependencies, estimates complexity, and generates consistent prompt structures.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tooling: claude-parallel
&lt;/h3&gt;

&lt;p&gt;I built &lt;code&gt;claude-parallel&lt;/code&gt; to automate the workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Step 1: Generate the plan&lt;/span&gt;
claude-parallel plan &lt;span class="nt"&gt;-P&lt;/span&gt; myproject &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"requirements.txt"&lt;/span&gt;

&lt;span class="c"&gt;# This launches a planning Claude session that:&lt;/span&gt;
&lt;span class="c"&gt;# - Breaks work into phases and tasks&lt;/span&gt;
&lt;span class="c"&gt;# - Creates prompt files in ~/.projects/myproject/prompts/&lt;/span&gt;
&lt;span class="c"&gt;# - Generates plan.json with the dependency DAG&lt;/span&gt;
&lt;span class="c"&gt;# - Creates a supervisor.txt prompt for monitoring&lt;/span&gt;

&lt;span class="c"&gt;# Step 2: Dispatch work to parallel sessions&lt;/span&gt;
claude-parallel dispatch &lt;span class="nt"&gt;-p&lt;/span&gt; prompts/phase-1-task-auth.txt src/auth.py
claude-parallel dispatch &lt;span class="nt"&gt;-p&lt;/span&gt; prompts/phase-1-task-tests.txt tests/test_auth.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;dispatch&lt;/code&gt; command automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a new tmux window&lt;/li&gt;
&lt;li&gt;Changes to the file's directory&lt;/li&gt;
&lt;li&gt;Launches Claude with the prompt&lt;/li&gt;
&lt;li&gt;Monitors completion via memento notes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tmux Automation
&lt;/h3&gt;

&lt;p&gt;For complex projects with many parallel sessions, I use &lt;code&gt;generate_tmuxinator_config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate tmuxinator config from prompt files&lt;/span&gt;
generate_tmuxinator_config &lt;span class="nt"&gt;-n&lt;/span&gt; myproject prompts/&lt;span class="k"&gt;*&lt;/span&gt;.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/.config/tmuxinator/myproject.yml

&lt;span class="c"&gt;# Launch all sessions at once&lt;/span&gt;
tmuxinator start myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a tmux session with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One window per prompt file&lt;/li&gt;
&lt;li&gt;Proper window naming for easy navigation&lt;/li&gt;
&lt;li&gt;All sessions starting in the correct directory&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How I Do It Today
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write high-level requirements&lt;/strong&gt; in a text file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run &lt;code&gt;claude-parallel plan&lt;/code&gt;&lt;/strong&gt; to generate work breakdown&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review the generated prompts&lt;/strong&gt; (adjust if needed)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Launch sessions&lt;/strong&gt; via &lt;code&gt;claude-parallel dispatch&lt;/code&gt; or &lt;code&gt;tmuxinator&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use memento for coordination&lt;/strong&gt; (automatically set up by the planner):

&lt;ul&gt;
&lt;li&gt;Sessions read/write status notes&lt;/li&gt;
&lt;li&gt;Sessions check phase completion before starting&lt;/li&gt;
&lt;li&gt;Blocker notes communicate issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rely on smoke tests&lt;/strong&gt; to catch integration issues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor via tmux status indicators&lt;/strong&gt; (see Part 2) or run the supervisor prompt&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Persona-Driven Architecture
&lt;/h3&gt;

&lt;p&gt;Assigning roles to sessions improves output quality, but I use personas differently than you might expect.&lt;/p&gt;

&lt;p&gt;I use Robert C. Martin (Uncle Bob) as the &lt;strong&gt;planner and architect&lt;/strong&gt;. When breaking down a complex feature into parallel tasks, I ask the planner session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are Robert C. Martin (Uncle Bob). Review this feature request and break it
down into clean, well-separated tasks for parallel implementation. Focus on
SOLID principles and clear interfaces between components.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives me a work breakdown that follows clean architecture principles: small, focused components with clear responsibilities.&lt;/p&gt;

&lt;p&gt;Then for the &lt;strong&gt;worker sessions&lt;/strong&gt; (the ones actually implementing the tasks), I experiment with different prompts. Sometimes specific personas help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"You are obsessed with performance and correctness" for algorithm-heavy code&lt;/li&gt;
&lt;li&gt;"You are paranoid about edge cases and defensive programming" for input validation&lt;/li&gt;
&lt;li&gt;"You value simplicity above all else, avoid any unnecessary complexity" for utility functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other times, I just use the task description from the planner without additional persona framing. I'm still experimenting with what works best for different types of work.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's Missing
&lt;/h3&gt;

&lt;p&gt;Current gaps in my supervisor pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No automatic conflict detection&lt;/strong&gt;: I manually ensure sessions don't edit the same files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No rollback mechanism&lt;/strong&gt;: If Session A breaks tests, I manually revert&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No progress tracking&lt;/strong&gt;: I eyeball tmux windows instead of having a dashboard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No automatic merging&lt;/strong&gt;: I manually integrate changes from parallel sessions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are ripe for automation. The MCP coordination server would solve 1-3. Number 4 might need a specialized "merger" session that reads changes from all other sessions and integrates them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Knowledge Accumulation Over Time
&lt;/h2&gt;

&lt;p&gt;Traditional LLM conversations are ephemeral. Each session starts fresh. But with memento, knowledge compounds.&lt;/p&gt;

&lt;p&gt;Example workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Week 1&lt;/strong&gt;: I discover that MCP servers should validate input strictly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I add to global context&lt;/strong&gt;: "MCP servers must validate all inputs and return clear error messages"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 2&lt;/strong&gt;: Claude builds a new MCP server, automatically applies that pattern&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 3&lt;/strong&gt;: I discover another pattern (connection pooling), add it to global context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Future sessions&lt;/strong&gt;: Apply both patterns automatically&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Over months, my global context evolved from 50 lines to 500+ lines of hard-won knowledge. New Claude sessions are more productive from day one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Memento Notes Index
&lt;/h3&gt;

&lt;p&gt;To make knowledge discoverable, I maintain a &lt;code&gt;memento-notes-index&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Development &amp;amp; Technical Guides&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="gs"&gt;**mcp-server-patterns**&lt;/span&gt;: Patterns for building reliable MCP servers
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**smoke-test-paradigm**&lt;/span&gt;: Why smoke tests work better than unit tests
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**elisp-testing-guide**&lt;/span&gt;: Fast testing with doomscript
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**code-review-guide**&lt;/span&gt;: How to review code and log issues for AI

&lt;span class="gu"&gt;## Quick Lookup by Use Case&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Building MCP servers → &lt;span class="sb"&gt;`mcp-server-patterns`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Emacs development → &lt;span class="sb"&gt;`elisp-testing-guide`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Testing frameworks → &lt;span class="sb"&gt;`smoke-test-paradigm`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Claude asks "How should I structure this?", I can say: "Check the notes index for relevant guides."&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Learnings
&lt;/h2&gt;

&lt;p&gt;After 6 months of parallel LLM workflows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smoke tests are a game-changer.&lt;/strong&gt; They catch 90% of issues with 10% of the effort of comprehensive test suites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared context is essential.&lt;/strong&gt; Without memento, each session reinvents the wheel. With it, knowledge compounds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Personas improve output quality.&lt;/strong&gt; "Be Uncle Bob" consistently produces cleaner code than "refactor this."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Informal coordination works at small scale.&lt;/strong&gt; For 3-5 parallel sessions, a shared note is enough. Beyond that, I'll need real tooling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every discovery should be captured.&lt;/strong&gt; If I solve a problem once, I never want to solve it again. Write it down in memento.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The patterns in this article work but aren't fully automated. I'm manually coordinating sessions, manually managing shared context, manually merging changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 4&lt;/strong&gt; covers experiments and works-in-progress: the project explorer tool, Emacs integration for code review, diff workflows, and ideas that didn't quite work out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 5&lt;/strong&gt; shifts to learning: using Claude to generate flashcards, worksheets, and annotated code for studying complex topics.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The memento system is open source at &lt;a href="https://github.com/charignon/memento" rel="noopener noreferrer"&gt;github.com/charignon/memento&lt;/a&gt;. The global context patterns are in my &lt;a href="https://github.com/charignon/dotfiles/blob/main/CLAUDE.md" rel="noopener noreferrer"&gt;CLAUDE.md&lt;/a&gt;. The flashcards smoke tests are at &lt;a href="https://github.com/charignon/flashcards" rel="noopener noreferrer"&gt;github.com/charignon/flashcards&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>Building with LLMs at Scale: Part 2 - Ergonomics and Observability</title>
      <dc:creator>Laurent Charignon</dc:creator>
      <pubDate>Fri, 17 Oct 2025 02:56:32 +0000</pubDate>
      <link>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-2-ergonomics-and-observability-1521</link>
      <guid>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-2-ergonomics-and-observability-1521</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part1-pain-points"&gt;Part 1&lt;/a&gt; described the problems of managing multiple LLM sessions. This article shows the ergonomic layer that solves them: visual indicators, session recording, logging, and telemetry.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Picture
&lt;/h2&gt;

&lt;p&gt;Here's my workflow using &lt;a href="https://github.com/tmux/tmux/wiki" rel="noopener noreferrer"&gt;tmux&lt;/a&gt; to manage multiple LLM sessions.&lt;/p&gt;

&lt;p&gt;Tmux is a terminal multiplexer—it lets you run multiple terminal sessions inside a single window and switch between them quickly. Think of it like having tabs in a browser, but for your terminal. You can have one tmux session with 10 different windows, each running a different LLM conversation, and easily switch between them with keyboard shortcuts.&lt;/p&gt;

&lt;p&gt;Here's how it works in practice:&lt;/p&gt;

&lt;p&gt;I open a new tmux window (like opening a new tab) and start an LLM session—maybe Claude Code working on a bug fix. Metrics tracking begins automatically in the background. As the LLM works, my tmux status bar (the line at the bottom of the terminal) shows a 🤖 emoji next to that window's name. I can glance at the status bar and instantly see that window 3 is busy with an LLM.&lt;/p&gt;

&lt;p&gt;When the LLM finishes and waits for my input, the emoji changes to 💬. If I'm currently in a different window (say, window 5 where I'm reviewing code), I just press &lt;code&gt;` n&lt;/code&gt; (backtick followed by n) to jump directly to the waiting session. No manually cycling through windows, no remembering which number it was.&lt;/p&gt;

&lt;p&gt;Every context switch gets recorded with a timestamp. A week later, when I need to understand what happened in that session—what prompts I gave, what the LLM suggested, what decisions were made—I can query the session history and replay the logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Visual Layer: Terminal Session Management
&lt;/h2&gt;

&lt;p&gt;Problem: 10 terminal windows (or in tmux terminology, 10 windows within one tmux session), each running a different LLM conversation. No visibility into which LLM needs attention.&lt;/p&gt;

&lt;p&gt;Solution: emoji indicators showing window state in the tmux status bar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;💬 memento        &lt;span class="c"&gt;# LLM waiting for input&lt;/span&gt;
🤖 appdaemon      &lt;span class="c"&gt;# LLM actively working&lt;/span&gt;
📝 config         &lt;span class="c"&gt;# Editor open&lt;/span&gt;
🐍 analyzer       &lt;span class="c"&gt;# Python script running&lt;/span&gt;
⌨️ bash           &lt;span class="c"&gt;# Shell waiting for command&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Window Status Script
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;tmux-window-status&lt;/code&gt; script analyzes each tmux pane (a pane is like a split section within a window) and adds contextual emojis. Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Capture recent output&lt;/strong&gt;: Grab the last 100 lines of text from the pane&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detect LLM patterns&lt;/strong&gt;: Look for LLM-specific text like &lt;code&gt;&amp;gt;&lt;/code&gt; prompts or dialog boxes asking "Do you want to..."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the process&lt;/strong&gt;: See what command is actually running in that pane&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return the right emoji&lt;/strong&gt;: Based on what we found, add the appropriate emoji to the window name&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the key detection logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;check_llm_waiting&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;pane_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;last_lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pane_content&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-5&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# Check for common LLM prompts&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$last_lines&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s2"&gt;"^&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="nv"&gt;$|&lt;/span&gt;&lt;span class="s2"&gt;^&amp;gt; "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        return &lt;/span&gt;0  &lt;span class="c"&gt;# LLM is waiting&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c"&gt;# Check for dialog boxes&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$last_lines&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s2"&gt;"Do you want to|❯.*Yes"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        return &lt;/span&gt;0  &lt;span class="c"&gt;# Waiting for decision&lt;/span&gt;
    &lt;span class="k"&gt;fi

    return &lt;/span&gt;1  &lt;span class="c"&gt;# Not waiting&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Jump to Next Waiting Window
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;tmux-next-waiting&lt;/code&gt; script cycles through windows where an LLM is waiting. It loops through all your tmux windows, checks which ones have the 💬 emoji (meaning an LLM is waiting for input), and jumps to the next one after your current window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# Find all windows with 💬 emoji (LLM waiting)&lt;/span&gt;
&lt;span class="nv"&gt;windows_waiting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;window &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;tmux list-windows &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"#{window_index}"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;formatted_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;~/bin/tmux-window-status &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$window_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pane_id&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$formatted_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s2"&gt;"💬"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nv"&gt;windows_waiting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$windows_waiting&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$window&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;

&lt;span class="c"&gt;# Jump to next waiting window after current&lt;/span&gt;
&lt;span class="c"&gt;# (wraps around to first if at end)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use this, bind it to a tmux key in your tmux configuration (&lt;code&gt;~/.tmux.conf&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bind-key n run-shell "~/bin/tmux-next-waiting"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now pressing &lt;code&gt;` n&lt;/code&gt; (assuming you've set &lt;code&gt;`&lt;/code&gt; as your tmux prefix key) jumps to the next LLM session that needs attention. The prefix key is like a "modifier" that tells tmux "the next key is a command for you." With this setup, switching is fast: &lt;code&gt;` 1&lt;/code&gt; goes to window 1, &lt;code&gt;` TAB&lt;/code&gt; toggles to your last window, &lt;code&gt;` n&lt;/code&gt; finds the next waiting LLM.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Logging Layer: Complete Auditability
&lt;/h2&gt;

&lt;p&gt;Remember the problem from Part 1? Code written last week is unrecognizable without session history. You need to understand what the LLM did, what decisions were made, and why certain approaches were taken.&lt;/p&gt;

&lt;p&gt;The solution: record everything. I use &lt;a href="https://asciinema.org/" rel="noopener noreferrer"&gt;asciinema&lt;/a&gt;, a terminal session recorder, to capture complete LLM sessions. Unlike text logs (which just save the text), asciinema records the actual terminal output with timing information—think of it like a video recording of your terminal session. You can replay sessions later and see exactly what appeared on screen, when it appeared, and in what order.&lt;/p&gt;

&lt;p&gt;For complex refactoring sessions or experiments, I use this wrapper script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# llm-record - Record LLM sessions with asciinema&lt;/span&gt;

&lt;span class="nv"&gt;RECORDING_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="s1"&gt;'+%Y%m%d-%H%M%S'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;RECORDINGS_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/llm-recordings"&lt;/span&gt;
&lt;span class="nv"&gt;RECORDING_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RECORDINGS_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RECORDING_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.cast"&lt;/span&gt;

asciinema rec &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"LLM Session: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RECORDING_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--idle-time-limit&lt;/span&gt; 10 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RECORDING_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--idle-time-limit 10&lt;/code&gt; flag compresses long waits (like when the LLM is thinking or making API calls) to 10 seconds in playback. This makes replaying sessions much faster—you're not sitting through minutes of "Processing..." messages.&lt;/p&gt;

&lt;p&gt;When Claude Code encounters bugs or issues, I can extract the exact terminal transcript with &lt;code&gt;asciinema cat&lt;/code&gt; and share it. This works around a limitation in current LLM tools: they don't have built-in access to session history, so providing a complete transcript helps them understand what went wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Telemetry Layer: Metrics and Patterns
&lt;/h2&gt;

&lt;p&gt;Visual indicators solve the immediate "which window needs attention?" problem. But I wanted to understand deeper patterns: how many parallel sessions do I actually run? When am I most productive? Which projects consume the most time?&lt;/p&gt;

&lt;p&gt;To answer these questions, I built a telemetry system using &lt;a href="https://prometheus.io/" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt;—an open-source monitoring system originally built at SoundCloud. Prometheus collects metrics (numerical measurements) over time and lets you query them later. A background script runs every 15 seconds, collecting metrics about my tmux environment and LLM sessions.&lt;/p&gt;

&lt;p&gt;The script tracks session-level metrics like total tmux sessions, windows per session, and which sessions are actively attached. It also captures LLM-specific data: the number of active LLM processes, memory usage per session (RSS in MB), CPU usage, session duration in minutes, and the working directory for each session.&lt;/p&gt;

&lt;p&gt;All of this gets pushed to a Prometheus pushgateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;LLM_SESSIONS_TOTAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gauge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;llm_sessions_total&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Total number of active LLM sessions&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;LLM_SESSION_MEMORY_MB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gauge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;llm_session_memory_mb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Memory usage per LLM session in MB&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pid&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;command&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;LLM_SESSION_DURATION_MINUTES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gauge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;llm_session_duration_minutes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Duration of LLM session in minutes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pid&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;command&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What This Reveals
&lt;/h3&gt;

&lt;p&gt;With proper dashboarding, the metrics answer practical questions. When are you most productive? You can see which times of day correlate with longer, more focused sessions. Which projects consume the most time? Resource usage aggregated by working directory shows exactly where hours go. Do you context-switch too much? Tracking window switches per hour reveals patterns you might not consciously notice.&lt;/p&gt;

&lt;p&gt;The data also catches problems early. If session memory usage steadily climbs over time, you know something's leaking. If you're consistently running 8+ parallel sessions, maybe your workflow needs simplification.&lt;/p&gt;

&lt;p&gt;Prometheus makes it easy to query historical patterns and correlate them with specific projects or time periods. The metrics themselves don't make you productive, but they reveal patterns that inform better workflow decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Learnings
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Visual indicators eliminate the "which window?" hunt&lt;/li&gt;
&lt;li&gt;Complete session history invaluable for debugging&lt;/li&gt;
&lt;li&gt;Metrics reveal workflow patterns you don't consciously notice&lt;/li&gt;
&lt;li&gt;Record complex sessions, not everything&lt;/li&gt;
&lt;li&gt;Automation essential—manual logging fails&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Are LLMs Making Us More Productive?
&lt;/h2&gt;

&lt;p&gt;The tools in this article—tmux integration, session recording, telemetry—exist because I'm managing 10 parallel LLM coding sessions. But that raises the obvious question: are LLMs actually making me more productive at writing code?&lt;/p&gt;

&lt;p&gt;I don't believe that's the case for everyone using them. Handing an LLM to a developer without workflow engineering is like giving someone a race car without teaching them to drive. They might go faster on straightaways, but they'll crash on the first turn.&lt;/p&gt;

&lt;p&gt;But if you know how to use them—if you build the right workflows, enforce quality with tests, coordinate multiple sessions, and maintain proper oversight—they're a game changer. The productivity gains are real, but they're not automatic. They come from deliberate workflow design.&lt;/p&gt;

&lt;p&gt;The ergonomic layer in this article is what makes those gains possible. Without visibility into session state, without audit trails, without metrics to understand patterns, you're flying blind. The tools don't make LLMs productive—they make &lt;em&gt;you&lt;/em&gt; productive when using LLMs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The ergonomics layer makes individual sessions manageable. But coordinating multiple LLM sessions to work together without conflicts requires higher-level abstractions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part3-abstractions/"&gt;Part 3: Higher-Level Abstractions&lt;/a&gt;&lt;/strong&gt; covers shared context systems for long-term memory, the smoke test paradigm for quality, and patterns for running a "team" of LLM instances on a single project.&lt;/p&gt;




</description>
      <category>productivity</category>
      <category>monitoring</category>
      <category>llm</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Building with LLMs at Scale: Part 1 - The Pain Points</title>
      <dc:creator>Laurent Charignon</dc:creator>
      <pubDate>Fri, 17 Oct 2025 02:49:51 +0000</pubDate>
      <link>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-1-the-pain-points-3c0o</link>
      <guid>https://forem.com/laurent_charignon/building-with-llms-at-scale-part-1-the-pain-points-3c0o</guid>
      <description>&lt;p&gt;Working with 10 parallel LLM coding sessions exposes problems that don't appear at smaller scale. Managing multiple conversations, maintaining context across sessions, and ensuring quality all require different approaches than single-session work.&lt;/p&gt;

&lt;p&gt;This series documents those problems and the solutions that emerged. The tools shown use Claude Code and Emacs, but the patterns apply broadly to any LLM workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pain Points
&lt;/h2&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Managing Multiple Conversations&lt;/strong&gt; - 10 terminal windows, no visibility into which sessions need attention&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lost Context&lt;/strong&gt; - No audit trail of past sessions or decisions made&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality &amp;amp; Regressions&lt;/strong&gt; - LLMs fix one thing, break another&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language-Specific Edit Challenges&lt;/strong&gt; - Parenthesis balance issues in Lisp&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project Exploration Speed&lt;/strong&gt; - 10+ minutes to load a 20-file project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Switching Between Sessions&lt;/strong&gt; - No shared knowledge between parallel sessions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review Without Full IDE Context&lt;/strong&gt; - Reviewing diffs without syntax highlighting and jump-to-def&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Long-Term Memory&lt;/strong&gt; - Every session starts from scratch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallelization Challenge&lt;/strong&gt; - Coordinating multiple LLMs working simultaneously&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety and Access Control&lt;/strong&gt; - Too easy to grant access to private data&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's dive into each of these.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 1: Managing Multiple Conversations
&lt;/h2&gt;

&lt;p&gt;Picture this: 10 terminal windows, each running a different LLM session. One is refactoring your note system, another is debugging a home automation script, a third is implementing a new feature. Zero visibility into which needs your attention.&lt;/p&gt;

&lt;p&gt;The problem becomes clear when context switching:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which session is waiting for input?&lt;/li&gt;
&lt;li&gt;Which is still processing?&lt;/li&gt;
&lt;li&gt;Which finished 10 minutes ago and has been idle?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without state tracking across sessions, every context switch means manually checking each window. You switch to a session only to find the LLM finished 10 minutes ago while you were focused elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 2: Lost Context
&lt;/h2&gt;

&lt;p&gt;Open a project you worked on last week with an LLM. The code looks unfamiliar. You don't remember writing it. Questions arise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What was the original prompt?&lt;/li&gt;
&lt;li&gt;Did I review this properly?&lt;/li&gt;
&lt;li&gt;What architectural decisions were made?&lt;/li&gt;
&lt;li&gt;Why this approach instead of alternatives?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without an audit trail of past sessions, there's no way to reconstruct the reasoning behind the code. You're essentially trusting that past-you made good decisions—but you have no record of what those decisions were.&lt;/p&gt;

&lt;p&gt;Automatic context compaction makes this worse. LLMs will drop older messages to fit within token limits, but I want explicit control over what gets retained from session to session, not an algorithm deciding what's "important."&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 3: Quality and Regressions
&lt;/h2&gt;

&lt;p&gt;Whack-a-mole development: LLMs fix one issue and silently break another. The problem wasn't the LLM's capabilities—it was my process. I was treating LLM sessions like conversations with a developer I trusted to test their own code.&lt;/p&gt;

&lt;p&gt;The first solution: treat every change like a pull request. Tests must pass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# After every LLM change&lt;/span&gt;
make &lt;span class="nb"&gt;test&lt;/span&gt;  &lt;span class="c"&gt;# Must pass before continuing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This catches regressions but doesn't solve architectural consistency. Code generated across dozens of separate sessions felt scattered, like it was designed by committee where no one talked to each other.&lt;/p&gt;

&lt;p&gt;The second solution: persona-based prompts. Instead of "Refactor this code":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are Robert C. Martin (Uncle Bob). Review this code and refactor
it according to clean code principles.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference was striking. Suddenly: smaller functions, better separation of concerns, consistent naming conventions across the codebase.&lt;/p&gt;

&lt;p&gt;You can use different personas for different needs. Want paranoid security review? "You are a security-minded, paranoid QA engineer who trusts nothing." Need simplicity? "You are obsessed with reducing complexity and eliminating unnecessary abstractions." The persona focuses the LLM's attention on specific concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 4: Language-Specific Edit Challenges
&lt;/h2&gt;

&lt;p&gt;Lisp-based languages (Elisp, Clojure, Scheme) are harder for LLMs to edit because of parenthesis balance.&lt;/p&gt;

&lt;p&gt;The problem: Remove one closing paren and get "end-of-file during parsing" with no location. The error could be 200 lines away from the actual edit.&lt;/p&gt;

&lt;p&gt;The feedback loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;LLM edits code&lt;/li&gt;
&lt;li&gt;Compile fails&lt;/li&gt;
&lt;li&gt;Hunt for unbalanced paren manually&lt;/li&gt;
&lt;li&gt;Fix and retry&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This affects any language with nested structure spanning many lines: deeply nested JSON, XML, etc.&lt;/p&gt;

&lt;p&gt;The solution: validation tooling that gives precise error locations. Without that, you're debugging blind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 5: Project Exploration Speed
&lt;/h2&gt;

&lt;p&gt;New codebase? Get ready to spend 10+ minutes on initial exploration. A 20-file project means feeding files one by one to the LLM, waiting for API calls, managing context windows.&lt;/p&gt;

&lt;p&gt;This creates a cold-start problem. Every new project or every time you switch projects means a lengthy ramp-up period before the LLM has enough context to be productive.&lt;/p&gt;

&lt;p&gt;The solution: a way to efficiently snapshot and load project context—not just individual files, but the structure, key patterns, and architectural decisions all at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 6: Context Switching Between Sessions
&lt;/h2&gt;

&lt;p&gt;I'd discover a great pattern in session A. Session B, working on a related problem, had no idea it existed.&lt;/p&gt;

&lt;p&gt;Each LLM conversation was an island. Problems with this isolation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can't share knowledge between sessions&lt;/li&gt;
&lt;li&gt;Contradictory decisions across different LLM instances&lt;/li&gt;
&lt;li&gt;Manual copy-paste required to propagate learnings&lt;/li&gt;
&lt;li&gt;If I made an architectural decision in conversation A, conversation B would make a different one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The solution: a shared context system where different LLM sessions can coordinate and learn from each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 7: Review Without Full IDE Context
&lt;/h2&gt;

&lt;p&gt;Code review without your IDE is code review on hard mode.&lt;/p&gt;

&lt;p&gt;The LLM generates a diff. You're looking at it in a terminal or web interface. You're missing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Syntax highlighting&lt;/li&gt;
&lt;li&gt;Jump-to-definition&lt;/li&gt;
&lt;li&gt;Project-wide search&lt;/li&gt;
&lt;li&gt;Static analysis&lt;/li&gt;
&lt;li&gt;Your configured linters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: The LLM renames &lt;code&gt;process()&lt;/code&gt; to &lt;code&gt;process_data()&lt;/code&gt;. Questions you can't answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What calls this function?&lt;/li&gt;
&lt;li&gt;Is this part of a larger refactoring?&lt;/li&gt;
&lt;li&gt;Did it affect other functions that depend on it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools like Cursor solve this with deep editor integration—the LLM changes happen natively in your IDE. But if you're using terminal-based LLM tools or trying to integrate with Emacs/Vim, you need a workflow to bring LLM-generated changes into your full development environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 8: No Long-Term Memory
&lt;/h2&gt;

&lt;p&gt;Sessions had amnesia. Yesterday's architectural decisions? Gone. Last week's patterns? Forgotten.&lt;/p&gt;

&lt;p&gt;Sure, I had a global CLAUDE.md file with preferences, but that was static. I couldn't easily capture evolving patterns like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"When working on MCP servers, always check the umcp wrapper patterns"&lt;/li&gt;
&lt;li&gt;"The smoke test paradigm works better than unit tests for these projects"&lt;/li&gt;
&lt;li&gt;"Remember that the memento CLI should never be called directly—use MCP"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These insights lived in my head, not in a form the LLM could access and build upon. Each new session started from zero, unable to leverage the accumulated knowledge from previous sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 9: Parallelization Challenge
&lt;/h2&gt;

&lt;p&gt;I wanted parallel LLM sessions building different parts of the same project. Chaos ensued.&lt;/p&gt;

&lt;p&gt;The ideal workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Session A: implements a feature&lt;/li&gt;
&lt;li&gt;Session B: writes tests for that feature&lt;/li&gt;
&lt;li&gt;Session C: updates documentation&lt;/li&gt;
&lt;li&gt;Session D: reviews the changes from A, B, and C&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But coordinating multiple LLM sessions is harder than coordinating humans. Problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sessions can't see each other's progress&lt;/li&gt;
&lt;li&gt;No natural communication channel between sessions&lt;/li&gt;
&lt;li&gt;They'll happily work on the same file and create conflicts&lt;/li&gt;
&lt;li&gt;No way to express dependencies (Session B needs Session A to finish first)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The solution: orchestration patterns to divide tasks, prevent conflicts, and merge results without manual intervention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 10: Safety and Access Control
&lt;/h2&gt;

&lt;p&gt;When you're in flow, you say 'yes' to everything. That's how the LLM reads your private notes.&lt;/p&gt;

&lt;p&gt;Claude Code prompts have become like cookie consent banners or Terms of Service pages. You've seen the prompt 50 times today. "Do you want to let Claude read this file?" Yes. "Run this command?" Yes. "Search this directory?" Yes. Decision fatigue sets in. You stop reading carefully. You just click yes to make the prompt go away and get back to work.&lt;/p&gt;

&lt;p&gt;This is exactly how website designers exploit users with cookie banners—they know after the 10th website, you'll just click "Accept All" without reading. The same psychological pattern applies to LLM tool use.&lt;/p&gt;

&lt;p&gt;I discovered a serious problem when building my note management system. Despite explicit prompts telling the LLM "do NOT access private notes," I'd occasionally review logs and find it had read private files anyway. This wasn't malicious—the LLM was trying to be helpful, pattern-matched similar file paths, and I'd reflexively approved the request without carefully reading which specific file it wanted.&lt;/p&gt;

&lt;p&gt;Risk areas where this becomes dangerous:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Personal notes or journals&lt;/li&gt;
&lt;li&gt;Configuration files with API keys or tokens&lt;/li&gt;
&lt;li&gt;Any sensitive data mixed with development work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fundamental tension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed vs Safety&lt;/strong&gt;: Careful review of every action slows you down&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context vs Control&lt;/strong&gt;: The LLM needs broad context to be useful, but that increases risk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation vs Oversight&lt;/strong&gt;: You want automated workflows, but automation can bypass safety checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real solution isn't better logging—it's making the wrong thing impossible by design. Don't rely on prompts or careful review. Build systems where sensitive data simply can't be accessed.&lt;/p&gt;

&lt;p&gt;For my note system, I mark notes as PUBLIC in org-mode by setting a property. Only PUBLIC notes are accessible to the LLM via MCP. The system enforces this at the API level—no amount of prompt engineering or reflexive approval can expose private notes.&lt;/p&gt;

&lt;p&gt;But this pattern doesn't scale well to code. You can't mark every file in a codebase as PUBLIC or PRIVATE.&lt;/p&gt;

&lt;p&gt;A more scalable approach: leverage Unix file permissions. Make LLM tools run as a specific user or group with restricted permissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private files: &lt;code&gt;chmod 600&lt;/code&gt; (owner-only)&lt;/li&gt;
&lt;li&gt;Public files: &lt;code&gt;chmod 644&lt;/code&gt; (world-readable)&lt;/li&gt;
&lt;li&gt;LLM runs as different user/group: physically cannot read private files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This enforces access control at the OS level. The LLM tool literally can't open the file, regardless of prompts or approval. You could even use &lt;code&gt;chattr +i&lt;/code&gt; on Linux to make sensitive files immutable.&lt;/p&gt;

&lt;p&gt;The challenge: this requires discipline in setting permissions and may conflict with normal development workflows. But it's the right direction—making violations impossible, not just logged.&lt;/p&gt;

&lt;p&gt;Other needed patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Directory-level access control (allow &lt;code&gt;~/projects/blog&lt;/code&gt;, block &lt;code&gt;~/.ssh&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Pattern-based restrictions (block &lt;code&gt;*.env&lt;/code&gt;, &lt;code&gt;*credentials*&lt;/code&gt;, &lt;code&gt;*secrets*&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;API-level enforcement that tools can't bypass&lt;/li&gt;
&lt;li&gt;Audit trails that make violations obvious&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Until we solve this systematically, the onus is on us to be vigilant—and that's exhausting when you're trying to move fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solutions
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ergonomics&lt;/strong&gt; (&lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part2-ergonomics"&gt;Part 2&lt;/a&gt;): Terminal integration showing LLM state, telemetry tracking all sessions, logging every command&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Abstractions&lt;/strong&gt; (&lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part3-abstractions"&gt;Part 3&lt;/a&gt;): Shared context between sessions, smoke test paradigm, coordinating parallel LLMs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Experiments&lt;/strong&gt; (&lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part4-experiments"&gt;Part 4&lt;/a&gt;): Project exploration tools, diff review workflows, lessons from failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning&lt;/strong&gt; (&lt;a href="https://dev.to/post/2025-09-30-llm-workflow-part5-learning"&gt;Part 5&lt;/a&gt;): Flashcard generation, annotated code worksheets, spaced repetition&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next articles show how each works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Part 2: Ergonomics Layer&lt;/strong&gt; &lt;em&gt;(coming soon)&lt;/em&gt; - Terminal integration for managing multiple LLM sessions, telemetry and logging infrastructure that makes everything auditable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3: Higher-Level Abstractions&lt;/strong&gt; &lt;em&gt;(coming soon)&lt;/em&gt; - Shared context systems for long-term memory, smoke tests as the foundation of quality, patterns for coordinating multiple LLM sessions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 4: Works in Progress&lt;/strong&gt; &lt;em&gt;(coming soon)&lt;/em&gt; - Project exploration tools, diff review workflows, experiments that didn't quite pan out (but taught me valuable lessons).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 5: Learning &amp;amp; Knowledge&lt;/strong&gt; &lt;em&gt;(coming soon)&lt;/em&gt; - Using LLMs to generate flashcards, worksheets, and heavily-annotated code for studying complex topics.&lt;/p&gt;




</description>
      <category>llm</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Building a Smart Home with AppDaemon: From Baby Monitors to Language Learning</title>
      <dc:creator>Laurent Charignon</dc:creator>
      <pubDate>Fri, 17 Oct 2025 02:49:40 +0000</pubDate>
      <link>https://forem.com/laurent_charignon/building-a-smart-home-with-appdaemon-from-baby-monitors-to-language-learning-4jg6</link>
      <guid>https://forem.com/laurent_charignon/building-a-smart-home-with-appdaemon-from-baby-monitors-to-language-learning-4jg6</guid>
      <description>&lt;p&gt;Over the past year, I've been building a comprehensive home automation system using &lt;a href="https://appdaemon.readthedocs.io/" rel="noopener noreferrer"&gt;AppDaemon&lt;/a&gt;, a Python framework for Home Assistant automation. What started as simple light controls has evolved into a sophisticated ecosystem of 30+ interconnected applications managing everything from CPAP machines to interactive language learning games for my child.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AppDaemon?
&lt;/h2&gt;

&lt;p&gt;Home Assistant's built-in automations are great for simple rules, but when you need complex logic, state management, or want to reuse code across multiple automations, AppDaemon shines. It provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full Python programming capabilities&lt;/li&gt;
&lt;li&gt;Object-oriented design with inheritance&lt;/li&gt;
&lt;li&gt;Async/await support for concurrent operations&lt;/li&gt;
&lt;li&gt;Direct access to Home Assistant's state and service APIs&lt;/li&gt;
&lt;li&gt;Easy testing with pytest&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Architecture: Base Class Pattern
&lt;/h2&gt;

&lt;p&gt;At the core of my system is a &lt;code&gt;BaseApp&lt;/code&gt; class that all automations inherit from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hass&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ArgClass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;global_vars&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;global_vars&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgClass&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statsd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;statsd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StatsClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statsd.lan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9125&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filtered_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fields_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filtered_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern provides several benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt;: Using dataclasses for arguments ensures type checking and validation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics Collection&lt;/strong&gt;: Built-in StatsD integration for monitoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Logging&lt;/strong&gt;: Standardized logging across all apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Reuse&lt;/strong&gt;: Common functionality available to all automations&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Real-World Applications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. CPAP Light Synchronization
&lt;/h3&gt;

&lt;p&gt;One of the more unique automations synchronizes bedroom lighting with my CPAP machine. When the CPAP starts (detected via power monitoring), the lights gradually dim to create ideal sleeping conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CPAPLightSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cpap_state_changed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cpap_sensor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;state&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cpap_state_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# CPAP is running
&lt;/span&gt;            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;turn_off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;light.bedroom&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Multi-Language Learning Game
&lt;/h3&gt;

&lt;p&gt;Perhaps the most ambitious application is an interactive language learning system for my son Luca. It integrates a smart button (Hatch Baby Rest) with text-to-speech to teach vocabulary in multiple languages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LucaMultiLanguageLearningArgs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;hatch_button&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;media_player&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;dictionary_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;available_languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="n"&gt;current_language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;french&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Loads JSON dictionaries for French, Spanish, Farsi, and other languages&lt;/li&gt;
&lt;li&gt;Tracks recently used words to avoid repetition&lt;/li&gt;
&lt;li&gt;Speaks word pairs (foreign word → English translation)&lt;/li&gt;
&lt;li&gt;Plays Spotify playlists during specific hours&lt;/li&gt;
&lt;li&gt;Handles Unicode characters gracefully for non-Latin scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Motion-Activated Devices
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;MotionActivatedDevice&lt;/code&gt; class demonstrates the power of abstraction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MotionActivatedDevice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseApp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;motion_detected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;should_activate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;activate_device&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule_deactivation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single class powers multiple automations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bathroom lights that stay on longer during nighttime&lt;/li&gt;
&lt;li&gt;Office fans that run when occupied&lt;/li&gt;
&lt;li&gt;Display screens that wake on approach&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Smart Environmental Control
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;CarbonDioxydeRegulator&lt;/code&gt; monitors CO₂ levels and automatically controls ventilation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;regulate_co2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;co2_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;co2_level&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;turn_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fan.office&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;co2_level&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;turn_off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fan.office&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Infrastructure
&lt;/h2&gt;

&lt;p&gt;Quality is ensured through comprehensive testing. The repository includes pytest-based tests that validate argument parsing, state changes, and service calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_args_types&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;apps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;importlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;import_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__dataclass_fields__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Enhanced Git Hooks for Quality
&lt;/h2&gt;

&lt;p&gt;To maintain code quality, I've implemented a sophisticated pre-commit hook that goes beyond simple test execution. The hook provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visual Progress Indicators&lt;/strong&gt;: Green checkmarks (✓) for passing checks, red crosses (✗) for failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Staged Test Results&lt;/strong&gt;: Shows exactly which tests passed or failed with formatted output&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Syntax Validation&lt;/strong&gt;: Checks all Python files for syntax errors before commit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debug Statement Detection&lt;/strong&gt;: Warns about leftover print statements or pdb imports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detailed Error Reporting&lt;/strong&gt;: Highlights file paths and line numbers in test failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hook transforms the typical pytest output into a developer-friendly format that makes it immediately obvious what needs attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metrics and Observability
&lt;/h2&gt;

&lt;p&gt;Every automation reports metrics to a StatsD server, enabling monitoring of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automation execution frequency&lt;/li&gt;
&lt;li&gt;State change patterns&lt;/li&gt;
&lt;li&gt;Error rates and types&lt;/li&gt;
&lt;li&gt;Performance metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This data feeds into Grafana dashboards, providing insights into home patterns and automation effectiveness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Learnings
&lt;/h2&gt;

&lt;p&gt;After a year of development, here are the key takeaways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with a solid foundation&lt;/strong&gt;: The BaseApp pattern has saved countless hours&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type hints are invaluable&lt;/strong&gt;: Dataclasses catch configuration errors early&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test everything&lt;/strong&gt;: Automated tests prevent regressions when updating complex automations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor everything&lt;/strong&gt;: Metrics reveal patterns you didn't know existed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it maintainable&lt;/strong&gt;: Clear naming and documentation matter when returning to code months later&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Looking Forward
&lt;/h2&gt;

&lt;p&gt;The system continues to evolve. Upcoming projects include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Voice-activated scene controls using local speech recognition&lt;/li&gt;
&lt;li&gt;Predictive heating/cooling based on weather forecasts and historical patterns&lt;/li&gt;
&lt;li&gt;Integration with security cameras for person detection&lt;/li&gt;
&lt;li&gt;Automated plant watering based on soil moisture sensors&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AppDaemon has transformed my home into a responsive environment that adapts to our family's needs. From ensuring optimal sleep conditions to helping my son learn new languages, these automations have become an invisible but essential part of daily life.&lt;/p&gt;

&lt;p&gt;The combination of Python's flexibility, Home Assistant's ecosystem, and AppDaemon's framework creates a powerful platform for home automation that goes far beyond simple "if this then that" rules.&lt;/p&gt;

&lt;p&gt;The full source code is available on &lt;a href="https://github.com/charignon/appdaemon" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, and I welcome contributions and questions from the community. Whether you're looking to automate a single room or your entire home, I hope these patterns and examples help you build something amazing.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have questions about specific automations or want to share your own AppDaemon projects? Feel free to reach out or open an issue on the repository.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>iot</category>
      <category>automation</category>
      <category>python</category>
    </item>
    <item>
      <title>Prompt Tracker: Turn Your Coding Sessions into a Star Wars Opening Crawl</title>
      <dc:creator>Laurent Charignon</dc:creator>
      <pubDate>Fri, 17 Oct 2025 02:23:12 +0000</pubDate>
      <link>https://forem.com/laurent_charignon/prompt-tracker-turn-your-coding-sessions-into-a-star-wars-opening-crawl-3m8b</link>
      <guid>https://forem.com/laurent_charignon/prompt-tracker-turn-your-coding-sessions-into-a-star-wars-opening-crawl-3m8b</guid>
      <description>&lt;p&gt;What if your coding sessions looked like a Star Wars opening crawl? Prompts scrolling through time, color-coded by quality, with dramatic bubbles floating across a timeline like ships in hyperspace?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt Tracker&lt;/strong&gt; transforms your Claude conversation history into an entertaining, interactive visualization—part productivity tool, part time-traveling dashboard, part cinematic experience. Watch your prompting habits unfold like an epic saga, rate your greatest hits, and learn from your mistakes—all while having way more fun than you should with a JSON log file.&lt;/p&gt;

&lt;p&gt;It's both &lt;strong&gt;informative&lt;/strong&gt; (analytics on your AI usage), &lt;strong&gt;productive&lt;/strong&gt; (build a library of your best prompts), and genuinely &lt;strong&gt;entertaining&lt;/strong&gt; (watching your 3am debugging sessions visualized as a chaotic cluster of red bubbles is oddly satisfying).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Lost Conversations
&lt;/h2&gt;

&lt;p&gt;Claude Code stores every conversation in &lt;code&gt;~/.claude/history.jsonl&lt;/code&gt;. While this is great for persistence, it's terrible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Learning from patterns&lt;/strong&gt;: Which prompts led to the best outcomes?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finding past solutions&lt;/strong&gt;: "I remember asking about Docker networking last month..."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracking productivity&lt;/strong&gt;: When do I have the most productive Claude sessions?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Building a prompt library&lt;/strong&gt;: Which prompting techniques actually work for me?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your conversation history is a goldmine of data about how you work with AI. But without tools to analyze it, those insights remain buried.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Star Wars Effect: Your Coding Sessions as Cinema
&lt;/h2&gt;

&lt;p&gt;The core feature is an interactive D3.js timeline that transforms your workday into a cinematic experience. Picture the Star Wars opening crawl, but instead of "A long time ago in a galaxy far, far away," it's "A productive Tuesday in your terminal..."&lt;/p&gt;

&lt;p&gt;[Video: /videos/prompt-tracker-demo.mp4]&lt;/p&gt;

&lt;p&gt;Each bubble is a prompt floating through time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Size&lt;/strong&gt; = Prompt length (that desperate 500-word debugging plea? You'll see it)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Color&lt;/strong&gt; = Quality (green stars ⭐️, red disasters 💀, gray unknowns ❓)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Position&lt;/strong&gt; = When you asked it (2am cluster? We've all been there)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swim lanes&lt;/strong&gt; = Projects (watch them flow like parallel storylines)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The fun part?&lt;/strong&gt; You can zoom into the chaos, pan across your day like a camera sweep, filter by project to see one saga at a time, and click any bubble to relive the moment—complete with a side panel where you can rate it from 1 to 5 stars.&lt;/p&gt;

&lt;p&gt;It's like watching a replay of your coding session, but with production value.&lt;/p&gt;

&lt;p&gt;Here's what it looks like in action:&lt;/p&gt;

&lt;p&gt;[Cast recording: /casts/prompt-tracker-cli-demo.cast]&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The CLI in action: checking stats, listing prompts, and generating timelines&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.laurentcharignon.com%2Fimages%2Fprompt-tracker-timeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.laurentcharignon.com%2Fimages%2Fprompt-tracker-timeline.png" alt="Web app opening with timeline visualization" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The interactive timeline showing a day's worth of conversations&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;Prompt Tracker is a single Python script (no dependencies!) that syncs data from Claude's history file into a local SQLite database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Sync your Claude history&lt;/span&gt;
./prompt-tracker &lt;span class="nb"&gt;sync&lt;/span&gt;

&lt;span class="c"&gt;# Generate today's timeline (auto-opens in browser)&lt;/span&gt;
./prompt-tracker timeline 2025-10-02

&lt;span class="c"&gt;# Or start a web server for interactive browsing&lt;/span&gt;
./prompt-tracker serve &lt;span class="nt"&gt;--port&lt;/span&gt; 8080

&lt;span class="c"&gt;# Rate your favorite prompts&lt;/span&gt;
./prompt-tracker rate 42 5

&lt;span class="c"&gt;# Search for specific topics&lt;/span&gt;
./prompt-tracker list &lt;span class="nt"&gt;--search&lt;/span&gt; &lt;span class="s2"&gt;"docker"&lt;/span&gt;

&lt;span class="c"&gt;# Filter by project&lt;/span&gt;
./prompt-tracker list &lt;span class="nt"&gt;--project&lt;/span&gt; /Users/you/repos/myproject

&lt;span class="c"&gt;# Find your best work&lt;/span&gt;
./prompt-tracker list &lt;span class="nt"&gt;--min-rating&lt;/span&gt; 4

&lt;span class="c"&gt;# Export as JSON for custom analysis&lt;/span&gt;
./prompt-tracker list &lt;span class="nt"&gt;--format&lt;/span&gt; json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Web Interface Mode
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;serve&lt;/code&gt; command launches a local web server that turns prompt browsing into a fully interactive experience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./prompt-tracker serve &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This opens an interface where you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate between different dates with URL routing (&lt;code&gt;/timeline/2025-10-02&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Rate prompts directly in the browser with AJAX updates&lt;/li&gt;
&lt;li&gt;Filter and explore without regenerating static HTML files&lt;/li&gt;
&lt;li&gt;Keep the server running while you work, refreshing to see new prompts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as the difference between watching a movie on DVD (static timelines) versus streaming (live web interface).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Database Schema
&lt;/h3&gt;

&lt;p&gt;At its core, Prompt Tracker maintains two simple tables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Prompts table - imported from history.jsonl
&lt;/span&gt;&lt;span class="n"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;TABLE&lt;/span&gt; &lt;span class="nf"&gt;prompts &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="n"&gt;INTEGER&lt;/span&gt; &lt;span class="n"&gt;PRIMARY&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="n"&gt;INTEGER&lt;/span&gt; &lt;span class="n"&gt;UNIQUE&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt; &lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;DATETIME&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Ratings and notes - your annotations
&lt;/span&gt;&lt;span class="n"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;TABLE&lt;/span&gt; &lt;span class="nf"&gt;prompt_metadata &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;prompt_id&lt;/span&gt; &lt;span class="n"&gt;INTEGER&lt;/span&gt; &lt;span class="n"&gt;PRIMARY&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;rating&lt;/span&gt; &lt;span class="n"&gt;INTEGER&lt;/span&gt; &lt;span class="nc"&gt;CHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;note&lt;/span&gt; &lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="n"&gt;DATETIME&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation means your annotations never touch the original history file—all ratings and notes stay local.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Building a Prompt Library
&lt;/h3&gt;

&lt;p&gt;After rating hundreds of prompts, patterns emerge. I noticed my 5-star prompts often share characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Specific context&lt;/strong&gt;: "In this React app using TypeScript and Vite..."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear success criteria&lt;/strong&gt;: "The function should handle these three edge cases..."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example-driven&lt;/strong&gt;: "Like this pattern we used in auth.ts..."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now when I face a new problem, I search my highest-rated prompts for similar situations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prompt-tracker list &lt;span class="nt"&gt;--min-rating&lt;/span&gt; 4 &lt;span class="nt"&gt;--search&lt;/span&gt; &lt;span class="s2"&gt;"typescript error handling"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reveals my own best practices—not generic advice, but patterns that have worked specifically for my projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Debugging Prompt Engineering
&lt;/h3&gt;

&lt;p&gt;Sometimes a prompt doesn't work. Was it too vague? Too specific? Missing context?&lt;/p&gt;

&lt;p&gt;The timeline visualization makes this obvious. I can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clusters of low-rated prompts → I was struggling with something&lt;/li&gt;
&lt;li&gt;Long gaps between prompts → Complex task or Claude got stuck&lt;/li&gt;
&lt;li&gt;Rapid-fire sequences → Iterative refinement working well&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Color-coding by rating reveals temporal patterns—are my morning prompts more effective than late-night ones?&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Tracking Productivity Patterns
&lt;/h3&gt;

&lt;p&gt;The 24-hour timeline shows when I'm most productive with Claude:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Morning (9-11am)&lt;/strong&gt;: Complex architecture discussions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Afternoon (2-4pm)&lt;/strong&gt;: Bug fixes and refactoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evening (7-9pm)&lt;/strong&gt;: Experimental projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This data-driven insight helps me schedule challenging work during high-effectiveness windows.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Knowledge Transfer to Memento
&lt;/h3&gt;

&lt;p&gt;When I find a particularly valuable prompt, I can publish it to my Memento knowledge base:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prompt-tracker publish 42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This extracts the prompt and creates a Memento note with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The original prompt text&lt;/li&gt;
&lt;li&gt;Any ratings and notes I've added&lt;/li&gt;
&lt;li&gt;Timestamp and project context&lt;/li&gt;
&lt;li&gt;Tags for searchability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These notes become part of my long-term LLM memory, available in future Claude sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;Prompt Tracker embraces simplicity:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single-file executable&lt;/strong&gt;: The entire CLI is one Python script. No installation, no dependency hell—just &lt;code&gt;chmod +x&lt;/code&gt; and run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero dependencies for core features&lt;/strong&gt;: SQLite is built into Python. JSON parsing is standard library. The CLI works anywhere Python 3.7+ exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Progressive enhancement&lt;/strong&gt;: The timeline visualization loads D3.js from CDN. If you're offline, you still have full CLI functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local-first&lt;/strong&gt;: Everything stays on your machine. No cloud services, no analytics, no data leaving your computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Statistics Dashboard
&lt;/h2&gt;

&lt;p&gt;Beyond visualizations, Prompt Tracker provides statistical insights:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;prompt-tracker stats

Total prompts: 1,247
Rated prompts: 89 &lt;span class="o"&gt;(&lt;/span&gt;7.1%&lt;span class="o"&gt;)&lt;/span&gt;
Average rating: 3.67

Rating distribution:
  ★☆☆☆☆    8  ████████
  ★★☆☆☆   14  ██████████████
  ★★★☆☆   31  ███████████████████████████████
  ★★★★☆   26  ██████████████████████████
  ★★★★★   10  ██████████

Top projects by prompt count:
  blog-automation: 156
  memento:        142
  appdaemon:      89
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reveals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How much you rely on Claude&lt;/li&gt;
&lt;li&gt;Whether you're consistently getting value (rating trends)&lt;/li&gt;
&lt;li&gt;Which projects generate the most questions&lt;/li&gt;
&lt;li&gt;Opportunities to improve (lots of 1-star prompts? time to refine your approach)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Full-Text Search
&lt;/h3&gt;

&lt;p&gt;SQLite's built-in text search makes finding past conversations instant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Find that Docker networking conversation from last month&lt;/span&gt;
prompt-tracker list &lt;span class="nt"&gt;--search&lt;/span&gt; &lt;span class="s2"&gt;"docker network"&lt;/span&gt; &lt;span class="nt"&gt;--date-from&lt;/span&gt; 2025-09-01

&lt;span class="c"&gt;# All your highest-rated debugging sessions&lt;/span&gt;
prompt-tracker list &lt;span class="nt"&gt;--min-rating&lt;/span&gt; 4 &lt;span class="nt"&gt;--search&lt;/span&gt; &lt;span class="s2"&gt;"bug"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notes and Context
&lt;/h3&gt;

&lt;p&gt;Sometimes the prompt alone doesn't capture why it worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add context about what made this prompt effective&lt;/span&gt;
prompt-tracker note 42 &lt;span class="s2"&gt;"Great example of providing full error stack trace"&lt;/span&gt;

&lt;span class="c"&gt;# Later, review notes on all your top prompts&lt;/span&gt;
prompt-tracker list &lt;span class="nt"&gt;--min-rating&lt;/span&gt; 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes become a meta-layer of learning—documenting not just what you asked, but why it was effective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Filtering
&lt;/h3&gt;

&lt;p&gt;The timeline's project-based swim lanes let you focus on specific areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click a project name to filter the timeline&lt;/li&gt;
&lt;li&gt;See all conversations related to one codebase&lt;/li&gt;
&lt;li&gt;Compare prompt patterns across different projects&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Word Cloud Analysis
&lt;/h2&gt;

&lt;p&gt;Bonus: Prompt Tracker includes scripts for linguistic analysis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate word cloud from all your prompts&lt;/span&gt;
python create_wordcloud.py

&lt;span class="c"&gt;# Technical terms only (filters out common words)&lt;/span&gt;
python create_technical_wordcloud.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These visualizations reveal your vocabulary patterns—do you ask about "bugs" or "issues"? "functions" or "methods"? The language you use affects Claude's responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Highlights
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Efficient Syncing
&lt;/h3&gt;

&lt;p&gt;The sync operation uses SQLite's &lt;code&gt;INSERT OR IGNORE&lt;/code&gt; to handle the append-only history file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;history_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;new_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;history_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
                INSERT OR IGNORE INTO prompts (timestamp, display, project, pasted_contents)
                VALUES (?, ?, ?, ?)
            &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;display&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;project&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;...))&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rowcount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;new_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;UNIQUE&lt;/code&gt; constraint on timestamp ensures no duplicates, and &lt;code&gt;INSERT OR IGNORE&lt;/code&gt; makes re-running sync idempotent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactive Timeline Generation
&lt;/h3&gt;

&lt;p&gt;The timeline uses D3.js with a custom time scale:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Map timestamps to 24-hour positions&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;xScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scaleLinear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;// 24 hours in milliseconds&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Color by rating&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;colorScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scaleLinear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ff4444&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ffaa00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#44ff44&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each prompt becomes an SVG circle with zoom/pan support and hover interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Installation takes 30 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone and make executable&lt;/span&gt;
git clone https://github.com/charignon/prompt_tracker.git
&lt;span class="nb"&gt;cd &lt;/span&gt;prompt_tracker
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x prompt-tracker

&lt;span class="c"&gt;# Sync your history&lt;/span&gt;
./prompt-tracker &lt;span class="nb"&gt;sync&lt;/span&gt;

&lt;span class="c"&gt;# Generate today's timeline&lt;/span&gt;
./prompt-tracker timeline &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y-%m-%d&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The timeline opens automatically in your default browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration with Existing Tools
&lt;/h2&gt;

&lt;p&gt;Prompt Tracker complements other productivity tools:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Memento&lt;/strong&gt;: Export valuable prompts as Memento notes for long-term memory&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Git&lt;/strong&gt;: The SQLite database can be version-controlled, synced across machines&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Analytics&lt;/strong&gt;: Export data as JSON for custom analysis in R, Python, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Note-taking&lt;/strong&gt;: Copy high-rated prompts into documentation, READMEs, guides&lt;/p&gt;

&lt;h2&gt;
  
  
  What I've Learned
&lt;/h2&gt;

&lt;p&gt;After tracking 1,200+ prompts over several months:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rating prompts immediately is crucial.&lt;/strong&gt; Wait a day and you forget what made it good or bad. Rate right after you see the response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The best prompts are specific.&lt;/strong&gt; 5-star prompts average 3x longer than 1-star prompts. Context matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Patterns emerge unexpectedly.&lt;/strong&gt; I didn't realize how often I ask about "testing patterns" until the word cloud showed it as my #2 topic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual feedback changes behavior.&lt;/strong&gt; Seeing red clusters on the timeline makes me more thoughtful about next prompts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Knowledge compounds.&lt;/strong&gt; Exporting prompts to Memento creates a feedback loop—Claude gets better context, leading to better prompts, which get added to Memento...&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Directions
&lt;/h2&gt;

&lt;p&gt;Ideas I'm exploring:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-powered clustering&lt;/strong&gt;: Use embeddings to group semantically similar prompts, revealing topics beyond keyword matching&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt templates&lt;/strong&gt;: Extract patterns from 5-star prompts to generate templates for common tasks&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collaborative learning&lt;/strong&gt;: Anonymous sharing of highly-rated prompts to learn from the community&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conversation threading&lt;/strong&gt;: Link related prompts across sessions to show how solutions evolved&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Export to Claude&lt;/strong&gt;: Feed your best prompts back into Claude as examples of effective communication&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Who knew analyzing your prompting habits could be this entertaining?&lt;/p&gt;

&lt;p&gt;Prompt Tracker proves that productivity tools don't have to be boring. By turning your Claude conversation history into a cinematic timeline—complete with color-coded bubbles, zoom controls, and Star Wars-level drama—it makes self-reflection actually &lt;em&gt;fun&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You get the productivity benefits (learning from patterns, building a prompt library, tracking what works), the analytical insights (which topics dominate, when you're most effective, how your style evolves), and the sheer entertainment value of watching your 3am debugging sessions play out like an action sequence.&lt;/p&gt;

&lt;p&gt;Every prompt is a tiny experiment. With Prompt Tracker, you don't just see which experiments succeed—you watch them unfold across time like chapters in an epic saga. And honestly? That's way more engaging than staring at a JSON file.&lt;/p&gt;

&lt;p&gt;So go ahead: turn your coding sessions into cinema. Rate your greatest hits. Learn from your disasters. And maybe, just maybe, have some fun while becoming a better prompt engineer.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Prompt Tracker is open source at &lt;a href="https://github.com/charignon/prompt_tracker" rel="noopener noreferrer"&gt;github.com/charignon/prompt_tracker&lt;/a&gt;. It's a single Python script with zero dependencies. MIT licensed—use freely and contribute improvements.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>productivity</category>
      <category>visualization</category>
      <category>claude</category>
    </item>
  </channel>
</rss>
