<?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: Przemek Marzec</title>
    <description>The latest articles on DEV Community by Przemek Marzec (@przemarzec).</description>
    <link>https://dev.to/przemarzec</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%2F4025572%2F0e4fade7-c225-4f20-a10a-ac5a7e22fec3.png</url>
      <title>DEV Community: Przemek Marzec</title>
      <link>https://dev.to/przemarzec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/przemarzec"/>
    <language>en</language>
    <item>
      <title>Action Records: Memory for Things an Agent Did</title>
      <dc:creator>Przemek Marzec</dc:creator>
      <pubDate>Mon, 20 Jul 2026 20:26:10 +0000</pubDate>
      <link>https://dev.to/sovantica/action-records-memory-for-things-an-agent-did-4472</link>
      <guid>https://dev.to/sovantica/action-records-memory-for-things-an-agent-did-4472</guid>
      <description>&lt;p&gt;Most agent memory examples start with facts: a user preference, a summary, a document chunk, a note extracted from a conversation. Those are useful, but they leave out a large part of what an agent actually needs to reason about later: what it planned to do, what it attempted, what succeeded, and what failed.&lt;/p&gt;

&lt;p&gt;Engrava models that surface with &lt;strong&gt;Action Records&lt;/strong&gt;. An action isn't a chat message, and it isn't a replacement for a task runner. It's a durable memory record for a state change the agent considers operationally meaningful.&lt;/p&gt;

&lt;p&gt;That distinction stays abstract until an agent has to recover context across sessions. "The deployment was discussed" is a different thing to have in memory than "the deployment was attempted and failed after the migration step." A text summary can hold the second sentence, but a first-class action record gives the agent something structured to query, connect, and verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why actions belong in memory
&lt;/h2&gt;

&lt;p&gt;Agents move through a loop: infer what should happen next, call a tool or ask a human for approval, observe the result, adjust. If memory only stores natural-language notes, that loop goes opaque over time — the agent can search for words, but it can't reliably ask for "the last failed attempt to update this resource" or "actions that were planned but never confirmed."&lt;/p&gt;

&lt;p&gt;Action Records make that state explicit. They represent states like &lt;code&gt;PLANNED&lt;/code&gt;, &lt;code&gt;EXECUTING&lt;/code&gt;, &lt;code&gt;CONFIRMED&lt;/code&gt;, and &lt;code&gt;FAILED&lt;/code&gt;, and connect to thoughts and edges in the same local store. This isn't about turning the memory system into an orchestrator — it's about keeping the memory database honest about the gap between what the agent knows and what it actually did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured state, still embedded
&lt;/h2&gt;

&lt;p&gt;Engrava keeps this in the same embedded SQLite-backed store as the rest of the memory graph, which matters for a couple of reasons. There's no separate service to stand up just to ask operational questions — thoughts, edges, action records, timestamps, lifecycle state, and optional journal entries all live in one local database. And the action state participates in the same query and retrieval model: an agent can record a thought for a request, link it to a planned action, update that action when the tool call completes, then later use MindQL and the Python API to inspect recent actions, narrow by status, or pull back the surrounding graph.&lt;/p&gt;

&lt;h2&gt;
  
  
  The journal is evidence, not a spell
&lt;/h2&gt;

&lt;p&gt;When journaling is enabled, Engrava records thought and edge mutations and action state transitions as hash-linked journal entries — a tamper-evident chain for the events that were journaled. The wording is deliberate. The journal is optional. It is not a database-wide integrity system, it doesn't make external side effects reversible, and it doesn't stop a privileged writer from replacing the database and journal together. What it gives you is a way to verify the continuity of the journaled chain when that journal has been enabled — which matters because action state has a different trust profile from an ordinary note. If an agent later sees an action marked confirmed, the application may want to know whether that confirmation is part of the expected local history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not just a task log
&lt;/h2&gt;

&lt;p&gt;A task log answers "what happened?" Agent memory has to answer a wider question: not only that an action happened, but what the agent believed when it chose it, which earlier facts led there, whether it moved through a known state sequence, and whether a failure should change how it retrieves or plans next time. Action Records are built to live &lt;em&gt;with&lt;/em&gt; the surrounding graph, not beside it — so execution memory stays close to semantic memory instead of collapsing into unstructured prose.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete example
&lt;/h2&gt;

