<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: LIKKI SAMARTH REDDY</title>
    <description>The latest articles on DEV Community by LIKKI SAMARTH REDDY (@likki_samarthreddy).</description>
    <link>https://dev.to/likki_samarthreddy</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4012504%2F822413e4-6454-47a3-bda0-49746f69cd32.png</url>
      <title>DEV Community: LIKKI SAMARTH REDDY</title>
      <link>https://dev.to/likki_samarthreddy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/likki_samarthreddy"/>
    <language>en</language>
    <item>
      <title>I Thought SQLite Was Fast—Until 50 AI Agents Started Writing at Once</title>
      <dc:creator>LIKKI SAMARTH REDDY</dc:creator>
      <pubDate>Thu, 02 Jul 2026 16:08:26 +0000</pubDate>
      <link>https://dev.to/likki_samarthreddy/i-thought-sqlite-was-fast-until-50-ai-agents-started-writing-at-once-59nf</link>
      <guid>https://dev.to/likki_samarthreddy/i-thought-sqlite-was-fast-until-50-ai-agents-started-writing-at-once-59nf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A real-world engineering experiment on checkpointing, persistence, and why your storage backend matters more than your AI model.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everyone talks about LLMs.&lt;/p&gt;

&lt;p&gt;Bigger models.&lt;br&gt;
Better prompts.&lt;br&gt;
Smarter agents.&lt;/p&gt;

&lt;p&gt;But almost nobody talks about what happens &lt;strong&gt;after&lt;/strong&gt; an AI agent has been running for hours.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where does its state live?&lt;/li&gt;
&lt;li&gt;How do you resume after a crash?&lt;/li&gt;
&lt;li&gt;How do hundreds of agents save progress simultaneously?&lt;/li&gt;
&lt;li&gt;What happens when persistence becomes the bottleneck?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those questions led me to build &lt;strong&gt;&lt;a href="https://github.com/likkisamarthreddy/livingai" rel="noopener noreferrer"&gt;Living AI&lt;/a&gt;&lt;/strong&gt;—an experimental checkpointing engine for long-running AI agents.&lt;/p&gt;

&lt;p&gt;Its purpose isn't to replace agent frameworks.&lt;/p&gt;

&lt;p&gt;It's to solve a simpler problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Persist agent state quickly without letting storage stall execution.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h1&gt;
  
  
  The Experiment
&lt;/h1&gt;

&lt;p&gt;I built Living AI around a few simple ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pluggable storage backends&lt;/li&gt;
&lt;li&gt;In-memory hot cache&lt;/li&gt;
&lt;li&gt;Compression&lt;/li&gt;
&lt;li&gt;Recovery API&lt;/li&gt;
&lt;li&gt;Execution-budgeted persistence&lt;/li&gt;
&lt;li&gt;Built-in performance metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
   │
   ▼
Checkpoint Engine
   │
   ├── Compress State
   ├── Update Hot Cache
   └── Persist to Storage
          │
          ├── SQLite
          └── Redis-compatible Store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of benchmarking models, I benchmarked the infrastructure beneath them.&lt;/p&gt;




&lt;h1&gt;
  
  
  Benchmark #1 — Single Agent
&lt;/h1&gt;

&lt;p&gt;First I tested a single long-running workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workload&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;500 checkpoints&lt;/li&gt;
&lt;li&gt;250 KB state&lt;/li&gt;
&lt;li&gt;Forced cache eviction&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;✅ Average save: &lt;strong&gt;13.45 ms&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ Hot-cache recovery: &lt;strong&gt;1.11 ms&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ Cold recovery (SQLite + decompression): &lt;strong&gt;1.48 ms&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At this point everything looked healthy.&lt;/p&gt;




&lt;h1&gt;
  
  
  Benchmark #2 — Then I Added 50 Concurrent Agents
&lt;/h1&gt;

&lt;p&gt;This is where things became interesting.&lt;/p&gt;

&lt;p&gt;Configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;50 concurrent agents&lt;/li&gt;
&lt;li&gt;1000 checkpoint attempts&lt;/li&gt;
&lt;li&gt;SQLite backend&lt;/li&gt;
&lt;li&gt;50 ms persistence budget&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;SQLite&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Successful writes&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timed-out writes&lt;/td&gt;
&lt;td&gt;995&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average write latency&lt;/td&gt;
&lt;td&gt;282 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum latency&lt;/td&gt;
&lt;td&gt;735 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At first glance, this looked terrible.&lt;/p&gt;

