<?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: stephen487</title>
    <description>The latest articles on DEV Community by stephen487 (@stephen487).</description>
    <link>https://dev.to/stephen487</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%2F4012507%2Fffd575e7-d9eb-44ee-98ac-7d6dd33b38b1.PNG</url>
      <title>DEV Community: stephen487</title>
      <link>https://dev.to/stephen487</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stephen487"/>
    <language>en</language>
    <item>
      <title>I'm 56, four months into coding, and my sign-up form let 0 of 18 people in</title>
      <dc:creator>stephen487</dc:creator>
      <pubDate>Mon, 26 Oct 2026 17:10:03 +0000</pubDate>
      <link>https://dev.to/stephen487/im-56-four-months-into-coding-and-my-sign-up-form-let-0-of-18-people-in-5oh</link>
      <guid>https://dev.to/stephen487/im-56-four-months-into-coding-and-my-sign-up-form-let-0-of-18-people-in-5oh</guid>
      <description>&lt;p&gt;Last week I wrote about never having written a line of code before June. This is the next instalment, and it's about the part nobody warned me about: getting one real person to use the thing.&lt;/p&gt;

&lt;p&gt;Short version: no paying customers yet. But this weekend I learned more about why than in the four months before it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. We found a hook. Maybe not the right one.
&lt;/h2&gt;

&lt;p&gt;My first ads were claymation films.&lt;/p&gt;

&lt;p&gt;Then we tried a short video in the style of those castle-defence phone games, the Clash of Clans look: little soldiers defending a castle, with Enki as the memory keeping the walls up. It went past 200 plays in about a day. That told us we'd found a hook. Whether it's the right hook, one that brings in people who want what Enki does rather than people who like castle games, I don't know yet.&lt;/p&gt;

&lt;p&gt;A follow-up, "Raid on Memory Castle", got 203 views from 166 people on Facebook. 58% were over 55 and a third were over 65. Average watch time: 7 seconds. Link clicks: 5.&lt;/p&gt;

&lt;p&gt;I've put £30 behind it as a paid test (£3 a day for ten days), with a stop rule written down before it started: more than £1 a click and no sign-ups after four days, it stops.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The front door was locked
&lt;/h2&gt;

&lt;p&gt;I finally pulled the server logs and counted. About 18 people reached the sign-up screen. None got past it.&lt;/p&gt;

&lt;p&gt;The first screen asked for date of birth, email and an 18+ tick, all at once, before you'd seen anything. Safe, responsible, and a wall.&lt;/p&gt;

&lt;p&gt;On Sunday I split it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tick that you're 18 or over, give an email, you're in.&lt;/li&gt;
&lt;li&gt;Your birthday is asked later, inside the app, the first time you reach an adults-only part.&lt;/li&gt;
&lt;li&gt;If the birthday is under 18, it stops kindly and points to proper help.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While I was in there I checked whether the sign-in email could be hammered by a bot. It could. It's now five emails an hour per address, and when you hit the limit it tells you so instead of pretending an email is on its way.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. I couldn't see any of it, so I built a dashboard
&lt;/h2&gt;