&lt;p&gt;Say an agent is rolling out a config change. It stores a thought for the request, records a &lt;code&gt;PLANNED&lt;/code&gt; action linked to that thought, and moves the action to &lt;code&gt;EXECUTING&lt;/code&gt; when it calls the deploy tool. The migration step fails, so the action lands in &lt;code&gt;FAILED&lt;/code&gt; — not as a line buried in a summary, but as a queryable record tied to the resource and to the thoughts around it.&lt;/p&gt;

&lt;p&gt;Two sessions later the agent picks the task back up. Instead of re-reading a wall of notes hoping the failure is mentioned, it asks the store directly: the last &lt;code&gt;FAILED&lt;/code&gt; action on that resource, and the thoughts connected to it. It retrieves the failed migration and the reasoning linked to it — and can choose not to repeat it blindly.&lt;/p&gt;

&lt;p&gt;A plain text log could hold "deploy failed." What it can't do is let the agent ask that question precisely, connect the answer to the decision that led there, and treat a failed action differently from a fact it merely read. That's the point of giving actions a first-class record instead of leaving them in prose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it sits
&lt;/h2&gt;

&lt;p&gt;Action Records are one piece of a compositional store: graph memory for relationships, hybrid search for recall, MindQL for structured reads, and an optional tamper-evident journal. None of it claims the memory "thinks" for the agent — the application still owns policy, approvals, and side effects. Engrava just gives it a local, queryable substrate that can remember more than facts alone.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>architecture</category>
    </item>
    <item>
      <title>How we built Engrava: from cognitive-architecture research to a production library</title>
      <dc:creator>Przemek Marzec</dc:creator>
      <pubDate>Tue, 14 Jul 2026 20:23:39 +0000</pubDate>
      <link>https://dev.to/sovantica/how-we-built-engrava-from-cognitive-architecture-research-to-a-production-library-4i7i</link>
      <guid>https://dev.to/sovantica/how-we-built-engrava-from-cognitive-architecture-research-to-a-production-library-4i7i</guid>
      <description>&lt;p&gt;Deterministic consolidation, a typed graph in SQLite, and an honest look at what agent-memory benchmarks can and can't measure.&lt;/p&gt;

&lt;p&gt;You're building an agent. It answers questions across many sessions, and by session three it has forgotten what it learned in session one.&lt;/p&gt;

&lt;p&gt;The reflex is to put a vector database in front of it - and now it remembers a blurry average of everything, ranked by cosine distance, contradicting itself and unable to tell a three-week-old preference from a stale throwaway. A graph database gives you structure, at the cost of a second persistence model with its own query language and deployment. A managed memory service starts you in a few lines, and moves the decision of what your agent remembers onto someone else's infrastructure.&lt;/p&gt;

&lt;p&gt;Underneath all of them is one problem: if every plausible fact is written the moment it appears, memory turns into an accumulation layer instead of a judgement layer. Engrava is our answer to that - local, structured, and deliberate about what it keeps in reach. Here is how it is built, and why.&lt;/p&gt;

&lt;h3&gt;
  
  
  We started with a question, not a&amp;nbsp;schema
&lt;/h3&gt;

&lt;p&gt;Before the storage design there was a long stretch of reading cognitive-architecture research, circling one question: what does a long-running agent actually need from memory if that memory has to stay inspectable? That framing is the reason Engrava is a typed graph and not a bag of embeddings, the reason consolidation is deterministic instead of an LLM rewrite pass, and the reason extraction stays above the database instead of hiding inside it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the memory actually&amp;nbsp;is
&lt;/h3&gt;

&lt;p&gt;Engrava is a typed knowledge graph with hybrid search, in a single SQLite file. Thoughts are nodes; typed edges carry the relationships a flat vector can't - that A caused B, that C specializes D. Retrieval fuses vector similarity, keyword match, recency, and priority rather than leaning on cosine distance alone. Turn on the journal and every thought and edge mutation is recorded in a tamper-evident SHA-256 chain. It is all in the free package.&lt;/p&gt;

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

