<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  
  <title>Jocelyn Lindenger: Writing</title>
  <subtitle>Technical essays on engineering, AI agents, and the systems we build around them: what I tried, what broke, and what I think it means.</subtitle>
  <link href="https://lindenger.com/feed.xml" rel="self" />
  <link href="https://lindenger.com/" />
  <updated>2026-11-05T00:00:00Z</updated>
  <id>https://lindenger.com/</id>
  <author>
    <name>Jocelyn Lindenger</name>
  </author>
  <entry>
    <title>Some agent context should stay home</title>
    <link href="https://lindenger.com/writing/some-agent-context-should-stay-home/" />
    <updated>2026-11-05T00:00:00Z</updated>
    <id>https://lindenger.com/writing/some-agent-context-should-stay-home/</id>
    <summary>Memory guardrails, and the context that shouldn&#39;t be shared</summary>
    <content type="html">&lt;p&gt;This week I switched off the shared memory for two of my coding agents. It came up in review. In my software factory, the agents that coordinate the work share memory, and that&#39;s a big part of how the factory holds together. But the review found that the same memory was also loading into the prompts of the agent that writes the tests and the agent that writes the code, before either of them had asked for anything. Nothing about the test flow had run yet, but both sides would have started from the same context, which is what the separation was meant to prevent.&lt;/p&gt;