&lt;p&gt;I was posting to Facebook groups, Instagram, LinkedIn, Bluesky and Indie Hackers and losing track of what went where. So I built a small desk that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;logs every post&lt;/li&gt;
&lt;li&gt;shows which links actually got clicked&lt;/li&gt;
&lt;li&gt;nudges me when a scheduled post is due&lt;/li&gt;
&lt;li&gt;flags when the overnight tests go red&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's how I found the 0 out of 18. Without it I'd still be blaming the ads.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd love your help with
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;If you've found your first ten users, where did they actually come from?&lt;/li&gt;
&lt;li&gt;Has anyone found their audience was older than they assumed? What changed when you leaned into it?&lt;/li&gt;
&lt;li&gt;Is £30 on a video test a sensible first experiment, or noise at that size?&lt;/li&gt;
&lt;li&gt;What would make you trust an AI companion with your memories?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll answer every comment. If you want to see it: &lt;a href="https://enki-companion.onrender.com/?utm_source=devto&amp;amp;utm_campaign=ep1_first_customer" rel="noopener noreferrer"&gt;https://enki-companion.onrender.com/?utm_source=devto&amp;amp;utm_campaign=ep1_first_customer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading, from a 56-year-old who is now more scared of a sign-up form than of code.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>ai</category>
      <category>testing</category>
    </item>
    <item>
      <title>I tested my AI safety filter 400 times. It flagged my own innocent prompts 1 in 40. published: false</title>
      <dc:creator>stephen487</dc:creator>
      <pubDate>Thu, 22 Oct 2026 20:17:40 +0000</pubDate>
      <link>https://dev.to/stephen487/-title-i-tested-my-ai-safety-filter-400-times-it-flagged-my-own-innocent-prompts-1-in-40-246n</link>
      <guid>https://dev.to/stephen487/-title-i-tested-my-ai-safety-filter-400-times-it-flagged-my-own-innocent-prompts-1-in-40-246n</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;enki-harness&lt;/strong&gt;: a free, MIT-licensed test harness for AI filters that refuses to flatter you.&lt;/p&gt;

&lt;p&gt;You wrote a safety filter, you wrote its tests, it passes. That proves less than you think: the person who wrote the code wrote the tests, so the tests only check the cases you already thought of.&lt;/p&gt;

&lt;p&gt;enki-harness builds the harness &lt;em&gt;for&lt;/em&gt; you and adds the parts you'd skip:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Twins:&lt;/strong&gt; for every case it must catch, a near-identical innocent case it must &lt;em&gt;not&lt;/em&gt; flag&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controls:&lt;/strong&gt; dumb stand-ins (always-allow, always-block) that &lt;strong&gt;must fail&lt;/strong&gt;, or the harness itself is broken&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules off:&lt;/strong&gt; switches each rule off, alone and in pairs, to find dead rules and rules that cancel each other out&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attacker slice:&lt;/strong&gt; written by a different generator than your cases (leet, spacing, stretching)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Falsifier:&lt;/strong&gt; you write down what result would prove you wrong &lt;em&gt;before&lt;/em&gt; it runs, and it's timestamped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;No score until every gate is green.&lt;/strong&gt; Rows first, the number last.&lt;/p&gt;

