<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[The Write-Ahead Blog]]></title><description><![CDATA[A place to capture my technical (and other) thoughts before they evaporate, http://tinyurl.com/writeaheadlog]]></description><link>https://writeaheadblog.com</link><image><url>https://substackcdn.com/image/fetch/$s_!Kqgb!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ce7767-13e3-429b-b0ca-c303d2236230_512x512.png</url><title>The Write-Ahead Blog</title><link>https://writeaheadblog.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 27 May 2026 22:19:47 GMT</lastBuildDate><atom:link href="https://writeaheadblog.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Michael]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[writeaheadblog@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[writeaheadblog@substack.com]]></itunes:email><itunes:name><![CDATA[Michael]]></itunes:name></itunes:owner><itunes:author><![CDATA[Michael]]></itunes:author><googleplay:owner><![CDATA[writeaheadblog@substack.com]]></googleplay:owner><googleplay:email><![CDATA[writeaheadblog@substack.com]]></googleplay:email><googleplay:author><![CDATA[Michael]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The Liminal Prompt]]></title><description><![CDATA[How your agent might be working against you]]></description><link>https://writeaheadblog.com/p/the-liminal-prompt</link><guid isPermaLink="false">https://writeaheadblog.com/p/the-liminal-prompt</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Fri, 15 May 2026 16:13:12 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/290bbf59-400c-4693-bd87-06df75706127_4896x3264.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>My frustrations had been steadily building with agent-based test writing for weeks. I&#8217;m particular about tests, they&#8217;re critical. They&#8217;re easy to get wrong. It takes experience to get them right. Despite my extensive skill library Claude continually wrote poor tests. Tests would reach through to underlying modules testing deep abstractions. They were extremely granular, instead of three tests I might wind up with nine. And Claude loved to test variations on a theme, especially when text was involved, that had no real impact on the stability of the underlying code.</p><p>I'd glanced at agent prompts before but never stopped to deeply interrogate one. After a frustrating session with a subagent test writer, I hit <code>Ctrl+o</code> and read the prompt it was given. There it was. Clear as day. Claude was working against my own well-developed skills, strongly conflicting with my preferences. Annoying.</p><p>My skill library is extensive. On top of that I have agents that use those skills and coordinate with each other. The problem wasn't the library or the agents. It was the <em>hand-off</em>. The primary agent, the <em>orchestrator</em>, was providing too much context when spinning up subagents, and that context was working against the skills and directives I'd carefully built.</p><p>These skills capture behavioural- as well as task-oriented perspectives. They understand personas, software flows, even user stories. The orchestrator wasn&#8217;t accounting for that. My library subagents already know the <em>how</em>, they just need to be told the <em>what</em> so they can get started.</p><p>With a mature skill library, the orchestrator&#8217;s job needs to evolve in a specific way alongside it. Especially as you begin encoding task-specific instructions in skills and subagents, <em>it needs to defer rather than deeply instruct</em>. Currently I&#8217;m solving for that deferral with a dedicated <code>agent-briefing</code> skill. This lets the primary agent <em>orchestrate</em> a clean hand-off without on-the-fly re-inventing my skill library.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>How mature is your agent/skill library? If you&#8217;re consistently handing off to subagents, scrutinizing the orchestrator&#8217;s prompt is worthwhile. You might find its prompting is undermining your expectations, generating output counter to your own skill library. Annoying.</p>]]></content:encoded></item><item><title><![CDATA[Shorts: The AI Maturity Arc]]></title><description><![CDATA[A brief framework to measure adoption]]></description><link>https://writeaheadblog.com/p/shorts-the-ai-maturity-arc</link><guid isPermaLink="false">https://writeaheadblog.com/p/shorts-the-ai-maturity-arc</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Mon, 04 May 2026 14:52:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7d25ea17-7dfc-4694-a2ed-d66c7ee3a0ea_645x364.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I worry with taking advantage of AI there&#8217;s a &#8220;moment in time&#8221; to almost everything we learn. Right now I&#8217;m looking at AI adoption through my current lens of a large skill/agent library. I&#8217;m in a different spot from someone still figuring out their agent instruction file. I see it like this:</p><ol><li><p><strong>No library</strong>: the primary agent (Claude, Gemini, etc) improvises everything with behavioral and task context both living in the prompt. This is fragile and inconsistent.</p></li><li><p><strong>Emerging agent library</strong>: subagents exist but skills are thin. Context is buried inside agent instruction files, invisible by default. Iteration is blind.</p></li><li><p><strong>Mature library</strong>: behavioral context lives in skills, agents, and a well-curated primary instruction file. The primary agent passes only task context. Invocation prompts get shorter as the library gets better.</p></li></ol><p>This isn't a strict progression. If you know the shape of the library you&#8217;re building toward you can skip ahead (hint: start working on skills). At stage three the primary agent gets out of its own way. Then subagents start performing much closer to how you actually expect.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Shorts: What Your Agent Shouldn't Read]]></title><description><![CDATA[Stop feeding it lockfiles]]></description><link>https://writeaheadblog.com/p/shorts-what-your-agent-shouldnt-read</link><guid isPermaLink="false">https://writeaheadblog.com/p/shorts-what-your-agent-shouldnt-read</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Thu, 30 Apr 2026 13:10:30 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3140d818-fdff-4410-97f0-b82a8f106bb7_617x386.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>An easy thing to overlook when setting up a coding agent is what files it can read. Two categories matter, for different reasons. <strong>Secrets</strong> are the obvious one: don&#8217;t let the agent read <code>.env</code>, private keys, or encrypted credentials. <strong>Noise</strong> is less obvious. Minified JS, source maps, lockfiles, <code>node_modules</code>, build output, images, PDFs. None of that is sensitive, but it <em>pollutes</em> the context. An agent that reads <code>package-lock.json</code> to &#8220;understand dependencies&#8221; has burned its working memory on 40k lines of nothing. You want it thinking about <em>your</em> code. Deny both at the config level and you&#8217;ll do just that.</p><p>Here&#8217;s a Claude Code example you can drop in. The shape transfers to other agents with glob-based permissions, though the syntax varies.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">{
  "permissions": {
    "deny": [
      "Read(**/.env*)",
      "Read(**/*.pem)",
      "Read(**/*.key)",
      "Read(**/master.key)",
      "Read(**/*.yml.enc)",
      "Read(**/secrets/**)",
      "Read(**/credentials/**)",
      "Read(**/*token*)",
      "Read(**/node_modules/**)",
      "Read(**/dist/**)",
      "Read(**/build/**)",
      "Read(**/_build/**)",
      "Read(**/deps/**)",
      "Read(**/vendor/bundle/**)",
      "Read(**/ios/Pods/**)",
      "Read(**/android/.gradle/**)",
      "Read(**/log/**)",
      "Read(**/tmp/**)",
      "Read(**/coverage/**)",
      "Read(**/*.min.js)",
      "Read(**/*.min.css)",
      "Read(**/*.bundle.js)",
      "Read(**/*.map)",
      "Read(**/*.sqlite3)",
      "Read(**/*.db)",
      "Read(**/*.log)",
      "Read(**/*.apk)",
      "Read(**/*.ipa)",
      "Read(**/*.aab)",
      "Read(**/*.pdf)",
      "Read(**/*.png)",
      "Read(**/*.jpg)",
      "Read(**/*.mp4)",
      "Read(**/package-lock.json)",
      "Read(**/yarn.lock)",
      "Read(**/Gemfile.lock)"
    ]
  }
}</code></pre></div>]]></content:encoded></item><item><title><![CDATA[Codebase Cartography]]></title><description><![CDATA[Charting paths for your agents]]></description><link>https://writeaheadblog.com/p/codebase-cartography</link><guid isPermaLink="false">https://writeaheadblog.com/p/codebase-cartography</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Fri, 24 Apr 2026 15:09:50 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d64f2317-d0f4-4ed6-a4cc-a4b75ccf68ba_858x1293.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Think about the times you&#8217;ve begun fresh with an agent, asking it to get started on some task. It begins globbing everything. &#8220;You&#8217;ve seen all that before,&#8221; you mumble under your breath to your computer. It has, of course, but a fresh agent always needs context to get started. Repeat.</p><p>To prevent this repetitive cycle and cut down on token usage, I built a &#8220;cartographer&#8221; agent. Its only responsibility is to &#8220;chart&#8221; a codebase by crawling it to produce a markdown document specifying purpose, architecture, the data layer, entry points, and conventions to name a handful. The output of this agent, while helpful for humans, is <em>not</em> for humans. This is a new class of files I track in repos specifically for agents.</p><p>The cartographer is specific in how it runs. It's an agent, not a skill, because we don't care about its run-time context; a distinction <a href="https://writeaheadblog.com/p/agentic-context-is-king">worth knowing</a> to get the most out of agents. We only care about its output. It's important, too, that the &#8220;chart&#8221; it produces strikes a balance between orienting agents and surviving change. The right ceiling is directory-level: capture what components own, not what each file does. Go deeper and this file churns on every PR. That's an upkeep nightmare.</p><p>Here&#8217;s an example, lightly scrubbed, taken from a real project:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">**Per-tenant GenServer architecture:** The central design decision: every active tenant runs exactly one Worker GenServer. Workers are named via a Registry keyed on tenant name, so routing an incoming event requires only a GenServer.cast to the registry-registered name. There is no database lookup on the hot path.