&lt;p&gt;Then I realized something important.&lt;/p&gt;

&lt;p&gt;The checkpoint engine wasn't slow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQLite had become the bottleneck.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because SQLite allows only one writer at a time, concurrent checkpoint requests began waiting on database locks.&lt;/p&gt;

&lt;p&gt;The engine's timeout policy skipped slow persistence attempts rather than blocking agent execution.&lt;/p&gt;

&lt;p&gt;That trade-off kept the agents responsive under load.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Real Test
&lt;/h1&gt;

&lt;p&gt;Without changing the checkpoint engine...&lt;/p&gt;

&lt;p&gt;Without changing compression...&lt;/p&gt;

&lt;p&gt;Without changing agent logic...&lt;/p&gt;

&lt;p&gt;I swapped only the storage backend.&lt;/p&gt;

&lt;p&gt;SQLite became a Redis-compatible implementation.&lt;/p&gt;

&lt;p&gt;Exactly the same workload.&lt;/p&gt;

&lt;p&gt;Exactly the same checkpoint engine.&lt;/p&gt;

&lt;p&gt;Here were the results.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;SQLite&lt;/th&gt;
&lt;th&gt;Redis-compatible&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SLA Compliance&lt;/td&gt;
&lt;td&gt;0.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average Write&lt;/td&gt;
&lt;td&gt;282 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.64 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p99 Write&lt;/td&gt;
&lt;td&gt;735 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.23 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That single experiment completely changed where optimization effort should go.&lt;/p&gt;

&lt;p&gt;The bottleneck wasn't checkpointing.&lt;/p&gt;

&lt;p&gt;It wasn't serialization.&lt;/p&gt;

&lt;p&gt;It wasn't caching.&lt;/p&gt;

&lt;p&gt;It was storage contention.&lt;/p&gt;




&lt;h1&gt;
  
  
  One More Surprise
&lt;/h1&gt;

&lt;p&gt;After removing storage contention, another bottleneck appeared.&lt;/p&gt;

&lt;p&gt;Compression.&lt;/p&gt;

&lt;p&gt;Large checkpoints (~793 KB) spent far more time compressing data than writing it.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Once storage became fast enough, CPU work became the limiting factor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's exactly the kind of bottleneck you &lt;em&gt;want&lt;/em&gt; to discover through benchmarking.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Living AI Is
&lt;/h1&gt;

&lt;p&gt;Living AI is an experiment in building infrastructure for long-running AI systems.&lt;/p&gt;

&lt;p&gt;Current components include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pluggable persistence layer&lt;/li&gt;
&lt;li&gt;Compression abstraction&lt;/li&gt;
&lt;li&gt;Hot memory cache&lt;/li&gt;
&lt;li&gt;Recovery API&lt;/li&gt;
&lt;li&gt;Performance metrics&lt;/li&gt;
&lt;li&gt;Benchmark suite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rather than optimizing prompts, the focus is on making agent execution more resilient and observable.&lt;/p&gt;




&lt;h1&gt;
  
  
  Lessons Learned
&lt;/h1&gt;

&lt;p&gt;This project reinforced three engineering lessons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Architecture matters more than micro-optimizations.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A clean storage abstraction made it possible to compare backends without rewriting checkpoint logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Benchmarks often reveal a different bottleneck than you expect.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I started by trying to optimize checkpointing.&lt;/p&gt;

&lt;p&gt;I ended up learning much more about storage systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Infrastructure deserves as much attention as models.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As AI agents become longer-lived and more autonomous, persistence, recovery, and state management become increasingly important parts of the stack.&lt;/p&gt;




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

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

&lt;ul&gt;
&lt;li&gt;Additional storage backends&lt;/li&gt;
&lt;li&gt;Faster compression algorithms&lt;/li&gt;
&lt;li&gt;Async persistence queues&lt;/li&gt;
&lt;li&gt;Framework integrations&lt;/li&gt;
&lt;li&gt;Larger-scale reproducible benchmarks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building AI agents, workflow engines, or distributed systems, I'd love to hear how you're approaching checkpointing and recovery.&lt;/p&gt;