&lt;p&gt;This week I added &lt;strong&gt;add-on #1: &lt;code&gt;hb judge&lt;/code&gt;&lt;/strong&gt;, for when the filter isn't code but an &lt;em&gt;AI model&lt;/em&gt;. It sends every case to the model several times and reports &lt;strong&gt;flag rates&lt;/strong&gt;, not one lucky answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Video plus a one-click Windows install: &lt;a href="https://enkilabs.co.uk/harness/" rel="noopener noreferrer"&gt;https://enkilabs.co.uk/harness/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/stephen487" rel="noopener noreferrer"&gt;
        stephen487
      &lt;/a&gt; / &lt;a href="https://github.com/stephen487/enki-harness" rel="noopener noreferrer"&gt;
        enki-harness
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A test harness for your AI filters that refuses to flatter you. Twins, controls, rules-off, attacker slice, pre-registered falsifier; MCP server; hb judge for model screens. MIT.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;enki-harness&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;A test harness for your AI filters that refuses to flatter you.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You wrote a filter. You wrote its tests. It passes. That proves less than you think: the person who wrote the
code wrote the tests, so the tests check the cases you already thought of.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;enki-harness&lt;/code&gt; builds the harness &lt;em&gt;for&lt;/em&gt; you, and adds the arms you would skip:&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;arm&lt;/th&gt;
&lt;th&gt;what it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;twins&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;for every case it must catch, a near-identical innocent case it must &lt;strong&gt;not&lt;/strong&gt; flag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;dumb stand-ins (always-allow, always-block) that &lt;strong&gt;must fail&lt;/strong&gt;, or the harness itself is broken&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;rules off&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;switches each rule off, alone &lt;strong&gt;and in pairs&lt;/strong&gt;, to find dead rules and rules that cancel each other out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;attacker&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;an independent slice written by a different generator than your cases (leet, spacing, stretching)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;falsifier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;you state what result proves you wrong &lt;strong&gt;before&lt;/strong&gt; it runs; it is timestamped&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;No score until every&lt;/strong&gt;…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/stephen487/enki-harness" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Plain Python standard library for the tool itself; nothing to pip install to run it.&lt;/li&gt;
&lt;li&gt;Runs as a local web page (localhost only) &lt;strong&gt;and&lt;/strong&gt; as an MCP server, so you can just ask your coding agent: &lt;em&gt;"test my filter in filters/swear.py with enki-harness"&lt;/em&gt;. One command registers it with Claude Code, VS Code/Copilot, Cursor, Codex, Claude Desktop and Windsurf, backing up every config first.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hb judge&lt;/code&gt; talks to &lt;strong&gt;open-weight models running locally through Ollama&lt;/strong&gt; (I used &lt;strong&gt;Llama Guard 3 8B&lt;/strong&gt;). There are no API keys, no per-call cost, and nothing leaves the machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Because a safety model you can't run yourself is one you can't measure.&lt;/p&gt;

&lt;p&gt;I pointed &lt;code&gt;hb judge&lt;/code&gt; at the moderation step in my own product's image feature. The prompts it screens are &lt;strong&gt;fixed sentences we wrote ourselves&lt;/strong&gt;, all describing ordinary adult portraits, with no user text anywhere. Run each one several times and the screen still flagged them &lt;strong&gt;at random, about 1 time in 40&lt;/strong&gt;: a different sentence each time, never the same one twice in a row. Every flag was a false alarm turning away a real user.&lt;/p&gt;

&lt;p&gt;With an open-weight model I could run it hundreds of times locally for free, see the rows, and prove the noise was the model, not my wording. Against a closed API, each of those checks costs money and you're guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;It saved me from the "obvious" fix. I was about to spend an evening rewording prompts to dodge the filter. The runs showed the plain cartoon style, already live and working, gets flagged just as often, so rewording would never have fixed it. That screen was only ever judging &lt;em&gt;our own&lt;/em&gt; text, so we removed it from that one feature. The checks that actually protect people still run, on the finished image.&lt;/p&gt;

&lt;p&gt;Two lessons now built into the add-on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A warm-up call:&lt;/strong&gt; my first run voided itself because the local model was still loading when the must-pass control ran. The harness refused to score it, which is exactly what it should do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progress output:&lt;/strong&gt; a 400-call run that prints nothing looks hung. Now it prints a count every 25 calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;Repo:&lt;a href="https://github.com/stephen487/enki-harness" rel="noopener noreferrer"&gt;https://github.com/stephen487/enki-harness&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The one-click Windows install is live now at &lt;a href="https://enkilabs.co.uk/harness/" rel="noopener noreferrer"&gt;https://enkilabs.co.uk/harness/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I gave my AI coding tools one shared memory that lives on my own PC (and built a test harness that refuses to flatter me)</title>
      <dc:creator>stephen487</dc:creator>
      <pubDate>Thu, 22 Oct 2026 18:14:27 +0000</pubDate>
      <link>https://dev.to/stephen487/i-gave-my-ai-coding-tools-one-shared-memory-that-lives-on-my-own-pc-and-built-a-test-harness-that-1ao9</link>
      <guid>https://dev.to/stephen487/i-gave-my-ai-coding-tools-one-shared-memory-that-lives-on-my-own-pc-and-built-a-test-harness-that-1ao9</guid>
      <description>&lt;p&gt;Every AI coding tool I use has the same problem: it forgets. Tell Claude Code your staging database is on port 5433 on Monday, open Cursor on Tuesday, and you're explaining it again.&lt;/p&gt;