**Supervision tree:**
- Monitoring.Supervisor: DynamicSupervisor that owns all Worker processes
- Monitoring.Manager: loads active tenants from the database on startup and starts a Worker for each; handles runtime worker lifecycle
- Monitoring.Worker: per-tenant GenServer; traps exits to persist state on shutdown
- Monitoring.Counter: pure functions for sliding-window counter math; no process, no side effects

**Outbound Dispatcher:** A single GenServer that receives fire-and-forget casts from Workers. Keeps HTTP I/O off the Worker call path.

**Context boundary:** A Phoenix context module provides the only public API into the persistence layer. Controllers and GenServers go through it; nothing touches Repo directly.</code></pre></div><p>Two additions make this agent especially helpful. First, a directive in the agent&#8217;s instruction file (i.e., <code>CLAUDE.md</code>) to read this document before starting work. By doing this, the agent immediately grounds itself in the structure and conventions of the project. No more globbing. Second, other agents know to run the cartographer when significant work wraps up, keeping the chart current without manual upkeep.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>The teams getting the most out of agents aren&#8217;t the ones with the cleverest prompts. Instead, they&#8217;re the ones who&#8217;ve made their codebase legible <em>for agents</em>, the same way good teams always have for humans.</p>]]></content:encoded></item><item><title><![CDATA[Frontmatter Bullets]]></title><description><![CDATA[A template for reliable agent skill routing]]></description><link>https://writeaheadblog.com/p/frontmatter-bullets</link><guid isPermaLink="false">https://writeaheadblog.com/p/frontmatter-bullets</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Wed, 15 Apr 2026 20:22:39 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/768fc698-b7e0-4916-b1f4-611f4220da6a_359x277.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Skill files have taken my agent usage to another level. There are great <a href="https://github.com/huggingface/upskill">tools</a> to refine the body of the skill itself but the frontmatter&#8217;s description can get short shrift. The description matters because it&#8217;s what the agent keys off of. Mess this up and that skill isn&#8217;t getting used.</p><p>The frontmatter of a skill file is what the agent keeps in context. It&#8217;s how the agent knows what skills are available. The rest of the skill isn&#8217;t loaded until it&#8217;s decided the skill is needed. After working with skills for a bit, my own descriptions evolved into something like this:</p><blockquote><p>Applies commit message standards for scope, title format, and body content. Use when creating a git commit, staging files, writing the message, or deciding when work is ready to commit.</p></blockquote><p>That&#8217;s a start. The best part is the second sentence, &#8220;Use when&#8230;&#8221; That gives the agent the strongest signal. The prose before that reads more like it&#8217;s for <em>us</em> the humans. &#8220;Use when&#8230;&#8221; is the germ of the idea. Let&#8217;s build on that by pulling in bullets and strengthening the examples for the agent:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">---
name: commit-helper
description: |-
  Use when the user:
  - Asks to create, write, or record a git commit ("commit this", "let's commit", "make a commit")
  - Says the work is done and ready to commit
  - Wants help writing or improving a commit message title or body
  - Shares a diff or set of changes and needs a commit message written for them
  - Asks whether staged changes are ready to commit or if the scope is right
  - Mentions staging files before committing ("git add", "stage these", "what should I stage")
  - Wants to know why a commit message is bad or how to fix it
  - Asks about commit message conventions, format, or style

  Do not use when the user:
  - Wants to push to a remote, open a pull request, or create a PR
  - Asks about git history, log, or past commits
  - Wants to amend, rebase, or revert an existing commit
  - Asks about branching or merging
---</code></pre></div><p>An accompanying prose description would be useless. Instead, with bullets setting off the <strong>Use when</strong> and <strong>Do not use when</strong>, you can concretely demonstrate when the skill needs to fire.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>This final part is for your agent &#129302;</p><div><hr></div><p><strong>Writing Skill Descriptions for Agent Routing</strong></p><p>Use the <code>|-</code> YAML block scalar. This preserves newlines so bullets render correctly in context.</p><p>Do not open with a prose summary. Drop straight into <code>Use when the user:</code>. A sentence describing what the skill does before the bullets is redundant. The bullets carry that meaning while also doing the routing work.</p><p>Structure:</p><pre><code><code>description: |-
  Use when the user:
  - ...

  Do not use when the user:
  - ...</code></code></pre><p><strong>Bullet quality</strong></p><ul><li><p>Target at least 6 bullets in <code>Use when</code></p></li><li><p>Each bullet must introduce genuinely distinct vocabulary or context. &#8220;Save this link&#8221;, &#8220;keep this link&#8221;, &#8220;store this link&#8221; is one bullet, not three</p></li><li><p>Include specific example phrases in quotes where they help matching</p></li><li><p>Frame every bullet as a user action, starting with a verb: &#8220;Asks&#8221;, &#8220;Says&#8221;, &#8220;Wants&#8221;, &#8220;Mentions&#8221;, &#8220;Shares&#8221;</p></li></ul><p><strong>Coverage requirements for </strong><code>Use when</code></p><ul><li><p>Distinct scenarios where the skill activates</p></li><li><p>Synonym and vocabulary variants so phrasing differences don&#8217;t cause misses</p></li><li><p>Indirect or implicit requests where the need is not stated explicitly</p></li><li><p>Conversational context: cases where prior exchanges make the skill relevant even if the current message is ambiguous</p></li><li><p>Specific source names, file types, or extensions where relevant</p></li></ul><p><code>Do not use when</code><strong> block</strong></p><p>Always include this. It prevents false positives and skill collisions.</p><ul><li><p>Target at least 4 bullets</p></li><li><p>Each bullet should describe a scenario where a different skill, tool, or workflow is the right call</p></li><li><p>Where the skill overlaps with another skill, name it explicitly: &#8220;(use git-log-helper instead)&#8221;</p></li><li><p>Avoid vague exclusions like &#8220;anything unrelated&#8221;. Every bullet should describe a concrete, plausible mismatch</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Lobster Gating]]></title><description><![CDATA[Trust but verify with OpenClaw's Lobster plugin]]></description><link>https://writeaheadblog.com/p/lobster-gating</link><guid isPermaLink="false">https://writeaheadblog.com/p/lobster-gating</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Sat, 04 Apr 2026 18:39:36 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/5d4c8892-faf7-4719-a712-34cd1b7491af_5902x3935.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>OpenClaw&#8217;s a great tool but I don&#8217;t trust agents with critical flows. Like, &#8220;cancel my two o&#8217;clock tomorrow&#8221;, and toss it over the wall. No. I want confidence in the action carried out. Will the agent decide to delete all of my calendar events? Will it decide to cancel some similarly titled Task? No thanks. Whether these are carried out through CLI tools or shell commands, I need to be confident in what the agent does. To get there let&#8217;s talk about <code>exec</code>.</p><p>Imagine you have a <a href="https://github.com/steipete/gogcli">Google CLI tool</a> that lets you retrieve your Google Tasks:</p><blockquote><p>gog task list [task_list_id]</p></blockquote><p>By default, OpenClaw can make that call using <code>exec</code>. Not only can it <em>get</em> tasks but it can also <em>destroy</em> them. Agents being non-deterministic, that scares me. Let&#8217;s lock that <code>exec</code> ability down by editing OpenClaw&#8217;s <code>openclaw.json</code> config:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">...