&lt;p&gt;The code is still evolving, and feedback from other engineers would be incredibly valuable.&lt;/p&gt;

&lt;p&gt;Check the code: &lt;a href="https://github.com/likkisamarthreddy/livingai" rel="noopener noreferrer"&gt;LivingAI&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>sql</category>
      <category>python</category>
    </item>
    <item>
      <title>Why AI Agents Need a 50ms SLA Checkpoint Engine (and How We Built One)</title>
      <dc:creator>LIKKI SAMARTH REDDY</dc:creator>
      <pubDate>Thu, 02 Jul 2026 16:01:00 +0000</pubDate>
      <link>https://dev.to/likki_samarthreddy/why-ai-agents-need-a-50ms-sla-checkpoint-engine-and-how-we-built-one-307m</link>
      <guid>https://dev.to/likki_samarthreddy/why-ai-agents-need-a-50ms-sla-checkpoint-engine-and-how-we-built-one-307m</guid>
      <description>&lt;p&gt;Building AI agents that survive production is a different problem than building AI agents that work in development.&lt;/p&gt;

&lt;p&gt;In development, your agent runs once, on your machine, with no concurrent users and a database that responds in milliseconds. In production, you have fifty agents running simultaneously, conversation histories that grow to hundreds of kilobytes, and a database that occasionally locks, times out, or becomes briefly unavailable.&lt;/p&gt;

&lt;p&gt;Most agent frameworks were not designed for this reality. And the gap shows up in one specific place: checkpointing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The silent killer in production agent architectures&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Checkpointing is how an agent saves its state between steps. Every major framework does it. LangGraph has SqliteSaver and PostgresSaver. CrewAI has its own persistence layer. The OpenAI Agents SDK has thread state management.&lt;/p&gt;

&lt;p&gt;What almost none of them account for is what happens when the database is slow.&lt;/p&gt;

&lt;p&gt;The standard implementation looks roughly like this:&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;save_checkpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&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;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# blocks until complete
&lt;/span&gt;    &lt;span class="nf"&gt;continue_execution&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under normal conditions, this is fine. Under concurrent load with SQLite, this is catastrophic. SQLite uses file-level write locking. When fifty agents try to write simultaneously, they queue behind each other. Write latencies spike from under a millisecond to over seven hundred milliseconds. Your agent, which was supposed to respond in two seconds, is now waiting three quarters of a second just to save its state at each step.&lt;/p&gt;

&lt;p&gt;We ran this exact scenario. Fifty concurrent agents, one thousand total writes, payloads growing from five to one hundred kilobytes as conversation histories accumulated. With SQLite as the backing store, average write latency was 282ms. The p99 was 735ms. SLA compliance, defined as completing the write within 50ms, was 0.5%.&lt;/p&gt;

&lt;p&gt;That is not a configuration problem. That is a fundamental architectural mismatch between SQLite's single-writer model and concurrent agent workloads.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The architecture we built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Living AI is our open-source solution to this problem. The core insight is that checkpointing should never block the agent execution thread, regardless of what the database is doing.&lt;/p&gt;

&lt;p&gt;The architecture has three components.&lt;/p&gt;

&lt;p&gt;The first is a hot RAM cache. When an agent saves state, it writes synchronously to an in-process LRU cache with a configurable TTL. This write is always sub-millisecond because it never touches disk or network. Reads check this cache first. In a running agent, the most recent state is almost always in the cache, which means the common read path resolves in microseconds.&lt;/p&gt;

&lt;p&gt;The second is a budgeted durable write. After updating the RAM cache, the engine attempts to write to the backing database. This write runs inside asyncio.wait_for with a hard timeout, fifty milliseconds by default. If the database cannot complete the write within budget, the engine drops the write, logs it as a missed checkpoint, and continues. The agent thread is never blocked.&lt;/p&gt;

&lt;p&gt;The third is a self-describing compression layer. Every state blob is compressed with zlib at level six and prepended with a one-byte codec header. The header value 0x00 means uncompressed, 0x01 means zlib. This detail matters more than it sounds: it means you can change the compression algorithm to zstd in the future without breaking any existing checkpoints. Old blobs read their own header and decompress correctly regardless of the current default.&lt;/p&gt;

