<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>pi examples on Programmer.ie: Modern AI programming</title>
		<link>http://programmer.ie/examples/pi/</link>
		<description>Recent content in pi examples on Programmer.ie: Modern AI programming</description>
		<generator>Hugo</generator>
		<language>en-US</language>
		
		
		
		
			<atom:link href="http://programmer.ie/examples/pi/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>Watch the agent loop call a tool</title>
				<link>http://programmer.ie/examples/pi/01-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/01-chapter/</guid>
				<description>&lt;p&gt;You can observe the loop without credentials. The provider scripts the assistant&amp;rsquo;s&#xA;responses; the &lt;strong&gt;real Agent&lt;/strong&gt; executes the tool and emits the events. This proves&#xA;orchestration, not a real model&amp;rsquo;s choice of tool or interpretation of its result.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;Use Node.js 22.18 or later with built-in TypeScript stripping. In an empty folder:&lt;/p&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#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;npm init -y&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm pkg set type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;module&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install @earendil-works/pi-agent-core@1.0.4 @earendil-works/pi-ai@1.0.4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;npm init -y&#xA;npm pkg set type=module&#xA;npm install @earendil-works/pi-agent-core@1.0.4 @earendil-works/pi-ai@1.0.4&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;Save the complete file below as &lt;code&gt;agent-core.ts&lt;/code&gt;, then run &lt;code&gt;node agent-core.ts&lt;/code&gt;.&#xA;It is an exact copy of the book&amp;rsquo;s canonical example, not a replacement harness.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Resolve a provider credential in precedence order</title>
				<link>http://programmer.ie/examples/pi/03-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/03-chapter/</guid>
				<description>&lt;p&gt;Pi resolves a provider credential from four sources and uses the &lt;strong&gt;first one that&#xA;yields a value&lt;/strong&gt;: a runtime API key, a stored &lt;code&gt;auth.json&lt;/code&gt; credential, an &lt;code&gt;apiKey&lt;/code&gt;&#xA;in &lt;code&gt;models.json&lt;/code&gt;, then the provider&amp;rsquo;s environment variable. This is a&#xA;configuration and decision-table walkthrough of the Chapter 3 tests; every key&#xA;below is a placeholder, and it resolves no real credential.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-four-sources-in-order&#34;&gt;The four sources, in order&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Order&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Source&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Where it comes from&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;1&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;runtime key&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;--api-key&lt;/code&gt;, or a runtime API call&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;2&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;stored credential&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;&amp;lt;agent-dir&amp;gt;/auth.json&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;3&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;model key&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;apiKey&lt;/code&gt; on the provider in &lt;code&gt;&amp;lt;agent-dir&amp;gt;/models.json&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;4&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;environment&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;the provider&amp;rsquo;s environment variable&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;The order surprises people: a key in &lt;code&gt;models.json&lt;/code&gt; sits &lt;em&gt;below&lt;/em&gt; a stored&#xA;credential, not above it. It exists to give a custom or self-hosted model its key;&#xA;it does not override a key you already logged in with.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Calculate a context budget</title>
				<link>http://programmer.ie/examples/pi/04-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/04-chapter/</guid>
				<description>&lt;p&gt;The compaction reference pinned to Pi &lt;strong&gt;1.0.4&lt;/strong&gt; documents the trigger as&#xA;&lt;code&gt;contextTokens &amp;gt; contextWindow - reserveTokens&lt;/code&gt;; the default reserve is 16,384.&#xA;The Chapter 4 tests use a scripted model with a 100,000-token window. These are&#xA;the inputs below: the window is a test model&amp;rsquo;s capacity, not every provider&amp;rsquo;s.&lt;/p&gt;&#xA;&lt;h2 id=&#34;copy-the-calculation&#34;&gt;Copy the calculation&lt;/h2&gt;&#xA;&lt;p&gt;Save this educational calculation as &lt;code&gt;budget.py&lt;/code&gt; and run &lt;code&gt;python budget.py&lt;/code&gt;.&#xA;It evaluates the documented inequality; it does not call or imitate Pi&amp;rsquo;s&#xA;compaction implementation.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Read a session file and its tree</title>
				<link>http://programmer.ie/examples/pi/05-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/05-chapter/</guid>
				<description>&lt;p&gt;A persistent Pi session is a plain JSONL file you can open in any editor. The&#xA;first line is a header, every later line is a tree entry with an &lt;code&gt;id&lt;/code&gt; and a&#xA;&lt;code&gt;parentId&lt;/code&gt;, and the model only ever sees the active branch. This is an&#xA;&lt;strong&gt;illustrative&lt;/strong&gt; trace plus a directory-name calculation, grounded in the&#xA;Chapter 5 tests; it is a drawing of the shape, not a transcript from your machine.&lt;/p&gt;</description>
			</item>
			<item>
				<title>See which tools Pi declares to the model</title>
				<link>http://programmer.ie/examples/pi/06-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/06-chapter/</guid>
				<description>&lt;p&gt;Pi declares an &lt;strong&gt;active tool set&lt;/strong&gt; to the model; that set is what the model may ask for.&#xA;Three inputs compose it: built-in tools, tools registered by extensions, and MCP tools.&#xA;&lt;code&gt;defaultTools&lt;/code&gt; edits the user&amp;rsquo;s selection, &lt;code&gt;--tools&lt;/code&gt; replaces it for one invocation, and&#xA;the same syntax means different things in the two places.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-default-selection-and-its-two-edits&#34;&gt;The default selection and its two edits&lt;/h2&gt;&#xA;&lt;p&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;. Within a&#xA;settings list a plain name &lt;em&gt;replaces&lt;/em&gt; the selection, &lt;code&gt;+name&lt;/code&gt; adds, and &lt;code&gt;-name&lt;/code&gt; removes,&#xA;in order:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Merge user and project settings</title>
				<link>http://programmer.ie/examples/pi/07-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/07-chapter/</guid>
				<description>&lt;p&gt;Pi merges two files: user-level &lt;code&gt;&amp;lt;agent-dir&amp;gt;/settings.json&lt;/code&gt; and, after you trust&#xA;the project, &lt;code&gt;&amp;lt;project&amp;gt;/.pi/settings.json&lt;/code&gt;. Scalars follow ordinary override, but&#xA;&lt;code&gt;defaultTools&lt;/code&gt; has its own rule, and an untrusted project&amp;rsquo;s settings are not read&#xA;at all. The fragments below are small &lt;strong&gt;illustrative&lt;/strong&gt; settings; the Chapter 7&#xA;tests assert each result on real files.&lt;/p&gt;&#xA;&lt;h2 id=&#34;scalar-settings-project-wins&#34;&gt;Scalar settings: project wins&lt;/h2&gt;&#xA;&lt;p&gt;User file:&lt;/p&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;compaction&amp;#34;&lt;/span&gt;: { &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;reserveTokens&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;keepRecentTokens&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5000&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;{&#xA;  &amp;#34;compaction&amp;#34;: { &amp;#34;reserveTokens&amp;#34;: 1000, &amp;#34;keepRecentTokens&amp;#34;: 5000 }&#xA;}&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;Project &lt;code&gt;.pi/settings.json&lt;/code&gt;:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Decide whether to trust a project</title>
				<link>http://programmer.ie/examples/pi/08-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/08-chapter/</guid>
				<description>&lt;p&gt;Pi asks a project-trust question only when the working directory holds something&#xA;that &lt;em&gt;would load&lt;/em&gt;, and the answer decides which protected resources load. The&#xA;order is command-line flag, then a &lt;code&gt;project_trust&lt;/code&gt; extension, then a saved&#xA;decision, then &lt;code&gt;defaultProjectTrust&lt;/code&gt;. Context files such as &lt;code&gt;AGENTS.md&lt;/code&gt; are not a&#xA;trigger and load either way. This is a decision-table walkthrough of the&#xA;Chapter 8 tests.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-triggers-a-decision&#34;&gt;What triggers a decision&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Present from the working directory&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Decision required&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;.pi/settings.json&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;yes&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;.pi/mcp.json&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;yes&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;.pi/extensions&lt;/code&gt;, &lt;code&gt;.pi/skills&lt;/code&gt;, &lt;code&gt;.pi/prompts&lt;/code&gt;, &lt;code&gt;.pi/themes&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;yes&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;.pi/SYSTEM.md&lt;/code&gt;, &lt;code&gt;.pi/APPEND_SYSTEM.md&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;yes&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;.agents/skills&lt;/code&gt; in this or an ancestor directory&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;yes&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;a bare &lt;code&gt;.pi&lt;/code&gt; directory&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;no&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; or &lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;no — a context file&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Trust is requested because something would load, not merely because &lt;code&gt;.pi&lt;/code&gt; exists.&#xA;A context file carries instructions and arrives regardless of the answer, which is&#xA;why declining trust does not stop it.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Inspect the shell prefix and session environment</title>
				<link>http://programmer.ie/examples/pi/09-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/09-chapter/</guid>
				<description>&lt;p&gt;Use Pi &lt;strong&gt;1.0.4&lt;/strong&gt; and its built-in Bash tool. You will compare the model&amp;rsquo;s command&#xA;with your own &lt;code&gt;!&lt;/code&gt; command. The configuration and manual commands below are an&#xA;educational adaptation of the existing Chapter 9 tests; the tests remain the&#xA;canonical executable evidence.&lt;/p&gt;&#xA;&lt;h2 id=&#34;configure-a-visible-prefix&#34;&gt;Configure a visible prefix&lt;/h2&gt;&#xA;&lt;p&gt;Merge this fragment into &lt;code&gt;&amp;lt;project&amp;gt;/.pi/settings.json&lt;/code&gt;, then run &lt;code&gt;/reload&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;shellCommandPrefix&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;export FROM_PREFIX=yes&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;{&#xA;  &amp;#34;shellCommandPrefix&amp;#34;: &amp;#34;export FROM_PREFIX=yes&amp;#34;&#xA;}&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;Pi prepends this prefix to both its built-in &lt;code&gt;bash&lt;/code&gt; tool and user-entered &lt;code&gt;!&lt;/code&gt; or&#xA;&lt;code&gt;!!&lt;/code&gt; commands. It runs again before every command. On native Windows, use Git&#xA;Bash; if needed set &lt;code&gt;shellPath&lt;/code&gt; to &lt;code&gt;C:\Program Files\Git\bin\bash.exe&lt;/code&gt;&#xA;with escaped backslashes in JSON. Do not set it to an interactive profile.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Decide which Pi mechanism a requirement needs</title>
				<link>http://programmer.ie/examples/pi/11-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/11-chapter/</guid>
				<description>&lt;p&gt;Two requirements that sound alike are different kinds of requirement. &amp;ldquo;Confirm before&#xA;anything under &lt;code&gt;migrations/&lt;/code&gt;&amp;rdquo; asks a person. &amp;ldquo;No force pushes&amp;rdquo; must hold whether or&#xA;not a person is there to be asked. Only an extension can act on a tool call before it&#xA;runs, so both belong in one &lt;code&gt;tool_call&lt;/code&gt; handler — but they need different code.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;Use Pi &lt;strong&gt;1.0.4&lt;/strong&gt; and one of the example repository&amp;rsquo;s test runners. The file below is the&#xA;chapter&amp;rsquo;s canonical extension, reproduced exactly:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Turn a Markdown file into a /review command</title>
				<link>http://programmer.ie/examples/pi/12-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/12-chapter/</guid>
				<description>&lt;p&gt;The &lt;code&gt;/review&lt;/code&gt; from chapter 11 is a four-line Markdown file. This page writes the&#xA;smallest prompt template that matters, expands it for a bare &lt;code&gt;/review&lt;/code&gt; and for one&#xA;argument, and then shows the two ordering rules behind &amp;ldquo;my template does not expand&amp;rdquo;.&#xA;This is documented Pi 1.0.4 behaviour, confirmed by a session test.&lt;/p&gt;&#xA;&lt;h2 id=&#34;write-the-template&#34;&gt;Write the template&lt;/h2&gt;&#xA;&lt;p&gt;Save this as &lt;code&gt;~/.pi/agent/prompts/review.md&lt;/code&gt; (or &lt;code&gt;&amp;lt;project&amp;gt;/.pi/prompts/review.md&lt;/code&gt;),&#xA;then run &lt;code&gt;/reload&lt;/code&gt; in an active session. It is the chapter&amp;rsquo;s template, unescaped for&#xA;readability:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Advertise a skill by description, load the body on demand</title>
				<link>http://programmer.ie/examples/pi/13-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/13-chapter/</guid>
				<description>&lt;p&gt;A prompt template waits until you type it. A skill begins when Pi recognises the &lt;em&gt;kind&lt;/em&gt;&#xA;of task. The whole mechanism turns on one field: the system prompt carries every skill&amp;rsquo;s&#xA;name, description and path, never the body, so the description is the entire routing&#xA;surface. This page writes a &lt;code&gt;SKILL.md&lt;/code&gt; and shows exactly what the model is told.&lt;/p&gt;&#xA;&lt;h2 id=&#34;write-the-skill&#34;&gt;Write the skill&lt;/h2&gt;&#xA;&lt;p&gt;A skill is a directory containing &lt;code&gt;SKILL.md&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#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&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;review-guard/&#xA;└── SKILL.md&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;review-guard&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;description&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reviews changed code against this repository&amp;#39;s conventions and runs its own checks. Use when reviewing a diff, a pull request, or uncommitted changes.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&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;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;1.&lt;/span&gt; Run &lt;span style=&#34;color:#e6db74&#34;&gt;`scripts/run-checks.sh`&lt;/span&gt; and read the output before reviewing anything.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;2.&lt;/span&gt; Read &lt;span style=&#34;color:#e6db74&#34;&gt;`references/checklist.md`&lt;/span&gt; and apply it to the diff.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3. Report findings ordered by severity, each with a file path.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;---&#xA;name: review-guard&#xA;description: Reviews changed code against this repository&amp;#39;s conventions and runs its own checks. Use when reviewing a diff, a pull request, or uncommitted changes.&#xA;---&#xA;&#xA;# Review guard&#xA;&#xA;1. Run `scripts/run-checks.sh` and read the output before reviewing anything.&#xA;2. Read `references/checklist.md` and apply it to the diff.&#xA;3. Report findings ordered by severity, each with a file path.&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;Place it in your user or project skills directory and run Pi from a location where it is&#xA;discoverable. The description states both &lt;em&gt;what&lt;/em&gt; the skill does and &lt;em&gt;when&lt;/em&gt; it applies;&#xA;&amp;ldquo;Reviews code&amp;rdquo; gives the model nothing to match against &amp;ldquo;implement this&amp;rdquo;, while the text&#xA;above does.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Give a skill files and a check script it can run</title>
				<link>http://programmer.ie/examples/pi/14-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/14-chapter/</guid>
				<description>&lt;p&gt;The review guard&amp;rsquo;s checklist is forty items; inlining it in &lt;code&gt;SKILL.md&lt;/code&gt; would load all&#xA;forty every time the skill fires. Bundle it as a file the body names instead. A bundled&#xA;file is a file on disk — it reaches the context only when the model reads it with its&#xA;own tool. The bundled script in this example needs a POSIX shell, so on Windows run it&#xA;under Git Bash.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Register a tool and a command from an extension</title>
				<link>http://programmer.ie/examples/pi/15-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/15-chapter/</guid>
				<description>&lt;p&gt;An extension is a TypeScript module whose default export receives &lt;code&gt;ExtensionAPI&lt;/code&gt;. Registering a tool&#xA;makes it active and declared to the model, while registering a command adds a &lt;code&gt;/&lt;/code&gt; command beside the&#xA;built-ins. This page loads both the smallest command extension and the running example&amp;rsquo;s&#xA;&lt;code&gt;review_scope&lt;/code&gt; tool; the only substitution is the model, a faux provider replaying a script.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;Pi &lt;strong&gt;1.0.4&lt;/strong&gt; loads local TypeScript with &lt;code&gt;jiti&lt;/code&gt;, so there is no build step. The command extension&#xA;below is the whole file, reproduced exactly:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Block a force push with a tool_call handler</title>
				<link>http://programmer.ie/examples/pi/16-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/16-chapter/</guid>
				<description>&lt;p&gt;A &lt;code&gt;tool_call&lt;/code&gt; handler runs before the tool it names, so it can refuse the call. The guard on this&#xA;page blocks destructive git commands — force pushes, &lt;code&gt;reset --hard&lt;/code&gt;, and &lt;code&gt;git clean -f&lt;/code&gt; — and when&#xA;there is no UI to ask, it refuses rather than allowing silently. The cases run through a faux&#xA;provider in a real session, so you see the guard, not a real model.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;The guard is the whole file, reproduced exactly:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Return structured tool results and route nested calls</title>
				<link>http://programmer.ie/examples/pi/17-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/17-chapter/</guid>
				<description>&lt;p&gt;A tool that executes returns data as well as text: a machine-readable &lt;code&gt;structuredContent&lt;/code&gt; for&#xA;scripts alongside the &lt;code&gt;content&lt;/code&gt; the model reads. This page&amp;rsquo;s tools declare risk with annotations and&#xA;run one another through &lt;code&gt;ctx.executeTool()&lt;/code&gt;, and those nested calls pass through the same &lt;code&gt;tool_call&lt;/code&gt;&#xA;gate as model-issued calls. The behaviour below is &lt;strong&gt;observed&lt;/strong&gt; through a real session; the model is&#xA;a faux provider replaying a script.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;A non-zero exit is a result, not a failed tool: &lt;code&gt;runCommand&lt;/code&gt; in &lt;code&gt;tools.ts&lt;/code&gt; catches &lt;code&gt;exec&lt;/code&gt;&amp;rsquo;s&#xA;rejection and returns the exit code as data. When the result is data, declare an &lt;code&gt;outputSchema&lt;/code&gt; and&#xA;return a matching &lt;code&gt;structuredContent&lt;/code&gt;; the caller below reads the value back from&#xA;&lt;code&gt;outcome.result&lt;/code&gt;. Annotations are hints a permission extension can read — with no hints,&#xA;&lt;code&gt;needsApproval&lt;/code&gt; is true (&lt;code&gt;approval.ts&lt;/code&gt;):&lt;/p&gt;</description>
			</item>
			<item>
				<title>Make what the model knows follow the active tools</title>
				<link>http://programmer.ie/examples/pi/18-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/18-chapter/</guid>
				<description>&lt;p&gt;Registering &lt;code&gt;run_checks&lt;/code&gt; has not told the model it exists. This example derives&#xA;prompt guidance from &lt;code&gt;pi.getActiveTools()&lt;/code&gt; and bounds a settle guard to a single&#xA;nudge — all observed over a scripted model, not a real one.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;Use Pi &lt;strong&gt;1.0.4&lt;/strong&gt; with the example repository&amp;rsquo;s test runner. These are excerpts of&#xA;the canonical extensions:&lt;/p&gt;&#xA;&lt;!-- pi-excerpt: examples/ch18-knowledge/review-guard-section.ts --&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;pi&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;before_agent_start&amp;#34;&lt;/span&gt;, (&lt;span style=&#34;color:#a6e22e&#34;&gt;event&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// getActiveTools(), not getAllTools(). getAllTools() reports every&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// *registered* tool, so a tool the session disabled would still be&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// described here — and the model would be told to use something it&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// cannot call. The active set is what is declared to the model.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;active&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pi&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getActiveTools&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;active&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;includes&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;run_checks&amp;#34;&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// Delete rather than leave stale: a section written for a previous&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// turn outlives the condition that produced it.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;delete&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;event&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;systemPromptOptions&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sections&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;review_guard&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;event&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;systemPromptOptions&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sections&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;review_guard&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;- `run_checks` runs this repository&amp;#39;s type check and unit tests. &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Use it instead of running a command yourself before reporting on a change. &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;- Force pushes are blocked by an extension. If a push is refused, do not retry with a different form.&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;&#x9;pi.on(&amp;#34;before_agent_start&amp;#34;, (event) =&amp;gt; {&#xA;&#x9;&#x9;// getActiveTools(), not getAllTools(). getAllTools() reports every&#xA;&#x9;&#x9;// *registered* tool, so a tool the session disabled would still be&#xA;&#x9;&#x9;// described here — and the model would be told to use something it&#xA;&#x9;&#x9;// cannot call. The active set is what is declared to the model.&#xA;&#x9;&#x9;const active = pi.getActiveTools();&#xA;&#x9;&#x9;if (!active.includes(&amp;#34;run_checks&amp;#34;)) {&#xA;&#x9;&#x9;&#x9;// Delete rather than leave stale: a section written for a previous&#xA;&#x9;&#x9;&#x9;// turn outlives the condition that produced it.&#xA;&#x9;&#x9;&#x9;delete event.systemPromptOptions.sections.review_guard;&#xA;&#x9;&#x9;&#x9;return;&#xA;&#x9;&#x9;}&#xA;&#xA;&#x9;&#x9;event.systemPromptOptions.sections.review_guard =&#xA;&#x9;&#x9;&#x9;&amp;#34;- `run_checks` runs this repository&amp;#39;s type check and unit tests. &amp;#34; &amp;#43;&#xA;&#x9;&#x9;&#x9;&amp;#34;Use it instead of running a command yourself before reporting on a change. &amp;#34; &amp;#43;&#xA;&#x9;&#x9;&#x9;&amp;#34;- Force pushes are blocked by an extension. If a push is refused, do not retry with a different form.&amp;#34;;&#xA;&#x9;});&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The section tracks the &lt;em&gt;active&lt;/em&gt; set, not the registered one: &lt;code&gt;pi.getAllTools()&lt;/code&gt;&#xA;reports every tool the session has defined, so a disabled tool would still be&#xA;described. The same handler can write a &lt;code&gt;tool_guidance&lt;/code&gt; section for the built-in&#xA;tools, dropping it when nothing matches.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Persist a guard&#39;s block count as a session entry</title>
				<link>http://programmer.ie/examples/pi/19-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/19-chapter/</guid>
				<description>&lt;p&gt;A module-level &lt;code&gt;let&lt;/code&gt; dies with the process: &lt;code&gt;/reload&lt;/code&gt; and resume both reset it. The&#xA;fix is to use the durable store Pi already hands you. This example logs every&#xA;blocked write as a &lt;code&gt;custom&lt;/code&gt; session entry that the model never sees, and rebuilds&#xA;the count from the active branch at &lt;code&gt;session_start&lt;/code&gt; and on navigation. The claims&#xA;are observed over a scripted model and a recording UI.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;Use Pi &lt;strong&gt;1.0.4&lt;/strong&gt; and one of the example repository&amp;rsquo;s test runners. The file below&#xA;is an excerpt of the chapter&amp;rsquo;s canonical &lt;code&gt;guard-blocks.ts&lt;/code&gt;:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Add a slash command and a custom screen that respect the mode rule</title>
				<link>http://programmer.ie/examples/pi/20-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/20-chapter/</guid>
				<description>&lt;p&gt;Whether a command can do anything at all depends on its mode: dialogs need&#xA;&lt;code&gt;ctx.hasUI&lt;/code&gt;, custom screens need a real terminal. This example is the smallest&#xA;&lt;code&gt;/guard&lt;/code&gt; command, that two-guard rule, and a column-sized component — all observed&#xA;on a scripted model.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;Use Pi &lt;strong&gt;1.0.4&lt;/strong&gt; and one of the example repository&amp;rsquo;s test runners. The smallest&#xA;command is one registration, loaded with &lt;code&gt;pi -e ./guard.ts&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;!-- pi-copy: examples/ch20-ui/guard-minimal.ts --&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;ExtensionAPI&lt;/span&gt; } &lt;span style=&#34;color:#66d9ef&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@earendil-works/pi-coding-agent&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;pi&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;ExtensionAPI&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;pi&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;registerCommand&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;guard&amp;#34;&lt;/span&gt;, {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;description&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Inspect and configure the path guard&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ui&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;notify&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`guard received: &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;`&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;info&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;import type { ExtensionAPI } from &amp;#34;@earendil-works/pi-coding-agent&amp;#34;;&#xA;&#xA;export default function (pi: ExtensionAPI) {&#xA;&#x9;pi.registerCommand(&amp;#34;guard&amp;#34;, {&#xA;&#x9;&#x9;description: &amp;#34;Inspect and configure the path guard&amp;#34;,&#xA;&#x9;&#x9;handler: async (args, ctx) =&amp;gt; {&#xA;&#x9;&#x9;&#x9;ctx.ui.notify(`guard received: &amp;#34;${args}&amp;#34;`, &amp;#34;info&amp;#34;);&#xA;&#x9;&#x9;},&#xA;&#x9;});&#xA;}&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The full command, from &lt;code&gt;guard-ui.ts&lt;/code&gt;, branches on the two questions — dialogs work&#xA;wherever &lt;code&gt;ctx.hasUI&lt;/code&gt; is true, and with no UI it says so on the way out:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Gate MCP tools by their full mcp__ name and treat annotations as hints</title>
				<link>http://programmer.ie/examples/pi/21-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/21-chapter/</guid>
				<description>&lt;p&gt;An MCP server&amp;rsquo;s tool arrives as &lt;code&gt;mcp__&amp;lt;server&amp;gt;__&amp;lt;tool&amp;gt;&lt;/code&gt;, so a &lt;code&gt;tool_call&lt;/code&gt; gate&#xA;keyed on the bare tool name silently lets every remote call through. This example&#xA;is a deny-list gate that keys on the full name, the registration pair that adds a&#xA;server for one session, and the difference between annotations a server declares&#xA;about itself and the exposure that decides whether the model is told the tool&#xA;exists. Only the far end and the model are faked; naming, exposure and gating are&#xA;Pi&amp;rsquo;s.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ship an extension, skills, and prompts as one Pi package</title>
				<link>http://programmer.ie/examples/pi/22-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/22-chapter/</guid>
				<description>&lt;p&gt;A Pi package is the distribution unit for everything you have written: an&#xA;extension, its skills, prompts and themes arrive as one directory or npm package&#xA;instead of a zip of a &lt;code&gt;.pi&lt;/code&gt; folder that breaks on someone else&amp;rsquo;s machine. There is&#xA;no standalone code file for this chapter, so this page is a command walkthrough&#xA;with placeholder names, grounded in what the shipped-binary test asserts.&lt;/p&gt;&#xA;&lt;h2 id=&#34;install-list-remove&#34;&gt;Install, list, remove&lt;/h2&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#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;pi install npm:@example/pi-tools@1.0.0              &lt;span style=&#34;color:#75715e&#34;&gt;# pinned npm version&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi install git:github.com/example/pi-tools@v1       &lt;span style=&#34;color:#75715e&#34;&gt;# cloned, reconciled to the ref&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi install ./local-package                          &lt;span style=&#34;color:#75715e&#34;&gt;# loaded from its path; nothing copied&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi list                                             &lt;span style=&#34;color:#75715e&#34;&gt;# what resolves, as one instance&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi remove &amp;lt;source&amp;gt;                                  &lt;span style=&#34;color:#75715e&#34;&gt;# and its resources stop loading&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi -e npm:@example/pi-tools                         &lt;span style=&#34;color:#75715e&#34;&gt;# try one invocation; no settings write&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi install --local ./local-package                  &lt;span style=&#34;color:#75715e&#34;&gt;# writes the project&amp;#39;s .pi/settings.json&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;pi install npm:@example/pi-tools@1.0.0              # pinned npm version&#xA;pi install git:github.com/example/pi-tools@v1       # cloned, reconciled to the ref&#xA;pi install ./local-package                          # loaded from its path; nothing copied&#xA;pi list                                             # what resolves, as one instance&#xA;pi remove &amp;lt;source&amp;gt;                                  # and its resources stop loading&#xA;pi -e npm:@example/pi-tools                         # try one invocation; no settings write&#xA;pi install --local ./local-package                  # writes the project&amp;#39;s .pi/settings.json&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;A local install records a path relative to the settings file and copies nothing;&#xA;&lt;code&gt;--local&lt;/code&gt; writes under the project&amp;rsquo;s &lt;code&gt;.pi&lt;/code&gt; and loads only after project trust is&#xA;granted. Identity by resolved path — a local package by its absolute path, a git&#xA;package by repository URL without the ref — means the same package listed twice&#xA;loads once.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Take over compaction summarization</title>
				<link>http://programmer.ie/examples/pi/23-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/23-chapter/</guid>
				<description>&lt;p&gt;Compaction changes what the next model request is &lt;strong&gt;built from&lt;/strong&gt;, never what the&#xA;session file holds. On Pi &lt;strong&gt;1.0.4&lt;/strong&gt; an extension can supply the summary through&#xA;&lt;code&gt;session_before_compact&lt;/code&gt; while Pi still chooses the cut point; every entry stays in&#xA;the file, and navigating back before the compaction sends the originals again.&lt;/p&gt;&#xA;&lt;h2 id=&#34;supply-the-summary-keep-the-cut-point&#34;&gt;Supply the summary, keep the cut point&lt;/h2&gt;&#xA;&lt;p&gt;An excerpt of &lt;code&gt;custom-summary.ts&lt;/code&gt;: it serialises the messages Pi is about to&#xA;replace, returns them as the summary, and echoes back Pi&amp;rsquo;s own &lt;code&gt;firstKeptEntryId&lt;/code&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Branch the session tree</title>
				<link>http://programmer.ie/examples/pi/24-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/24-chapter/</guid>
				<description>&lt;p&gt;A stored session is a tree of entries linked by &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;parentId&lt;/code&gt;, and the&#xA;current position is the leaf. &lt;code&gt;/tree&lt;/code&gt; moves inside that tree, &lt;code&gt;/fork&lt;/code&gt; starts a new&#xA;session from an earlier prompt, and &lt;code&gt;/clone&lt;/code&gt; copies the active branch into a new&#xA;session. The trace below is &lt;strong&gt;illustrative&lt;/strong&gt;; the claims it draws are the ones&#xA;&lt;code&gt;branching.test.ts&lt;/code&gt; asserts on 1.0.4, with &lt;code&gt;/fork&lt;/code&gt; and &lt;code&gt;/clone&lt;/code&gt; on the shipped&#xA;binary.&lt;/p&gt;&#xA;&lt;h2 id=&#34;choose-the-command&#34;&gt;Choose the command&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Action&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Result&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Use it when&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;/tree&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;moves within the current session file&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;related alternatives belong together&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;/fork&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;new session from an earlier user prompt&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;the alternative becomes separate work&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;/clone&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;copy of the active branch in a new session&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;you want a separate copy of current state&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;a-tiny-branch-as-entries&#34;&gt;A tiny branch, as entries&lt;/h2&gt;&#xA;&lt;p&gt;The shared history is linear until question B is edited. Submitting the edited&#xA;prompt creates a &lt;strong&gt;sibling&lt;/strong&gt; — two children of the same parent, one session file.&#xA;The abandoned branch is not sent, and is not gone:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Steer a run without interrupting it</title>
				<link>http://programmer.ie/examples/pi/25-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/25-chapter/</guid>
				<description>&lt;p&gt;Typing while Pi works is not an interruption: a steering message enters &lt;strong&gt;after the&#xA;current turn&amp;rsquo;s tool calls and before the next request&lt;/strong&gt;, a follow-up waits until the&#xA;agent would otherwise stop, and Escape aborts and returns your queued text. The&#xA;walkthrough below mirrors &lt;code&gt;ch25-queue/queue.test.ts&lt;/code&gt; on 1.0.4, which queues&#xA;messages into a real session running a deliberately slow tool with a scripted&#xA;provider.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-timeline&#34;&gt;The timeline&lt;/h2&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#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;turn 1   prompt &amp;#34;start&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         the model asks for the slow tool; its tool calls run&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         you type steer &amp;#34;change direction&amp;#34;      → queued, not yet readable by the model&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;turn_end after the last tool result&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         next request  system | user:start | assistant | toolResult | user:change direction&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;turn 2   the model answers the correction&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         a follow-up queued earlier is still waiting&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;agent_settled  nothing left outstanding → the follow-up is finally delivered&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;turn 1   prompt &amp;#34;start&amp;#34;&#xA;         the model asks for the slow tool; its tool calls run&#xA;         you type steer &amp;#34;change direction&amp;#34;      → queued, not yet readable by the model&#xA;turn_end after the last tool result&#xA;         next request  system | user:start | assistant | toolResult | user:change direction&#xA;turn 2   the model answers the correction&#xA;         a follow-up queued earlier is still waiting&#xA;agent_settled  nothing left outstanding → the follow-up is finally delivered&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The request shape in the middle is exactly what the test asserts: steering landed&#xA;after the tool result and before the next prompt (&lt;code&gt;shape()&lt;/code&gt; in the test omits the&#xA;system message). One ordering you cannot guess from the keys: &lt;strong&gt;steering drains&#xA;before follow-ups&lt;/strong&gt;, even when the follow-up was queued first.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Name the eight message roles</title>
				<link>http://programmer.ie/examples/pi/26-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/26-chapter/</guid>
				<description>&lt;p&gt;Pi uses the &lt;code&gt;AgentMessage&lt;/code&gt; union in SDK state, lifecycle events, RPC responses, and&#xA;persisted session entries — one type across four surfaces. On &lt;strong&gt;1.0.4&lt;/strong&gt; the coding&#xA;agent extends it with four roles, and applications can add still more by declaration&#xA;merging. The declaration below reproduces the exported types from&#xA;&lt;code&gt;ch26-message-types/declared.ts&lt;/code&gt;; &lt;code&gt;assert-equal.ts&lt;/code&gt; checks those reproductions two&#xA;ways against the real exports.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-eight-roles&#34;&gt;The eight roles&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Role&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;What it is for&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;system&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;the prompt and tool state; later system messages patch it&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;user&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;a prompt: a string or an array of text/image blocks&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;assistant&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;content blocks, &lt;code&gt;usage&lt;/code&gt;, &lt;code&gt;stopReason&lt;/code&gt;, the three-way model identity&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;toolResult&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;a tool&amp;rsquo;s result, joined to its call by &lt;code&gt;toolCallId&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;bashExecution&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;a direct shell command — not an LLM tool result&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;custom&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;an extension context message, converted to a user message&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;branchSummary&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;the summary a &lt;code&gt;branch_summary&lt;/code&gt; entry becomes in context&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;compactionSummary&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;the summary a &lt;code&gt;compaction&lt;/code&gt; entry becomes in context&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;the-declaration-that-carries-the-caveat&#34;&gt;The declaration that carries the caveat&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;SystemMessage&lt;/code&gt; is the role with the book&amp;rsquo;s most famous mismatch, so it is the one&#xA;worth showing. An excerpt of the declared reproduction — a declaration, not&#xA;executable code:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Read a session file with the chapter&#39;s program</title>
				<link>http://programmer.ie/examples/pi/27-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/27-chapter/</guid>
				<description>&lt;p&gt;A Pi session is a JSONL file: one JSON object per line, a &lt;code&gt;session&lt;/code&gt; header first,&#xA;then entries linked by &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;parentId&lt;/code&gt;. This format is the &lt;strong&gt;shared source&lt;/strong&gt;&#xA;for the session claims in Chapters 5, 6, 23 and 24 — they reference its&#xA;declaration rather than redefining it — so a working reader is the most direct way&#xA;to see what they all mean. Below is Chapter 27&amp;rsquo;s own reading program on &lt;strong&gt;1.0.4&lt;/strong&gt;,&#xA;reproduced exactly.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Separate discovery from admission in the context pipeline</title>
				<link>http://programmer.ie/examples/pi/28-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/28-chapter/</guid>
				<description>&lt;p&gt;&amp;ldquo;the model read my AGENTS.md&amp;rdquo; hides four facts: the file exists, Pi&#xA;discovered it, something admitted it, and it is in the request the model&#xA;receives. Each fails on its own and each has a different owner. The excerpts&#xA;below ran as the Chapter 28 tests against a temporary tree — default loader,&#xA;no model.&lt;/p&gt;&#xA;&lt;h2 id=&#34;discovery-a-walk-up-not-a-scan-down&#34;&gt;Discovery: a walk up, not a scan down&lt;/h2&gt;&#xA;&lt;p&gt;Starting Pi in &lt;code&gt;repo/src/billing&lt;/code&gt;, discovery walks up from the working&#xA;directory to the agent directory — never sideways or down, so&#xA;&lt;code&gt;repo/docs/AGENTS.md&lt;/code&gt; does not apply to work started in &lt;code&gt;repo/src/billing&lt;/code&gt;&#xA;even though both are in one repository:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Normalise a provider&#39;s overflow message so Pi can recover</title>
				<link>http://programmer.ie/examples/pi/29-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/29-chapter/</guid>
				<description>&lt;p&gt;A failed request has three different answers: repeat it (transient), repair&#xA;the context and retry once (overflow), or stop. Pi recognises its own&#xA;overflow signal; a custom provider&amp;rsquo;s message may not. The extension below maps&#xA;only that provider&amp;rsquo;s overflow text onto the marker Pi recognises, so recovery&#xA;can run. Everything here was observed on &lt;strong&gt;1.0.4&lt;/strong&gt; against a scripted provider&#xA;in a session with compaction enabled — a real &lt;code&gt;AgentSession&lt;/code&gt;, no real model.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Drive one agent through three interfaces</title>
				<link>http://programmer.ie/examples/pi/31-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/31-chapter/</guid>
				<description>&lt;p&gt;The terminal is one of five ways to drive the agent, and switching drivers&#xA;changes how you watch it, not what it is. Two tiny drivers below put that&#xA;claim in front of the same agent-core agent, and a shipped-binary test pushes&#xA;it across print, JSON and RPC. Everything here ran on &lt;strong&gt;1.0.4&lt;/strong&gt; under a&#xA;scripted model — it exercises how each interface observes the agent, not a&#xA;provider&amp;rsquo;s output.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Run Pi with no person attached</title>
				<link>http://programmer.ie/examples/pi/32-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/32-chapter/</guid>
				<description>&lt;p&gt;A CI job and a pre-commit hook both need Pi with no terminal. The mode&#xA;determines how input enters the agent, how output is exposed and how a failure&#xA;is reported. Every claim below was observed on &lt;strong&gt;1.0.4&lt;/strong&gt; by driving the&#xA;shipped &lt;code&gt;pi&lt;/code&gt; binary as a child process with a scripted model — the real&#xA;command line, mode selection and exit codes, with no credential and no&#xA;provider.&lt;/p&gt;&#xA;&lt;h2 id=&#34;pick-the-mode&#34;&gt;Pick the mode&lt;/h2&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#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;pi --print &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Summarize the changes&amp;#34;&lt;/span&gt;                        &lt;span style=&#34;color:#75715e&#34;&gt;# one final string, then exit&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi --mode json &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Review this repository&amp;#34;&lt;/span&gt; &amp;gt; events.jsonl    &lt;span style=&#34;color:#75715e&#34;&gt;# events on stdout&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git diff | pi --print &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Review this change&amp;#34;&lt;/span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;# piped stdin, prepended to the prompt&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi --mode json &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@notes.md&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;summarise&amp;#34;&lt;/span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;# @path includes a text file&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi --mode json -- &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-5 degrees is cold&amp;#34;&lt;/span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;# -- stops option parsing&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pi --print &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Review this change&amp;#34;&lt;/span&gt; --tools read,grep,find,ls --no-session&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;pi --print &amp;#34;Summarize the changes&amp;#34;                        # one final string, then exit&#xA;pi --mode json &amp;#34;Review this repository&amp;#34; &amp;gt; events.jsonl    # events on stdout&#xA;git diff | pi --print &amp;#34;Review this change&amp;#34;                # piped stdin, prepended to the prompt&#xA;pi --mode json &amp;#34;@notes.md&amp;#34; &amp;#34;summarise&amp;#34;                    # @path includes a text file&#xA;pi --mode json -- &amp;#34;-5 degrees is cold&amp;#34;                    # -- stops option parsing&#xA;pi --print &amp;#34;Review this change&amp;#34; --tools read,grep,find,ls --no-session&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;With terminal stdin and stdout, Pi opens the terminal UI unless a mode is&#xA;selected. When either stream is redirected and neither JSON nor RPC is&#xA;selected, it chooses print mode — so a script that merely pipes input and&#xA;captures output gets print mode implicitly. Be explicit anyway; a script that&#xA;relies on TTY detection changes behaviour when run from an interactive shell.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Read the JSON event stream record by record</title>
				<link>http://programmer.ie/examples/pi/33-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/33-chapter/</guid>
				<description>&lt;p&gt;&lt;code&gt;pi --mode json&lt;/code&gt; is not a single JSON result: it is a stream of records, each&#xA;one JSON object terminated by LF, with stdout carrying nothing else. The&#xA;records below are illustrative drawings of that shape — the calling&#xA;conventions themselves were observed on &lt;strong&gt;1.0.4&lt;/strong&gt; by running the shipped&#xA;binary under a scripted model and inspecting the stream.&lt;/p&gt;&#xA;&lt;h2 id=&#34;framing-rules&#34;&gt;Framing rules&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Split only on LF; strip an optional preceding carriage return so CRLF input parses.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;U+2028 inside a string is legal JSON, not a record boundary.&lt;/strong&gt; A&#xA;&lt;code&gt;readline&lt;/code&gt;-style reader splits a record in half; the test demonstrates this&#xA;on real output.&lt;/li&gt;&#xA;&lt;li&gt;The first record is the session header, version 3, and it is not part of&#xA;the tree.&lt;/li&gt;&#xA;&lt;li&gt;Read stdout continuously — a reader that stops consuming records can stall&#xA;Pi when the pipe buffer fills. Stdout carries JSONL only; diagnostics go to&#xA;stderr.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;illustrative-records&#34;&gt;Illustrative records&lt;/h2&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;session&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2024-12-03T14:00:00.000Z&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;cwd&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/project&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;agent_start&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;message_update&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;usage&amp;#34;&lt;/span&gt;:{},&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;assistantMessageEvent&amp;#34;&lt;/span&gt;:{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text_delta&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;contentIndex&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;delta&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;the quick &amp;#34;&lt;/span&gt;}}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tool_execution_start&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;toolCallId&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;c1&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;toolName&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bash&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;:{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;command&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;echo hi&amp;#34;&lt;/span&gt;}}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tool_execution_end&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;toolCallId&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;c1&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;toolName&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bash&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;:{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;:[{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hi&amp;#34;&lt;/span&gt;}]},&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;isError&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;message_end&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;:{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;assistant&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;:[{&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hi&amp;#34;&lt;/span&gt;}],&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;stopReason&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stop&amp;#34;&lt;/span&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;{&amp;#34;type&amp;#34;:&amp;#34;session&amp;#34;,&amp;#34;version&amp;#34;:3,&amp;#34;id&amp;#34;:&amp;#34;uuid&amp;#34;,&amp;#34;timestamp&amp;#34;:&amp;#34;2024-12-03T14:00:00.000Z&amp;#34;,&amp;#34;cwd&amp;#34;:&amp;#34;/project&amp;#34;}&#xA;{&amp;#34;type&amp;#34;:&amp;#34;agent_start&amp;#34;}&#xA;{&amp;#34;type&amp;#34;:&amp;#34;message_update&amp;#34;,&amp;#34;usage&amp;#34;:{},&amp;#34;assistantMessageEvent&amp;#34;:{&amp;#34;type&amp;#34;:&amp;#34;text_delta&amp;#34;,&amp;#34;contentIndex&amp;#34;:0,&amp;#34;delta&amp;#34;:&amp;#34;the quick &amp;#34;}}&#xA;{&amp;#34;type&amp;#34;:&amp;#34;tool_execution_start&amp;#34;,&amp;#34;toolCallId&amp;#34;:&amp;#34;c1&amp;#34;,&amp;#34;toolName&amp;#34;:&amp;#34;bash&amp;#34;,&amp;#34;args&amp;#34;:{&amp;#34;command&amp;#34;:&amp;#34;echo hi&amp;#34;}}&#xA;{&amp;#34;type&amp;#34;:&amp;#34;tool_execution_end&amp;#34;,&amp;#34;toolCallId&amp;#34;:&amp;#34;c1&amp;#34;,&amp;#34;toolName&amp;#34;:&amp;#34;bash&amp;#34;,&amp;#34;result&amp;#34;:{&amp;#34;content&amp;#34;:[{&amp;#34;type&amp;#34;:&amp;#34;text&amp;#34;,&amp;#34;text&amp;#34;:&amp;#34;hi&amp;#34;}]},&amp;#34;isError&amp;#34;:false}&#xA;{&amp;#34;type&amp;#34;:&amp;#34;message_end&amp;#34;,&amp;#34;message&amp;#34;:{&amp;#34;role&amp;#34;:&amp;#34;assistant&amp;#34;,&amp;#34;content&amp;#34;:[{&amp;#34;type&amp;#34;:&amp;#34;text&amp;#34;,&amp;#34;text&amp;#34;:&amp;#34;hi&amp;#34;}],&amp;#34;stopReason&amp;#34;:&amp;#34;stop&amp;#34;}}&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;These are &lt;strong&gt;illustrative&lt;/strong&gt;: ids, timestamps and text are placeholders; the&#xA;fields follow the asserted contracts, not a captured transcript.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Embed an agent in your process with SDK sessions</title>
				<link>http://programmer.ie/examples/pi/34-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/34-chapter/</guid>
				<description>&lt;p&gt;An SDK session moves the agent into your own Node.js or Bun process: &lt;code&gt;createAgentSession()&lt;/code&gt; returns a typed &lt;code&gt;AgentSession&lt;/code&gt;, and the events you once parsed out of a pipe arrive as objects that keep the cumulative &lt;code&gt;partial&lt;/code&gt; snapshots the JSON stream strips. Inside your process, rules the terminal used to handle silently become yours to state. Everything here is &lt;strong&gt;observed&lt;/strong&gt; — &lt;code&gt;sdk.test.ts&lt;/code&gt; drives a real &lt;code&gt;AgentSession&lt;/code&gt; whose provider is scripted, on Pi &lt;strong&gt;1.0.4&lt;/strong&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Drive a live Pi subprocess over JSONL</title>
				<link>http://programmer.ie/examples/pi/35-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/35-chapter/</guid>
				<description>&lt;p&gt;RPC keeps Pi in a separate process and talks to it as newline-delimited JSON, so you&#xA;decide the lifetime of the child — across a process you wait for an event, not a&#xA;promise. The price is a protocol: command and response records, a stream of session&#xA;events that carry no command id, and a fourth family, extension UI records, that&#xA;travels in both directions. Everything below is &lt;strong&gt;observed&lt;/strong&gt; against the &lt;strong&gt;shipped&#xA;binary&lt;/strong&gt;, on Pi &lt;strong&gt;1.0.4&lt;/strong&gt;, by a hand-written client that splits on LF only.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Get one typed answer from one model call</title>
				<link>http://programmer.ie/examples/pi/36-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/36-chapter/</guid>
				<description>&lt;p&gt;Most of what an application needs from a model is one question and one answer.&#xA;&lt;code&gt;assess.ts&lt;/code&gt; is that rung — &lt;strong&gt;layer 1, model/provider access&lt;/strong&gt;, the floor of the&#xA;five-rung stack: one request, no loop, no session, no terminal. A tool declaration is&#xA;a schema the model fills in, and &lt;code&gt;validateToolCall()&lt;/code&gt; makes the answer a typed value&#xA;or an exception, all &lt;strong&gt;observed&lt;/strong&gt; under scripted responses on Pi &lt;strong&gt;1.0.4&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;Use Pi &lt;strong&gt;1.0.4&lt;/strong&gt; and the example repository&amp;rsquo;s test runner. The file below is the&#xA;chapter&amp;rsquo;s canonical source, reproduced exactly:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Run the agent loop on its own with a corpus tool</title>
				<link>http://programmer.ie/examples/pi/37-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/37-chapter/</guid>
				<description>&lt;p&gt;&lt;code&gt;research-agent.ts&lt;/code&gt; wraps &lt;code&gt;pi-agent-core&lt;/code&gt;&amp;rsquo;s &lt;code&gt;Agent&lt;/code&gt; — the class the coding agent is&#xA;built on — with one corpus-reading tool and an injected stream function: &lt;strong&gt;layer 2,&#xA;the agent core&lt;/strong&gt;, with the coding agent&amp;rsquo;s sessions, trust gate, extensions and&#xA;terminal absent. Unlike chapter 1&amp;rsquo;s self-contained printing script, this is a library&#xA;function: the corpus, model and stream function come from the caller, and the&#xA;transcript is data you assert on. All below is &lt;strong&gt;observed&lt;/strong&gt; under scripted responses&#xA;on Pi &lt;strong&gt;1.0.4&lt;/strong&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Return a schema-valid value from a bounded model loop</title>
				<link>http://programmer.ie/examples/pi/38-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/38-chapter/</guid>
				<description>&lt;p&gt;A stochastic step is a typed function: text in, a value that matches your TypeBox&#xA;schema out, and no third outcome. The model can only finish by calling a &lt;code&gt;submit&lt;/code&gt;&#xA;tool whose parameters are that schema, so prose cannot leak past the seam. This page&#xA;runs the canonical &lt;code&gt;step.ts&lt;/code&gt; on &lt;strong&gt;pi-agent-core 1.0.4&lt;/strong&gt; with a scripted provider.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;The only way out is the &lt;code&gt;submit&lt;/code&gt; tool; &lt;code&gt;terminate: true&lt;/code&gt; is the hint that ends the&#xA;loop (excerpt of the canonical &lt;code&gt;step.ts&lt;/code&gt;, full file linked below):&lt;/p&gt;</description>
			</item>
			<item>
				<title>Map each agent-core hook by what it can still decide</title>
				<link>http://programmer.ie/examples/pi/39-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/39-chapter/</guid>
				<description>&lt;p&gt;A hook is a real seam only for decisions it can still make when it fires.&#xA;&lt;code&gt;beforeToolCall&lt;/code&gt; is the one hook that can refuse an effect; &lt;code&gt;afterToolCall&lt;/code&gt; rewrites&#xA;the story but cannot undo the deed. This page reproduces the observed order on&#xA;&lt;strong&gt;pi-agent-core 1.0.4&lt;/strong&gt;, then the seam matrix that says which decisions are still&#xA;cheap where.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-order-observed&#34;&gt;The order, observed&lt;/h2&gt;&#xA;&lt;p&gt;One tool-using run, a recorder on every hook — the exact assertion from the test:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Compose a pipeline with the weakest component at each position</title>
				<link>http://programmer.ie/examples/pi/40-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/40-chapter/</guid>
				<description>&lt;p&gt;Composition does not imply agency. A claim checker needs four kinds of component — a&#xA;plain function, a typed model call, a membership check and an agent — and each one is&#xA;used only where the weaker ones cannot decide. This page shows the load-bearing parts&#xA;of the canonical &lt;code&gt;examples/ch40-composition/pipeline.ts&lt;/code&gt;, run on &lt;strong&gt;Pi 1.0.4&lt;/strong&gt; with a&#xA;scripted provider.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;The two deterministic pieces need no model at all — and one of them is the check the&#xA;model&amp;rsquo;s output must pass:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Measure agent reliability with pass@1 and pass^k</title>
				<link>http://programmer.ie/examples/pi/41-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/41-chapter/</guid>
				<description>&lt;p&gt;Three activities all get called &amp;ldquo;testing&amp;rdquo;: scripted (a response you chose),&#xA;structural (assert on events, not wording) and evaluation (how often the whole thing&#xA;works over repeated runs). This page is the evaluation harness — the measuring parts&#xA;of &lt;code&gt;eval.ts&lt;/code&gt;, excerpted — on &lt;strong&gt;Pi 1.0.4&lt;/strong&gt;. The &amp;ldquo;model&amp;rdquo; below is a seeded 85% coin,&#xA;so this measures the harness&amp;rsquo;s arithmetic, not any provider; the ledger contains&#xA;&lt;strong&gt;no real-model evidence&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-it&#34;&gt;Run it&lt;/h2&gt;&#xA;&lt;p&gt;The chapter&amp;rsquo;s canonical &lt;code&gt;eval.ts&lt;/code&gt; is a self-contained file (types included); these&#xA;are its load-bearing pieces. &lt;code&gt;evaluate()&lt;/code&gt; runs every task &lt;code&gt;k&lt;/code&gt; times, counts a thrown&#xA;run as a failure, and returns the two rates:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Read a self-declared annotation as a claim, not a control</title>
				<link>http://programmer.ie/examples/pi/42-chapter/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>http://programmer.ie/examples/pi/42-chapter/</guid>
				<description>&lt;p&gt;Capability is not authority, and almost nothing you can write is a boundary — an&#xA;operating-system boundary is. This page shows the point on &lt;strong&gt;Pi 1.0.4&lt;/strong&gt; with&#xA;&lt;code&gt;AgentTool.replay&lt;/code&gt;: a field a tool fills in about itself, and nothing in the type&#xA;verifies it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-declaration-and-the-scan&#34;&gt;The declaration, and the scan&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;write_file&lt;/code&gt; declares itself &lt;code&gt;replay: &amp;quot;safe&amp;quot;&lt;/code&gt; — nothing in the declaration checks&#xA;the claim:&lt;/p&gt;&#xA;&lt;!-- pi-excerpt: examples/ch42-authority/replay.test.ts --&gt;&#xA;&lt;div class=&#34;bookkit-example-code&#34; data-example-code&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;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// The tool chooses its own recovery policy. Nothing here checks that the choice is true.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;writeFile&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;AgentTool&lt;/span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;typeof&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;&amp;gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write_file&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;label&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write_file&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;description&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write a file&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;parameters&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;Params&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;replay&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;safe&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#75715e&#34;&gt;// a claim by the inspected party&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;execute() {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [{ &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;text&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ok&amp;#34;&lt;/span&gt; }], &lt;span style=&#34;color:#a6e22e&#34;&gt;details&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;undefined&lt;/span&gt; };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;textarea data-example-source hidden readonly aria-hidden=&#34;true&#34; aria-label=&#34;Code source&#34;&gt;// The tool chooses its own recovery policy. Nothing here checks that the choice is true.&#xA;const writeFile: AgentTool&amp;lt;typeof Params&amp;gt; = {&#xA;&#x9;name: &amp;#34;write_file&amp;#34;,&#xA;&#x9;label: &amp;#34;write_file&amp;#34;,&#xA;&#x9;description: &amp;#34;write a file&amp;#34;,&#xA;&#x9;parameters: Params,&#xA;&#x9;replay: &amp;#34;safe&amp;#34;, // a claim by the inspected party&#xA;&#x9;async execute() {&#xA;&#x9;&#x9;return { content: [{ type: &amp;#34;text&amp;#34;, text: &amp;#34;ok&amp;#34; }], details: undefined };&#xA;&#x9;},&#xA;};&lt;/textarea&gt;&#xA;  &lt;button type=&#34;button&#34; data-example-copy hidden&gt;Copy code&lt;/button&gt;&lt;span role=&#34;status&#34;&gt;&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The companion test scans the four packages&amp;rsquo; shipped JavaScript for readers:&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