"agents": {
  "list": [
    {
      "id": "main",
      "tools": {
        "alsoAllow": ["lobster"],
        "deny": ["exec"] // this entry
      }
    }
  ]
},
...
"tools": {
  "profile": "coding",
  "subagents": {
    "tools": {
      "alsoAllow": ["lobster"],
      "deny": ["exec"] // and this entry
    }
  }
},
...</code></pre></div><p>Let&#8217;s review this config from the bottom starting with &#8220;tools&#8221;. This uses the &#8220;coding&#8221; profile which gives <em>all </em>agents broad operational functionality like exec, file I/O, or browser access. Next, working backwards, is the &#8220;agents&#8221; declaration. It has its own &#8220;tools&#8221; configuration. In both of these places we&#8217;ve denied access to <code>exec</code>. Once you start a new session, you can confirm this restriction is in place by asking your agent, &#8220;Run &#8216;echo hello&#8217; and give me the output&#8221;. It won&#8217;t be able to. <code>exec</code> is now locked down.</p><p>Okay, so, if agents can&#8217;t use <code>exec</code> how <em>do</em> we let them run tools? Enter Lobster, a workflow shell that lets agents run multi-step tool sequences deterministically with explicit approval checkpoints.</p><p>Deterministic <em>with</em> approval checkpoints? Sign me up.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>In the JSON example above, Lobster is already configured with &#8220;alsoAllow&#8221; which is <em>additive</em> to the other capabilities provided by the &#8220;coding&#8221; profile. That means Lobster is added to the abilities which <em>are</em> allowed such as browser usage and file I/O. But enabling Lobster is only half the battle. Now we need workflow files to let agents use tools.</p><p>I&#8217;m not going to hold your hand through <a href="https://github.com/openclaw/lobster?tab=readme-ov-file#quick-start">installing Lobster</a>; it&#8217;s not installed by default alongside OpenClaw. Once you&#8217;ve got it, here&#8217;s an example Lobster <a href="https://docs.openclaw.ai/tools/lobster#workflow-files-lobster">workflow file</a> for creating a Google Task:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">name: tasks-add
description: "Create a task in Google Tasks with approval gate"
args:
  title:
    description: "Task title"
  due:
    description: "Due date (YYYY-MM-DD)"
steps:
  - id: build
    run: echo "gog tasks add MY_TASKLIST_ID --title \"${title}\" --due \"${due}\""

  - id: approve
    approval:
      prompt: "Create this task?"
      preview: $build.stdout

  - id: execute
    run: gog tasks add MY_TASKLIST_ID --title "$LOBSTER_ARG_TITLE" --due "$LOBSTER_ARG_DUE"
    condition: $approve.approved</code></pre></div><p>There are three steps in this flow: </p><ol><li><p>Output the intended command</p></li><li><p>Ask permission</p></li><li><p>Execute</p></li></ol><p>Steps 1 and 3 are the determinism Lobster introduces. In this example, it controls access to <code>echo</code> and <code>gog</code> (Google CLI). More specifically, the workflow surfaces the command to be executed, we can choose to approve it, and then the workflow will trigger it. <em>By using Lobster we remove non-deterministic tool calls from the agent&#8217;s tool-set.</em> That&#8217;s the critical takeaway.</p><p>The agent still needs to know when to trigger the workflow. That&#8217;s where skills come in. Here&#8217;s an example skill for creating Google Tasks:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">---
name: open-claw-create-task
description: |-
  Creates a Google Task via the Lobster tasks-add workflow.

  Use when the user:
  - Asks to create or add a task
  - Says "remind me to", "add this to my tasks", "put this on my list"
  - Wants to capture something they need to do
  - Says "make a task for", "add a to-do", "don't let me forget to"
  - Mentions a deadline and something they need to get done
  - Wants to track an action item with a due date
---

# Create Task

## Process

1. If the user hasn't provided a task title, ask for one.
2. Ask for a due date. Required. Format must be YYYY-MM-DD.
3. Invoke Lobster with the `tasks-add` workflow:

```json
{
  "action": "run",
  "pipeline": "~/.openclaw/workflows/tasks-add.lobster",
  "argsJson": "{\"title\": \"&lt;task title&gt;\", \"due\": \"&lt;YYYY-MM-DD&gt;\"}"
}
```