&lt;p&gt;The ordering of the first two components is the critical design decision. The RAM cache is updated before the database write is attempted. This means even if every database write times out, the agent still has access to its current state through the cache, and crash recovery still works. We stress tested this directly: in our hyperscale test with 150 concurrent agents and 0.77MB state payloads, 99.3% of database writes timed out, and recovery success rate was 100% across all 1500 agents.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What the benchmark numbers actually show&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We ran three test tiers and want to be transparent about what each one measures.&lt;/p&gt;

&lt;p&gt;The single-agent benchmark, which is what the README headline numbers come from, uses the SQLite store with one writer and 50KB compressed blobs. Checkpoint write latency at p50 is 0.3ms, at p95 is 0.8ms, at p99 is approximately 1ms. Hot cache reads resolve in around 4 microseconds.&lt;/p&gt;

&lt;p&gt;The production workload test uses 50 concurrent agents, 1000 total writes, and payloads growing from 5KB to 100KB. This is where the SQLite versus Redis comparison becomes meaningful:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;SQLite&lt;/th&gt;
&lt;th&gt;Redis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SLA compliance within 50ms&lt;/td&gt;
&lt;td&gt;0.5%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average write latency&lt;/td&gt;
&lt;td&gt;282ms&lt;/td&gt;
&lt;td&gt;0.64ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p99 write latency&lt;/td&gt;
&lt;td&gt;735ms&lt;/td&gt;
&lt;td&gt;1.23ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery success rate&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The hyperscale test uses 150 concurrent agents, 1500 total writes, and 0.77MB payloads representing large context windows with long histories and extensive tool call records:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;SQLite&lt;/th&gt;
&lt;th&gt;Redis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SLA compliance within 50ms&lt;/td&gt;
&lt;td&gt;0.7%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p99 write latency&lt;/td&gt;
&lt;td&gt;above 800ms for successes&lt;/td&gt;
&lt;td&gt;62ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery success rate&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p99 recovery read latency&lt;/td&gt;
&lt;td&gt;8.84ms&lt;/td&gt;
&lt;td&gt;6.61ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total execution time&lt;/td&gt;
&lt;td&gt;85.81s&lt;/td&gt;
&lt;td&gt;68.54s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One honest observation about the Redis hyperscale p99 of 62ms: this is slightly above the 50ms SLA, and all writes still completed because asyncio loop scheduling allowed them through. The bottleneck at this scale is not the database. It is CPU. Compressing a 0.77MB blob with zlib is a CPU-bound operation that runs under Python's GIL. At that payload size, the compression itself takes approximately 40ms, which leaves little budget for I/O. Teams hitting this ceiling have two options: switch to zstd, which compresses significantly faster, or offload compression to a process pool executor. We will add both as configuration options in a future release.&lt;/p&gt;

&lt;p&gt;The important pattern across all three tiers is that recovery success rate is 100% regardless of SLA compliance. The two metrics are independent because recovery reads from the RAM cache, not the database. SLA compliance tells you how much of your state made it to durable storage. Recovery success tells you whether your agents can resume after a crash. Both matter, but they are not the same number.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;How Living AI fits with LangGraph and CrewAI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Living AI is not a replacement for agent frameworks. LangGraph handles graph compilation, conditional routing, state schemas, and the execution model that makes complex multi-agent workflows possible. CrewAI handles crew orchestration, role assignment, and agent collaboration. These are problems Living AI does not solve and does not try to solve.&lt;/p&gt;

&lt;p&gt;What Living AI adds is the production reliability layer that sits underneath the framework:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your agent logic
    ↓
LangGraph / CrewAI / OpenAI Agents
    ↓
Living AI runtime
    ↓
Redis / PostgreSQL / SQLite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The framework decides where the agent goes. Living AI makes sure it gets there reliably, can recover if it crashes, and leaves a complete execution record for debugging and compliance.&lt;/p&gt;

&lt;p&gt;The adapter layer makes this composable. Each framework adapter is a thin translation layer that maps framework execution events to Living AI's ExecutionNode model. The core runtime has zero framework dependencies. Swapping from LangGraph to CrewAI does not change how checkpointing, recovery, or replay works.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The replay capability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Crash recovery is the obvious use case. But the more interesting capability for day-to-day development is replay.&lt;/p&gt;

