<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Pi Agents on Programmer.ie: Modern AI programming</title>
    <link>http://programmer.ie/books/pi/</link>
    <description>Recent content in Pi Agents on Programmer.ie: Modern AI programming</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Fri, 02 Oct 2026 09:00:00 +0100</lastBuildDate>
    <atom:link href="http://programmer.ie/books/pi/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>The Loop You Are Writing For</title>
      <link>http://programmer.ie/books/pi/01-chapter/</link>
      <pubDate>Thu, 01 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/01-chapter/</guid>
      <description>&lt;p&gt;You are going to write an extension. Before that, you need to know what it is&#xA;extending.&lt;/p&gt;&#xA;&lt;p&gt;This is the step most people skip. They install Pi, run a task, get something&#xA;nearly right, and start writing code against a mental model built from&#xA;observation. The model is usually close enough to work and wrong in a few named&#xA;places, and those places are where every interesting bug lives.&lt;/p&gt;&#xA;&lt;p&gt;So this chapter is one turn of Pi, described exactly, with the places you can&#xA;attach to it named.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Install, First Session, First Task</title>
      <link>http://programmer.ie/books/pi/02-chapter/</link>
      <pubDate>Thu, 01 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/02-chapter/</guid>
      <description>&lt;p&gt;Before you can write for an agent, you have to run one. This chapter gets you&#xA;from nothing to a session with real work in it, and then spends most of its&#xA;length on the part that is actually hard: giving the agent a task it can&#xA;finish.&lt;/p&gt;&#xA;&lt;h2 id=&#34;install&#34;&gt;Install&lt;/h2&gt;&#xA;&lt;p&gt;On macOS or Linux, Pi has an installer:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -fsSL https://pi.dev/install.sh | sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or install from npm, which requires Node.js 22.19 or newer:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Models and Thinking Level</title>
      <link>http://programmer.ie/books/pi/03-chapter/</link>
      <pubDate>Thu, 01 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/03-chapter/</guid>
      <description>&lt;p&gt;Something is not working. The agent is not using your tool. It is ignoring an&#xA;instruction. It stops halfway. Before you go looking in your extension, check&#xA;which model is running and what thinking level it is set to.&lt;/p&gt;&#xA;&lt;p&gt;This is not a joke about blaming the model. It is a description of how the&#xA;system is layered: model choice and thinking level sit &lt;em&gt;underneath&lt;/em&gt; every&#xA;mechanism in this book, and they change behaviour in ways that look exactly&#xA;like bugs in the layer above.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Context Window Is a Budget</title>
      <link>http://programmer.ie/books/pi/04-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/04-chapter/</guid>
      <description>&lt;p&gt;You are halfway through a refactor. Pi has read forty files, run the test suite twice,&#xA;and rewritten the same module three times because each attempt turned out to conflict&#xA;with the last. Nothing is wrong. The transcript simply filled up, and the oldest parts&#xA;of it stopped being sent to the model.&lt;/p&gt;&#xA;&lt;p&gt;Most people meet this as a mood: Pi got worse at the task. It is easier to reason about&#xA;as arithmetic. Every model request costs a fixed slice of a fixed window, and Pi spends&#xA;that slice in named places you can read, count, and change.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Sessions and Where They Live</title>
      <link>http://programmer.ie/books/pi/05-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/05-chapter/</guid>
      <description>&lt;p&gt;You want to know what Pi actually did. Not what it summarised in the final message —&#xA;what it did. That means opening the session file, and it turns out the file is plain&#xA;JSONL you can read with any text editor, and every line is a node in a tree.&lt;/p&gt;&#xA;&lt;p&gt;That tree is the reason Pi can offer &lt;code&gt;/tree&lt;/code&gt;, &lt;code&gt;/fork&lt;/code&gt; and &lt;code&gt;/clone&lt;/code&gt;, and it carries the&#xA;book&amp;rsquo;s most-repeated distinction: &lt;strong&gt;a session is a tree; the model&amp;rsquo;s context is one&#xA;path through it.&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Built-In Tools</title>
      <link>http://programmer.ie/books/pi/06-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/06-chapter/</guid>
      <description>&lt;p&gt;Pi shows every tool call and result while it works. That is a promise about visibility, not about restriction: it does not ask before every tool call, and the tools run with the operating-system permissions of the process.&lt;/p&gt;&#xA;&lt;p&gt;What you can control is the &lt;em&gt;set&lt;/em&gt;. &lt;code&gt;settings.md&lt;/code&gt; defaults &lt;code&gt;defaultTools&lt;/code&gt; to &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, and &lt;code&gt;write&lt;/code&gt;. Every run starts from that list unless you change it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-eight&#34;&gt;The eight&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;cli.md&lt;/code&gt; lists the built-in tools and their purpose:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Settings and Where Configuration Comes From</title>
      <link>http://programmer.ie/books/pi/07-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/07-chapter/</guid>
      <description>&lt;p&gt;You edit &lt;code&gt;settings.json&lt;/code&gt;, run &lt;code&gt;/reload&lt;/code&gt;, and the setting does not take effect. Or it takes effect in a way you did not predict. Both come from the same cause: you were reasoning about one file when Pi merges several.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;configuration.md&lt;/code&gt; gives the shape in one sentence. Pi supports user-level and project configuration. User-level lives in the agent directory, defaulting to &lt;code&gt;~/.pi/agent&lt;/code&gt;. Project configuration lives in &lt;code&gt;.pi&lt;/code&gt; under the working directory and loads after project trust is granted — with one exception, &lt;code&gt;sessionDir&lt;/code&gt;, which Pi reads before resolving trust so it can locate sessions.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Project .pi Directory and Trust</title>
      <link>http://programmer.ie/books/pi/08-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/08-chapter/</guid>
      <description>&lt;p&gt;You clone a repository. It contains &lt;code&gt;.pi/extensions/migrate-schema.ts&lt;/code&gt;, and &lt;code&gt;migrate-schema.ts&lt;/code&gt; calls &lt;code&gt;execSync&lt;/code&gt; with a string built from a prompt. Pi asks whether you trust the folder. You are being asked a real question, and the honest answer is that the prompt is ambiguous about what &amp;ldquo;yes&amp;rdquo; buys you.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;security.md&lt;/code&gt; answers it precisely, and the answer has a wrinkle worth knowing before you answer.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-triggers-the-prompt&#34;&gt;What triggers the prompt&lt;/h2&gt;&#xA;&lt;p&gt;Pi requires a project-trust decision when it finds any of these from the current working directory:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Shells, Processes, and Environment Variables</title>
      <link>http://programmer.ie/books/pi/09-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/09-chapter/</guid>
      <description>&lt;p&gt;You ask Pi to run &lt;code&gt;ll&lt;/code&gt;, and it reports &lt;code&gt;ll: command not found&lt;/code&gt;. You press up in your own terminal and &lt;code&gt;ll&lt;/code&gt; works. Nothing is broken. Pi started a different shell.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;shell-aliases.md&lt;/code&gt; states the cause in the first line: Pi starts a separate non-interactive shell process for each Bash command. Non-interactive Bash does not expand aliases by default and usually does not load the same startup files as an interactive terminal.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Writing a Task Pi Can Finish</title>
      <link>http://programmer.ie/books/pi/10-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/10-chapter/</guid>
      <description>&lt;p&gt;The most common failure is not a bad model. It is a task that never said what &amp;ldquo;done&amp;rdquo; meant. You wrote &amp;ldquo;clean up the auth module&amp;rdquo;, Pi spent forty turns, and produced something you now have to review as carefully as writing it yourself.&lt;/p&gt;&#xA;&lt;p&gt;Pi does not help you here by asking. &lt;code&gt;quickstart.md&lt;/code&gt; says Pi shows each file read, search, command, and edit it performs, and that it does not ask before every tool call. The specification of the task is entirely in your prompt.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Four Ways to Change Pi</title>
      <link>http://programmer.ie/books/pi/11-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/11-chapter/</guid>
      <description>&lt;p&gt;You keep typing the same three lines before every code review. Then you notice the same file appearing in three repositories. Then someone asks for a &lt;code&gt;/review-tests&lt;/code&gt; command and you write forty lines of TypeScript to expand a string.&lt;/p&gt;&#xA;&lt;p&gt;Every one of those three moves was available. Pi&amp;rsquo;s documentation gives a one-line rule for choosing between them — &lt;code&gt;quickstart.md&lt;/code&gt; says to start with the least powerful mechanism that meets your need — and then leaves the reader to guess what &amp;ldquo;least powerful&amp;rdquo; means at three in the afternoon.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Prompt Templates</title>
      <link>http://programmer.ie/books/pi/12-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/12-chapter/</guid>
      <description>&lt;p&gt;The &lt;code&gt;/review&lt;/code&gt; you typed in chapter 11 was real — it lives at &lt;code&gt;.pi/prompts/review.md&lt;/code&gt;, four lines of frontmatter and three of body. This chapter is about everything that file can do and, just as importantly, what it cannot.&lt;/p&gt;&#xA;&lt;p&gt;The one-line summary from &lt;code&gt;prompt-templates.md&lt;/code&gt;: templates turn Markdown files into reusable &lt;code&gt;/&lt;/code&gt; commands, and you want one when you would otherwise retype the same prompt without adding executable behaviour or a larger set of supporting instructions.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Skills</title>
      <link>http://programmer.ie/books/pi/13-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/13-chapter/</guid>
      <description>&lt;p&gt;&lt;code&gt;/review&lt;/code&gt; from chapter 12 only runs when you type it. The problem it solves has a sibling: work that should begin the moment Pi recognises the &lt;em&gt;kind&lt;/em&gt; of task, without you naming the command first.&lt;/p&gt;&#xA;&lt;p&gt;That is a skill, and the entire mechanism turns on one field you are tempted to rush.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-a-skill-actually-is&#34;&gt;What a skill actually is&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;skills.md&lt;/code&gt; opens with the definition: skills give Pi specialized instructions and supporting files for a particular kind of work. Pi advertises each available skill by name and description, then loads its full instructions only when the task calls for them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Skills That Carry Files</title>
      <link>http://programmer.ie/books/pi/14-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/14-chapter/</guid>
      <description>&lt;p&gt;The review guard&amp;rsquo;s checklist is forty items. Three screens of Markdown in &lt;code&gt;SKILL.md&lt;/code&gt; would load all forty every time the skill fires, including for the small reviews where only three apply.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;skills.md&lt;/code&gt; offers a better arrangement: skills can bundle scripts, references, and assets alongside their instructions. The body stays short and names the files; the files load only when the instructions say to read them.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-layout&#34;&gt;The layout&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;review-guard/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── SKILL.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── scripts/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── run-checks.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── collect-diff.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── references/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── checklist.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── severity-rubric.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── assets/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    └── finding-template.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The four directory names are not enforced. &lt;code&gt;skills.md&lt;/code&gt; shows exactly this shape in its own example — &lt;code&gt;scripts/&lt;/code&gt;, &lt;code&gt;references/&lt;/code&gt;, &lt;code&gt;assets/&lt;/code&gt; — and the convention is what makes a skill legible to the next person. Nothing stops you adding &lt;code&gt;templates/&lt;/code&gt; or &lt;code&gt;data/&lt;/code&gt;; nothing encourages you either.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Your First Extension</title>
      <link>http://programmer.ie/books/pi/15-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/15-chapter/</guid>
      <description>&lt;p&gt;The review guard can ask the model to run &lt;code&gt;scripts/run-checks.sh&lt;/code&gt;. It cannot offer a new operation, block a dangerous command, or show a status line. Those need code, and &lt;code&gt;quickstart.md&lt;/code&gt; is unambiguous: executable tools, commands, or event handlers means an extension.&lt;/p&gt;&#xA;&lt;p&gt;This chapter builds the smallest extension that does something a skill cannot.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-an-extension-is&#34;&gt;What an extension is&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;extensions.md&lt;/code&gt;: extensions are TypeScript modules loaded into the Pi process, and their factory functions register tools, commands, shortcuts, providers, event handlers, renderers, and terminal UI.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Events and the Extension Lifecycle</title>
      <link>http://programmer.ie/books/pi/16-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/16-chapter/</guid>
      <description>&lt;p&gt;The review guard can suggest running the checks. It cannot stop a &lt;code&gt;git push --force&lt;/code&gt; that the model decides to run while fixing a conflict.&lt;/p&gt;&#xA;&lt;p&gt;Only a &lt;code&gt;tool_call&lt;/code&gt; handler can do that, because &lt;code&gt;tool_call&lt;/code&gt; fires &lt;em&gt;before&lt;/em&gt; the call runs. Getting that right requires knowing the lifecycle, because handlers run in registration order and a return value only matters for events declared to accept one.&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-events-dispatch&#34;&gt;How events dispatch&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;extensions.md&lt;/code&gt; states three rules:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Tools in Depth</title>
      <link>http://programmer.ie/books/pi/17-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/17-chapter/</guid>
      <description>&lt;p&gt;Chapter 15&amp;rsquo;s &lt;code&gt;review-scope&lt;/code&gt; tool told the model which command to run. That is a tool shaped like a suggestion. This chapter turns it into a tool shaped like a tool: it executes, it returns structured data, it declares its risk, and it knows whether it is even visible to the model.&lt;/p&gt;&#xA;&lt;h2 id=&#34;five-exposures&#34;&gt;Five exposures&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;exposure&lt;/code&gt; controls how the model reaches a tool. &amp;ldquo;Callable&amp;rdquo; means callable from other tools through &lt;code&gt;ctx.executeTool()&lt;/code&gt; — which is what &lt;code&gt;codemode&lt;/code&gt; scripts do.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Changing What Pi Knows</title>
      <link>http://programmer.ie/books/pi/18-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/18-chapter/</guid>
      <description>&lt;p&gt;The guard works. Pi asks before a force push, &lt;code&gt;run_checks&lt;/code&gt; runs the project&amp;rsquo;s own tests, and the failing-test tool answers with structured data.&lt;/p&gt;&#xA;&lt;p&gt;What still goes wrong is quieter. Pi reviews a diff using &lt;code&gt;npm test&lt;/code&gt; instead of &lt;code&gt;run_checks&lt;/code&gt;, because nothing in its context said that tool existed. Then compaction happens, the summary drops the mention, and the next turn does it again.&lt;/p&gt;&#xA;&lt;p&gt;This chapter is about the four surfaces that change what the model knows, and which one to reach for.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Extension State and Persistence</title>
      <link>http://programmer.ie/books/pi/19-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/19-chapter/</guid>
      <description>&lt;p&gt;Your &lt;code&gt;guard&lt;/code&gt; extension blocks writes to &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;.git/&lt;/code&gt;. It works on Monday. On Tuesday you run &lt;code&gt;/reload&lt;/code&gt;, and the block count in &lt;code&gt;/guard status&lt;/code&gt; reads zero. On Wednesday you resume the session from disk and it reads zero again.&lt;/p&gt;&#xA;&lt;p&gt;Nothing is broken. The count was never stored anywhere that survives a process. It lived in a module-level &lt;code&gt;let&lt;/code&gt; that the factory closed over, and the factory runs again on every load. The fix is not &amp;ldquo;save it to disk somewhere sensible&amp;rdquo;. The fix is to understand that Pi already hands your extension a durable, branch-aware place to put state: the session file.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Slash Commands and Custom UI</title>
      <link>http://programmer.ie/books/pi/20-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/20-chapter/</guid>
      <description>&lt;p&gt;Your &lt;code&gt;guard&lt;/code&gt; extension logs blocked writes. The reader wants to see them. The obvious move is a &lt;code&gt;/guard&lt;/code&gt; command that opens a picker. You write it, run &lt;code&gt;pi --print&lt;/code&gt; on a CI machine, and the command silently does nothing because print mode has no UI at all.&lt;/p&gt;&#xA;&lt;p&gt;That silence is not a bug. It is the rule you must design around before you write the command, not after. This chapter is about that rule, and about the three levels of interface Pi actually offers an extension.&lt;/p&gt;</description>
    </item>
    <item>
      <title>MCP Servers</title>
      <link>http://programmer.ie/books/pi/21-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/21-chapter/</guid>
      <description>&lt;p&gt;The &lt;code&gt;guard&lt;/code&gt; extension intercepts &lt;code&gt;write&lt;/code&gt; and &lt;code&gt;edit&lt;/code&gt;. It works beautifully. Then someone on the team installs a Jira MCP server, and the model closes a ticket through &lt;code&gt;mcp__jira__transition_issue&lt;/code&gt; without the guard ever being consulted.&lt;/p&gt;&#xA;&lt;p&gt;It was not consulted because the guard never claimed that path was its responsibility — and, more importantly, because whether it &lt;em&gt;is&lt;/em&gt; covered turns out to be a real question with a documented answer. This chapter is about registering MCP servers, controlling how their tools reach the model, and the one thing a permission extension can and cannot learn from them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Packages: Shipping an Agent</title>
      <link>http://programmer.ie/books/pi/22-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/22-chapter/</guid>
      <description>&lt;p&gt;You have an extension. It registers a tool, a &lt;code&gt;/guard&lt;/code&gt; command, a renderer for its own session entries, and a skill that tells the model when to use the tool. A colleague wants it. You send them a zip of your &lt;code&gt;.pi&lt;/code&gt; folder, and it breaks: their &lt;code&gt;guard&lt;/code&gt; package is a different copy of the same dependencies, their skill paths resolve against their own project, and the entry renderer never fires because the custom entry types do not match.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Compaction</title>
      <link>http://programmer.ie/books/pi/23-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/23-chapter/</guid>
      <description>&lt;p&gt;Two hours into a refactor, the footer says you are at 87% context. Nothing is wrong. Then it says the agent compacted, and the model asks you to re-explain the schema it was told about an hour ago.&lt;/p&gt;&#xA;&lt;p&gt;That re-asking is the real behaviour of compaction, not a bug in your prompt. The old messages were not deleted — they are all still in the session file — but they are no longer in the next request. What the model now has instead is a paragraph written by another model about what those messages said.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Branching and Forking</title>
      <link>http://programmer.ie/books/pi/24-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/24-chapter/</guid>
      <description>&lt;p&gt;The agent picked a schema you did not want, edited eleven files, and is confidently three steps into an approach you have already decided against. You press Escape. Now what?&lt;/p&gt;&#xA;&lt;p&gt;There are three answers, and choosing the wrong one costs you the work you actually wanted. &lt;code&gt;/tree&lt;/code&gt; moves within the session. &lt;code&gt;/fork&lt;/code&gt; starts a new session from an earlier message. &lt;code&gt;/clone&lt;/code&gt; copies the current branch into a new session. The distinction is not cosmetic — it decides whether the abandoned attempt is still there when you come back.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Steering, Queuing, and Changing Direction</title>
      <link>http://programmer.ie/books/pi/25-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/25-chapter/</guid>
      <description>&lt;p&gt;The agent is eleven tool calls into migrating your schema. You can see it is going to be wrong in about three more steps, and stopping it now would waste everything it has already learned about the database layer.&lt;/p&gt;&#xA;&lt;p&gt;You type. You press Enter. And the message waits — because Pi was not going to interrupt mid-tool-call, and the moment it delivers your instruction is a specific, documented point in the loop.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Message Types</title>
      <link>http://programmer.ie/books/pi/26-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/26-chapter/</guid>
      <description>&lt;p&gt;You write an extension that renders tool results. It works on the streaming events, fails on the saved session, and fails differently on the model request. The three surfaces use the same types — but not the same values, and one field in particular is not what its name suggests.&lt;/p&gt;&#xA;&lt;p&gt;This chapter is the reference for the shapes themselves.&lt;/p&gt;&#xA;&lt;h2 id=&#34;one-union-four-surfaces&#34;&gt;One union, four surfaces&lt;/h2&gt;&#xA;&lt;p&gt;&amp;ldquo;Pi uses &lt;code&gt;AgentMessage&lt;/code&gt; values in SDK state, lifecycle events, RPC responses, and persisted session message entries.&amp;rdquo;&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Session File Format</title>
      <link>http://programmer.ie/books/pi/27-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/27-chapter/</guid>
      <description>&lt;p&gt;You open a session file to find out what the agent actually saw. There are four hundred lines. Somewhere in them is the system prompt, most of a conversation that has been summarized away, a branch you abandoned last week, and a &lt;code&gt;custom&lt;/code&gt; entry from an extension storing its own counter.&lt;/p&gt;&#xA;&lt;p&gt;Which of those reached the model is not obvious from the file. This chapter is about the file and the rule that decides.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Context Files and Project Instructions</title>
      <link>http://programmer.ie/books/pi/28-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/28-chapter/</guid>
      <description>&lt;p&gt;Compaction summarized away the schema you explained. The model asks you to restate it. You will not restate it.&lt;/p&gt;&#xA;&lt;p&gt;The fix is not a better prompt. It is a file. Chapter 23&amp;rsquo;s last paragraph pointed at this: durable facts belong on disk, where they are read fresh on every request instead of travelling through a history that gets compressed.&lt;/p&gt;&#xA;&lt;p&gt;This chapter is about that mechanism — which files, in which order, and under what conditions.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Failures, Retries, and Recovery</title>
      <link>http://programmer.ie/books/pi/29-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/29-chapter/</guid>
      <description>&lt;p&gt;The provider returns 529 overloaded. Pi waits two seconds and tries again. Twice more. Then it stops and tells you the model is unavailable.&lt;/p&gt;&#xA;&lt;p&gt;That is correct — and it is the &lt;em&gt;least&lt;/em&gt; interesting failure Pi handles. There are three responses to a failed request, they are not interchangeable, and picking the wrong one is how an agent ends up retrying a request that could never succeed.&lt;/p&gt;&#xA;&lt;h2 id=&#34;three-responses-three-meanings&#34;&gt;Three responses, three meanings&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Retry.&lt;/strong&gt; The failure was transient. The request was fine; the server was not. Repeat it.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Debugging Pi</title>
      <link>http://programmer.ie/books/pi/30-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/30-chapter/</guid>
      <description>&lt;p&gt;The extension worked yesterday. Today the same command does nothing, the transcript looks fine, and there is no error anywhere. You have three things you can look at, and none of them is a stack trace: &lt;code&gt;/debug&lt;/code&gt;, &lt;code&gt;/bug&lt;/code&gt;, and &lt;code&gt;/session&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;That is not a gap in the tooling — it is a shape. Pi is a long-lived process with an event pipeline, an extension runtime that can be replaced mid-session, and a model that produces whatever it produces. Most failures here are not crashes. They are a lifecycle rule violated, a mode guard missing, or a message that is not where you expected it. This chapter is about reaching for the right artefact for each class, and about the small number of extension rules that explain most of what goes wrong.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Terminal Interface</title>
      <link>http://programmer.ie/books/pi/31-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/31-chapter/</guid>
      <description>&lt;p&gt;&lt;code&gt;Shift+Enter&lt;/code&gt; submits instead of inserting a line. Your custom theme is unreadable in someone else&amp;rsquo;s terminal. A click handler works for you and not for the person who filed the bug.&lt;/p&gt;&#xA;&lt;p&gt;None of these is a Pi bug, and each has a documented cause. The terminal interface is not one thing — it is a stack, and at every layer there is a contract that can be satisfied or not. Knowing which layer failed is most of the work.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Headless Pi</title>
      <link>http://programmer.ie/books/pi/32-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/32-chapter/</guid>
      <description>&lt;p&gt;A CI job needs to run a review over a diff. A pre-commit hook needs to summarise what just changed. Neither has a person, and neither wants a terminal.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;pi&lt;/code&gt; already handles this, and the handling is almost entirely documented in one place: &lt;code&gt;cli-integration.md&lt;/code&gt;. But the interesting question is not &amp;ldquo;how do I print the answer&amp;rdquo; — it is &lt;strong&gt;what is different when the agent has no person attached&lt;/strong&gt;, because most of what you built in the previous twenty-nine chapters assumed one.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The JSON Event Stream</title>
      <link>http://programmer.ie/books/pi/33-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/33-chapter/</guid>
      <description>&lt;p&gt;You piped &lt;code&gt;pi --mode json&lt;/code&gt; into a log and now you have four thousand lines and a question: which ones are the answer?&lt;/p&gt;&#xA;&lt;p&gt;The event stream is the canonical reference for everything JSON and RPC mode share, and &lt;code&gt;json.md&lt;/code&gt; is unusually honest about one thing — it is a &lt;em&gt;wire format&lt;/em&gt;, deliberately reduced from the in-process one. If you build on it without reading that reduction, your reconstruction will drift. This chapter takes the stream apart: the framing, the vocabulary, and the one rule that governs reconstruction.&lt;/p&gt;</description>
    </item>
    <item>
      <title>SDK Sessions</title>
      <link>http://programmer.ie/books/pi/34-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/34-chapter/</guid>
      <description>&lt;p&gt;Your integration is written in TypeScript. It parses JSON, reconstructs deltas, and correlates nothing because there are no commands. All of that work exists only because of a process boundary you chose.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;@earendil-works/pi-coding-agent&lt;/code&gt; embeds Pi directly, and &lt;code&gt;sdk.md&lt;/code&gt; opens with the recommendation in its first two lines: use the SDK for in-process TypeScript integration; for a language-independent or isolated subprocess, use CLI integration instead. This chapter is about what the boundary buys you back and what it charges.&lt;/p&gt;</description>
    </item>
    <item>
      <title>RPC</title>
      <link>http://programmer.ie/books/pi/35-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/35-chapter/</guid>
      <description>&lt;p&gt;You want to drive Pi from an editor plugin, from a Python service, or from an IDE — but you do not want to reimplement the SDK&amp;rsquo;s event types in another language, and you do not want the agent living inside your process where a bad tool call can take your server with it.&lt;/p&gt;&#xA;&lt;p&gt;RPC is the fourth interface in this progression and the one that keeps the isolation. This chapter is about the protocol: what flows in each direction, how you correlate, and the subprotocol that almost nobody realises exists.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Authority, Isolation, and What Makes an Agent Worth Building</title>
      <link>http://programmer.ie/books/pi/36-chapter/</link>
      <pubDate>Fri, 02 Oct 2026 09:00:00 +0100</pubDate>
      <guid>http://programmer.ie/books/pi/36-chapter/</guid>
      <description>&lt;p&gt;Everything so far has been a mechanism. Tools, extensions, events, sessions, modes, protocols. This chapter is about the one question that turns a set of mechanisms into something you would let near a production repository — and about what you are then able to claim.&lt;/p&gt;&#xA;&lt;p&gt;Two claims carry the chapter. &lt;strong&gt;Capability is not authority:&lt;/strong&gt; Pi can do almost anything the account that started it can do, and several documented mechanisms bear on whether it &lt;em&gt;should&lt;/em&gt; do a particular thing. None of them is a sandbox, and all of them are real. And &lt;strong&gt;almost nothing in this book is an authority boundary except an operating-system boundary.&lt;/strong&gt; Everything else is a procedure, a gate, or a convention — and a procedure can be designed well while remaining a procedure.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