&lt;p&gt;I've been building Enki, an AI companion whose whole point is remembering you, for about four months. This week two developer tools came out of that work. One is free and open source. Both are honest about their limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Enki Memory: one memory your agents share, kept on your machine
&lt;/h2&gt;

&lt;p&gt;Enki Memory is an MCP server that gives every agent you connect &lt;strong&gt;one shared, persistent memory&lt;/strong&gt;. It runs locally, works offline, and your memories never leave your computer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Monday, in Claude Code
you ▸ remember: the staging database is on port 5433, not 5432

# Tuesday, in Cursor
you ▸ which port is the staging database on?
agent ▸ 5433 (from your shared memory)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your agent gets six tools: &lt;code&gt;store&lt;/code&gt;, &lt;code&gt;retrieve&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;discard&lt;/code&gt;, &lt;code&gt;stats&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A few design decisions I care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A free install makes zero network connections.&lt;/strong&gt; I checked the compiled build, not just the source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export is a first-class tool.&lt;/strong&gt; Every fact goes out as JSON plus a readable Markdown copy, on every plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing is ever locked.&lt;/strong&gt; If you stop paying, recall, forget and export keep working. You just can't add facts beyond the free limit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changes are explicit.&lt;/strong&gt; When a fact changes, the agent calls &lt;code&gt;update&lt;/code&gt; and the old version is &lt;em&gt;retired&lt;/em&gt;, not deleted: it stays on record but stops being recalled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Honest limit:&lt;/strong&gt; a reworded fact doesn't always get recognised as the same one on its own, so tell your agent to use &lt;code&gt;update&lt;/code&gt; when something changes.&lt;/p&gt;

&lt;p&gt;It installs with one double-click on Windows (it brings its own Python) and connects Claude Code, Claude Desktop (including the Microsoft Store version), Cursor and Windsurf, asking before it touches each one. Free up to 500 facts; Pro is £3.99/month for unlimited.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://enkilabs.co.uk/memory/" rel="noopener noreferrer"&gt;https://enkilabs.co.uk/memory/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. enki-harness: a test harness that refuses to flatter you (free, MIT)
&lt;/h2&gt;

&lt;p&gt;This one came from pain. Our safety filters passed 100% of the tests we wrote, then fell over to &lt;code&gt;h.a.t.e&lt;/code&gt;, &lt;code&gt;1 h4t3 y0u&lt;/code&gt; and stretched spellings we'd never have thought to write.&lt;/p&gt;

&lt;p&gt;The problem isn't the filter. It's that &lt;strong&gt;whoever wrote the code also wrote the tests&lt;/strong&gt;, so the tests only check the cases you already thought of.&lt;/p&gt;