&lt;p&gt;When an agent produces a wrong answer, or books the wrong flight, or sends the wrong message, the question you want to answer is: what exactly happened, and why did the model make that decision? With a standard observability tool, you have logs. You can see what happened. But you cannot re-run the execution with the exact same inputs to reproduce and debug the behavior.&lt;/p&gt;

&lt;p&gt;Living AI stores every prompt, every response, every tool call, and every intermediate state in an append-only execution graph. The replay engine can re-execute any recorded run in four modes.&lt;/p&gt;

&lt;p&gt;FULL replay re-executes every node from scratch, making real API calls and tool invocations. FROM_NODE replay re-executes from a specific node, skipping the work that preceded it. MOCK_TOOLS replay is the most useful for debugging: it re-runs the LLM reasoning with recorded tool responses served from the execution history, so you can iterate on prompt changes without making real API calls or triggering real side effects. COUNTERFACTUAL replay re-executes with modified input at a specific node, letting you test what would have happened if a particular tool had returned a different value.&lt;/p&gt;

&lt;p&gt;The MOCK_TOOLS mode is what makes Living AI useful beyond just crash recovery. If a customer reports that the AI booked the wrong flight, you can replay that exact execution, inspect the LLM's reasoning at each step with the recorded context, and identify where the decision went wrong, all without touching a live system.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Getting started&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The core library has zero runtime dependencies. Everything uses the Python standard library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;livingai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Redis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"livingai[redis]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For PostgreSQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"livingai[postgres]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A minimal crash recovery example:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;livingai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CheckpointEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SQLiteStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExecutionNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;RecoveryEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NodeType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&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;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CheckpointEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLiteStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent.db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ExecutionNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;execution_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;run-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;NodeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plan ready&lt;/span&gt;&lt;span class="sh"&gt;"&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;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;serialized agent state&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;charge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ExecutionNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;execution_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;run-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;NodeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TOOL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output&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;receipt&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;R-1&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;await&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;recovery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecoveryEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CheckpointEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLiteStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent.db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;recovery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;run-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resume from:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resume_node_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;skip effects:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skipped_nodes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skip effects line is the one that matters. Tool nodes are marked non-idempotent by default. The recovery engine will never re-run them. If your agent charged a card on step six and crashed on step eight, the card is not charged again on recovery.&lt;/p&gt;

&lt;p&gt;The examples directory in the repository has five runnable demos covering crash recovery, MOCK_TOOLS debugging, cost tracking, and the LangGraph adapter. None of them require an LLM API key or network access.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Choosing a store for your workload&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One lesson from the benchmarks worth making explicit: the right store depends on your concurrency level, not your preference.&lt;/p&gt;

&lt;p&gt;SQLite is the right default for local development and single-agent workloads. It requires zero configuration, ships with Python, and performs well under low concurrency. The benchmark numbers at p99 under 1ms are real and achievable in this scenario.&lt;/p&gt;

&lt;p&gt;Redis is the right choice for production workloads with multiple concurrent agents. The switch is one import change and a connection URL. No agent logic changes. No core configuration changes. SLA compliance goes from 0.5% to 100%.&lt;/p&gt;

&lt;p&gt;PostgreSQL is the right choice when you need long-term durable storage with query capabilities, cost aggregation across runs, and the ability to reconstruct execution history after a process restart that evicted the Redis cache.&lt;/p&gt;

&lt;p&gt;You can also layer them: Redis as the hot tier for active executions, PostgreSQL as the cold tier for historical records. This is the configuration we recommend for teams running agents at scale.&lt;/p&gt;




&lt;p&gt;The project is Apache-2.0 licensed and completely open source.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://dev.tourl"&gt;github.com/likkisamarthreddy/livingai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are running agents in production and have hit reliability problems we have not covered here, open a GitHub Discussion. We are actively building the next milestone, which is a FastAPI cloud backend with a web-based replay UI, and real production feedback is shaping what gets built.&lt;/p&gt;




</description>
      <category>ai</category>
      <category>opensource</category>
      <category>openai</category>
      <category>github</category>
    </item>
  </channel>
</rss>