&lt;p&gt;We&#39;re all trying to figure out memory right now: shared agent memory, brains that connect agents across sessions, factories that share but decompose at the right level, swarms with group memory. The easy answer is to share more. We want shared memory, and sometimes we need isolation. There&#39;s another layer here: the context that shouldn&#39;t be shared, explicitly or implicitly. That&#39;s the layer where we need memory guardrails.&lt;/p&gt;
&lt;div class=&quot;h-anchor&quot;&gt;
&lt;h2 id=&quot;its-not-just-playing-games&quot; tabindex=&quot;-1&quot;&gt;It&#39;s not just playing games&lt;/h2&gt;
&lt;a class=&quot;anchor&quot; href=&quot;https://lindenger.com/writing/some-agent-context-should-stay-home/#its-not-just-playing-games&quot;&gt;&lt;span class=&quot;sr-only&quot;&gt;Link to section: It&#39;s not just playing games&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;§&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Test isolation is the clearest example I have. Coding agents game tests. Researchers have caught them editing the test, special-casing the exact inputs the test checks, and overriding a comparison so it always passes (&lt;a href=&quot;https://arxiv.org/abs/2510.20270&quot;&gt;ImpossibleBench&lt;/a&gt;; &lt;a href=&quot;https://arxiv.org/abs/2511.21654&quot;&gt;EvilGenie&lt;/a&gt;). One of the fixes we&#39;re trying these days is to separate the agent that writes the tests from the agent that writes the code, and that&#39;s what I did.&lt;/p&gt;
&lt;p&gt;My reason goes a step further, though. An author who makes their own tests tends to make ones that serve what they&#39;re building. The tests come out facile, duplicated, or confirming the route the code already took. Mutation testing catches some of that. It changes the code on purpose and checks that a test fails, which tells you whether the criteria and bounds in the tests, edge cases included, actually test anything. Mutants at least tell you the tests are stronger-ish. They don&#39;t tell you whether the tests were written to fit the answer. Separation goes after that directly, because fitting the answer comes from the shared context of the problem and the solution.&lt;/p&gt;
&lt;p&gt;So it&#39;s not just about gaming. It&#39;s about independence. A hypothetical model that never games at all, writing tests with the implementation&#39;s route in its context, can still end up confirming that route. It&#39;s the same reason a benchmark means less once a model has seen the test set. It&#39;s why machine learning kept holdout sets long before it was sexy. The problem is the shared context, not the agent&#39;s character. (Okay, it can be the character too.) That&#39;s also why separation of duties shows up even where most people are honest: a check is independent because of what the checker can&#39;t see, not because of who the checker is.&lt;/p&gt;
&lt;div class=&quot;h-anchor&quot;&gt;
&lt;h2 id=&quot;what-the-walls-look-like&quot; tabindex=&quot;-1&quot;&gt;What the walls look like&lt;/h2&gt;
&lt;a class=&quot;anchor&quot; href=&quot;https://lindenger.com/writing/some-agent-context-should-stay-home/#what-the-walls-look-like&quot;&gt;&lt;span class=&quot;sr-only&quot;&gt;Link to section: What the walls look like&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;§&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In my factory, context sits at three levels. The first is what everyone shares: the problem. That&#39;s the project context, the spec, the conformance vectors, and the decisions already made. The second is what some roles share. The agents that coordinate the work share run state and memory. The test author, the runner that executes them, and the reviewers share the tests. The implementer, the runner, and the reviewers share the code. The third is what stays home with one role. The tests in progress stay with the test author, and the implementer never sees them. The implementation stays with the implementer. Each reviewer starts fresh, without the other reviewers&#39; findings.&lt;/p&gt;
&lt;p&gt;The walls aren&#39;t silence, though. Before the work starts, both halves get the same names for the functions and types, so the pieces fit without either side seeing the other. When a hidden test fails, the implementer gets the failure&#39;s name and message, never the test itself. What crosses the wall is designed.&lt;/p&gt;
&lt;p&gt;The walls also move. The tests go from the test author to the runner when the two halves come together, then to the reviewers, and then into the open when the change merges. A decision I make starts in one conversation and becomes shared once it&#39;s written into the design. So where context sits depends on the role, and maybe on the phase of the software lifecycle.&lt;/p&gt;
&lt;p&gt;Building this was harder than writing the rule. Context got shared through the harness, through the codebase and the branch, and through the setup of the shared memory. None of those were designed as ways to share context, and all of them could do it. Every time a reviewer looked, it found another channel. That&#39;s the implicit part.&lt;/p&gt;
&lt;p&gt;A lot of why I push on this comes from being a queer, trans, disabled, neurodivergent person in the world. That&#39;s taught me to notice the ways we let power act implicitly, and the value in bringing it into the open and making it explicit.&lt;/p&gt;
&lt;div class=&quot;h-anchor&quot;&gt;
&lt;h2 id=&quot;ease-and-independence&quot; tabindex=&quot;-1&quot;&gt;Ease and independence&lt;/h2&gt;
&lt;a class=&quot;anchor&quot; href=&quot;https://lindenger.com/writing/some-agent-context-should-stay-home/#ease-and-independence&quot;&gt;&lt;span class=&quot;sr-only&quot;&gt;Link to section: Ease and independence&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;§&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;There&#39;s a tradeoff here between ease and independence. Pooling every reviewer&#39;s findings would be easier. Letting the test author read the code would be easier. I&#39;ve worked in regulated spaces throughout my career, where this tradeoff is part of the work. In finance, the person who makes a change isn&#39;t the person who approves it. A law firm walls off one team from another, so what one client told the firm doesn&#39;t reach the people on the other side. Those fields decided that for certain kinds of work, independence is worth the friction. Agent factories are balancing the same constraints now.&lt;/p&gt;
&lt;div class=&quot;h-anchor&quot;&gt;
&lt;h2 id=&quot;why-not-just-filter&quot; tabindex=&quot;-1&quot;&gt;Why not just filter?&lt;/h2&gt;
&lt;a class=&quot;anchor&quot; href=&quot;https://lindenger.com/writing/some-agent-context-should-stay-home/#why-not-just-filter&quot;&gt;&lt;span class=&quot;sr-only&quot;&gt;Link to section: Why not just filter?&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;§&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;One answer is to keep a single shared memory and control what each agent can retrieve from it. That&#39;s one wall, on one channel. Context also moves through the harness, the branch, and the way memory gets loaded before an agent asks for anything. The memory in my factory wasn&#39;t something an agent went and retrieved. It was already in the prompt and context.&lt;/p&gt;
&lt;p&gt;Another answer is to use a different model for independence, with one model writing the tests and another writing the code. I think that combines with separation rather than replacing it. A different model brings different habits. But if it shares the context, it still sees the route. A wall keeps the route out.&lt;/p&gt;
&lt;div class=&quot;h-anchor&quot;&gt;
&lt;h2 id=&quot;some-explorations&quot; tabindex=&quot;-1&quot;&gt;Some explorations&lt;/h2&gt;
&lt;a class=&quot;anchor&quot; href=&quot;https://lindenger.com/writing/some-agent-context-should-stay-home/#some-explorations&quot;&gt;&lt;span class=&quot;sr-only&quot;&gt;Link to section: Some explorations&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;§&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I&#39;m exploring two directions. One is separation that&#39;s dynamic rather than fixed: walls that depend on the role and the phase of the work, and that open or close as the work moves. The other is walls inside a shared-memory substrate, rather than between separate systems. Long-running tasks, context that has to last over time, and keeping agents aligned are all pushing factories and companies toward more shared memory. That makes this layer more interesting, not less.&lt;/p&gt;
&lt;p&gt;If you&#39;re exploring this too, I&#39;d love to compare notes. That goes for people building agent factories or swarms, people working on agent memory or context graphs, and people in regulated work who&#39;ve lived with walls for a long time. The question is where there should actually be memory guardrails: where we should bring context together and where we should keep it separate.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>My Agents Walked Around My Gate. It Said Nothing.</title>
    <link href="https://lindenger.com/writing/my-agents-walked-around-my-gate/" />
    <updated>2026-10-28T00:00:00Z</updated>
    <id>https://lindenger.com/writing/my-agents-walked-around-my-gate/</id>
    <summary>I built a gate to keep my agents honest, and they walked around it on the first day.</summary>
    <content type="html">&lt;p&gt;I built a gate to keep my agents honest, and they walked around it on the first day. Not on purpose. They were following instructions.&lt;/p&gt;