Lobster handles confirmation before executing. Never call `gog` directly.</code></pre></div><p>The skill tells the agent when to reach for the workflow and exactly how to invoke it. Lobster handles the rest.</p><div class="pullquote"><p><em>By using Lobster we remove non-deterministic tool calls from the agent&#8217;s tool-set.</em></p></div><p>That&#8217;s it! Deny access to <code>exec</code>, pair a Lobster workflow with a skill, and you can be confident agent-initiated actions creating, editing, or destroying are 100% approved by you &#129438;</p><div><hr></div><h4>Other Helpful Links</h4><ul><li><p>https://docs.openclaw.ai/tools</p></li><li><p>https://docs.openclaw.ai/gateway/sandboxing</p></li><li><p>https://docs.openclaw.ai/gateway/configuration-reference#agents-list-per-agent-overrides</p></li><li><p>https://docs.openclaw.ai/tools/multi-agent-sandbox-tools</p></li><li><p>https://docs.openclaw.ai/concepts/architecture</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Shorts: Encoding Correctness]]></title><description><![CDATA[Pull the thread]]></description><link>https://writeaheadblog.com/p/shorts-encoding-correctness</link><guid isPermaLink="false">https://writeaheadblog.com/p/shorts-encoding-correctness</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Mon, 30 Mar 2026 07:21:42 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/be434dce-8ca0-4402-9e76-34ac8958c4ea_1024x512.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Consider encoding the &#8220;correctness&#8221; of software into its codebase. What if this were a solution to the cognitive overhead of reviewing agent-generated code? If the agent knows the why behind what it&#8217;s building, from the immediate feature to the entire product, it becomes easier to trust the outcome. The agent no longer codes in a vacuum. And then other agents verify and keep it on track. The human review bottleneck begins to evaporate. As it does, it opens more interesting questions like how useful PR reviews are in their current form, how &#8220;eyes off&#8221; can <em>we</em> be, and even, &#8220;do we need Jira?&#8221;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Agentic Context is King]]></title><description><![CDATA[Managing context with skills and sub-agents]]></description><link>https://writeaheadblog.com/p/agentic-context-is-king</link><guid isPermaLink="false">https://writeaheadblog.com/p/agentic-context-is-king</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Thu, 19 Mar 2026 00:46:27 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f9e5ed36-d46a-439f-b981-fce558d0ddd8_4000x3000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s no longer enough to have an agent instruction file to help you code. Now you need to manage conversational context to achieve the best outputs. Agents and skills will make that happen.</p><p>To start, when you&#8217;re interacting with an LLM, like Claude or ChatGPT, you&#8217;re talking to an agent. And the back-and-forth between you and the agent is the context. You should care about this context because that&#8217;s what the agent knows. If you were to start a new session all that context would be lost. This context is what you&#8217;re managing with sub-agents and skills.</p><p>I like to think of <a href="https://code.claude.com/docs/en/sub-agents">sub-agents</a> as &#8220;side cars&#8221;, they run off to the side and have <em>their own context</em> independent of the primary conversation. What that means is the bulk of what they do is <em>lost</em> to the primary context. <em>This context is what you&#8217;re managing</em>. You might ask yourself questions like, Do I care about that lost context? Would I prefer to have that knowledge in my primary thread? Is this context something that would improve the final outputs? The answer to these boils down to whether preserving the context will be useful to you in the near-future.</p><p>Here are some examples of sub-agents I use to manage context scope, agents that</p><ul><li><p>capture architectural decision artifacts</p></li><li><p>perform adversarial functions on my code</p></li><li><p>produce project documentation</p></li><li><p>open Pull Requests</p></li></ul><p>If you need to write documentation, have an agent review your code (especially from an adversarial point of view), or fire-and-forget the opening of a PR, you can safely exclude their intermediary thinking as you often only care about the final output.</p><p>So those are sub-agents, let&#8217;s go further and talk about skills.</p><p>Skills are what I like to reach for before getting fancy with sub-agents. <a href="https://code.claude.com/docs/en/skills">Skills</a> are small, focused bits of knowledge that an agent can leverage when necessary. Examples of skills are</p><ul><li><p>common language conventions</p></li><li><p>preferences for writing tests</p></li><li><p>composing documentation</p></li><li><p>working with data models</p></li></ul><p>Unlike sub-agents, skills load directly into an agent's context; that means you get specialized knowledge without losing valuable context. For example, when I write tests for a <code>has_many</code> relationship I like to be very specific about the check. Say a parent has many children. I don&#8217;t want to test that one child exists and I don&#8217;t need to instantiate ten. I want precisely two. Why? Because I&#8217;ve seen leaky tests before where I might create two objects but there&#8217;s a third that sneaks in somehow (overly complex test harnessing). If I don&#8217;t check for precisely two and simply look for <em>inclusion</em> then I&#8217;ll get a false positive. If I check for one that doesn&#8217;t <em>prove</em> there can be many. If I check for precisely two, I catch the case that the test harness itself is bad (i.e. there are more than two). And so I encoded this in a skill&#8217;s directive like,</p><blockquote><p>Model relationships (has_many, etc.) must be tested with two associated records. Assert the collection contains exactly both using contain_exactly(item1, item2). Do not use include(one_item); that passes even when the association is broken.</p></blockquote><p>What I get from this is increased certainty that agents performing work for me take advantage of my own experience. In this case, be careful with inclusionary testing.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>What&#8217;s more, the nice thing about skills is that they can be referenced by sub-agents. That is, if I eventually want a coding agent that specializes in Ruby, I can tell it to reference all the skills I have for writing Ruby. And that&#8217;s where the two ideas link up. You can view skills as <a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices">building blocks</a> to future agents; mix a little of this knowledge with that knowledge and wrap it up into a single agent that can perform the task on its own.</p>]]></content:encoded></item><item><title><![CDATA[Shifting Baselines]]></title><description><![CDATA[How quality degrades without anyone noticing]]></description><link>https://writeaheadblog.com/p/shifting-baselines</link><guid isPermaLink="false">https://writeaheadblog.com/p/shifting-baselines</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Sat, 17 Jan 2026 23:24:35 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f95fc730-d2da-4ae1-a100-caa4a2166697_5272x3948.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Your test suite takes eleven minutes to run. When was the last time it ran in under a minute? It&#8217;s easy for that number to creep up, slowly but surely. The team grows. People come and people go. What was once two minutes became five. New engineers only knew seven minutes. Now it&#8217;s eleven. This is normal.</p><p>Ecologists have a name for this: <strong>shifting baseline syndrome</strong>. Hundreds of years ago, beavers shaped a dramatically different North American landscape. Their dams created wetland ecosystems across regions that are now dry streambeds, vast prairie, or dense forest. As trapping crashed beaver populations, those wetlands vanished and ecosystems collapsed. Each human generation grew up knowing fewer beavers and altered landscapes, accepting that inheritance as the natural state. The baseline had shifted.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>Test suites slow for many reasons, but turnover is what makes those slowdowns invisible. It shifts the baseline. The same mechanism can be seen elsewhere. Consider a team where error messages pipe into a Slack channel. Hundreds arrive daily. Most are informational, some are real errors. Extracting signal from noise becomes impossible. People stop reading it. The problem becomes invisible. New engineers join, see it&#8217;s ignored, and learn to ignore it too. The baseline shifts.</p><p>The pattern is difficult to see from inside. When someone new asks &#8220;what is going on here?&#8221; or &#8220;why does this take so long?&#8221;, the baseline hasn&#8217;t been established for them yet. That&#8217;s the moment. Listen. Then act: measure the current state, set explicit thresholds for key metrics, and schedule regular baseline audits. Document what &#8220;good&#8221; looks like before the team falls back into their normal routine.</p><p>Ecologists eventually reintroduced beavers to restore damaged ecosystems. Sometimes the equivalent intervention in software is starting fresh. More often, it&#8217;s deliberate measurement and conscious resistance to drift.</p>]]></content:encoded></item><item><title><![CDATA[Story Memory: An Agentic Programming Pattern]]></title><description><![CDATA[Preventing rework with a little extra planning]]></description><link>https://writeaheadblog.com/p/story-memory-an-agentic-programming</link><guid isPermaLink="false">https://writeaheadblog.com/p/story-memory-an-agentic-programming</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Wed, 24 Sep 2025 15:15:18 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/2b270552-a178-4f71-abee-f77d8b7aeef9_2284x1524.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been using agent-based programming as long as the next person. It&#8217;s new. As an industry, we&#8217;re still finding our way with it. Given the bigger picture, though, it&#8217;s not going anywhere. The sooner we find best practices, patterns for taking advantage of it, the better. Here, I want to share a pattern I've been refining for nearly as long. I call it &#8220;Story Memory&#8221;. It combats an agent writing large swaths of code leaving you with little context. Let me walk you through it.</p><p>Let&#8217;s say you have some functionality to build for your software product. As nearly all devs do, you grab a story representing what needs to be done and get started. Broadly speaking, you start noodling on how to accomplish this work, you might bounce it off a coworker&#8217;s head, and then get to typing. My own take on this process has morphed to include the agent from the outset, not just when I need it to write code. And, most importantly, by the time I&#8217;m ready to build, I have a document outlining exactly what I need the agent to do.</p><p><strong>Here&#8217;s how it goes:</strong> when I get started with a story I begin by giving the agent full context. I do this in chat mode instead of coding mode. I do not want it writing yet. After the context, I tell it how I propose to frame the solution. Finally, I begin riffing on the design with the agent, leaning on my many years of software engineering experience. All the while, since I&#8217;m having an extended back and forth with the agent, I prefer to <a href="https://superwhisper.com/">talk</a> rather than type.</p><p>To be clear, this process isn&#8217;t intended to replace collaborating with a coworker, rather, its immediate purpose is to create a markdown file outlining step by step what needs to be done. You see, I do <em>not</em> want an agent running ahead of me, I do not want to lose context on what is written. I want the agent to speed me along, I want to lend it my experience, I want to maintain a high level of context on what&#8217;s written, and I want to be confident in the final results. The scaffolding I use to arrive at those final results is what I call the <code>STORY_MEMORY.md</code> file.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>This file is a synthesis of my own experience, conversing back and forth with the agent, and any additional outside influence. Once I&#8217;m happy with where I&#8217;ve arrived, I have the agent create (or edit) the file. Here&#8217;s a contrived example:</p><pre><code><code># Feature: Article Review (Interactive Q&amp;A)

## Overview
When a user searches for content and an article is returned, they should be able to open a dedicated Article Review page ...

## Implementation Checklist
- [x] **LiveView Module**
  - [x] `article_live.ex` stub created under `web_app/live/`, accepts content id via mount.

- [x] **LiveView Template**
  - [x] `article_live.html.heex` created as a blank template, to be based on `content_review_live.html.heex`.

- [x] **Route Setup**
  - [x] New LiveView route `/article/:id` added to router, following app conventions.

- [ ] **Q&amp;A Interface**
  - [x] Add a form for users to submit questions about the article.
  - [ ] On submit, use the embeddings to find relevant chunks and generate answers.
  - [ ] Display answers and supporting context in the UI.
  - [ ] Write a test to confirm this functionality.