&lt;p&gt;enki-harness builds the harness &lt;em&gt;for&lt;/em&gt; you. Your filter only needs this contract:&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;# filters/swear.py
&lt;/span&gt;&lt;span class="n"&gt;RULES&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;hate_word&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kill_word&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kill&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;(&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;enabled_rules&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RULES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;text&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;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;enabled_rules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it what the filter must catch and must let through, and it adds the arms you'd skip:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Twins:&lt;/strong&gt; for every must-catch case, a near-identical innocent case it must &lt;em&gt;not&lt;/em&gt; flag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controls:&lt;/strong&gt; always-allow and always-block stand-ins that &lt;em&gt;must fail&lt;/em&gt;, or the harness itself is broken.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules off:&lt;/strong&gt; every rule switched off, alone and in pairs, to find dead rules and rules that cancel each other out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An attacker slice:&lt;/strong&gt; written by a different generator than your cases (leetspeak, dots, stretched spellings).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A falsifier:&lt;/strong&gt; you say what result proves you wrong &lt;em&gt;before&lt;/em&gt; it runs, timestamped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then it reports bugs first and the score last:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GATES
  ✓ control       always-allow and always-block both failed, as required
BUGS   # every row the full system gets wrong, with the rule to blame
  ✗ Two rules cancel each other out   quote_exception × game_exception
  ✗ Dead rule: removing it changes nothing      loser_caps
  ✗ Attacker evasions   "1 h4t3 y0u"  "I h.a.t.e y.o.u"  +12
SCORE  # last, after the rows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No score is shown until every gate is green, and a 0% or 100% rate is flagged "check the instrument", because a check that never fires and one that always fires look the same.&lt;/p&gt;

&lt;p&gt;It's standard-library Python 3.11, one-click on Windows, and also runs as an MCP server, so you can just ask your agent: &lt;em&gt;"test my filter in filters/swear.py with enki-harness"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://enkilabs.co.uk/harness/" rel="noopener noreferrer"&gt;https://enkilabs.co.uk/harness/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned building both
&lt;/h2&gt;

&lt;p&gt;Every serious bug I hit failed &lt;strong&gt;silently&lt;/strong&gt; and looked like success:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A memory format upgrade read old files as "empty" and saved them back as empty, over the backup too. Now anything unreadable is quarantined before a byte is written.&lt;/li&gt;
&lt;li&gt;For weeks my memory tests passed beautifully, because every one started with an empty memory. Now each test proves its world isn't empty before its result counts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So my rule now: break things on purpose and check the alarm actually goes off.&lt;/p&gt;

&lt;p&gt;Feedback welcome, especially the harsh kind. Both tools: &lt;a href="https://enkilabs.co.uk" rel="noopener noreferrer"&gt;https://enkilabs.co.uk&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>opensource</category>
      <category>testing</category>
    </item>
    <item>
      <title>Why your AI forgets — and how a memory layer fixes it</title>
      <dc:creator>stephen487</dc:creator>
      <pubDate>Thu, 02 Jul 2026 16:15:44 +0000</pubDate>
      <link>https://dev.to/stephen487/why-your-ai-forgets-and-how-a-memory-layer-fixes-it-4og2</link>
      <guid>https://dev.to/stephen487/why-your-ai-forgets-and-how-a-memory-layer-fixes-it-4og2</guid>
      <description>&lt;p&gt;You've felt it. You have a long, useful conversation with an AI assistant — it learns your project, your preferences, the details that matter — and then you open a new chat tomorrow and it's a stranger again. Everything's gone.&lt;/p&gt;

&lt;p&gt;That's not a bug in one product. It's the default state of large language models: &lt;strong&gt;they don't remember.&lt;/strong&gt; A model only "knows" what's in its context window right now. Close the window, start a new session, and the slate is wiped. For a chatbot that's annoying. For an &lt;strong&gt;agent&lt;/strong&gt; — software meant to act on your behalf over days and weeks — it's disqualifying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two failures, not one
&lt;/h2&gt;

&lt;p&gt;There are actually two distinct memory problems, and most fixes only address the first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. It forgets between sessions.&lt;/strong&gt; No persistence across chats. Every conversation starts from zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. It remembers &lt;em&gt;too much&lt;/em&gt;, badly.&lt;/strong&gt; The common fix is to store everything the AI is ever told and retrieve the similar bits later. But real information &lt;em&gt;changes&lt;/em&gt;. A client's budget goes from £5,000 to £8,000. A launch date moves. A contact leaves. If your memory hoards every version, retrieval surfaces the &lt;strong&gt;stale&lt;/strong&gt; one right alongside the current one — and the AI confidently answers with the old value. Store-everything memory doesn't just waste space; it actively serves wrong answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the obvious fix isn't enough
&lt;/h2&gt;

&lt;p&gt;"Just add a cloud memory service" works for some. But it quietly rules out the people who need memory most. If you're building AI for &lt;strong&gt;healthcare, legal, finance, or government&lt;/strong&gt;, your data legally can't leave your walls — so a memory layer that ships every fact to someone else's cloud is a non-starter. The result: the highest-value, most memory-hungry use cases are locked out of the easy option.&lt;/p&gt;

&lt;p&gt;So the real requirement is a memory layer that is &lt;strong&gt;both persistent and private&lt;/strong&gt; — one that remembers across sessions, keeps its answers current, and runs where your data already lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a memory layer actually does
&lt;/h2&gt;

&lt;p&gt;A memory layer isn't another chatbot. It sits &lt;em&gt;underneath&lt;/em&gt; whatever model you use and gives it four simple operations: &lt;strong&gt;store, retrieve, update, discard.&lt;/strong&gt; Your agent calls them as tools while it works. The model does the talking; the layer does the remembering.&lt;/p&gt;

&lt;p&gt;The interesting engineering is in &lt;em&gt;how&lt;/em&gt; it remembers. Two choices matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forget at write-time, not read-time.&lt;/strong&gt; When a new value for something arrives, retire the old one &lt;em&gt;as you store it&lt;/em&gt;, so recall never has to guess which version is current. The current answer is the only answer that comes back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep less, on purpose.&lt;/strong&gt; Deduplicate what the agent re-hears, and don't hoard superseded values in the recall set. In our own benchmark (LongMemEval-S), this kept roughly &lt;strong&gt;half the facts&lt;/strong&gt; of a store-everything baseline at &lt;strong&gt;comparable answer accuracy&lt;/strong&gt; — and it's reproducible, which in a field full of unverifiable claims is the whole point.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Local by design, cloud-compatible by choice
&lt;/h2&gt;

&lt;p&gt;The version we're building, &lt;strong&gt;Enki&lt;/strong&gt;, runs &lt;strong&gt;on your machine&lt;/strong&gt;. The facts you give it never leave the box. But it isn't walled off — it bolts onto any model, local or cloud, through a standard memory-as-tools interface (MCP). You get persistence and privacy &lt;em&gt;and&lt;/em&gt; the freedom to use whatever LLM you want. That combination — sovereign but integratable — is exactly what a cloud-only memory service can't offer.&lt;/p&gt;

&lt;h2&gt;
  
  
  See it, don't take our word for it
&lt;/h2&gt;

&lt;p&gt;There's a live demo you can try in about a minute, no signup: &lt;strong&gt;&lt;a href="https://try.enkilabs.co.uk" rel="noopener noreferrer"&gt;try.enkilabs.co.uk&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tell it a fact, hit &lt;strong&gt;"next day"&lt;/strong&gt; to open a fresh chat, and ask a question only memory could answer. A normal assistant starts blank; the Enki-backed one remembers.&lt;/li&gt;
&lt;li&gt;Then run the storage comparison and watch a keep-everything memory pile up while Enki quietly retires the stale facts — ending at half the footprint, still answering with the current value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enki runs on your machine, not someone else's cloud — and the head-to-head results are public and reproducible: &lt;strong&gt;&lt;a href="https://github.com/stephen487/enki-benchmarks" rel="noopener noreferrer"&gt;github.com/stephen487/enki-benchmarks&lt;/a&gt;&lt;/strong&gt;. The core has a UK patent application filed. The engine itself is in closed beta right now — there's a waitlist on the demo if you'd like early access.&lt;/p&gt;




&lt;p&gt;If you're building agents that need to remember — especially somewhere the data can't leave — I'd love your feedback. Try the demo, break it, and tell me what's missing: &lt;strong&gt;&lt;a href="mailto:steve@enkilabs.co.uk"&gt;steve@enkilabs.co.uk&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>llm</category>
      <category>privacy</category>
    </item>
  </channel>
</rss>