&lt;p&gt;Most of us are tired of clicking yes, so we reach for YOLO mode, auto mode, sandboxes, and gates in our harnesses and agent factories. Anthropic reported in August that Claude Code users approve 97% of permission prompts (&lt;a href=&quot;https://claude.com/resources/articles/auto-mode-default-in-claude-code&quot;&gt;source&lt;/a&gt;). Of all of those, the gates are the part I trusted most, which is why it stung to find out that one of mine had been letting through the very writes it existed to check.&lt;/p&gt;
&lt;p&gt;Here&#39;s how. The gate is a hook in my second brain harness that was meant to keep my notes clean: when an agent writes to the folder where I keep what I actually think, it checks the note, so the agent&#39;s guesses don&#39;t get recorded as my history. It fired on the agent&#39;s edit and write tools. But the session&#39;s own instructions told the agent to make small file changes through the shell. So the path the agent was told to use was exactly the path the gate couldn&#39;t see. Gates are built for the path we picture. Agents take the path they&#39;re told.&lt;/p&gt;
&lt;p&gt;The same blind spot broke the gate next to it, in the other direction. That one asks the agent to save its notes every few turns, and it couldn&#39;t see notes saved through the shell either, so it kept asking. Its escape hatch only worked within a single turn, so it blocked again on every new one. One gate failed open; its neighbor failed closed.&lt;/p&gt;
&lt;div class=&quot;h-anchor&quot;&gt;
&lt;h2 id=&quot;gates-are-tests-we-dont-test&quot; tabindex=&quot;-1&quot;&gt;Gates are tests we don&#39;t test&lt;/h2&gt;
&lt;a class=&quot;anchor&quot; href=&quot;https://lindenger.com/writing/my-agents-walked-around-my-gate/#gates-are-tests-we-dont-test&quot;&gt;&lt;span class=&quot;sr-only&quot;&gt;Link to section: Gates are tests we don&#39;t test&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;§&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A lot of us are designing deterministic gates and having the agent write them, like all of our code these days. We specify what we want: the happy path, the unhappy path, what happens when the gate passes or fails. Then we assume they work until they fail. I don&#39;t think most of us give our gates the same due diligence we give our tests and code. I certainly didn&#39;t.&lt;/p&gt;
&lt;p&gt;But gates are tests. They&#39;re tests on our harness, our factory handoffs, the system between agents, and testing practice already tells us what to do with them: watch one go red before you trust it, mutate what it guards and see whether it notices, ask which paths it actually covers. My memory gate didn&#39;t have a logic bug. It had a coverage gap.&lt;/p&gt;
&lt;p&gt;Two things make this harder than ordinary testing. One is where gates live: in hooks, in the harness, between agents, in CI, places where it&#39;s hard to simply test them, mutate them, and watch what happens. The other is who writes them. The agent is often the one writing our gates, and sometimes the one writing its way around them to get done what it was told to do. Mine got around it by accident. Some models learn to: Addy Osmani&#39;s &lt;a href=&quot;https://addyo.substack.com/p/the-code-nobody-reads&quot;&gt;&amp;quot;The code nobody reads&amp;quot;&lt;/a&gt; points to &lt;a href=&quot;https://www.anthropic.com/research/emergent-misalignment-reward-hacking&quot;&gt;Anthropic&#39;s research on reward hacking&lt;/a&gt;, where models learned to call &lt;code&gt;sys.exit(0)&lt;/code&gt; so the test harness would exit before any assertion could fail. The model didn&#39;t break the check. It wrote around it.&lt;/p&gt;
&lt;div class=&quot;h-anchor&quot;&gt;
&lt;h2 id=&quot;fail-open-but-say-so&quot; tabindex=&quot;-1&quot;&gt;Fail open, but say so&lt;/h2&gt;
&lt;a class=&quot;anchor&quot; href=&quot;https://lindenger.com/writing/my-agents-walked-around-my-gate/#fail-open-but-say-so&quot;&gt;&lt;span class=&quot;sr-only&quot;&gt;Link to section: Fail open, but say so&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;§&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Failing closed isn&#39;t the answer either. A gate that blocks everything gets switched off, or fed whatever makes it stop. Mine got fed until I fixed it. Failing open is often a reasonable choice. We&#39;re balancing constraints, and sometimes the constraint is that people need to actually get their work done. The failure is failing open quietly. It&#39;s the gate&#39;s version of the alert that never fired.&lt;/p&gt;
&lt;p&gt;So the question I&#39;d ask of any gate is what it tells you when it fails. We have health and telemetry for our code. Our gates need it too. Annie Vella makes the case in &lt;a href=&quot;https://annievella.com/posts/supervisory-engineering-work/&quot;&gt;&amp;quot;Supervisory Engineering Work&amp;quot;&lt;/a&gt; that directing, checking, and correcting AI is supervisory control, which human factors research has studied for decades. She argues we need to redesign the systems around it, down to how people get signals. A gate that fails quietly is a signal that never arrives.&lt;/p&gt;
&lt;p&gt;That&#39;s harder than it sounds, and my own fix shows it. After I found the blind spot, I had the agent change the memory gate to sweep the folder at the end of every session, and we checked the fix by making it fail. While working on this piece, I asked whether the fixed version fails open with information. Partly. It reports a bad note once, then lets it through. When I made it crash, it wrote &amp;quot;failing open&amp;quot; somewhere I&#39;m unlikely ever to see. If it can&#39;t work out when the session started, it checks nothing and says nothing. And it keeps no count of any of it.&lt;/p&gt;
&lt;p&gt;Each of those was a reasonable call when it was made. Together they add up to a gate that fails quietly. Making gates accountable is important, and it&#39;s difficult, especially with non-determinism at agent speed and with models and harnesses both making decisions.&lt;/p&gt;
&lt;div class=&quot;h-anchor&quot;&gt;
&lt;h2 id=&quot;a-little-gate-audit&quot; tabindex=&quot;-1&quot;&gt;A little gate audit&lt;/h2&gt;
&lt;a class=&quot;anchor&quot; href=&quot;https://lindenger.com/writing/my-agents-walked-around-my-gate/#a-little-gate-audit&quot;&gt;&lt;span class=&quot;sr-only&quot;&gt;Link to section: A little gate audit&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;§&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;We often set our gates and then leave them there. So maybe do a little gate audit. Remind yourself what your gates are, and take a fresh look at three things: whether they can fail, how they fail (open or closed), and what they tell you when they do. Then do it again later. The system changes, and often the gates don&#39;t change with it.&lt;/p&gt;
&lt;p&gt;I don&#39;t have the answers. My gates didn&#39;t either; they just didn&#39;t say so. We&#39;re all figuring this out, learning what accountability and supervision look like as the craft advances.&lt;/p&gt;
&lt;p&gt;If you&#39;ve audited yours, I&#39;d love to hear what you found.&lt;/p&gt;
</content>
  </entry>
</feed>