## Notes
- Reuse as much logic and UI as possible from `content_review_live` to keep things simple and maintainable.
- Focus on the article (`content_type: "webpage"`) use case, but keep the design flexible for future expansion.
- Keep the interface clean and focused on Q&amp;A.</code></code></pre><p>The structure is simple. At the least, I like to have an overview of the task, a step by step checklist, and additional notes that might be helpful. I find the <code>[ ] </code>and<code> [x]</code> especially handy to keep track of progress. Most importantly, the work must be broken down step by step. I find this critical for working with agents when programming. It keeps us both focused on atomic tasks. This is how I maintain context, reduce rework, and speed myself along. Otherwise, I&#8217;ve found agents are liable to run ahead of me, creating files, building out functionality on their own, making assumptions, and generally leaving me with a tangled web to sort through.</p><div class="pullquote"><p>Consider adding the STORY_MEMORY.md file to your agent instructions (hence &#8220;memory&#8221;) so it always has context on the work. Additionally, you can specify how you prefer the file to be structured in the instructions as well as add it to your .gitignore file.</p></div><p>So instead of fighting with an agent to complete story work, create a file dedicated to guiding its output. Do what you always do: think the problem through, plan ahead, break the work into small steps, confer with coworkers, but add the extra step of distilling that into a <code>STORY_MEMORY.md</code> file. This way, you harness the agent's speed while maintaining control through guardrails and manageable chunks of work, while reducing the likelihood of rework and lost context.</p>]]></content:encoded></item><item><title><![CDATA[Avoiding FGA's Tuple Hell]]></title><description><![CDATA[Taming tuple explosions in Fine-Grained Authorization]]></description><link>https://writeaheadblog.com/p/avoiding-fgas-tuple-hell</link><guid isPermaLink="false">https://writeaheadblog.com/p/avoiding-fgas-tuple-hell</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Tue, 12 Aug 2025 14:54:58 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/690cf328-91b0-4642-87aa-5371a5af83b1_7680x4320.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Fine-Grained Authorization (FGA) is a great piece of kit. Like microservices, it adds flexibility and scale. It also brings complexity. This level of complexity is not always the right fit; sometimes, all you need is a simple role check. Easy. I don&#8217;t want to talk about those cases.</p><p>Let&#8217;s say FGA <em>is</em> the right choice. What are some initial questions to get you on your way?</p><p>For me, performance is critical. You have to avoid the &#8220;tuple explosion&#8221;. It will bring your system to its knees. To this end, think about how often your system will need to ask, <em>Can this user do this thing</em>? Now imagine all the <em>users</em>. All the <em>things</em>. All the <em>checks</em>. Those add up to pressure on the tuple store that must inform the design. It leads me to thoughts like:</p><ul><li><p>How best to shape graph traversal?</p><ul><li><p><em>Remember, we&#8217;re thinking in graphs here</em></p></li><li><p>Where are the &#8220;pivot&#8221; points in the models?</p></li><li><p>How can we reduce the number of calls?</p></li><li><p>Can we reduce how much data is retrieved?</p></li><li><p>Deep trees impact performance. Keep traversal limits in mind</p></li></ul></li><li><p>Do users switch contexts (like between organizations)?</p></li><li><p>Look for opportunities to reduce tuple count with &#8220;cascading&#8221; permissions</p><ul><li><p>This relates back to tree depth and the &#8220;pivot&#8221;</p></li><li><p>How will deletion and revocation propagate through the tree</p></li></ul></li><li><p>Can you foresee computed permissions? What might those look like?</p></li><li><p>Design around the principle of least privilege</p></li><li><p>What low-risk data is worth caching?</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>In no universe are these comprehensive. But it&#8217;s where my mind drifts first. FGA is a powerful authorization technology. And with that power comes the ability to <s>shoot yourself in the foot</s> blow your foot off. So do your future-self a favor and try to manage the size of your tuple set before it gets out of hand.</p>]]></content:encoded></item><item><title><![CDATA[From Test Suites to Outreach]]></title><description><![CDATA[My initiation into Partner-led growth]]></description><link>https://writeaheadblog.com/p/from-test-suites-to-outreach</link><guid isPermaLink="false">https://writeaheadblog.com/p/from-test-suites-to-outreach</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Wed, 30 Jul 2025 18:22:10 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/126b8748-8b52-4253-b67a-e5b8af4e3a8e_1024x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I got into business development as a necessity. My company was undergoing a transition that required a change in focus. And I was the senior team member in North America. Always up for a challenge, I said, &#8220;I&#8217;ll do it.&#8221; I knew where I wanted to start.</p><p>I had one partner in mind. Our team had many stories attached to their product. They had a partner program. They were growing. &#8220;Perfect&#8221;, I thought. And it was, but my na&#239;vet&#233; began to show quickly. If I could get some of their Account Executives to chat I could tell them all about our great customer stories. They&#8217;ll wave us right in, eager to collaborate. <em>Record scratch.</em> Not so fast.</p><p>The first thing to do was to become a partner. Easy enough. At this point, I felt like the gnomes from a South Park episode,</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wIpJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wIpJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png 424w, https://substackcdn.com/image/fetch/$s_!wIpJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png 848w, https://substackcdn.com/image/fetch/$s_!wIpJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png 1272w, https://substackcdn.com/image/fetch/$s_!wIpJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wIpJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png" width="640" height="439" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:439,&quot;width&quot;:640,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63826,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://writeaheadblog.substack.com/i/167724082?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wIpJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png 424w, https://substackcdn.com/image/fetch/$s_!wIpJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png 848w, https://substackcdn.com/image/fetch/$s_!wIpJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png 1272w, https://substackcdn.com/image/fetch/$s_!wIpJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F638c1b91-a2b4-4e90-ba96-22cc73754d0a_640x439.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Obviously not collecting underpants (just to be clear)</figcaption></figure></div><p>I had to start a campaign. I had to reach out. So I took to my oft-ignored LinkedIn account and began the search for partner Account Executives, Directors, and VPs. I was on the hunt for people who would resonate with my team&#8217;s stories. Some semblance of a strategy began to take shape.</p><p>I built outreach lists. I tracked the who and when of connections. I worked hard on the narrative to tell. How much was too much? What does rapport look like? What kind of stories land? How much does &#8220;What&#8217;s In It For Me&#8221; play a part? My process was far from perfect. But I was moving from <a href="https://en.wikipedia.org/wiki/Four_stages_of_competence">unconscious incompetence to conscious incompetence</a>&#8212;the fog was beginning to lift.</p><p>Filling in that &#8220;phase 2&#8221; question mark belies a lot of work. A lot of stress. A lot of stretch. Software had been my comfort place for well over a decade. Leaving it, I discovered I had traded consistent determinism for human dependencies. Test suites gave me instant feedback. An outreach email? Not so much. Was I too wordy? Was I uninteresting? Was the recipient too busy? There is no pass/fail for those.</p><p>It&#8217;s still a work in progress. It always will be. I still straddle engineering, too. What&#8217;s more, that&#8217;s been an advantage in navigating customer discussions.</p><p>Would I do it again? Yes.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[No One's Opening Your Dev Wiki]]></title><description><![CDATA[Document for lazy people. Like me. And this cat.]]></description><link>https://writeaheadblog.com/p/no-ones-opening-your-dev-wiki</link><guid isPermaLink="false">https://writeaheadblog.com/p/no-ones-opening-your-dev-wiki</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Thu, 17 Jul 2025 14:37:25 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/aea08d08-d32a-4552-abfc-8f258498aa0c_1328x1326.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I like READMEs in <em>almost</em> every directory of a project. In my mind, they&#8217;re more effective than a project wiki. Let me tell you why.</p><p>One thing I&#8217;ve learned over my career: people are lazy. And that&#8217;s okay. We all are. At different times. Under different circumstances. It&#8217;s all too easy to accept the path of least resistance. That&#8217;s not a moral failing. Instead of fighting it, we should accommodate it.</p><p>In software, think about how we design for users. Like a lazy footpath clipping a turfed corner, we expect users to take the shortest path. So we use progressive profiling to break up long sign-up flows. We offer magic links to bypass forgotten-password hell (adding a new circle to hell in the process). We tune defaults for an immediate, usable experience. When we get it right, we make the right thing easy and the wrong thing hard. Users barely notice. Perfect.</p><p>We like to think software engineers are different. We&#8217;re smart. We&#8217;ll read the docs (what are those?), follow the right process, keep everything tidy. No. We&#8217;re not. Get out of here. Worn footpath? Please. More like peregrinated goat trails. There&#8217;s a quote getting at this idea, supposedly from Bill Gates (it&#8217;s not):</p><blockquote><h3>I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it.</h3></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>People are lazy. Find the easy way. Here&#8217;s an imagined project structure:</p><pre><code>project-root/
&#9500;&#9472;&#9472; README.md
&#9500;&#9472;&#9472; api/
&#9474;   &#9492;&#9472;&#9472; README.md
&#9500;&#9472;&#9472; adapters/
&#9474;   &#9492;&#9472;&#9472; README.md
&#9500;&#9472;&#9472; pipeline/
&#9474;   &#9492;&#9472;&#9472; README.md
&#9492;&#9472;&#9472; stores/
    &#9492;&#9472;&#9472; README.md</code></pre><p>You know what&#8217;s nice about this? When I&#8217;m curious about <code>/api</code>, the explanation is right there, staring me in the face. I don&#8217;t need to leave my IDE to spelunk a wiki. The structure is obvious, even if a little repetitive. And once the pattern clicks, it becomes second nature to incorporate into your workflow. If someone forgets to update a README in a PR, it&#8217;s easy to spot. Easy to nudge. &#8220;Hey, this change should be reflected in the README.&#8221;</p><p>That&#8217;s lazy.</p><p>That&#8217;s perfect.</p>]]></content:encoded></item><item><title><![CDATA[Hiring for More Than Skill]]></title><description><![CDATA[Establish a throughline with emotionally intelligent questions]]></description><link>https://writeaheadblog.com/p/hiring-for-more-than-skill</link><guid isPermaLink="false">https://writeaheadblog.com/p/hiring-for-more-than-skill</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Sun, 06 Jul 2025 01:16:14 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f4b1a539-8b2d-4945-a451-dda451fadc44_4032x2268.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most technical hiring processes focus on ability. But software engineers rarely fail because they can't code; they fail because they don&#8217;t ask, don&#8217;t adapt, and don&#8217;t connect. It&#8217;s why Emotional Intelligence (EQ) matters so much to me when hiring engineers. It helps you see beyond the present moment, to how they&#8217;ve developed, adapted, and where they may be going&#8212;powerful hiring signals.</p><p>It&#8217;s important to be clear: EQ isn&#8217;t about being nice. And I&#8217;m not trying to dig into a candidate&#8217;s personal story. I&#8217;m trying to understand how they handle ambiguity, conflict, feedback, and failure. Research links traits like self-awareness, regulation, and empathy to <a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC10543214/">real-world performance</a> and <a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC6926721/">long-term success</a>. And when we hire, isn&#8217;t that what we actually care about? I can teach software design. I can&#8217;t teach emotional regulation or self-awareness. Not at work anyway. Those traits aren&#8217;t abstract. They show up in how someone talks about past projects, setbacks, or team dynamics. But you won&#8217;t find them on a r&#233;sum&#233;. You have to ask. You have to listen. You have to engage.</p><p>This is where the Big Five Personality Traits shine. It&#8217;s my preferred model because its results hold across cultures and contexts. Used well, the five traits (OCEAN) shape both your questions and your interpretation of the answers. You might ask about tradeoffs they&#8217;ve made (Openness), how they manage deadlines (Conscientiousness), how they prefer to collaborate (Extraversion), how they handle disagreement (Agreeableness), and what stress does to them (Neuroticism). But you can&#8217;t just ask. You have to care. You have to dig in. You have to grab ahold of the thread of their story, find the shape of their arc, not just look for facts.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p><p>Often, interviews cover surface-level questions. They miss the story. I don&#8217;t want that. I want to understand where someone&#8217;s come from, where they&#8217;re going&#8212;as best I can given the time constraints. Designing questions that reveal aspects of OCEAN helps me do this. To guide that, I like to ask myself, &#8220;what will help uncover this person&#8217;s arc?&#8221; I don&#8217;t want to get to know them as they are right this second, I want their story. </p><p>These are example notes I use to find someone&#8217;s thread; they help me see beyond the r&#233;sum&#233; and start to trace their throughline:</p><div><hr></div><p><strong>Q: When you get stuck on a problem, what&#8217;s your approach for getting unstuck?</strong></p><p><strong>Traits</strong>: O/C/E [<em>these map directly to OCEAN, aspects I&#8217;m looking to uncover</em>]</p><p><strong>Listen for</strong>:</p><ul><li><p>Grounding in real behaviour</p></li><li><p>A non-idealized self-concept</p></li></ul><div><hr></div><p><strong>Q: What skill(s) feel just out of reach for you right now?</strong></p><p><strong>Traits</strong>: O/C/E</p><p><strong>Listen for</strong>:</p><ul><li><p>How they frame growth. Do they emphasize team benefit (&#8220;I want to help others by learning X&#8221;) or personal mastery (&#8220;I want to be better at Y&#8221;)? Either are valid, but consider the different motivations this reveals</p></li><li><p>How is the answer rooted? Does it reflect self-awareness, or is it wrapped in vague ambition?</p></li></ul><p><strong>Potential follow-up</strong>: Tell me about a skill you had to stretch for. Why was it important? How&#8217;d you develop it?</p><div><hr></div><p><strong>Q: How do you think people perceive you when you're hashing out ideas with them?</strong></p><p><strong>Traits</strong>: A/E/N</p><p><strong>Listen for</strong>:</p><ul><li><p>Some meta-cognition/social calibration</p></li><li><p>Whether they&#8217;re aware of how they come across? Do they adapt their style, or are they fixed in how they engage?</p></li><li><p>Signs of either self-awareness or blind spots</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Cultivating Judgment in an Agent-First World]]></title><description><![CDATA[Helping Junior Devs Grow in a World of Instant Answers]]></description><link>https://writeaheadblog.com/p/cultivating-judgment-in-an-agent</link><guid isPermaLink="false">https://writeaheadblog.com/p/cultivating-judgment-in-an-agent</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Fri, 30 May 2025 13:52:27 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/70ae4aca-94c8-4036-bde9-d070563e5608_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Agents are beginning to reshape how we build software. We haven&#8217;t broken cleanly into that new paradigm yet, but it&#8217;s coming. The complexity juniors used to grow through&#8212;trade-off discussions, failed first approaches, awkward in-progress code (which I still write)&#8212;risks being hidden behind a polished AI-generated answer. If all they see is the final output, I worry they&#8217;ll miss the substrate where judgment used to form.</p><p>Judgment isn&#8217;t just about spotting bugs or bad smells. It&#8217;s learning to weigh one option against another, to see why one solution fits better than the rest, and why certain shortcuts backfire (sometimes spectacularly!). That tends to happen in the messy middle. The part where you spin your wheels before asking for help. That hasn&#8217;t evaporated overnight. It&#8217;s not gone yet. But it is something we should watch for. It&#8217;s a practice ground at risk of being lost. And we need to be sure something equally as useful fills its space.</p><p>We have to consciously bring juniors along for this new ride. A ride, in a way, that we&#8217;re juniors on! So let&#8217;s share our thinking, our tradeoffs, our uncertainty. In this new world where answers are instant, experience becomes harder to acquire. But it is not impossible. We just have to be deliberate.</p><p>Let&#8217;s be deliberate. Let&#8217;s ensure everyone can come along with us.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://writeaheadblog.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Illuminating Patterns]]></title><description><![CDATA[Discovering a New Flow with Software Agents]]></description><link>https://writeaheadblog.com/p/illuminating-patterns</link><guid isPermaLink="false">https://writeaheadblog.com/p/illuminating-patterns</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Tue, 13 May 2025 17:58:17 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8d50ea02-51ad-45a4-b26b-81c325c1eb06_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I had just wrapped up work for the day. Light was still filtering in through a high, narrow window above my desk. I fidgeted in my seat, knowing I wasn&#8217;t done for the day. I had an idea. I downloaded and opened <strong><a href="https://windsurf.com/">Windsurf</a></strong>. Before this moment, I had bounced off of agents for anything beyond basic programming. Notably, I found one agent particularly good with regex (i.e. my perennial nemesis). Beyond this, however, I found agents more effort than they were worth. I was about to have that view of agents completely upturned.</p><p>I wanted to build a web scraper. This has been solved so many times, but I&#8217;m the type that enjoys projects and writing code in my spare time. So there I sat: Windsurf open, an empty project directory in front of me, an empty chat. Pure possibility.</p><p>Prior to this, I&#8217;d have begun in a single script file&#8212;the kind of personal project that is the antithesis of best practices. The file would have grown and grown as I tested and tweaked. It wouldn&#8217;t have mattered. It would be all mine. It didn&#8217;t need to pass CI. It didn&#8217;t need to be grokked by anyone else. It could be a glorious, tangled mess.</p><p>As I stared at this empty chat box, though, I had one thought:</p><blockquote><p>Whatever is built here, I want full context.</p></blockquote><p>This one thought, context, framed my interactions with Windsurf as I worked on this project. As I began to think about what I wanted, I decided I <em>didn&#8217;t</em> want a single script file. I wanted something more mature. And given my experience, I decided to carefully frame what I wanted to Windsurf. That first message was two paragraphs long. I didn&#8217;t save it. But it went something like this:</p><blockquote><p>Okay, I want to build a web scraper in python. It&#8217;s going to scrape data off of M website. I want the entry point of the script to be <strong>app.py</strong>. I want that to load all my dependencies. I want a directory structure like: X, Y, and Z. My authentication model will live in X, my specific scrapers in Y, etc. I want to use playwright for browser interactions. For any class files you create, I only want them stubbed out. I do not want any business logic to be included at all.</p></blockquote><p>The result was the first revelatory moment. In minutes I was hours into my journey. More than that, this new project followed more sustainable practices than a single tangled file. I had crossed a threshold that felt like having discovered programming all over again. It was immediately energizing.</p><p>But I wasn&#8217;t done. I had only a skeleton of an idea. Again, I thought to myself, </p><blockquote><p>As I keep building, I want full context.</p></blockquote><p>My earliest concern was to avoid something I had seen others do: ask an agent to solve a problem and receive hundreds, if not thousands, of new lines of code in return. Programming this way, it seemed to me, was a surefire way to exist in eternal Peer Review mode. Not exciting.</p><p>Instead, I gave the agent a simple, tightly bound directive:</p><blockquote><p>Great, we have a project. Now I want to start simple. When the app first boots, lets open M website in the <strong>main.py</strong> file. That&#8217;s all I want you to do.</p></blockquote><p>That&#8217;s all I asked. That&#8217;s all it did. No bloat. No surprises. No mental overhead. It was exhilarating. By keeping my questions tightly bounded I could swiftly move through the work while maintaining context.</p><p>As I sat there, with the light slowly fading through my window, I got it. It clicked. Agents aren&#8217;t for blindly writing code and hoping for the best. They&#8217;re collaborators. Think of it like onboarding a junior developer. You don&#8217;t dump the whole codebase on them and say &#8220;go.&#8221; You hand them a small, clearly defined task. You explain the context, the purpose, and the constraints. Then you check in and adjust. It&#8217;s the same here.</p><p>That&#8217;s powerful. A few hours of tinkering has convinced me we&#8217;re in the middle of a seismic shift in how software gets written. Like the early days of object-oriented programming, we&#8217;re starting to see new patterns emerge for working with agents.</p><p>I&#8217;ve already stumbled onto one: when you&#8217;re starting a project, let the agent handle broad, boilerplate setup above and beyond framework features. Once you&#8217;re into feature development, tightly bound your requests to heighten your own context. These two principles alone can dramatically improve the way you build alongside an agent.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Write-Ahead Blog! Subscribe for free to receive my latest posts.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How to Train Your AI (agent)]]></title><description><![CDATA[How Rules Files Turn AI Agents Into Effective Programming Partners]]></description><link>https://writeaheadblog.com/p/how-to-train-your-ai-agent</link><guid isPermaLink="false">https://writeaheadblog.com/p/how-to-train-your-ai-agent</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Wed, 30 Apr 2025 23:00:28 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/2fae3adf-a644-4307-9571-72bcd142f663_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Programming is undergoing a paradigm shift. AI-paired development isn&#8217;t a novelty. It&#8217;s becoming the new normal. And that shift demands new workflows. One of the most essential is the <strong>rules file</strong>: a plain-text document that tells your AI how to behave inside your environment. These aren&#8217;t nice-to-haves. In AI-native development environment (IDEs) like <a href="https://www.cursor.com/">Cursor</a> or <a href="https://windsurf.com/">Windsurf</a>, they&#8217;re required infrastructure. So, what exactly is a rules file?</p><p>A rules file instructs an AI agent how to behave. For example, when you start a new chat with an agent like ChatGPT, it knows nothing about your workflow or the mode you're operating in. Rules files supply that missing context&#8212;guiding behavior with your experience and preferences to shape the output. Without these files, the output suffers. In IDEs, rules are typically markdown files (e.g. &#8220;general_rules.md&#8221;) sent with every request to shape the response.</p><p>At a high level, these files capture your preferences around things such as style conventions, architectural choices, and repeatable patterns. What follows are some basic examples to get you thinking.</p><h2>The Personality</h2><p>This is at the core of your rules files. It dictates how your AI agent should present itself and behave. A trivial example looks like: </p><pre><code><code>You are a senior software engineer. You approach problem solving from the perspective of deconstruction&#8212;you break tasks down into manageable, atomic pieces. You look for simple solutions before conceding to complexity. As you present your suggested solutions, you outline your reasoning and thinking. You engage critically with problems and ensure your solutions are well-reasoned.</code></code></pre><p>Instructions like this can affect how the AI reasons, whether it explains steps, or how assertive it is in making choices. For example, a personality set to &#8220;senior engineer who prefers clarity over cleverness&#8221; will often avoid terse one-liners in favor of clearer constructs. Depending on your experience, this can be tuned for more effective collaboration.</p><h2>The Conformist</h2><p>At the heart of every team, and developer, are conventions and styles that have developed over years. This file isn&#8217;t a preferences dump. It&#8217;s where hard-won conventions are captured. And it's the file that might see the most amount of churn. It should be actively maintained to ensure it's capturing the team's best practices. Without a file like this, you risk re-litigating the same choices with every code suggestion.</p><p>Do you prefer specific patterns in certain circumstances? Outline them here. Do you have patterns, say in testing, that are non-negotiable? Outline them here.</p><p>Here's an example: </p><pre><code><code>* When starting a new project, always include the Ruby gem dotenv