&lt;p&gt;Every thought has a priority, recomputed each time the consolidation cycle (the dreaming: block) runs - one deterministic pass over the store weighing five signals: recency, staleness, confirmation, confidence, frequency. They combine into a score, checked against gates before promotion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dreaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;signals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;recency&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;staleness&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;confirmation&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;confidence&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;frequency&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;promote_threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75&lt;/span&gt;
  &lt;span class="na"&gt;gates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;min_confirmations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;max_promoted_per_run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default is conservative on purpose: with min_confirmations: 2, a fact the agent has seen once is not promoted - it stays fully retrievable, just not lifted into the active set until the agent has re-confirmed it. That is the point of the cycle: keep memory a judgement layer, so a single noisy pass can't reshape what the agent treats as settled. No language-model call, no network call, no embedding recomputation - arithmetic over SQLite rows, same inputs and same outputs every run, and the policy is a YAML file you can review in a pull request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why it is shaped like the brain's memory - and where it&amp;nbsp;isn't
&lt;/h3&gt;

&lt;p&gt;Three findings shaped three choices. Diekelmann &amp;amp; Born (2010) describe memory stabilization during sleep as selective - the brain keeps a subset of traces, not all of them, which is what the priority score and the promotion gates do. Yassa &amp;amp; Stark (2011) describe how the hippocampus keeps similar experiences from collapsing into one average, so in Engrava thoughts stay distinct nodes and similarity doesn't auto-merge them. Rao &amp;amp; Ballard (1999), and Clark's synthesis (2013), frame the brain as stabilizing what repeated experience confirms, which is where the confirmation and confidence signals come from. We did not build a brain - we took the pressures biological memory evolved under and applied them to a file on disk.&lt;/p&gt;

&lt;h3&gt;
  
  
  The part of benchmarks nobody wants to&amp;nbsp;say
&lt;/h3&gt;

&lt;p&gt;We didn't tune Engrava to top a leaderboard. And dreaming - the consolidation cycle that gives Engrava its character - doesn't move our retrieval benchmark. We turned it on, we turned it off, and the accuracy barely shifts.&lt;/p&gt;

&lt;p&gt;It isn't a bug we're hiding; it's a sign the benchmark is measuring something dreaming isn't for. These benchmarks are short-horizon question-answering over a fixed transcript. Dreaming is lifecycle management - over the weeks an agent stays alive, it decides what stays in reach and what settles out, so the store doesn't rot into an accumulation layer. Whether that discipline pays off over long horizons is genuinely hard to measure, and the benchmarks that exist can't see it.&lt;/p&gt;

&lt;p&gt;Comparable evidence across consolidation systems is thin, too: implementations, datasets, reader models, and evaluation setups vary too much for clean comparisons, and the underlying sleep-consolidation research is itself contested. So we won't attach an improvement claim to dreaming that our own retrieval test doesn't support. Dreaming is deterministic, inspectable, and does a specific job; whether that job matters is yours to decide.&lt;/p&gt;

&lt;p&gt;The wider point holds for the field: half of these benchmarks aren't measuring the same mechanism. Some run a language model inside the memory pipeline; some don't. And the reader model can move the headline number more than the memory architecture does - hold the memory fixed, swap in a stronger reader, and the same system posts a very different score. When we do publish a number, we publish the whole run - reader, judge, dataset, setup - so anyone can reproduce it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stealing SQLite's&amp;nbsp;posture
&lt;/h3&gt;

&lt;p&gt;SQLite runs inside the host process, writes to one file, ships as one library, and is one of the most-tested databases in existence. We wanted that posture. Engrava is a Python library - pip install engrava, and the store is a file on your disk. No server to run, no port to open, no separate auth; your agent imports it like any dependency, nothing leaves the host unless you wire up a remote embedding provider yourself, and it is MIT-licensed. It is not a multi-tenant fleet service - if your agent is a horizontally-scaled cluster needing shared memory across machines, embedded is the wrong shape. For a single agent, it is usually the simpler fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where the category is&amp;nbsp;now
&lt;/h3&gt;

&lt;p&gt;When we started, this was fairly open space. By the time we shipped it wasn't - several teams, Anthropic among them, had shipped consolidation under the same "dreaming" name, borrowing the same sleep metaphor, around the same time. The category converged fast. What separates these tools now isn't the vocabulary; it's whether the consolidation is something you can open up, configure, and run yourself, or something that happens elsewhere on your behalf.&lt;/p&gt;

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

&lt;p&gt;Engrava is live on &lt;a href="https://pypi.org/project/engrava/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt; - the graph, deterministic consolidation, hybrid search, the audit journal, and MindQL are all in the free package. &lt;br&gt;
If you're building an agent, try it:&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;engrava
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo is on &lt;a href="https://github.com/sovantica/engrava" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;; issues and discussions are open.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>agents</category>
      <category>memory</category>
    </item>
  </channel>
</rss>