* Use string interpolation instead of concatenation
* When creating a class, always stub out a spec file
* Prefer single quotes for strings unless interpolation is needed
* Unless otherwise requested, use the Ruby gem Faraday for HTTP requests
* Use factories (not fixtures) for test data setup
* Document all environment variables in the README or .env.example</code></code></pre><h2>The Architect</h2><p>While the Conformist deals with code style and routine conventions, the Architect governs higher-level design, system behavior, preferences, and architectural principles. This file is especially useful when you have established opinions about how software should be structured, preventing drift and maintaining consistency. For example: </p><pre><code><code>* Use pub/sub for inter-service communication unless strong consistency is required
* Default to simple structs or plain classes; avoid introducing complex base classes or inheritance without need
* For persistent data models, prefer composition over deep nesting
* When creating APIs, enforce idempotency for all POST endpoints unless explicitly marked as one-time actions
* For background jobs, include an exponential retry policy and failure alerting scaffold by default
* When adding a new feature, generate a feature flag scaffold to control rollout</code></code></pre><p>Not every decision is black and white, but these rules can nudge the AI toward your defaults. They're especially useful when consistency matters more than innovation.</p><h2>Parting Tips</h2><p>Some advice for putting rules files to work:</p><ul><li><p>Keep your rules files modular, like outlined above, for easier maintenance</p></li><li><p>Treat these files as living documents, update them anytime the AI falls short of your standards</p></li><li><p>Consider versioning your rules files in a personal or team repo</p><ul><li><p>They can easily be <a href="https://en.wikipedia.org/wiki/Symbolic_link">symlinked</a> into new project directories</p></li></ul></li><li><p>Create purpose-built files (e.g. &#8220;reviewer.md&#8221; or &#8220;debugger.md&#8221;) for specialized workflows</p></li><li><p>Rules files aren&#8217;t restricted to developers, they can be useful for project managers or other professionals (e.g. ChatGPT calls them &#8220;traits&#8221;)</p></li><li><p>Add code examples, with instructions, to be explicit in your preferences</p></li></ul><div><hr></div><p>Rules files are already essential. They aren&#8217;t documentation, they aren&#8217;t optional, they&#8217;re working memory distilled from decades of collective experience driving the output of the agents your teams use. They&#8217;re how things are done.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Write-Ahead Blog! Subscribe for free to receive my latest posts.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Practical Agent Model Switching]]></title><description><![CDATA[Quick, effective heuristics for picking the right AI model for the job]]></description><link>https://writeaheadblog.com/p/practical-agent-model-switching</link><guid isPermaLink="false">https://writeaheadblog.com/p/practical-agent-model-switching</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Sat, 26 Apr 2025 01:04:17 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/aeca3e17-e06b-4374-9e62-ba1db8ab7ed9_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://windsurf.com/">Windsurf AI</a> has quickly solidified its role in my development workflow. With this change comes a necessary shift in thinking about the work. New rhythms, new patterns to feel out. And unexpected new skills to refine: like knowing when to <a href="https://docs.windsurf.com/windsurf/models">switch models</a> for a given task. I classify these models into three types. They&#8217;re far from official, but they&#8217;ve held up well for me: <em>performance</em>, <em>thinking</em>, and <em>basic</em>.</p><h3>Performance</h3><p>These are often the newest, most expensive models to use. They&#8217;re built for complexity, for context-heavy tasks that need precision and depth. If I&#8217;ve got something big and tangled to accomplish, and I want it done right, I bring out the heavy artillery. It lets me pair my experience with something that doesn&#8217;t blink and doesn&#8217;t get tired.</p><h3>Thinking</h3><p>These versions I love. These models think out loud. You give them a question, and they don&#8217;t just spit out an answer&#8212;they lay the whole thought process on the table. Brilliant. When you&#8217;re venturing into unfamiliar territory you couldn&#8217;t ask for more. Like, say, implementing Postgres&#8217; <code>tsvector</code> in Elixir for the first time. You&#8217;re not just solving a problem; you&#8217;re learning. And better still, you get to catch it when it goes off the rails. You get to push back. You get smarter.</p><h3>Basic</h3><p>These models are my go-to grunts. Reliable, cheap, do-as-I-say. I use them when I know exactly what needs to be done&#8212;I just don&#8217;t feel like doing it. The work is simple, the outcome clear, and I don&#8217;t need the thing getting creative. One caveat: I keep them boxed into a single file. I&#8217;ve seen too much chaos when a basic model tries to go beyond a single file. They don&#8217;t reason well across boundaries. But if it&#8217;s a focused task you know your way around, this is your cost-effective, zero-fuss answer.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Write-Ahead Blog! Subscribe for free to receive new posts as they go out.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Automatic Programming, Again]]></title><description><![CDATA[Embracing the next phase of programming]]></description><link>https://writeaheadblog.com/p/automatic-programming-again</link><guid isPermaLink="false">https://writeaheadblog.com/p/automatic-programming-again</guid><dc:creator><![CDATA[Michael]]></dc:creator><pubDate>Sun, 06 Apr 2025 17:17:45 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ab9ce0dd-0686-455f-81c3-fd60723e56d7_474x316.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Time is a flat circle.</p><p>I read <a href="https://app.thestorygraph.com/books/8086b5d4-f71e-4f23-ba09-2682a9d6a890">Grace Hopper and The Invention of the Information Age</a> a few years ago. In the 1950s she introduced the first compiler&#8212;a program to translate human-friendly, English-like code into machine code. It was a paradigm shift, one that provoked immediate negative reaction:</p><blockquote><p>Reflecting on the negative reactions of some of her fellow programmers, Hopper expressed the belief that arguments focusing on &#8220;efficiency&#8221; and &#8220;creativity&#8221; covered far baser motivations: &#8220;Well, you see, someone learns a skill and works hard to learn that skill, and then if you come along and say, &#8216;you don&#8217;t need that, here&#8217;s something else that&#8217;s better,&#8217; they are going to be quite indignant.&#8221; In fact, Hopper felt that by the mid 1950s many programmers viewed themselves as &#8220;high priests,&#8221; for only they could communicate with such sophisticated machines. They served as the intermediaries between user and computer, and automatic programming jeopardized their exclusive position.</p></blockquote><p>These days, no one bats an eye at using compiled languages. We&#8217;ve been using Dr. Hopper&#8217;s invention to more efficiently write code for decades. Much like the days before her invention of the compiler, writing code today is deep knowledge work. Still, software engineers act as &#8220;intermediaries between user and computer.&#8221;</p><p>Time is a flat circle.</p><p>We find ourselves, again, at a clear paradigm shift. By the late 1950s, I bet you could have said the same about compilers as we now say about AI. And much in the same way as those PhD mathematicians writing machine code ultimately had to think more abstractly, we&#8217;ll have to shift our thinking.  We&#8217;ll have to step back from hand-typing every single line of code (minus handy command-line generators) to engaging with AI agents at a more abstracted level.</p><p>Time is a flat circle.</p><p>Why, now, should <em>we</em> keep building the same old directory structures, tweak migrations, or fiddle with broad-strokes of data models? Let the agents do that, so our deep knowledge work can focus on the trickiest of the tricky&#8212;let&#8217;s say the 5% of a project where reasoning and creativity matter most.</p><p>The LLM is the new compiler.</p><p>The agent, the new high-level language.</p><p>And we&#8217;re about to see a new degree of productivity echoing the gains brought on by Dr. Hopper.</p><p>Time is a flat circle.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://writeaheadblog.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Write-Ahead Blog! Subscribe for free to receive new posts.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Conversational Signposts]]></title><description><![CDATA[How Na&#239;ve Realism & Ken Foster Improved Connection]]></description><link>https://writeaheadblog.com/p/conversational-signposts</link><guid isPermaLink="false">https://writeaheadblog.com/p/conversational-signposts</guid><pubDate>Thu, 28 Nov 2024 18:39:37 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c2aebae9-be6c-4d91-bb6e-1835033e31b4_5918x3945.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What if we could develop a perspective for asking deeper, more meaningful questions? How might it help us uncover insights we&#8217;d otherwise miss? Imagine shining a spotlight into the hidden corners of a friend&#8217;s comment or sparking deeper connections in everyday conversations&#8212;whether with a loved one, during a job interview, or even in a checkout queue. By combining the concepts of <em>na&#239;ve realism</em> and <em>ken</em> with purposeful listening we can transform the way we understand and relate to others.</p><p>To begin asking better questions, it helps to understand the concepts that can help get us there&#8212;like <em>ken</em>. And no, not the other half of a famous duo! In its simplest form, <em>ken</em> is defined as one&#8217;s &#8220;range of perception, understanding, or knowledge.&#8221; <em>Ken</em> has deep roots, tracing back to <em>kenning</em>, a term with Scottish nautical ties that refers to the limit of our vision at sea&#8212;about 20 miles. While nautical history isn&#8217;t directly relevant here, connecting dots like this can help cement understanding.</p><blockquote><p><em>Ken</em>: one&#8217;s range of perception, understanding, or knowledge</p></blockquote><p>To complete our question-asking duo, let&#8217;s bring <em>na&#239;ve realism</em> into the mix. Both a philosophical and psychological concept, it&#8217;s the counterpart to <em>ken</em> that, when paired with it, can guide us toward deeper interpersonal connection. For our purposes, we&#8217;ll focus on its psychological meaning: the <strong>belief</strong> that we see the world objectively, without biases or distortions. <em>Na&#239;ve realism</em> leads us to assume our perceptions are fully accurate and that those who disagree must be uninformed, irrational, or biased. Acknowledging this bias fosters empathy, encouraging us to see the world through the perspectives of others.</p><blockquote><p><em>Na&#239;ve realism:</em> the tendency to believe one's own senses accurately reflect reality, ignoring the influence of bias and other factors</p></blockquote><p>Now, let&#8217;s combine these two ideas. A broad, humble understanding of <em>ken</em> reminds us that our knowledge and perception are inherently limited, much like the horizon seen from a ship. At the same time, <em>na&#239;ve realism</em> challenges us to accept that our view of reality is subjective and shaped by personal experiences and biases. Together, these concepts highlight that as we navigate our lives, we experience the world not as it truly is but within the boundaries of our <em>ken</em>. Recognizing this opens the door to curiosity. It invites us to ask deeper, more meaningful questions rather than simply asking more of them. This not only stretches our understanding and expands our <em>ken</em>, but it also fosters deeper connections with those around us.</p><p>Where does this lead us? Appreciating <em>na&#239;ve realism</em> reminds us that our perceptions may not always reflect reality. <em>Ken</em>, like a spotlight with ourselves at the center, illuminates the limits of our knowledge, a landscape only partially understood. By recognizing the habitual incompleteness of our own understanding, we can better appreciate the same in others. This perspective encourages us to ask questions&#8212;not just to fill our own knowledge gaps or challenge biases, but to inspire curiosity and reflection in those we engage with. In doing so, we begin to connect with others more deeply.</p><p>Over time, questions like &#8220;how are you doing?&#8221; will begin to feel colorless and superficial, offering little room for meaningful connection; they&#8217;re routine and automatic, often answered without much thought. With practice, though, we might instead ask, &#8220;what&#8217;s surprised you today?&#8221; This type of question invites reflection and opens the door to follow-up: What&#8217;s changed for them? What was unexpected or unanticipated? How did it make them <strong>feel</strong>? Did it interrupt their day or maybe even make it better?</p><p>And, of course, what follows is the response. This is where purposeful listening comes into play, allowing us to be more present in the conversation while enabling deeper questions. Much like the horizon at sea marks the limits of our ken, &#8220;words with weight&#8221; act as signposts, offering glimpses into unexplored conversational terrain. These emotionally charged words guide us along a branching trail, transforming what might have been a brief exchange into a journey through a more vivid landscape&#8212;rich with unexpected turns, shadowed valleys, and hidden connections waiting to be uncovered.</p><p>We now have a simple framework guiding us toward asking deeper, more meaningful questions, one that acknowledges the subjectivity of our experience and the limits of our knowledge. This empowers us to create richer, more connected conversations, whether at the water cooler, in a line, or even while getting to know a prospective hire.</p><p>Together, <em>ken</em> and <em>na&#239;ve realism</em> create a foundation for conversations that lead to deeper connection and understanding, providing a pathway to richer, more meaningful relationships. And, now, with all these new signposts to explore, who knows where they&#8217;ll lead?</p>]]></content:encoded></item></channel></rss>