<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">agents-exe</title><id>https://lucasdicioccio.github.io/agents-exe/atom.xml</id><updated>2026-10-04T15:53:54Z</updated><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-ITERATIVE-WORKFLOW.html</id><title type="text">Iterative Development Workflow</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/ITERATIVE-WORKFLOW.md"&gt;&lt;code&gt;documentation/ITERATIVE-WORKFLOW.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="iterative-development-workflow"&gt;Iterative Development Workflow&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;How to handle multi-step, recursive, or iterative invocations on this codebase.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="invocation-patterns"&gt;Invocation Patterns&lt;/h3&gt;
&lt;h4 id="pattern-1-fresh-start-no-previous-state"&gt;Pattern 1: Fresh Start (No Previous State)&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;When:&lt;/strong&gt; First time working on this codebase, or no knowledge base.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Initialize knowledge base tables
&lt;/li&gt;
&lt;li&gt;Scan all source files → &lt;code&gt;code_index&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Read existing docs → &lt;code&gt;docs_index&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Identify documentation gaps
&lt;/li&gt;
&lt;li&gt;Create initial documentation plan
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Initialize if empty&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; &lt;span class="cf"&gt;IF&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;EXISTS&lt;/span&gt; project_overview (&lt;span class="op"&gt;..&lt;/span&gt;.);&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; &lt;span class="cf"&gt;IF&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;EXISTS&lt;/span&gt; code_index (&lt;span class="op"&gt;..&lt;/span&gt;.);&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; &lt;span class="cf"&gt;IF&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;EXISTS&lt;/span&gt; docs_index (&lt;span class="op"&gt;..&lt;/span&gt;.);&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; &lt;span class="cf"&gt;IF&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;EXISTS&lt;/span&gt; commits_seen (&lt;span class="op"&gt;..&lt;/span&gt;.);&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Populate code_index&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- (scan all .hs files with bash_list-files and bash_grep-files)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-2-continue-previous-work"&gt;Pattern 2: Continue Previous Work&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;When:&lt;/strong&gt; Knowledge base exists, continuing documentation task.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Query what was completed
&lt;/li&gt;
&lt;li&gt;Check for new commits since last work
&lt;/li&gt;
&lt;li&gt;Review current docs_index state
&lt;/li&gt;
&lt;li&gt;Pick up where left off
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- What was documented?&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; module_name, last_updated &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; documented_in &lt;span class="kw"&gt;IS&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; last_updated &lt;span class="kw"&gt;DESC&lt;/span&gt;;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- What&amp;#39;s missing?&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; filepath, module_name &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; documented_in &lt;span class="kw"&gt;IS&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt;;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Any new commits?&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="kw"&gt;FROM&lt;/span&gt; commits_seen &lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; commit_date &lt;span class="kw"&gt;DESC&lt;/span&gt; &lt;span class="kw"&gt;LIMIT&lt;/span&gt; &lt;span class="dv"&gt;10&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-3-handle-new-code-changes"&gt;Pattern 3: Handle New Code Changes&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;When:&lt;/strong&gt; Code has changed since last documentation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check commits_seen vs git log
&lt;/li&gt;
&lt;li&gt;Read new commit details
&lt;/li&gt;
&lt;li&gt;Identify affected modules
&lt;/li&gt;
&lt;li&gt;Update documentation
&lt;/li&gt;
&lt;li&gt;Record commits as processed
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Get recent commits&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;bash_get_git_log&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Read specific commit&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;bash_get_git_commit&lt;/span&gt; abc123&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Find affected files&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;bash_grep-files&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;changed_pattern&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-4-deep-dive-on-subsystem"&gt;Pattern 4: Deep Dive on Subsystem&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;When:&lt;/strong&gt; Need to document one specific subsystem thoroughly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Identify all modules in subsystem
&lt;/li&gt;
&lt;li&gt;Read each module source
&lt;/li&gt;
&lt;li&gt;Extract types and functions
&lt;/li&gt;
&lt;li&gt;Create/update doc file
&lt;/li&gt;
&lt;li&gt;Link all modules in code_index
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find subsystem modules&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; module_name &lt;span class="kw"&gt;LIKE&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;System.Agents.Subsystem.%&amp;#39;&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="chunking-strategy"&gt;Chunking Strategy&lt;/h3&gt;
&lt;p&gt;Large documentation tasks should be chunked:&lt;/p&gt;
&lt;h4 id="by-subsystem"&gt;By Subsystem&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Chunk 1: Core (Base, Runtime, AgentTree)
Chunk 2: Tools (Bash, MCP, OpenAPI, IO)
Chunk 3: Sessions (Types, Loop, Store)
Chunk 4: Interfaces (CLI, TUI, MCP Server)
Chunk 5: Utilities (FileLoader, ExportImport)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="by-document"&gt;By Document&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Iteration 1: README.md (overview)
Iteration 2: architecture.md (core)
Iteration 3: tools.md (tools)
Iteration 4: cli-commands.md (CLI)
Iteration 5: Remaining docs
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="state-tracking-between-iterations"&gt;State Tracking Between Iterations&lt;/h4&gt;
&lt;p&gt;Always update the knowledge base at the end of each iteration:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Record what&amp;#39;s been documented&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;UPDATE&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SET&lt;/span&gt; documented_in &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;documentation/architecture.md&amp;#39;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    last_updated &lt;span class="op"&gt;=&lt;/span&gt; datetime(&lt;span class="st"&gt;&amp;#39;now&amp;#39;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; module_name &lt;span class="kw"&gt;IN&lt;/span&gt; (&lt;span class="st"&gt;&amp;#39;System.Agents.Base&amp;#39;&lt;/span&gt;, &lt;span class="st"&gt;&amp;#39;System.Agents.Runtime&amp;#39;&lt;/span&gt;);&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- If new doc created&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;INSERT&lt;/span&gt; &lt;span class="kw"&gt;INTO&lt;/span&gt; docs_index (doc_path, title, description, related_modules)&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;VALUES&lt;/span&gt; (&lt;span class="st"&gt;&amp;#39;documentation/new-feature.md&amp;#39;&lt;/span&gt;, &lt;span class="st"&gt;&amp;#39;New Feature&amp;#39;&lt;/span&gt;, &lt;span class="st"&gt;&amp;#39;Description&amp;#39;&lt;/span&gt;, &lt;span class="st"&gt;&amp;#39;Module1, Module2&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="recursive-documentation"&gt;Recursive Documentation&lt;/h3&gt;
&lt;h4 id="when-documenting-recursion-features"&gt;When Documenting Recursion Features&lt;/h4&gt;
&lt;p&gt;The codebase has recursion (agents calling agents). When documenting:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Acknowledge the recursion&lt;/strong&gt; - Note that this is a recursive feature
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Show depth tracking&lt;/strong&gt; - Document &lt;code&gt;ctxMaxDepth&lt;/code&gt;, &lt;code&gt;CallStackEntry&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explain limits&lt;/strong&gt; - Document how infinite loops are prevented
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-reference&lt;/strong&gt; - Link to related recursive patterns
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;## Agent Recursion&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;Agents can call other agents, creating a call stack:&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="in"&gt;```haskell&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; ctxCallStack ::&lt;/span&gt; [&lt;span class="dt"&gt;CallStackEntry&lt;/span&gt;]  &lt;span class="co"&gt;-- Tracks recursion&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxMaxDepth ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;          &lt;span class="co"&gt;-- Prevents infinite loops&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;See also: &lt;a href="/agents-exe/docs-tools.html#recursion-control"&gt;Tool Context&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
### Self-Referential Documentation

This document itself is recursive - it documents how to document. When updating:
- Keep patterns general enough to apply to future changes
- Don't make assumptions about specific future tasks
- Focus on process, not content

## Knowledge Base Consistency Checks

Between iterations, verify:

```sql
-- Check 1: All modules have valid doc references
SELECT module_name, documented_in 
FROM code_index 
WHERE documented_in IS NOT NULL 
  AND documented_in NOT IN (SELECT doc_path FROM docs_index);

-- Check 2: All docs reference valid modules
SELECT di.doc_path, di.related_modules
FROM docs_index di
LEFT JOIN code_index ci ON di.related_modules LIKE '%' || ci.module_name || '%'
WHERE ci.module_name IS NULL;

-- Check 3: No duplicate doc entries
SELECT doc_path, COUNT(*) 
FROM docs_index 
GROUP BY doc_path 
HAVING COUNT(*) &amp;gt; 1;

-- Check 4: Timestamps are recent
SELECT module_name, last_updated
FROM code_index
WHERE last_updated &amp;lt; datetime('now', '-7 days')
  AND documented_in IS NOT NULL;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="decision-tree"&gt;Decision Tree&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Invoked on codebase
       │
       ▼
Knowledge base exists?
       │
   ┌───┴───┐
   │       │
  Yes     No
   │       │
   ▼       ▼
Check     Initialize
state     tables
   │       │
   └───┬───┘
       ▼
Task specified?
       │
   ┌───┴───┐
   │       │
  Yes     No
   │       │
   ▼       ▼
Do task   Identify
          gaps
       │
       ▼
Multiple subtasks?
       │
   ┌───┴───┐
   │       │
  Yes     No
   │       │
   ▼       ▼
Chunk    Complete
work     task
   │
   ▼
Update KB
   │
   ▼
Done (or next iteration)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="handoff-notes"&gt;Handoff Notes&lt;/h3&gt;
&lt;p&gt;When work will continue in next invocation, include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;What’s done&lt;/strong&gt;: List completed documentation
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What’s next&lt;/strong&gt;: Specific next steps
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blockers&lt;/strong&gt;: Any issues to resolve
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context&lt;/strong&gt;: Relevant state from knowledge base
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example handoff:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;## Handoff Summary&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;Completed:&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;documentation/architecture.md (core types, runtime, agent tree)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;documentation/tools.md (bash tools, partial MCP)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;Next:&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;Complete MCP section in tools.md&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;Document OpenAPI tools&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;Create mcp.md for protocol details&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;Blockers: None&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;Context:&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;12 of 79 modules documented&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;Runtime and AgentTree fully covered&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;Tools subsystem 60% complete&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="common-iteration-sequences"&gt;Common Iteration Sequences&lt;/h3&gt;
&lt;h4 id="sequence-full-documentation-pass"&gt;Sequence: Full Documentation Pass&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Iteration 1: README + architecture
Iteration 2: Tools system
Iteration 3: Sessions + TUI
Iteration 4: CLI + Export/Import
Iteration 5: File loading + cleanup
Iteration 6: Review + cross-references
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="sequence-new-feature-documentation"&gt;Sequence: New Feature Documentation&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Iteration 1: Understand feature (read code)
Iteration 2: Document core types
Iteration 3: Document API/functions
Iteration 4: Add examples
Iteration 5: Update related docs
Iteration 6: Add to README/index
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="sequence-maintenance-update"&gt;Sequence: Maintenance Update&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Iteration 1: Check new commits
Iteration 2: Identify affected docs
Iteration 3: Update affected sections
Iteration 4: Verify consistency
Iteration 5: Record commits processed
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="tool-usage-by-phase"&gt;Tool Usage by Phase&lt;/h3&gt;
&lt;h4 id="discovery-phase"&gt;Discovery Phase&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bash_list-files&lt;/code&gt; - Find all source files
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bash_grep-files&lt;/code&gt; - Search for patterns
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bash_get_git_log&lt;/code&gt; - See recent changes
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="analysis-phase"&gt;Analysis Phase&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bash_get_git_commit&lt;/code&gt; - Read specific changes
&lt;/li&gt;
&lt;li&gt;Read source files with grep results
&lt;/li&gt;
&lt;li&gt;Query &lt;code&gt;code_index&lt;/code&gt; for relationships
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="documentation-phase"&gt;Documentation Phase&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bash_write-file&lt;/code&gt; - Create/update docs
&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;docs_index&lt;/code&gt; with new entries
&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;code_index&lt;/code&gt; with document links
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-phase"&gt;Verification Phase&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Query for consistency
&lt;/li&gt;
&lt;li&gt;Check cross-references
&lt;/li&gt;
&lt;li&gt;Verify all modules covered
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="anti-patterns-to-avoid"&gt;Anti-Patterns to Avoid&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Don’t&lt;/strong&gt; document without updating knowledge base
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don’t&lt;/strong&gt; create docs without adding to &lt;code&gt;docs_index&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don’t&lt;/strong&gt; leave &lt;code&gt;code_index&lt;/code&gt; modules unlinked
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don’t&lt;/strong&gt; assume previous state - always query
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don’t&lt;/strong&gt; document too much in one iteration (fatigue/errors)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don’t&lt;/strong&gt; forget the summary line (first line of response)
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="success-metrics"&gt;Success Metrics&lt;/h3&gt;
&lt;p&gt;Good iterative documentation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each iteration has clear scope
&lt;/li&gt;
&lt;li&gt;Knowledge base stays consistent
&lt;/li&gt;
&lt;li&gt;No lost work between invocations
&lt;/li&gt;
&lt;li&gt;Progress is measurable (X of Y modules done)
&lt;/li&gt;
&lt;li&gt;Final docs are comprehensive and cross-referenced
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="quick-reference-card"&gt;Quick Reference Card&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;STARTING:
  SELECT * FROM project_overview;
  SELECT * FROM docs_index;
  SELECT * FROM code_index WHERE documented_in IS NULL;

DURING:
  Read source → Extract types → Write doc → Update KB

ENDING:
  UPDATE code_index SET documented_in = 'documentation/X.md' ...
  INSERT INTO docs_index ... (if new doc)
  SELECT consistency checks

HANDOFF:
  List done, next steps, blockers, context
  Include summary line as first line
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;Use this workflow for multi-step documentation tasks.&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-ITERATIVE-WORKFLOW.html" rel="alternate"/><summary type="text">&gt; How to handle multi-step, recursive, or iterative invocations on this codebase. ## Invocation Patterns ### Pattern 1: Fresh Start (No Previous State) **When:** First time working on this codebase, or no knowledge base. **Steps:** 1. Initi</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-bash-tools-v2.html</id><title type="text">Spec: bash tools v2, long-running tool processes</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/bash-tools-v2.md"&gt;&lt;code&gt;todos/bash-tools-v2.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="spec-bash-tools-v2-long-running-tool-processes"&gt;Spec: bash tools v2, long-running tool processes&lt;/h2&gt;
&lt;p&gt;Status: proposal, 2026-09-25, from issue #539 and a robot-chat conversation
the same day. Nothing implemented. The v1 protocol (&lt;code&gt;documentation/binary-tool.md&lt;/code&gt;)
stays valid unchanged: a tool that does not say otherwise is a v1 tool.&lt;/p&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;
&lt;p&gt;A bash tool today is one process per call: &lt;code&gt;describe&lt;/code&gt; once, then &lt;code&gt;run&lt;/code&gt; with
the arguments, stdin written once and closed, stdout collected until exit,
and that stdout is the tool result. Progress exists (&lt;code&gt;tool.progressed&lt;/code&gt;
events carry each line as it arrives, see &lt;code&gt;runProcessReportingOutput&lt;/code&gt;), but
the model only ever sees the final stdout, and a tool cannot be talked to
while it runs.&lt;/p&gt;
&lt;p&gt;v2 lets a tool declare that it is a &lt;strong&gt;process&lt;/strong&gt; rather than a function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it may keep running after answering, streaming information out in
chunks the runtime understands (a declared event shape);
&lt;/li&gt;
&lt;li&gt;its stdin may stay open, the runtime feeding it JSON events shaped as the
tool declares, so the model (or another tool, or mail) can keep talking to
it;
&lt;/li&gt;
&lt;li&gt;from the model’s perspective such a tool is stateful: starting it returns
a handle (start it twice and there are two handles, each addressable on
its own); the tool family gets one typed &lt;code&gt;send&lt;/code&gt; tool taking a handle and
an event, and one shared system tool (&lt;code&gt;processes&lt;/code&gt;: list, status, tail,
stop) serves every family, so process management never multiplies the
session’s tools;
&lt;/li&gt;
&lt;li&gt;the tool declares how it wants to be run, in the spirit of a systemd
unit or a daemontools service directory: the user to run as, an envdir,
a run directory, timeouts, what to do when it exits.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The runtime change is large (D2 below says how it lands in slices); the
protocol change is small, and this document is mostly the protocol.&lt;/p&gt;
&lt;h3 id="1-the-describe-document-v2"&gt;1. The &lt;code&gt;describe&lt;/code&gt; document, v2&lt;/h3&gt;
&lt;p&gt;A v2 tool adds &lt;code&gt;&amp;quot;protocol&amp;quot;: 2&lt;/code&gt; to its &lt;code&gt;describe&lt;/code&gt; output. Everything v1
defines keeps its meaning (&lt;code&gt;slug&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;args&lt;/code&gt;, &lt;code&gt;empty-result&lt;/code&gt;).
Three optional objects and one flag (&lt;code&gt;check&lt;/code&gt;, §1.5) are new.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;protocol&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;log_watcher&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;check&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Follows a log file and reports matching lines&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;backing_type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;arity&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;single&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;mode&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;dashdashspace&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;the file to follow&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;process&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;mode&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;stream&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;output&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;framing&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;jsonl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;event&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;object&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="dt"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;line&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;level&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="dt"&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;line&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;input&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt;  &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;framing&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;jsonl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;event&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;object&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="dt"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;op&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;enum&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;pattern&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;pause&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;resume&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="dt"&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;op&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;ready&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;kind&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;line&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;match&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;^ready$&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;runtime&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;run_as&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;logs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;group&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;logs&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;sandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;fs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;read&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;/var/log&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;write&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;state&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;net&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;none&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;envdir&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;env&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;environment&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;LC_ALL&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;C&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;rundir&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;state&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;timeout&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;start&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;stop&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;idle&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;on_exit&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;report&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;cancel&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SIGTERM&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="11-process-what-kind-of-process-this-is"&gt;1.1 &lt;code&gt;process&lt;/code&gt;: what kind of process this is&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Values&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;mode&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;oneshot&lt;/code&gt; (default), &lt;code&gt;stream&lt;/code&gt;, &lt;code&gt;service&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;oneshot&lt;/code&gt; is v1: run to completion, stdout is the result. &lt;code&gt;stream&lt;/code&gt;: the result is the sequence of output events until exit; the call completes when the process exits. &lt;code&gt;service&lt;/code&gt;: the process is expected to outlive the call; starting it returns a handle and the model works with it through the process tool (§3).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;output.framing&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;jsonl&lt;/code&gt; (default for v2), &lt;code&gt;lines&lt;/code&gt;, &lt;code&gt;chunks&lt;/code&gt;&lt;/td&gt;&lt;td&gt;How stdout is cut into events: one JSON object per line, one text line per event, or raw chunks as they arrive (binary-safe, for tools that produce no lines).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;output.event&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a JSON Schema&lt;/td&gt;&lt;td&gt;The shape of one output event under &lt;code&gt;jsonl&lt;/code&gt;. Validated by the runtime; an event that does not match is delivered as an &lt;code&gt;invalid&lt;/code&gt; event carrying the raw line, never dropped silently. Optional under &lt;code&gt;lines&lt;/code&gt;/&lt;code&gt;chunks&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;input.framing&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;jsonl&lt;/code&gt; (default), &lt;code&gt;lines&lt;/code&gt;&lt;/td&gt;&lt;td&gt;How the runtime writes events to stdin. Absent &lt;code&gt;input&lt;/code&gt;: stdin gets the v1 &lt;code&gt;mode: stdin&lt;/code&gt; arguments and is closed, as today.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;input.event&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a JSON Schema&lt;/td&gt;&lt;td&gt;What the runtime accepts to send to this process; also the schema of the &lt;code&gt;event&lt;/code&gt; argument of the family's typed &lt;code&gt;send&lt;/code&gt; tool (§2.4).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;digest&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"per": "round"}&lt;/code&gt;, &lt;code&gt;{"per": "events", "n": N}&lt;/code&gt;, &lt;code&gt;{"per": "seconds", "n": N}&lt;/code&gt; (default &lt;code&gt;round&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;For a &lt;code&gt;service&lt;/code&gt;: how chatty output is folded into mail (§2.3). Declared by the tool, per tool, because its author knows what an event is worth.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ready&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"kind": "line", "match": REGEX}&lt;/code&gt;, &lt;code&gt;{"kind": "exit"}&lt;/code&gt;, &lt;code&gt;{"kind": "immediate"}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;When the process counts as started: a stdout line matching (its first events are still delivered), its exit (a &lt;code&gt;oneshot&lt;/code&gt;), or right away. Bounded by &lt;code&gt;runtime.timeout.start&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;stderr is never part of the result. It is captured into the process’s
bounded output ring (§2.3) and traced, as today.&lt;/p&gt;
&lt;h4 id="12-runtime-how-to-run-it"&gt;1.2 &lt;code&gt;runtime&lt;/code&gt;: how to run it&lt;/h4&gt;
&lt;p&gt;Every field is optional; an absent field keeps v1 behaviour (run as the
agents-exe process, its environment plus the session context variables,
its working directory, no timeouts beyond the call’s, cancellation kills
the process group).&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;run_as&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"user", "group"}&lt;/code&gt;: run the process as this user and group. The runtime uses one mechanism it was configured with (&lt;code&gt;setpriv&lt;/code&gt;, &lt;code&gt;sudo -u&lt;/code&gt;, &lt;code&gt;runuser&lt;/code&gt;, or a refusal when none is configured); the tool never names the mechanism. Same shape and reasoning as salmon's &lt;code&gt;RunAs&lt;/code&gt;/&lt;code&gt;Mechanism&lt;/code&gt; (&lt;code&gt;multi-user-privilege-separation.md&lt;/code&gt; there).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sandbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"fs": {"read": [...], "write": [...]}, "net": "host"\|"none", "tmp": "shared"\|"private"}&lt;/code&gt;: what the process may touch (§1.4). Enforced by one operator-configured mechanism, &lt;code&gt;bwrap&lt;/code&gt; or &lt;code&gt;landlock&lt;/code&gt;; never images or containers.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;envdir&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A subdirectory name under the operator's explicit &lt;code&gt;--envdir-root&lt;/code&gt;, read the daemontools way: one file per variable, file name is the name, file content is the value. Read at start; absent files are absent variables. Lets an operator provision secrets without touching the tool or the checkout. There is no implicit default location: a tool that declares &lt;code&gt;envdir&lt;/code&gt; while no &lt;code&gt;--envdir-root&lt;/code&gt; was given fails to load with a &lt;code&gt;LoadingError&lt;/code&gt; naming the field.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;environment&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Literal variables, added last (they win over &lt;code&gt;envdir&lt;/code&gt;).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;rundir&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A directory, relative to the tool's directory, created if missing and made the process's working directory; where a &lt;code&gt;service&lt;/code&gt; keeps its state.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;timeout&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;start&lt;/code&gt;: seconds to reach &lt;code&gt;ready&lt;/code&gt; or fail the start; &lt;code&gt;stop&lt;/code&gt;: seconds between the cancel signal and &lt;code&gt;SIGKILL&lt;/code&gt;; &lt;code&gt;idle&lt;/code&gt;: seconds without any output or input event after which a &lt;code&gt;service&lt;/code&gt; is stopped (&lt;code&gt;null&lt;/code&gt;: never).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;on_exit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;For a &lt;code&gt;service&lt;/code&gt;: &lt;code&gt;report&lt;/code&gt; (default: the model is told, the handle becomes final), &lt;code&gt;restart&lt;/code&gt; (bring it back, bounded by a small backoff; every restart is an event), &lt;code&gt;fail&lt;/code&gt; (the call that started it fails if it has not completed yet).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;cancel&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The signal sent first on cancel/stop: &lt;code&gt;SIGTERM&lt;/code&gt; (default), &lt;code&gt;SIGINT&lt;/code&gt;, or a JSON event &lt;code&gt;{"send": {...}}&lt;/code&gt; written to stdin before the signal, for tools that prefer a polite request.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="13-commands-and-help-several-actions-in-one-binary-from-539"&gt;1.3 &lt;code&gt;commands&lt;/code&gt; and &lt;code&gt;help&lt;/code&gt;: several actions in one binary (from #539)&lt;/h4&gt;
&lt;p&gt;Out of scope of the process story but part of the same &lt;code&gt;describe&lt;/code&gt; bump:
&lt;code&gt;&amp;quot;commands&amp;quot;: [ {&amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;args&amp;quot;} ]&lt;/code&gt; lets one binary expose
several tools (&lt;code&gt;slug.name&lt;/code&gt; each), and &lt;code&gt;help&lt;/code&gt; (&lt;code&gt;./tool help [command]&lt;/code&gt;)
gives the runtime a longer text to disclose on demand rather than in every
system prompt. A &lt;code&gt;setup&lt;/code&gt; step (&lt;code&gt;./tool setup&lt;/code&gt;) that provisions the tool’s
own dependencies is left for a later spec: it is an operator concern, not a
runtime one.&lt;/p&gt;
&lt;h4 id="14-sandbox-what-the-process-may-touch-without-images"&gt;1.4 &lt;code&gt;sandbox&lt;/code&gt;: what the process may touch, without images&lt;/h4&gt;
&lt;p&gt;A small declaration, no more: &lt;code&gt;fs.read&lt;/code&gt; and &lt;code&gt;fs.write&lt;/code&gt; are lists of paths
(absolute, or relative to the tool’s directory), &lt;code&gt;net&lt;/code&gt; is &lt;code&gt;host&lt;/code&gt; (default)
or &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;tmp&lt;/code&gt; is &lt;code&gt;shared&lt;/code&gt; (default) or &lt;code&gt;private&lt;/code&gt;. Everything not listed
is not granted; the tool’s own directory is always readable so it can run.
Like &lt;code&gt;run_as&lt;/code&gt;, the tool names what it needs and the &lt;strong&gt;operator&lt;/strong&gt; names how
it is enforced (&lt;code&gt;--sandbox bwrap&lt;/code&gt;, &lt;code&gt;--sandbox landlock&lt;/code&gt; or &lt;code&gt;--sandbox auto&lt;/code&gt;);
a tool that declares &lt;code&gt;sandbox&lt;/code&gt; with no mechanism configured fails to load
with a &lt;code&gt;LoadingError&lt;/code&gt;, it never runs unconfined by silence. There is &lt;strong&gt;no
silent default&lt;/strong&gt;: the two mechanisms give different guarantees (bubblewrap
hides paths and really cuts the network, Landlock denies access and covers
TCP only), so picking one for the operator could quietly weaken what a tool
asked for.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--sandbox auto&lt;/code&gt; is the explicit opt-in to “per tool, the strongest
mechanism that can honour every declared field”: bubblewrap first, then
Landlock, and a tool declaring &lt;code&gt;net: none&lt;/code&gt; or &lt;code&gt;tmp: private&lt;/code&gt; skips Landlock
rather than being weakened, failing to load when no mechanism qualifies.
It is the ordered-backends idea of §1.5 applied to mechanisms, and
&lt;code&gt;agents-exe check --probe&lt;/code&gt; prints what &lt;code&gt;auto&lt;/code&gt; resolved to for each tool. &lt;code&gt;sandbox&lt;/code&gt; composes with
&lt;code&gt;run_as&lt;/code&gt; (the sandbox is set up for the process that runs as that user).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;bubblewrap&lt;/strong&gt; builds a mount namespace: only the declared paths (plus the
minimum to exec the tool) exist, &lt;code&gt;net: none&lt;/code&gt; is a network namespace,
&lt;code&gt;tmp: private&lt;/code&gt; a fresh tmpfs, and the process dies with agents-exe. It
needs unprivileged user namespaces, which many distributions restrict: a
plain &lt;code&gt;bwrap&lt;/code&gt; on the Ubuntu machine this was written on failed with
&lt;code&gt;setting up uid map: Permission denied&lt;/code&gt; (&lt;code&gt;kernel.apparmor_restrict_unprivileged_userns=1&lt;/code&gt;;
not conclusive, that shell may itself have been inside another sandbox).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Landlock&lt;/strong&gt; is a kernel security module needing no privilege and no
namespaces: the runtime applies a ruleset in the child before &lt;code&gt;exec&lt;/code&gt;.
Paths outside the ruleset are denied (not hidden), and on kernels with
network rules it can deny TCP bind and connect, which is not the same as
no network (to verify in the slice, then state precisely in &lt;code&gt;check&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;agents-exe check&lt;/code&gt; probes the configured mechanism for real, the way it would
run a tool, and reports what it can and cannot enforce (for example
“&lt;code&gt;net: none&lt;/code&gt; best effort under landlock”). Where a mechanism cannot honour a
declared field the tool fails to load naming the field; it is never silently
weakened.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Non-goal: image or container isolation.&lt;/strong&gt; agents-exe has no notion of an
image, and this spec adds none. A tool that wants podman or docker calls it
from its own script, like any other command, and agents-exe sees an ordinary
process. (Reviewed against &lt;code&gt;juhp/encapsule&lt;/code&gt;, an interactive podman
dev-shell: useful vocabulary for named capabilities, the wrong shape for a
non-interactive tool call.)&lt;/p&gt;
&lt;p&gt;These are declarations, not privileges: an agent’s configuration (and the
operator’s &lt;code&gt;--set&lt;/code&gt;/&lt;code&gt;--pin&lt;/code&gt; parameters, &lt;code&gt;tool-partial-application.md&lt;/code&gt;) may
refuse or override them. &lt;code&gt;run_as&lt;/code&gt; in particular is only honoured when the
operator configured a mechanism; otherwise the tool loads with a
&lt;code&gt;LoadingError&lt;/code&gt; naming the field, the same way a &lt;code&gt;with&lt;/code&gt; binding that names
an undeclared parameter does today.&lt;/p&gt;
&lt;h4 id="15-health-a-real-probe-and-ordered-backends-per-capability"&gt;1.5 Health: a real probe, and ordered backends per capability&lt;/h4&gt;
&lt;p&gt;The pattern comes from Agent-Reach (a “capability layer” that selects and
health-checks the upstream tools an agent uses, MIT): the same capability
can be served by several tools, and whether one &lt;em&gt;works here, now&lt;/em&gt; is found
by running a cheap command, never by looking the binary up on &lt;code&gt;PATH&lt;/code&gt; (a
stale shim passes &lt;code&gt;which&lt;/code&gt; and cannot execute).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;check&lt;/code&gt;, a third verb.&lt;/strong&gt; A v2 tool may say &lt;code&gt;&amp;quot;check&amp;quot;: true&lt;/code&gt; in &lt;code&gt;describe&lt;/code&gt;
and then answers &lt;code&gt;./tool check&lt;/code&gt;: a cheap, &lt;strong&gt;read-only&lt;/strong&gt; self-test (no
writes, no login, no remote mutation, no long-lived process; a &lt;code&gt;service&lt;/code&gt;
is not started) that prints one JSON document and exits 0 when the tool is
usable:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;detail&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;jina reader answered 429&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;fix&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;set JINA_API_KEY in the envdir&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;detail&lt;/code&gt; and &lt;code&gt;fix&lt;/code&gt; are for the operator, &lt;code&gt;fix&lt;/code&gt; is a prescription. The
runtime runs &lt;code&gt;check&lt;/code&gt; exactly as it would run the tool (same &lt;code&gt;runtime&lt;/code&gt;:
&lt;code&gt;run_as&lt;/code&gt;, &lt;code&gt;sandbox&lt;/code&gt;, &lt;code&gt;envdir&lt;/code&gt;, timeouts), so a probe that passes proves the
sandbox and the user work too. A tool that cannot be checked without side
effects omits &lt;code&gt;check&lt;/code&gt;; it is then &lt;code&gt;unverified&lt;/code&gt; (it loaded and &lt;code&gt;describe&lt;/code&gt;
answered, nothing more) and is never reported &lt;code&gt;ok&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A capability is an ordered list of backends.&lt;/strong&gt; The model sees one tool,
&lt;code&gt;web_read&lt;/code&gt;; the agent configuration says which tool binaries can serve it,
preferred first:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;web_read&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;backends&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;tools/web/read-jina&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools/web/read-curl&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;All backends of a capability must declare the same &lt;code&gt;args&lt;/code&gt; (checked at load,
a &lt;code&gt;LoadingError&lt;/code&gt; otherwise) so the model’s schema does not depend on which
one is active. Switching backends is reordering the list, or an operator
override &lt;code&gt;--backend web_read=read-curl&lt;/code&gt; that moves the named backend first
(an unknown name is ignored, so a stale override never hides a working
backend). The &lt;strong&gt;active backend&lt;/strong&gt; is the first one whose probe is &lt;code&gt;ok&lt;/code&gt;,
else the first &lt;code&gt;unverified&lt;/code&gt; one, else none (the capability fails to load
when required, is omitted with a warning otherwise). Every tool result
carries the backend that served it, so the model can say what it used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A failed call does not silently retry the next backend.&lt;/strong&gt; The model sees
the failure and which backend produced it; automatic fallback is left out of
the first slice (open question).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;agents-exe check --probe [--json]&lt;/code&gt;&lt;/strong&gt; runs every probe and reports, per
capability, the active backend and every candidate:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;web_read&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;active&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-jina&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;backends&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-jina&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;ms&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;310&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-curl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;unverified&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;status&lt;/code&gt; is &lt;code&gt;ok&lt;/code&gt;, &lt;code&gt;failed&lt;/code&gt; (with &lt;code&gt;detail&lt;/code&gt; and &lt;code&gt;fix&lt;/code&gt;), &lt;code&gt;unverified&lt;/code&gt; or
&lt;code&gt;skipped&lt;/code&gt; (a sandbox mechanism that cannot enforce a declared field, §1.4).
Plain &lt;code&gt;check&lt;/code&gt; keeps its meaning (configuration loads: exit 0 / 1); with
&lt;code&gt;--probe&lt;/code&gt; it exits 2 when the configuration loads but a required capability
has no active backend. Do not confuse it with &lt;code&gt;ready&lt;/code&gt; (§1.1): &lt;code&gt;ready&lt;/code&gt; says a
process that was started is up, &lt;code&gt;check&lt;/code&gt; says a tool could work before
anything is started.&lt;/p&gt;
&lt;h3 id="2-the-runtime-side"&gt;2. The runtime side&lt;/h3&gt;
&lt;h4 id="21-a-oneshot-v2-tool"&gt;2.1 A &lt;code&gt;oneshot&lt;/code&gt; v2 tool&lt;/h4&gt;
&lt;p&gt;Identical to v1 except that &lt;code&gt;output.framing&lt;/code&gt;/&lt;code&gt;output.event&lt;/code&gt; apply: the
result delivered to the model is the events, rendered as a JSON array (or
the joined lines), and each event is also a &lt;code&gt;tool.progressed&lt;/code&gt; payload as it
arrives. Nothing else changes; this is the cheap slice that makes the new
&lt;code&gt;describe&lt;/code&gt; real.&lt;/p&gt;
&lt;h4 id="22-a-stream-tool"&gt;2.2 A &lt;code&gt;stream&lt;/code&gt; tool&lt;/h4&gt;
&lt;p&gt;The call runs as an asynchronous call (&lt;code&gt;RunAsync&lt;/code&gt;, &lt;code&gt;async-tool-calls.md&lt;/code&gt;):
the model gets the &lt;code&gt;running&lt;/code&gt; placeholder, events arrive as progress, the
call completes when the process exits, and the result is the full event
sequence (bounded: the last N events, N from the agent’s config, the count
of elided ones stated). &lt;code&gt;wait&lt;/code&gt;, &lt;code&gt;get-tool-call-status&lt;/code&gt; and
&lt;code&gt;cancel-tool-call&lt;/code&gt; work unchanged; &lt;code&gt;get-tool-call-status&lt;/code&gt; shows the latest
events, which is the “tail” the model needs mid-run.&lt;/p&gt;
&lt;h4 id="23-a-service-tool-the-process-handle"&gt;2.3 A &lt;code&gt;service&lt;/code&gt; tool: the process handle&lt;/h4&gt;
&lt;p&gt;Starting a &lt;code&gt;service&lt;/code&gt; tool is a call that completes at &lt;code&gt;ready&lt;/code&gt;: its result
is a &lt;strong&gt;process handle&lt;/strong&gt; &lt;code&gt;{&amp;quot;process&amp;quot;: &amp;quot;&amp;lt;id&amp;gt;&amp;quot;, &amp;quot;tool&amp;quot;: &amp;quot;log_watcher&amp;quot;, &amp;quot;status&amp;quot;: &amp;quot;running&amp;quot;, &amp;quot;since&amp;quot;: ...}&lt;/code&gt;, an entity in the OS world like a tool
call is today (&lt;code&gt;OS.Conversation.ToolCalls&lt;/code&gt;), owned by the session. Each
start is a new process with its own handle: an agent that starts
&lt;code&gt;log_watcher&lt;/code&gt; on two files holds two handles and talks to either by its
handle; nothing is deduplicated or shared between starts. A handle has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the declared &lt;code&gt;input.event&lt;/code&gt; schema (what &lt;code&gt;send&lt;/code&gt; accepts);
&lt;/li&gt;
&lt;li&gt;a bounded ring of its output events and of its stderr lines (same shape
as a node’s output ring in salmon’s &lt;code&gt;serve&lt;/code&gt;: small, per process, what an
operator wants when it fails);
&lt;/li&gt;
&lt;li&gt;its lifecycle: &lt;code&gt;starting&lt;/code&gt;, &lt;code&gt;running&lt;/code&gt;, &lt;code&gt;stopping&lt;/code&gt;, &lt;code&gt;exited&lt;/code&gt; (code),
&lt;code&gt;failed&lt;/code&gt; (why), &lt;code&gt;restarting&lt;/code&gt; (n);
&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;runtime&lt;/code&gt; it was started with, resolved (which user, which envdir).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A process belongs to the session that started it. It survives across the
session’s runs (it is exactly the “background call” case, &lt;code&gt;evictIdle&lt;/code&gt; and
&lt;code&gt;hasRunningCalls&lt;/code&gt; already keep such a session resident) but &lt;strong&gt;not&lt;/strong&gt; a
restart of agents-exe: &lt;code&gt;recoverOnStartup&lt;/code&gt; marks it &lt;code&gt;failed: lost on restart&lt;/code&gt;, as it does for orphaned async calls, and the model learns it
from the process tool. Durable services are a node of their own in
whatever supervises agents-exe, not this spec (D3).&lt;/p&gt;
&lt;p&gt;Output events of a running service are delivered to the model as &lt;strong&gt;mail&lt;/strong&gt;
(&lt;code&gt;session-mailbox.md&lt;/code&gt;): each event, or a digest of them as the tool’s
&lt;code&gt;digest&lt;/code&gt; declares (default: per round) when they are chatty, is an envelope
from &lt;code&gt;process:&amp;lt;id&amp;gt;&lt;/code&gt;, so the model’s turn
is woken the same way any other asynchronous news wakes it, with the same
&lt;code&gt;wakeOn&lt;/code&gt; controls. This is the &lt;code&gt;notify&lt;/code&gt; progress level that spec deferred
(D9 there), given a producer.&lt;/p&gt;
&lt;h4 id="24-process-tools-one-typed-send-per-family-one-shared-processes"&gt;2.4 Process tools: one typed &lt;code&gt;send&lt;/code&gt; per family, one shared &lt;code&gt;processes&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Two layers, split by what varies:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Per family, one typed tool.&lt;/strong&gt; For each &lt;code&gt;service&lt;/code&gt; tool &lt;code&gt;T&lt;/code&gt; in the toolbox
the runtime generates, at load, one companion tool &lt;code&gt;T.send&lt;/code&gt; (&lt;code&gt;slug.name&lt;/code&gt;,
the same naming as &lt;code&gt;commands&lt;/code&gt;, §1.3). Its arguments are &lt;code&gt;process&lt;/code&gt; (the
handle) and &lt;code&gt;event&lt;/code&gt;, whose schema is the declared &lt;code&gt;input.event&lt;/code&gt; verbatim,
so the model gets a typed function per family instead of an untyped
argument, and a family with two running processes is addressed by handle:
&lt;code&gt;log_watcher.send {process: p1, event: ...}&lt;/code&gt; and &lt;code&gt;{process: p2, ...}&lt;/code&gt;. The
answer is the events the process produced in reply within a short window,
or &lt;code&gt;accepted&lt;/code&gt;. The companion exists from load, not from start, so the tool
list (and the tool cache) does not change while processes come and go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shared across families, one tool.&lt;/strong&gt; Everything that does not depend on a
family’s schema is one system capability with sub-commands (the shape of
&lt;code&gt;get-tool-call-status&lt;/code&gt; and friends), so a session holding ten service
families still has one management tool:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Sub-command&lt;/th&gt;&lt;th&gt;Arguments&lt;/th&gt;&lt;th&gt;Answer&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;list&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;every process of the session (and, for a root agent, of its sub-sessions), with tool, status and age&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;process&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the handle with its counters, last events, last stderr lines, and the accepted input schema&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tail&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;process&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the last &lt;code&gt;n&lt;/code&gt; output events, oldest first&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;stop&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;process&lt;/code&gt;, &lt;code&gt;force?&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the declared cancel, then &lt;code&gt;SIGKILL&lt;/code&gt; after &lt;code&gt;timeout.stop&lt;/code&gt;; the exit becomes the answer&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The model discovers which processes exist through &lt;code&gt;list&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt;; a
tool’s &lt;code&gt;description&lt;/code&gt; should say it is a service and name the events it
accepts, in a sentence.&lt;/p&gt;
&lt;h3 id="3-what-the-model-sees-end-to-end"&gt;3. What the model sees, end to end&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;The tool list holds &lt;code&gt;log_watcher&lt;/code&gt; (start it), &lt;code&gt;log_watcher.send&lt;/code&gt;
(talk to one of its processes) and &lt;code&gt;processes&lt;/code&gt; (list, status, tail,
stop, for anything started). Starting is an ordinary tool call with the
declared &lt;code&gt;args&lt;/code&gt;, and may be done twice: each start returns its own handle.
&lt;/li&gt;
&lt;li&gt;The result is the handle. The model continues; when the watcher reports
a line, mail arrives: &lt;code&gt;from process:p1 {&amp;quot;line&amp;quot;: &amp;quot;...&amp;quot;, &amp;quot;level&amp;quot;: &amp;quot;error&amp;quot;}&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The model calls &lt;code&gt;log_watcher.send {process: p1, event: {op: &amp;quot;pattern&amp;quot;, value: &amp;quot;ERROR&amp;quot;}}&lt;/code&gt;; the answer is &lt;code&gt;accepted&lt;/code&gt; or the watcher’s reply.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;processes stop p1&lt;/code&gt; when done; or the session ends and every process of
it is stopped with its declared cancel (a session delete stops them the
way it cancels runs).
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="decisions-proposed"&gt;Decisions (proposed)&lt;/h3&gt;
&lt;p&gt;D1. &lt;strong&gt;The protocol number, not new commands.&lt;/strong&gt; &lt;code&gt;&amp;quot;protocol&amp;quot;: 2&lt;/code&gt; in
&lt;code&gt;describe&lt;/code&gt; is the whole opt-in; &lt;code&gt;run&lt;/code&gt; keeps its name and argument passing,
so a v2 tool can be tried as a v1 tool by ignoring the new fields.&lt;/p&gt;
&lt;p&gt;D2. &lt;strong&gt;Independent features, each shippable&lt;/strong&gt; (the feature &lt;code&gt;9914ff73&lt;/code&gt; is
split as needed). (1) &lt;code&gt;describe&lt;/code&gt; v2 parsing, &lt;code&gt;oneshot&lt;/code&gt; with framing and
validation; (2) &lt;code&gt;runtime&lt;/code&gt; for &lt;code&gt;oneshot&lt;/code&gt; tools (&lt;code&gt;envdir&lt;/code&gt; with
&lt;code&gt;--envdir-root&lt;/code&gt;, &lt;code&gt;environment&lt;/code&gt;, &lt;code&gt;rundir&lt;/code&gt;, &lt;code&gt;timeout.stop&lt;/code&gt;, &lt;code&gt;cancel&lt;/code&gt;) and
&lt;code&gt;run_as&lt;/code&gt; and &lt;code&gt;sandbox&lt;/code&gt; behind operator-configured mechanisms (&lt;code&gt;bwrap&lt;/code&gt;,
&lt;code&gt;landlock&lt;/code&gt;), which ship ahead of the
process modes because a low-privilege &lt;code&gt;oneshot&lt;/code&gt; tool is valuable alone;
(3) &lt;code&gt;stream&lt;/code&gt; on the existing async engine; (4) &lt;code&gt;service&lt;/code&gt;: the handle
entity, mail delivery and &lt;code&gt;digest&lt;/code&gt;, the typed &lt;code&gt;T.send&lt;/code&gt; companions, the
shared &lt;code&gt;processes&lt;/code&gt; capability, and the &lt;code&gt;runtime&lt;/code&gt; fields only a service
uses (&lt;code&gt;timeout.idle&lt;/code&gt;, &lt;code&gt;on_exit&lt;/code&gt;). #539’s &lt;code&gt;commands&lt;/code&gt;/&lt;code&gt;help&lt;/code&gt; are a fifth,
independent slice, and (§1.5) the &lt;code&gt;check&lt;/code&gt; verb with &lt;code&gt;check --probe --json&lt;/code&gt;
is a sixth, small one that lands with (1); capabilities with ordered
backends and the &lt;code&gt;--backend&lt;/code&gt; override are a seventh, depending on it.&lt;/p&gt;
&lt;p&gt;D3. &lt;strong&gt;Not durable across an agents-exe restart.&lt;/strong&gt; A service is lost with the
process that started it and reported as such; supervising long-lived
services belongs to systemd/salmon, which can restart agents-exe itself.
Revisit only with a concrete need (&lt;code&gt;os-as-standalone-server.md&lt;/code&gt; G11 says
the same of watches and run handles).&lt;/p&gt;
&lt;p&gt;D4. &lt;strong&gt;Events, not bytes, at the model boundary.&lt;/strong&gt; The model never sees a
raw stream; it sees validated events (or &lt;code&gt;invalid&lt;/code&gt; ones with the raw
text). &lt;code&gt;chunks&lt;/code&gt; framing exists for tools, not for the model: the runtime
delivers chunks to progress consumers and to the ring only.&lt;/p&gt;
&lt;p&gt;D5. &lt;strong&gt;Mail, not polling, for a service’s output.&lt;/strong&gt; The existing mailbox is
how asynchronous news reaches a session; a second channel would duplicate
its wake rules. Chatty services get digests, bounded by the ring, and the
digest policy is the tool’s own declaration.&lt;/p&gt;
&lt;p&gt;D6. &lt;strong&gt;A typed &lt;code&gt;send&lt;/code&gt; per family, a shared &lt;code&gt;processes&lt;/code&gt; for the rest.&lt;/strong&gt; One
handle per start, several handles per family; the family’s input schema
lives in one generated &lt;code&gt;T.send&lt;/code&gt; tool present from load (an agent
configuration may omit it, saving its tokens), while &lt;code&gt;list&lt;/code&gt;,
&lt;code&gt;status&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt; and &lt;code&gt;stop&lt;/code&gt; are shared so the session’s tool list does not
grow with the number of families’ management surfaces.&lt;/p&gt;
&lt;p&gt;D7. &lt;strong&gt;Explicit envdir root.&lt;/strong&gt; Secrets are provisioned where the operator
says (&lt;code&gt;--envdir-root&lt;/code&gt;), never found by convention next to the tool.&lt;/p&gt;
&lt;p&gt;D8. &lt;strong&gt;Process isolation, not image isolation.&lt;/strong&gt; &lt;code&gt;sandbox&lt;/code&gt; is enforced by
bubblewrap or Landlock, chosen by the operator (explicitly, or with the
opt-in &lt;code&gt;--sandbox auto&lt;/code&gt;, never by a silent default); agents-exe never builds,
pulls or names an image. It composes with &lt;code&gt;run_as&lt;/code&gt;, refuses rather than
weakens, and is probed by &lt;code&gt;check&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;D9. &lt;strong&gt;Probe, don’t look up.&lt;/strong&gt; Whether a tool works is found by running it
(&lt;code&gt;check&lt;/code&gt;, under its real &lt;code&gt;runtime&lt;/code&gt;), read-only, reported as &lt;code&gt;ok&lt;/code&gt;, &lt;code&gt;failed&lt;/code&gt;,
&lt;code&gt;unverified&lt;/code&gt; or &lt;code&gt;skipped&lt;/code&gt;; a tool that cannot be probed safely is
&lt;code&gt;unverified&lt;/code&gt;, never &lt;code&gt;ok&lt;/code&gt;. Backends are an ordered list per capability, the
first &lt;code&gt;ok&lt;/code&gt; one is active, and the tool result names the backend used.
Pattern from Agent-Reach (§1.5).&lt;/p&gt;
&lt;h3 id="resolved-in-review-2026-09-25-pr-574-comments"&gt;Resolved in review (2026-09-25, PR #574 comments)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;send&lt;/code&gt;: one tool per process family with a handle and a typed event; a
second start of the same tool gives a second handle, addressable on its
own; process management (&lt;code&gt;list&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;) is shared so it
does not pollute the session’s tools (§2.4, D6).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run_as&lt;/code&gt; for &lt;code&gt;oneshot&lt;/code&gt;: yes, split into its own feature ahead of the
process modes (D2).
&lt;/li&gt;
&lt;li&gt;Digest policy: per tool, declared in &lt;code&gt;process.digest&lt;/code&gt; (§1.1, §2.3).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;envdir&lt;/code&gt;: explicit, an operator &lt;code&gt;--envdir-root&lt;/code&gt; with a per-tool
subdirectory, no implicit location (§1.2, D7).
&lt;/li&gt;
&lt;li&gt;The generated &lt;code&gt;T.send&lt;/code&gt; companion is optional per agent: an agent
configuration may omit it for a service the model may start but never talk
to, which saves the tool’s tokens (owner’s answer, 2026-09-25; D6).
&lt;/li&gt;
&lt;li&gt;Isolation backend: bubblewrap and Landlock, no images; whoever wants podman
calls it from the tool’s own script (§1.4, D8).
&lt;/li&gt;
&lt;li&gt;Sandbox mechanism selection: no silent default; the operator picks, or opts
in to &lt;code&gt;--sandbox auto&lt;/code&gt; (strongest mechanism that honours every declared
field), shown by &lt;code&gt;check --probe&lt;/code&gt; (owner, 2026-09-25; §1.4, D8).
&lt;/li&gt;
&lt;li&gt;Health: adopt Agent-Reach’s doctor pattern (ordered backends, a real probe,
&lt;code&gt;--json&lt;/code&gt;), but not Agent-Reach itself, which is deferred as heavy
(owner, 2026-09-25; §1.5, D9).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="open-questions"&gt;Open questions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Where is a capability’s backend list declared: in the agent configuration
(as sketched), or in a manifest next to the tool directories so several
agents share it?
&lt;/li&gt;
&lt;li&gt;When are probes run and how long are they cached: once at load, lazily on
the first call, or with a TTL? A probe that costs a network call should
not run on every session start.
&lt;/li&gt;
&lt;li&gt;Automatic fallback to the next backend on a failed call: worth it for
transient failures if the tool declares which exit codes mean “try
another” (&lt;code&gt;fallback_on&lt;/code&gt;), or is the model seeing the failure enough?
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-bash-tools-v2.html" rel="alternate"/><summary type="text">Status: proposal, 2026-09-25, from issue &amp;#35;539 and a robot-chat conversation</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-file-loader.html</id><title type="text">File Loader</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/file-loader.md"&gt;&lt;code&gt;documentation/file-loader.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="file-loader"&gt;File Loader&lt;/h2&gt;
&lt;p&gt;The file loader utilities provide JSON file loading, section-based file parsing, and directory scanning for agent configurations and tools.&lt;/p&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                      File Loader System                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │ FileLoader   │  │ FileLoader.  │  │ FileLoader.  │          │
│  │ (main API)   │  │ JSON         │  │ Section      │          │
│  │              │  │ (parsing)    │  │ (extract)    │          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
│                                                                  │
│  Functions:                                                      │
│  - listJsonDirectory  - readJsonDescriptionFile                  │
│  - loadJsonFile       - parseAgentJson                           │
│  - findSection        - extractSection                           │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="core-types"&gt;Core Types&lt;/h3&gt;
&lt;h4 id="fileloader-systemagentsfileloader"&gt;FileLoader (&lt;code&gt;System.Agents.FileLoader&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;module&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.FileLoader&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ( &lt;span class="kw"&gt;module&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Base&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="kw"&gt;module&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.FileLoader.JSON&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="dt"&gt;Trace&lt;/span&gt; (&lt;span class="op"&gt;..&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="dt"&gt;Agents&lt;/span&gt; (&lt;span class="op"&gt;..&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , listJsonDirectory&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , loadJsonFile&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="dt"&gt;InvalidAgentError&lt;/span&gt; (&lt;span class="op"&gt;..&lt;/span&gt;)&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ) &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;LoadJsonFile&lt;/span&gt; &lt;span class="op"&gt;!&lt;/span&gt;&lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;LoadJsonFileFailure&lt;/span&gt; &lt;span class="op"&gt;!&lt;/span&gt;&lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Agents&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Agents&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; dir ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agents ::&lt;/span&gt; [&lt;span class="dt"&gt;AgentDescription&lt;/span&gt;]&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;InvalidAgentError&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;LoadFailure&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="fileloaderjson-systemagentsfileloaderjson"&gt;FileLoader.JSON (&lt;code&gt;System.Agents.FileLoader.JSON&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;module&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.FileLoader.JSON&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;readJsonDescriptionFile ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;AgentDescription&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;parseAgentJson ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ByteString&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;AgentDescription&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="fileloadersection-systemagentsfileloadersection"&gt;FileLoader.Section (&lt;code&gt;System.Agents.FileLoader.Section&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;module&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.FileLoader.Section&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Extract a delimited section from file content&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;extractSection ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;           &lt;span class="co"&gt;-- Start delimiter (e.g., &amp;quot;----&lt;/span&gt;&lt;span class="re"&gt;BEGIN&lt;/span&gt;&lt;span class="co"&gt;----&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;           &lt;span class="co"&gt;-- End delimiter (e.g., &amp;quot;----&lt;/span&gt;&lt;span class="re"&gt;END&lt;/span&gt;&lt;span class="co"&gt;----&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;           &lt;span class="co"&gt;-- File content&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;        &lt;span class="co"&gt;-- Extracted section&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find section with default delimiters&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;findSection ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;           &lt;span class="co"&gt;-- Section name&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;           &lt;span class="co"&gt;-- File content  &lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;        &lt;span class="co"&gt;-- Extracted content&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="directory-scanning"&gt;Directory Scanning&lt;/h3&gt;
&lt;h4 id="listjsondirectory"&gt;listJsonDirectory&lt;/h4&gt;
&lt;p&gt;Recursively finds all &lt;code&gt;.json&lt;/code&gt; files in a directory:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;listJsonDirectory ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [&lt;span class="dt"&gt;FilePath&lt;/span&gt;]&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;listJsonDirectory path &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    entries &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; listDirectory path&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    files &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; forM entries &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;entry &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;let&lt;/span&gt; fullPath &lt;span class="ot"&gt;=&lt;/span&gt; path &lt;span class="op"&gt;&amp;lt;/&amp;gt;&lt;/span&gt; entry&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        isDir &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; doesDirectoryExist fullPath&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;if&lt;/span&gt; isDir&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;then&lt;/span&gt; listJsonDirectory fullPath&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; [fullPath &lt;span class="op"&gt;|&lt;/span&gt; isJson fullPath]&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;concat&lt;/span&gt; files&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    isJson p &lt;span class="ot"&gt;=&lt;/span&gt; takeExtension p &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;.json&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Directory structure:&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- agents/&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--   ├── main.json&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--   ├── helpers/&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--   │   ├── helper1.json&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--   │   └── helper2.json&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--   └── utils.json&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;listJsonDirectory &lt;span class="st"&gt;&amp;quot;agents&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Returns: [&amp;quot;agents/main.json&amp;quot;, &amp;quot;agents/helpers/helper1.json&amp;quot;, &lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--           &amp;quot;agents/helpers/helper2.json&amp;quot;, &amp;quot;agents/utils.json&amp;quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="with-tracing"&gt;With Tracing&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;loadJsonFile ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;InvalidAgentError&lt;/span&gt; &lt;span class="dt"&gt;AgentDescription&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;loadJsonFile tracer path &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    runTracer tracer (&lt;span class="dt"&gt;LoadJsonFile&lt;/span&gt; path)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; readJsonDescriptionFile path&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; result &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Right&lt;/span&gt; desc &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Right&lt;/span&gt; desc&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Left&lt;/span&gt; err &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            runTracer tracer (&lt;span class="dt"&gt;LoadJsonFileFailure&lt;/span&gt; path err)&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Left&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;LoadFailure&lt;/span&gt; path err&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="json-parsing"&gt;JSON Parsing&lt;/h3&gt;
&lt;h4 id="agent-description-parsing"&gt;Agent Description Parsing&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;readJsonDescriptionFile ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;AgentDescription&lt;/span&gt;)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;readJsonDescriptionFile path &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    contents &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="dt"&gt;ByteString&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;readFile&lt;/span&gt; path&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; parseAgentJson contents&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;parseAgentJson ::&lt;/span&gt; &lt;span class="dt"&gt;ByteString&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;AgentDescription&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;parseAgentJson &lt;span class="ot"&gt;=&lt;/span&gt; eitherDecodeStrict&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="json-schema"&gt;JSON Schema&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;A helpful assistant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;You are helpful.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;mcpServers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;McpSimpleBinary&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;filesystem&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;executable&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/usr/bin/mcp-fs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;--root&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/home/user&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;openApiToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAPIServer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;SpecUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.example.com/openapi.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;BaseUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.example.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Headers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;${API_TOKEN}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;helper&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./helper.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="section-extraction"&gt;Section Extraction&lt;/h3&gt;
&lt;h4 id="use-case-multi-part-prompt-files"&gt;Use Case: Multi-part Prompt Files&lt;/h4&gt;
&lt;p&gt;Section extraction allows embedding multiple content blocks in a single file:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;# My Prompt File&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;Some instructions here.&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;----BEGIN SYSTEM----&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;You are a code reviewer. Focus on:&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;Security issues&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;Performance&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ss"&gt;- &lt;/span&gt;Maintainability&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;----END SYSTEM----&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;----BEGIN EXAMPLE----&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;Example review output format...&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;----END EXAMPLE----&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;Rest of file...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="extracting-sections"&gt;Extracting Sections&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.FileLoader.Section&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;content &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; Text.readFile &lt;span class="st"&gt;&amp;quot;prompt.md&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; systemPrompt &lt;span class="ot"&gt;=&lt;/span&gt; extractSection &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;----BEGIN SYSTEM----&amp;quot;&lt;/span&gt; &lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;----END SYSTEM----&amp;quot;&lt;/span&gt; &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        content&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; exampleOutput &lt;span class="ot"&gt;=&lt;/span&gt; extractSection&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;----BEGIN EXAMPLE----&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;----END EXAMPLE----&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        content&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="named-sections"&gt;Named Sections&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Using findSection with default delimiters&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;findSection ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;findSection name content &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    extractSection start end content&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    start &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;----BEGIN &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; name &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;----&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    end   &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;----END &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; name &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;----&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Usage&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;findSection &lt;span class="st"&gt;&amp;quot;PROMPT&amp;quot;&lt;/span&gt; content&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;findSection &lt;span class="st"&gt;&amp;quot;CONTEXT&amp;quot;&lt;/span&gt; content&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;findSection &lt;span class="st"&gt;&amp;quot;EXAMPLES&amp;quot;&lt;/span&gt; content&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="configuration-loading"&gt;Configuration Loading&lt;/h3&gt;
&lt;h4 id="agents-execfgjson"&gt;agents-exe.cfg.json&lt;/h4&gt;
&lt;p&gt;Project configuration discovery:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;locateAgentsExeConfig ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;locateAgentsExeConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    go &lt;span class="op"&gt;=&amp;lt;&amp;lt;&lt;/span&gt; getCurrentDirectory&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    go &lt;span class="st"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    go &lt;span class="st"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    go path &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;let&lt;/span&gt; tentative &lt;span class="ot"&gt;=&lt;/span&gt; path &lt;span class="op"&gt;&amp;lt;/&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;agents-exe.cfg.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        exists &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; doesFileExist tentative&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;if&lt;/span&gt; exists&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; tentative&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;else&lt;/span&gt; go (takeDirectory path)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Search order:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start at current directory
&lt;/li&gt;
&lt;li&gt;Check for &lt;code&gt;agents-exe.cfg.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If not found, move to parent
&lt;/li&gt;
&lt;li&gt;Repeat until root
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="configuration-schema"&gt;Configuration Schema&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentsExeConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentsExeConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; agentsConfigDir ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentsDirectories ::&lt;/span&gt; [&lt;span class="dt"&gt;FilePath&lt;/span&gt;]&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentsFiles ::&lt;/span&gt; [&lt;span class="dt"&gt;FilePath&lt;/span&gt;]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentsLogs ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;AgentsExeLogConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentsExeLogConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentsExeLogConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; logJsonHttpEndpoint ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; logJsonPath ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; logRawPath ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; logSessionsJsonPrefix ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;FromJSON&lt;/span&gt; &lt;span class="dt"&gt;AgentsExeConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;FromJSON&lt;/span&gt; &lt;span class="dt"&gt;AgentsExeLogConfig&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="error-handling"&gt;Error Handling&lt;/h3&gt;
&lt;h4 id="json-parse-errors"&gt;JSON Parse Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;InvalidAgentError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;LoadFailure&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Example error messages:&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;quot;LoadFailure ./agent.json: Error in $.modelName: expected Text, got Number&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;quot;LoadFailure ./agent.json: Missing required field &amp;#39;systemPrompt&amp;#39;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="file-not-found"&gt;File Not Found&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleFileError ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IOException&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;InvalidAgentError&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleFileError path e &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Left&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;LoadFailure&lt;/span&gt; path (&lt;span class="fu"&gt;show&lt;/span&gt; e)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;loadJsonFileSafe ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;InvalidAgentError&lt;/span&gt; &lt;span class="dt"&gt;AgentDescription&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;loadJsonFileSafe path &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (loadJsonFile silentTracer path) &lt;span class="ot"&gt;`catch`&lt;/span&gt; handleFileError path&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="validation"&gt;Validation&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;validateAgent ::&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ValidationError&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;validateAgent agent &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    when (T.null &lt;span class="op"&gt;$&lt;/span&gt; slug agent) &lt;span class="op"&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Left&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;MissingField&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    when (T.null &lt;span class="op"&gt;$&lt;/span&gt; apiKeyId agent) &lt;span class="op"&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Left&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;MissingField&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    when (T.null &lt;span class="op"&gt;$&lt;/span&gt; modelUrl agent) &lt;span class="op"&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Left&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;MissingField&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ... more validation&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="file-watching"&gt;File Watching&lt;/h3&gt;
&lt;h4 id="hot-reload-support"&gt;Hot Reload Support&lt;/h4&gt;
&lt;p&gt;The bash toolbox uses file watching for hot reloading:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- From BashToolbox module&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;initializeBackroundToolbox ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ToolboxError&lt;/span&gt; &lt;span class="dt"&gt;Toolbox&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;initializeBackroundToolbox tracer dir &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Initial tool discovery&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; discoverTools dir&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create background thread for watching&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    backgroundVal &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; Background.backgroundVal &lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        tracer&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        (&lt;span class="dt"&gt;BashToolsLoadingTrace&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; toolName)&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        (loadTools dir)&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Right&lt;/span&gt; &lt;span class="dt"&gt;Toolbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { tools &lt;span class="ot"&gt;=&lt;/span&gt; backgroundVal&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , triggerReload &lt;span class="ot"&gt;=&lt;/span&gt; Background.triggerReload backgroundVal&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="file-notification"&gt;File Notification&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- From FileNotification module&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;watchDirectory ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;  &lt;span class="co"&gt;-- Callback on change&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;WatchHandle&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="best-practices"&gt;Best Practices&lt;/h3&gt;
&lt;h4 id="configuration-files"&gt;Configuration Files&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Use .json extension&lt;/strong&gt;: Consistent with loader expectations
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validate on load&lt;/strong&gt;: Check required fields
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use UTF-8 encoding&lt;/strong&gt;: Standard for JSON
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pretty print&lt;/strong&gt;: Human-readable config files
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comments in separate file&lt;/strong&gt;: JSON doesn’t support comments
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="section-extraction-1"&gt;Section Extraction&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Clear delimiters&lt;/strong&gt;: Use distinctive markers
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nesting awareness&lt;/strong&gt;: Don’t overlap sections
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graceful degradation&lt;/strong&gt;: Handle missing sections
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Document format&lt;/strong&gt;: Explain section usage
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="directory-structure"&gt;Directory Structure&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;project/
├── agents-exe.cfg.json      # Project config
├── agents/
│   ├── main.json            # Main agent
│   ├── helpers/
│   │   ├── code-helper.json
│   │   └── doc-helper.json
│   └── shared-tools/        # Shared tool library
├── sessions/                # Session storage
│   └── session-*.json
└── prompts/                 # Reusable prompts
    ├── code-review.md
    └── pr-description.md
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="examples"&gt;Examples&lt;/h3&gt;
&lt;h4 id="loading-multiple-agents"&gt;Loading Multiple Agents&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.FileLoader&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Prod.Tracer&lt;/span&gt; (silentTracer)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;loadAllAgents ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [&lt;span class="dt"&gt;AgentDescription&lt;/span&gt;]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;loadAllAgents dir &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    jsonFiles &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; listJsonDirectory dir&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    results &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;mapM&lt;/span&gt; (loadJsonFile silentTracer) jsonFiles&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; [agent &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Right&lt;/span&gt; agent &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; results]&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- With error reporting&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;loadAllAgentsWithErrors ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ([&lt;span class="dt"&gt;AgentDescription&lt;/span&gt;], [&lt;span class="dt"&gt;InvalidAgentError&lt;/span&gt;])&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;loadAllAgentsWithErrors dir &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    jsonFiles &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; listJsonDirectory dir&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    results &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;mapM&lt;/span&gt; (loadJsonFile silentTracer) jsonFiles&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; (errors, agents) &lt;span class="ot"&gt;=&lt;/span&gt; partitionEithers results&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; (agents, errors)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="extracting-code-from-markdown"&gt;Extracting Code from Markdown&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.FileLoader.Section&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;extractHaskellCode ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;extractHaskellCode content &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    extractSection &lt;span class="st"&gt;&amp;quot;```haskell&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;```&amp;quot;&lt;/span&gt; content&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;&amp;lt;|&amp;gt;&lt;/span&gt; extractSection &lt;span class="st"&gt;&amp;quot;```hs&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;```&amp;quot;&lt;/span&gt; content&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;extractAllSections ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;extractAllSections content &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    catMaybes &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; (&lt;span class="ot"&gt;`findSection`&lt;/span&gt; content) sectionNames&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    sectionNames &lt;span class="ot"&gt;=&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;PROMPT&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;CONTEXT&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;EXAMPLES&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;INSTRUCTIONS&amp;quot;&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="custom-config-loading"&gt;Custom Config Loading&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;loadProjectConfig ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;AgentsExeConfig&lt;/span&gt;)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;loadProjectConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    mPath &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; locateAgentsExeConfig&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; mPath &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Just&lt;/span&gt; path &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eitherDecodeFileStrict&amp;#39; path&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;case&lt;/span&gt; result &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="dt"&gt;Left&lt;/span&gt; err &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Config error: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;++&lt;/span&gt; err&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="dt"&gt;Right&lt;/span&gt; config &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; config&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="integration-with-other-modules"&gt;Integration with Other Modules&lt;/h3&gt;
&lt;h4 id="agenttree-integration"&gt;AgentTree Integration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- AgentTree uses FileLoader to discover agents&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;loadAgentTree ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;AgentTreeError&lt;/span&gt; &lt;span class="dt"&gt;AgentTree&lt;/span&gt;)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;loadAgentTree rootFile &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Load root agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    rootResult &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; readJsonDescriptionFile rootFile&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; rootResult &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Left&lt;/span&gt; err &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Left&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;LoadError&lt;/span&gt; err&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Right&lt;/span&gt; rootDesc &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="co"&gt;-- Discover child agents&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;let&lt;/span&gt; toolDir &lt;span class="ot"&gt;=&lt;/span&gt; toolDirectory (agent rootDesc)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            childFiles &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; listJsonDirectory toolDir&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="co"&gt;-- ... build tree&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="cli-integration"&gt;CLI Integration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Main.hs uses FileLoader for agent discovery&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;initArgParserArgs ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ArgParserArgs&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;initArgParserArgs &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    agentsExecConfig &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; locateAgentsExeConfig&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; agentsExecConfig &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Just&lt;/span&gt; path &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; loadFromConfig path&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; loadDefaults&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    loadFromConfig path &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        config &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eitherDecodeFileStrict&amp;#39; path&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        jsonPaths &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;traverse&lt;/span&gt; listJsonDirectory (agentsDirectories config)&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;ArgParserArgs&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            { defaultAgentFiles &lt;span class="ot"&gt;=&lt;/span&gt; agentsFiles config &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;concat&lt;/span&gt; jsonPaths&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-file-loader.html" rel="alternate"/><summary type="text">The file loader utilities provide JSON file loading, section-based file parsing, and directory scanning for agent configurations and tools. ## Overview ``` ┌───────────────────────────</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-agent-templates.html</id><title type="text">Agent templates</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/agent-templates.md"&gt;&lt;code&gt;documentation/agent-templates.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="agent-templates"&gt;Agent templates&lt;/h2&gt;
&lt;p&gt;An agent file can be a &lt;a href="https://github.com/lucasdicioccio/tramaj"&gt;tramaj&lt;/a&gt;
program instead of JSON. The program is evaluated once, when the agent is
loaded, and must produce the JSON an agent file holds. From there on nothing
changes: the value goes through the same parser as a &lt;code&gt;.json&lt;/code&gt; file, and
&lt;code&gt;check&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;tui&lt;/code&gt;, &lt;code&gt;serve&lt;/code&gt; and the rest see an ordinary agent.&lt;/p&gt;
&lt;p&gt;Use a template when several agents should share a sandbox or a toolbox, or
when one agent definition should vary with a value the operator picks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#a-first-template"&gt;A first template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#where-templates-are-found"&gt;Where templates are found&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#parameters-ctx"&gt;Parameters: &lt;code&gt;$ctx&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#libraries"&gt;Libraries&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-agents-library"&gt;The &lt;code&gt;agents&lt;/code&gt; library&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#seeing-the-result"&gt;Seeing the result&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#limits"&gt;Limits&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="a-first-template"&gt;A first template&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;agents/coder.tramaj&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@a=import(&amp;quot;agents&amp;quot;, {}).vals

@code=$a.sandbox({
  name: &amp;quot;code&amp;quot;,
  allow: $a.under($ctx.workspace, [&amp;quot;src&amp;quot;, &amp;quot;test&amp;quot;]),
  deny: [$a.pattern(&amp;quot;*.key&amp;quot;)]
})

$a.agent({
  slug: &amp;quot;coder&amp;quot;,
  apiKeyId: &amp;quot;main-key&amp;quot;,
  flavor: &amp;quot;OpenAIv1&amp;quot;,
  modelUrl: &amp;quot;https://api.openai.com/v1&amp;quot;,
  modelName: &amp;quot;gpt-4o&amp;quot;,
  announce: &amp;quot;edits code under the workspace&amp;quot;,
  systemPrompt: [&amp;quot;You edit code under `$ctx.workspace`.&amp;quot;],
  parameters: [{name: &amp;quot;workspace&amp;quot;, description: &amp;quot;root of the checkout&amp;quot;}],
  builtinToolboxes: [
    $a.developer-toolbox({
      name: &amp;quot;dev&amp;quot;,
      capabilities: [&amp;quot;read-file-range&amp;quot;, &amp;quot;write-file-range&amp;quot;, &amp;quot;patch-file&amp;quot;],
      sandbox: $code
    }),
    $a.lua-toolbox({name: &amp;quot;lua&amp;quot;, sandbox: $code})
  ]
})
&lt;/code&gt;&lt;/pre&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--set&lt;/span&gt; workspace=/srv/app check &lt;span class="at"&gt;--agent-file&lt;/span&gt; agents/coder.tramaj&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;@name=expr&lt;/code&gt; binds a name, &lt;code&gt;$name&lt;/code&gt; reads it, and the last expression is the
result. &lt;code&gt;$code&lt;/code&gt; is written once and used by two toolboxes. The language
itself (objects, arrays, lambdas, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;branch&lt;/code&gt;, string interpolation with
backticks) is described in tramaj’s
&lt;a href="https://github.com/lucasdicioccio/tramaj/blob/main/specs/reference.md"&gt;reference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One program is one agent. The result is the whole agent file, envelope
included (&lt;code&gt;{&amp;quot;tag&amp;quot;: &amp;quot;OpenAIAgentDescription&amp;quot;, &amp;quot;contents&amp;quot;: {...}}&lt;/code&gt;), which is
what &lt;code&gt;$a.agent({...})&lt;/code&gt; builds.&lt;/p&gt;
&lt;h3 id="where-templates-are-found"&gt;Where templates are found&lt;/h3&gt;
&lt;p&gt;Wherever a &lt;code&gt;.json&lt;/code&gt; agent file is, under the extension &lt;code&gt;.tramaj&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--agent-file path/to/agent.tramaj&lt;/code&gt;;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agentsFiles&lt;/code&gt; and &lt;code&gt;agentsDirectories&lt;/code&gt; in &lt;code&gt;agents-exe.cfg.json&lt;/code&gt;;
&lt;/li&gt;
&lt;li&gt;the default directory, &lt;code&gt;~/.config/agents-exe/default&lt;/code&gt;;
&lt;/li&gt;
&lt;li&gt;an agent’s tool directories, where sub-agents are discovered;
&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;path&lt;/code&gt; of an &lt;code&gt;extraAgents&lt;/code&gt; entry.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;--agent SLUG&lt;/code&gt; evaluates templates to learn their slugs. A template that does
not evaluate (a parameter it needs has no value, say) is set aside there, so
that it does not prevent selecting another agent.&lt;/p&gt;
&lt;h3 id="parameters-ctx"&gt;Parameters: &lt;code&gt;$ctx&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A template’s &lt;code&gt;$ctx&lt;/code&gt; holds the process parameters: the values given with
&lt;code&gt;--set&lt;/code&gt;, &lt;code&gt;--set-json&lt;/code&gt;, &lt;code&gt;--pin&lt;/code&gt;, &lt;code&gt;--pin-json&lt;/code&gt; and &lt;code&gt;--params-file&lt;/code&gt; (see
&lt;a href="/agents-exe/docs-parameters-and-bindings.html"&gt;Parameters, bindings, and narrowing sub-agents&lt;/a&gt;).
&lt;code&gt;$ctx.workspace&lt;/code&gt; is the value of &lt;code&gt;--set workspace=...&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A template declares what it reads, in the &lt;code&gt;parameters&lt;/code&gt; of the agent it
produces, as an agent declares the parameters its bindings use. Loading
fails when the template:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;reads&lt;/th&gt;&lt;th&gt;error&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a parameter with no value&lt;/td&gt;&lt;td&gt;names the parameter and the &lt;code&gt;--set&lt;/code&gt; flag to give&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a parameter absent from &lt;code&gt;parameters&lt;/code&gt;&lt;/td&gt;&lt;td&gt;undeclared parameter&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a parameter declared with scope &lt;code&gt;session&lt;/code&gt; or &lt;code&gt;message&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a template is evaluated once, at load, and those have no value then&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a parameter declared &lt;code&gt;secret&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the value would be written into the configuration; bind it to a tool argument instead&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;$ctx&lt;/code&gt; as a whole (&lt;code&gt;lookup($ctx, ...)&lt;/code&gt;, &lt;code&gt;has($ctx, ...)&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;each parameter is read by name, so that the reads can be checked&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Evaluation happens at load and only then. A value that changes per session
or per message stays a parameter binding; it is not something a template
can read.&lt;/p&gt;
&lt;p&gt;A declared &lt;code&gt;default&lt;/code&gt; is not seen by the template: only values the operator
supplied are in &lt;code&gt;$ctx&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="libraries"&gt;Libraries&lt;/h3&gt;
&lt;p&gt;A library is a tramaj file whose top-level bindings other programs read:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;libs/team.tramaj&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@a=import(&amp;quot;agents&amp;quot;, {}).vals
@code=$a.sandbox({name: &amp;quot;code&amp;quot;, allow: $a.under($ctx.workspace, [&amp;quot;src&amp;quot;, &amp;quot;test&amp;quot;])})
@dev=$a.developer-toolbox({name: &amp;quot;dev&amp;quot;, capabilities: [&amp;quot;read-file-range&amp;quot;], sandbox: $code})
null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An agent template imports it by file name, passing what the library reads
from its own &lt;code&gt;$ctx&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@a=import(&amp;quot;agents&amp;quot;, {}).vals
@team=import(&amp;quot;team&amp;quot;, {workspace: ctx(workspace)}).vals

$a.agent({
  slug: &amp;quot;reviewer&amp;quot;,
  ...
  parameters: [{name: &amp;quot;workspace&amp;quot;}],
  builtinToolboxes: [$team.dev]
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ctx(workspace)&lt;/code&gt; hands the template’s own &lt;code&gt;$ctx.workspace&lt;/code&gt; to the library,
and counts as a read of &lt;code&gt;workspace&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Library directories are listed in &lt;code&gt;agents-exe.cfg.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsDirectories&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./agents&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tramajLibraries&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./libs&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Every &lt;code&gt;.tramaj&lt;/code&gt; file of a listed directory is a library named after the file
(&lt;code&gt;libs/team.tramaj&lt;/code&gt; is &lt;code&gt;team&lt;/code&gt;). When two directories hold the same name, the
earlier one wins, and a directory wins over the built-in &lt;code&gt;agents&lt;/code&gt; library. A
library that does not parse stops startup, with its file name.&lt;/p&gt;
&lt;p&gt;Keep library directories apart from agent directories: in an agent
directory, every &lt;code&gt;.tramaj&lt;/code&gt; file is loaded as an agent.&lt;/p&gt;
&lt;h3 id="the-agents-library"&gt;The &lt;code&gt;agents&lt;/code&gt; library&lt;/h3&gt;
&lt;p&gt;Always available, as &lt;code&gt;import(&amp;quot;agents&amp;quot;, {})&lt;/code&gt;. Every function takes one object;
fields marked optional may be left out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Path predicates&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;function&lt;/th&gt;&lt;th&gt;result&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dir(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the directory and everything below it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dir-shallow(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the directory's own files&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dir-exactly(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the directory itself&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;file(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;pattern(glob)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;file names matching a glob&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;extensions([ext])&lt;/code&gt;&lt;/td&gt;&lt;td&gt;file extensions, without the dot&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;any-of([p])&lt;/code&gt;, &lt;code&gt;all-of([p])&lt;/code&gt;, &lt;code&gt;none-of([p])&lt;/code&gt;&lt;/td&gt;&lt;td&gt;combinations&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;allow-all&lt;/code&gt;, &lt;code&gt;deny-all&lt;/code&gt;&lt;/td&gt;&lt;td&gt;constants&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;under(root, [path])&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a list: &lt;code&gt;dir&lt;/code&gt; of each path below &lt;code&gt;root&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Sandboxes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sandbox({allow, deny, name, maxFileSize})&lt;/code&gt;: &lt;code&gt;allow&lt;/code&gt; is a list of predicates
and is required; &lt;code&gt;deny&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;maxFileSize&lt;/code&gt; are optional. A path is
allowed when an &lt;code&gt;allow&lt;/code&gt; entry matches and no &lt;code&gt;deny&lt;/code&gt; entry does.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sandbox-ref(name)&lt;/code&gt;: a reference to a sandbox the agent declares in its
&lt;code&gt;fileSandboxes&lt;/code&gt; map (see &lt;a href="/agents-exe/docs-tools.html#named-sandboxes"&gt;Named Sandboxes&lt;/a&gt;), usable
wherever a toolbox takes &lt;code&gt;sandbox&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$a.agent({
  ...,
  fileSandboxes: {code: $a.sandbox({allow: [$a.dir(&amp;quot;./src&amp;quot;)]})},
  builtinToolboxes: [
    $a.developer-toolbox({name: &amp;quot;dev&amp;quot;, capabilities: [&amp;quot;read-file-range&amp;quot;], sandbox: $a.sandbox-ref(&amp;quot;code&amp;quot;)}),
    $a.lua-toolbox({name: &amp;quot;lua&amp;quot;, sandbox: $a.sandbox-ref(&amp;quot;code&amp;quot;)})
  ]
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Toolboxes&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;function&lt;/th&gt;&lt;th&gt;fields&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;developer-toolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;capabilities&lt;/code&gt;; optional &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;sandbox&lt;/code&gt;, &lt;code&gt;activation&lt;/code&gt;, &lt;code&gt;buildCommand&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;system-toolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;capabilities&lt;/code&gt;; optional &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;sandbox&lt;/code&gt;, &lt;code&gt;activation&lt;/code&gt;, &lt;code&gt;envVarFilter&lt;/code&gt;, &lt;code&gt;commandFilter&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;lua-toolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;name&lt;/code&gt;; optional &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;maxMemoryMB&lt;/code&gt;, &lt;code&gt;maxExecutionTimeSeconds&lt;/code&gt;, &lt;code&gt;allowedTools&lt;/code&gt;, &lt;code&gt;allowedHosts&lt;/code&gt;, &lt;code&gt;sandbox&lt;/code&gt;, &lt;code&gt;activation&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tools-dir&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;path&lt;/code&gt;; optional &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;activation&lt;/code&gt;, &lt;code&gt;bindings&lt;/code&gt; (a &lt;code&gt;bashToolboxes&lt;/code&gt; entry)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tool&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;path&lt;/code&gt;; optional &lt;code&gt;activation&lt;/code&gt;, &lt;code&gt;bindings&lt;/code&gt; (a &lt;code&gt;bashToolboxes&lt;/code&gt; entry)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;mcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;executable&lt;/code&gt;; optional &lt;code&gt;args&lt;/code&gt;, &lt;code&gt;activation&lt;/code&gt;, &lt;code&gt;env&lt;/code&gt; (an &lt;code&gt;mcpServers&lt;/code&gt; entry)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;helper&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;slug&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;; optional &lt;code&gt;with&lt;/code&gt;, &lt;code&gt;narrowable&lt;/code&gt; (an &lt;code&gt;extraAgents&lt;/code&gt; entry)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Agent&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;agent({...})&lt;/code&gt; wraps an agent’s fields in the file’s envelope.&lt;/p&gt;
&lt;p&gt;Anything the library has no function for is written as the plain JSON object
it is: a template’s objects are JSON objects.&lt;/p&gt;
&lt;h3 id="seeing-the-result"&gt;Seeing the result&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--set&lt;/span&gt; workspace=/srv/app check &lt;span class="at"&gt;--show-config&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; agents/coder.tramaj&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;prints the JSON the template evaluated to, then the usual &lt;code&gt;check&lt;/code&gt; line.
&lt;code&gt;--show-config&lt;/code&gt; prints a &lt;code&gt;.json&lt;/code&gt; agent file as it is.&lt;/p&gt;
&lt;h3 id="limits"&gt;Limits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mcp-server&lt;/code&gt;, &lt;code&gt;tool-call&lt;/code&gt; and &lt;code&gt;session&lt;/code&gt; take no process parameters, so a
template that reads &lt;code&gt;$ctx&lt;/code&gt; does not load there. &lt;code&gt;session&lt;/code&gt; also sees the
built-in library only.
&lt;/li&gt;
&lt;li&gt;The developer toolbox’s &lt;code&gt;validate-agent&lt;/code&gt; and &lt;code&gt;create-agent&lt;/code&gt; tools read
JSON agent files only.
&lt;/li&gt;
&lt;li&gt;Agents stored through &lt;code&gt;agents-server&lt;/code&gt;’s API are JSON; a stored agent
cannot be a template yet, and there are no stored libraries.
&lt;/li&gt;
&lt;li&gt;Plain &lt;code&gt;agents-server&lt;/code&gt; has the built-in library only. &lt;code&gt;agents-exe serve&lt;/code&gt;
adds the &lt;code&gt;tramajLibraries&lt;/code&gt; of &lt;code&gt;agents-exe.cfg.json&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-agent-templates.html" rel="alternate"/><summary type="text">An agent file can be a [tramaj](https://github.com/lucasdicioccio/tramaj) program instead of JSON. The program is evaluated once, when the agent is loaded, and must produce the JSON an agent file holds. From there on nothing changes: the va</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-advanced-configuration.html</id><title type="text">Advanced Configuration</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/advanced-configuration.md"&gt;&lt;code&gt;documentation/advanced-configuration.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="advanced-configuration"&gt;Advanced Configuration&lt;/h2&gt;
&lt;p&gt;This guide covers advanced configuration patterns for agents-exe, including recursive agent references, mutual recursion, and runtime safety controls.&lt;/p&gt;
&lt;h3 id="table-of-contents"&gt;Table of Contents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#recursive-agent-references"&gt;Recursive Agent References&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#self-references"&gt;Self-References&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#mutual-recursion"&gt;Mutual Recursion&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#configuration-via-extraagents"&gt;Configuration via extraAgents&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#recursion-safety"&gt;Recursion Safety&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#depth-limits"&gt;Depth Limits&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#call-stack-tracking"&gt;Call Stack Tracking&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#configuration-examples"&gt;Configuration Examples&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#basic-recursive-agent"&gt;Basic Recursive Agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#mutually-recursive-agents"&gt;Mutually Recursive Agents&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#hierarchical-agent-with-recursion"&gt;Hierarchical Agent with Recursion&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#best-practices"&gt;Best Practices&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#troubleshooting"&gt;Troubleshooting&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="recursive-agent-references"&gt;Recursive Agent References&lt;/h3&gt;
&lt;p&gt;By default, agents can only reference sub-agents located in their &lt;code&gt;toolDirectory&lt;/code&gt;. This creates a strict tree hierarchy. However, some use cases require:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Self-references&lt;/strong&gt;: An agent that can call itself for iterative refinement
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mutual recursion&lt;/strong&gt;: Agent A calls Agent B, which calls Agent A
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-tree references&lt;/strong&gt;: Agents in different branches need to collaborate
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;extraAgents&lt;/code&gt; configuration field enables these patterns by allowing explicit declarations of agent references outside the normal directory hierarchy.&lt;/p&gt;
&lt;h4 id="how-it-works"&gt;How It Works&lt;/h4&gt;
&lt;p&gt;When an agent defines &lt;code&gt;extraAgents&lt;/code&gt;, the system uses a &lt;strong&gt;two-phase initialization&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Discovery Phase&lt;/strong&gt;: All agent configurations are loaded via BFS traversal
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation Phase&lt;/strong&gt;: References are validated (all slugs must exist)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runtime Shell Phase&lt;/strong&gt;: Runtime shells are created with empty tool lists
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wiring Phase&lt;/strong&gt;: Tool references are resolved via the &lt;code&gt;RuntimeRegistry&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tree Building Phase&lt;/strong&gt;: The final &lt;code&gt;AgentTree&lt;/code&gt; is constructed
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This approach allows cycles in the agent reference graph while preventing runtime failures from missing references.&lt;/p&gt;
&lt;h4 id="self-references"&gt;Self-References&lt;/h4&gt;
&lt;p&gt;An agent can reference itself to implement iterative refinement patterns:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────┐
│  refine-code    │◄────────────────┐
│  (self-ref)     │                 │
└────────┬────────┘                 │
         │                          │
         │ tool call                │
         ▼                          │
┌─────────────────┐                 │
│  refine-code    │─────────────────┘
│  (same agent)   │
└─────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Iterative code improvement (“make it faster”, “add tests”)
&lt;/li&gt;
&lt;li&gt;Progressive document refinement
&lt;/li&gt;
&lt;li&gt;Recursive problem decomposition with depth limits
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="mutual-recursion"&gt;Mutual Recursion&lt;/h4&gt;
&lt;p&gt;Two or more agents can reference each other:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────┐      ┌─────────────┐
│  planner    │─────►│  executor   │
│             │◄─────│             │
└─────────────┘      └─────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Planning and execution loops
&lt;/li&gt;
&lt;li&gt;Code generation and review cycles
&lt;/li&gt;
&lt;li&gt;Question-answering with fact-checking
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="configuration-via-extraagents"&gt;Configuration via extraAgents&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;extraAgents&lt;/code&gt; field in an agent’s JSON configuration declares references to agents outside the &lt;code&gt;toolDirectory&lt;/code&gt; hierarchy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Field Structure:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ExtraAgentRef&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ExtraAgentRef&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; extraAgentSlug ::&lt;/span&gt; &lt;span class="dt"&gt;AgentSlug&lt;/span&gt;   &lt;span class="co"&gt;-- ^ How to reference this agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; extraAgentPath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;    &lt;span class="co"&gt;-- ^ Path to agent JSON file&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: The &lt;code&gt;slug&lt;/code&gt; field in &lt;code&gt;extraAgents&lt;/code&gt; must match the target agent’s
actual &lt;code&gt;slug&lt;/code&gt; as defined in its JSON file. It is NOT an alias. The system uses
this slug to look up the agent in the registry after all configurations are loaded.&lt;/p&gt;
&lt;p&gt;For example, if you want to reference an agent defined in &lt;code&gt;helper.json&lt;/code&gt; that has
&lt;code&gt;&amp;quot;slug&amp;quot;: &amp;quot;my-helper&amp;quot;&lt;/code&gt;, your extraAgents entry must use &lt;code&gt;&amp;quot;slug&amp;quot;: &amp;quot;my-helper&amp;quot;&lt;/code&gt;,
not any other name.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;JSON Format:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-key&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAI&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;helper-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;../helpers/helper-agent.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./agent.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;A recursive agent that can call itself.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You are a helpful assistant.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You can call yourself recursively for complex tasks.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Field Descriptions:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;slug&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Must match the target agent's actual &lt;code&gt;slug&lt;/code&gt; as defined in its JSON file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;path&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Relative or absolute path to the agent's JSON file&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: A common mistake is to use an arbitrary name for the &lt;code&gt;slug&lt;/code&gt; field
in &lt;code&gt;extraAgents&lt;/code&gt;. This will cause a &lt;code&gt;MissingAgentReference&lt;/code&gt; error because the
system cannot find an agent with that slug. Always ensure the slug in
&lt;code&gt;extraAgents&lt;/code&gt; matches the &lt;code&gt;slug&lt;/code&gt; field in the target agent’s configuration file.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3 id="recursion-safety"&gt;Recursion Safety&lt;/h3&gt;
&lt;p&gt;Unbounded recursion can lead to infinite loops and excessive API costs. The system provides multiple safety mechanisms.&lt;/p&gt;
&lt;h4 id="depth-limits"&gt;Depth Limits&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;ToolExecutionContext&lt;/code&gt; tracks recursion depth via a call stack:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; ctxCallStack ::&lt;/span&gt; [&lt;span class="dt"&gt;CallStackEntry&lt;/span&gt;]  &lt;span class="co"&gt;-- ^ Call chain tracking&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxMaxDepth  ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;         &lt;span class="co"&gt;-- ^ Optional depth limit&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ... other fields&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;CallStackEntry&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;CallStackEntry&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; callAgentSlug      ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; callConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; callDepth          ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;When an agent calls another agent, the system:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Creates a new &lt;code&gt;CallStackEntry&lt;/code&gt; with incremented depth
&lt;/li&gt;
&lt;li&gt;Checks against &lt;code&gt;ctxMaxDepth&lt;/code&gt; if set
&lt;/li&gt;
&lt;li&gt;Returns &lt;code&gt;Left (MaxRecursionDepthExceeded callStack)&lt;/code&gt; if limit exceeded
&lt;/li&gt;
&lt;li&gt;Otherwise, continues with the new context
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: Currently, depth limits are enforced at runtime via the context, not at configuration time. Future versions may support &lt;code&gt;maxRecursionDepth&lt;/code&gt; in agent configuration.&lt;/p&gt;
&lt;h4 id="call-stack-tracking"&gt;Call Stack Tracking&lt;/h4&gt;
&lt;p&gt;Every nested agent call appends to the call stack:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Depth 0: [root]                    -- Initial context
Depth 1: [agent-a, root]           -- After first call
Depth 2: [agent-b, agent-a, root]  -- After second call
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The call stack enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Debugging&lt;/strong&gt;: Full call chain in error messages
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cycle detection&lt;/strong&gt;: Check if an agent is already in the stack
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context-aware behavior&lt;/strong&gt;: Different logic at different depths
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Helper Functions:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check current recursion depth&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;currentRecursionDepth ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check if at or beyond specific depth&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;isAtDepth ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Get full call chain (root first)&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;callChain ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;CallStackEntry&lt;/span&gt;]&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check for cycles (agent already in stack)&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;isAgentInCallStack ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="configuration-examples"&gt;Configuration Examples&lt;/h3&gt;
&lt;h4 id="basic-recursive-agent"&gt;Basic Recursive Agent&lt;/h4&gt;
&lt;p&gt;An agent that can call itself for iterative code refinement:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Directory Structure:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;refine-agent/
├── agent.json
└── tools/
    └── some-tool.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;agent.json:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;refine-code&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai-key&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAI&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4o&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;refine-code&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./agent.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Code refinement agent with self-recursion.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You are a code refinement specialist.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Analyze the provided code and suggest improvements.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;If the task is complex, break it into steps and call&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;the &amp;#39;refine-code&amp;#39; tool iteratively, up to 3 levels deep.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Track your progress and stop when improvements diminish.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Note that the &lt;code&gt;slug&lt;/code&gt; in &lt;code&gt;extraAgents&lt;/code&gt; (&lt;code&gt;&amp;quot;refine-code&amp;quot;&lt;/code&gt;) matches the agent’s own
&lt;code&gt;slug&lt;/code&gt; field. This is required for self-references to work correctly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;-p&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Refactor this Python function for performance:&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;               &lt;span class="at"&gt;-f&lt;/span&gt; myscript.py &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;               &lt;span class="at"&gt;--agent-file&lt;/span&gt; refine-agent/agent.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="mutually-recursive-agents"&gt;Mutually Recursive Agents&lt;/h4&gt;
&lt;p&gt;A planner and executor that collaborate in a loop:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Directory Structure:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;plan-exec/
├── planner.json
├── executor.json
└── tools/
    └── validate.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;planner.json:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;task-planner&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai-key&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAI&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4o&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;task-executor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./executor.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Task planner that delegates to executor.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You are a strategic planner.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Break down complex tasks into executable steps.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Use the &amp;#39;task-executor&amp;#39; tool to execute each step.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Review results and iterate up to 5 times if needed.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;executor.json:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;task-executor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai-key&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAI&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4o&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;task-planner&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./planner.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Task executor that can request replanning.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You are an execution specialist.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Implement the planned steps precisely.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;If execution fails or needs adjustment,&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;call &amp;#39;task-planner&amp;#39; with context for revised planning.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Stop after 5 iterations to prevent infinite loops.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Note that in &lt;code&gt;planner.json&lt;/code&gt;, the &lt;code&gt;extraAgents&lt;/code&gt; slug is &lt;code&gt;&amp;quot;task-executor&amp;quot;&lt;/code&gt; which
must match the &lt;code&gt;slug&lt;/code&gt; field in &lt;code&gt;executor.json&lt;/code&gt;. Similarly, in &lt;code&gt;executor.json&lt;/code&gt;,
the &lt;code&gt;extraAgents&lt;/code&gt; slug is &lt;code&gt;&amp;quot;task-planner&amp;quot;&lt;/code&gt; which must match the &lt;code&gt;slug&lt;/code&gt; field in
&lt;code&gt;planner.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;-p&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Set up a Django project with user auth:&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;               &lt;span class="at"&gt;--agent-file&lt;/span&gt; plan-exec/planner.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="hierarchical-agent-with-recursion"&gt;Hierarchical Agent with Recursion&lt;/h4&gt;
&lt;p&gt;A boss agent with recursive worker agents at different levels:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Directory Structure:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hierarchy/
├── boss.json
├── senior-dev.json
├── junior-dev.json
└── tools/
    ├── git.sh
    └── test.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;boss.json:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;boss&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai-key&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAI&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4o&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;senior-dev&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./senior-dev.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Project manager coordinating development.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You are a technical project manager.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Delegate architecture decisions to senior-dev.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Track overall progress and ensure quality.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;senior-dev.json:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;senior-dev&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai-key&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAI&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4o-mini&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;junior-dev&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./junior-dev.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;senior-dev&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./senior-dev.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Senior developer for architecture and review.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You are a senior software developer.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Design architecture and review implementations.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Delegate implementation tasks to junior-dev.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Use self-recursion for complex code reviews (max 2 levels).&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;junior-dev.json:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;junior-dev&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai-key&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAI&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4o-mini&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Junior developer for implementation.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You are a junior software developer.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Implement features following senior-dev specifications.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;Write tests and documentation for all code.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="best-practices"&gt;Best Practices&lt;/h3&gt;
&lt;h4 id="1-always-set-depth-limits"&gt;1. Always Set Depth Limits&lt;/h4&gt;
&lt;p&gt;When implementing recursive patterns, explicitly track depth and set limits:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- In tool implementation&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; pushAgentContext &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt; newConvId parentCtx &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Left&lt;/span&gt; (&lt;span class="dt"&gt;MaxRecursionDepthExceeded&lt;/span&gt; stack) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Max depth reached. Current chain: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;++&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt; (&lt;span class="fu"&gt;map&lt;/span&gt; callAgentSlug stack)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Right&lt;/span&gt; newCtx &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; continueWithSubAgent newCtx&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="2-document-recursion-patterns"&gt;2. Document Recursion Patterns&lt;/h4&gt;
&lt;p&gt;Add clear documentation in system prompts:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;You can call yourself recursively using the &amp;#39;my-agent&amp;#39; tool.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;IMPORTANT: Stop after 3 levels of recursion.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;Track recursion depth in your reasoning.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="3-use-appropriate-models"&gt;3. Use Appropriate Models&lt;/h4&gt;
&lt;p&gt;Different recursion depths benefit from different models:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Depth&lt;/th&gt;&lt;th&gt;Recommendation&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1-2 (root + 1 level)&lt;/td&gt;&lt;td&gt;Use strongest model (gpt-4o)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3-5&lt;/td&gt;&lt;td&gt;Can use lighter model (gpt-4o-mini)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5+&lt;/td&gt;&lt;td&gt;Review architecture; may indicate wrong approach&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="4-validate-configuration"&gt;4. Validate Configuration&lt;/h4&gt;
&lt;p&gt;Use the &lt;code&gt;check&lt;/code&gt; command to validate recursive configurations:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check &lt;span class="at"&gt;--agent-file&lt;/span&gt; my-recursive-agent.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify all &lt;code&gt;extraAgents&lt;/code&gt; paths resolve
&lt;/li&gt;
&lt;li&gt;Check for duplicate slugs
&lt;/li&gt;
&lt;li&gt;Warn about detected cycles (cycles are allowed but warned)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-monitor-costs"&gt;5. Monitor Costs&lt;/h4&gt;
&lt;p&gt;Recursive agents can incur unexpected API costs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Log recursion depth in your traces
&lt;/li&gt;
&lt;li&gt;Set up budget alerts
&lt;/li&gt;
&lt;li&gt;Consider using lighter models for deep recursion
&lt;/li&gt;
&lt;li&gt;Test with depth limits before removing them
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="6-prefer-explicit-over-implicit"&gt;6. Prefer Explicit Over Implicit&lt;/h4&gt;
&lt;p&gt;Be explicit about which agents can recurse:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;explicit-self&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./agent.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Rather than relying on implicit discovery.&lt;/p&gt;
&lt;h4 id="7-handle-cycle-warnings"&gt;7. Handle Cycle Warnings&lt;/h4&gt;
&lt;p&gt;When the system detects cycles, it logs warnings but continues:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CyclicReferencesWarning [[&amp;quot;agent-a&amp;quot;, &amp;quot;agent-b&amp;quot;, &amp;quot;agent-a&amp;quot;]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Review these warnings to ensure cycles are intentional.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="troubleshooting"&gt;Troubleshooting&lt;/h3&gt;
&lt;h4 id="missingagentreference-error"&gt;“MissingAgentReference” Error&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; An agent references a slug that doesn’t exist.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ReferenceError: Missing agent reference 'self-reference'
  Referrer: 'local:lrm' in file: localdev-agents/kimi-07.err1.json
  
  Hint: The slug 'self-reference' was not found in any loaded agent configuration.
  
  Did you mean to reference one of these agents?
    - 'local:lrm' (defined in localdev-agents/kimi-07.err1.json)
  
  Remember: The 'slug' in extraAgents must match the target agent's actual slug,
  not an arbitrary name. Check that your extraAgents configuration uses the 
  correct slug from the target file.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Common Causes:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;slug&lt;/code&gt; in &lt;code&gt;extraAgents&lt;/code&gt; doesn’t match the target agent’s actual &lt;code&gt;slug&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The referenced agent file doesn’t exist at the specified path
&lt;/li&gt;
&lt;li&gt;The referenced agent file has a different &lt;code&gt;slug&lt;/code&gt; than expected
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check that the &lt;code&gt;slug&lt;/code&gt; in &lt;code&gt;extraAgents&lt;/code&gt; matches the target agent’s &lt;code&gt;slug&lt;/code&gt; field exactly
&lt;/li&gt;
&lt;li&gt;Verify the &lt;code&gt;path&lt;/code&gt; in &lt;code&gt;extraAgents&lt;/code&gt; points to the correct file
&lt;/li&gt;
&lt;li&gt;Open the target agent’s JSON file and confirm its &lt;code&gt;slug&lt;/code&gt; field
&lt;/li&gt;
&lt;li&gt;Remember: The &lt;code&gt;slug&lt;/code&gt; in &lt;code&gt;extraAgents&lt;/code&gt; is NOT an alias - it must match the target’s actual slug
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Example Fix:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you have an agent file &lt;code&gt;helper.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-helper&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="er"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Your &lt;code&gt;extraAgents&lt;/code&gt; entry must use &lt;code&gt;&amp;quot;slug&amp;quot;: &amp;quot;my-helper&amp;quot;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-helper&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./helper.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Using &lt;code&gt;&amp;quot;slug&amp;quot;: &amp;quot;helper&amp;quot;&lt;/code&gt; or any other name will cause the error.&lt;/p&gt;
&lt;h4 id="duplicateagentslug-error"&gt;“DuplicateAgentSlug” Error&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; The same slug is defined in multiple files.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ReferenceError (DuplicateAgentSlug &amp;quot;helper&amp;quot; [&amp;quot;./a/helper.json&amp;quot;, &amp;quot;./b/helper.json&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Rename one of the agents
&lt;/li&gt;
&lt;li&gt;Use different slugs for different purposes
&lt;/li&gt;
&lt;li&gt;Consolidate duplicate definitions
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="infinite-recursion"&gt;Infinite Recursion&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Agents call each other indefinitely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;High API costs
&lt;/li&gt;
&lt;li&gt;Sessions don’t terminate
&lt;/li&gt;
&lt;li&gt;Repeated tool calls with similar parameters
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add explicit depth tracking to system prompts
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;pushAgentContext&lt;/code&gt; with &lt;code&gt;ctxMaxDepth&lt;/code&gt; in tool implementations
&lt;/li&gt;
&lt;li&gt;Add termination conditions (“stop if no improvements”)
&lt;/li&gt;
&lt;li&gt;Review and simplify agent collaboration patterns
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="performance-issues"&gt;Performance Issues&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Recursive agents are slow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use lighter models for deep recursion levels
&lt;/li&gt;
&lt;li&gt;Reduce context window by summarizing earlier results
&lt;/li&gt;
&lt;li&gt;Cache intermediate results
&lt;/li&gt;
&lt;li&gt;Consider flattening the recursion into iteration
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3 id="summary"&gt;Summary&lt;/h3&gt;
&lt;p&gt;Recursive agent references enable powerful patterns like iterative refinement and collaborative problem-solving. The key points are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;extraAgents&lt;/code&gt; to declare references outside &lt;code&gt;toolDirectory&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Important&lt;/strong&gt;: The &lt;code&gt;slug&lt;/code&gt; in &lt;code&gt;extraAgents&lt;/code&gt; must match the target agent’s actual &lt;code&gt;slug&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The system validates all references before runtime
&lt;/li&gt;
&lt;li&gt;Implement depth limits via &lt;code&gt;ToolExecutionContext&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Monitor for cycles and unintended infinite recursion
&lt;/li&gt;
&lt;li&gt;Document recursion patterns in system prompts
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more information, see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.AgentTree&lt;/code&gt; - Loading and initialization
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Tools.Context&lt;/code&gt; - Recursion tracking
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Base&lt;/code&gt; - &lt;code&gt;ExtraAgentRef&lt;/code&gt; type
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-advanced-configuration.html" rel="alternate"/><summary type="text">This guide covers advanced configuration patterns for agents-exe, including recursive agent references, mutual recursion, and runtime safety controls. ## Table of Contents - [Recursive Agent References](#recursive-agent-references) - [Self-</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-parameters-and-bindings.html</id><title type="text">Parameters, bindings, and narrowing sub-agents</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/parameters-and-bindings.md"&gt;&lt;code&gt;documentation/parameters-and-bindings.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="parameters-bindings-and-narrowing-sub-agents"&gt;Parameters, bindings, and narrowing sub-agents&lt;/h2&gt;
&lt;p&gt;Most agent frameworks give a tool’s arguments to the model in full, or hide
them entirely behind a wrapper script the author has to hand-maintain. This
feature gives you a middle ground with no code: an agent’s author declares a
handful of named &lt;strong&gt;parameters&lt;/strong&gt; — a tenant id, an API token, a base URL — and
then &lt;strong&gt;binds&lt;/strong&gt; them straight into any tool’s arguments. The model never sees
the bound value, never has to be told it, and never gets a chance to
mistype, leak, or override it. A secret parameter never even enters the
conversation, the session file, or a trace.&lt;/p&gt;
&lt;p&gt;The same mechanism reaches down the agent tree: one agent can partially
apply a &lt;em&gt;sub-agent’s&lt;/em&gt; tools before handing it a task — “call the diff
reviewer, but its own &lt;code&gt;git diff&lt;/code&gt; tool is pinned to this repo and this
branch” — without changing the sub-agent’s file at all, and without ever
seeing the values the sub-agent’s own author chose to keep hidden.&lt;/p&gt;
&lt;p&gt;If you only need one binding once, &lt;a href="#bindings"&gt;Bindings&lt;/a&gt; is all you need.
The rest of this document exists for when you need more: per-session
values from &lt;code&gt;agents-server&lt;/code&gt;, sub-agents that narrow other sub-agents, or a
narrowing worth reusing under a name.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#quick-example"&gt;Quick example&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#declaring-parameters"&gt;Declaring parameters&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#supplying-values"&gt;Supplying values&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#bindings"&gt;Bindings&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#secrets"&gt;Secrets&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#passing-parameters-to-sub-agents-with"&gt;Passing parameters to sub-agents (&lt;code&gt;with&lt;/code&gt;)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#narrowing-sub-agents-at-call-time"&gt;Narrowing sub-agents at call time&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#naming-a-narrowing-derive_agent"&gt;Naming a narrowing (&lt;code&gt;derive_agent&lt;/code&gt;)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#design-notes"&gt;Design notes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="quick-example"&gt;Quick example&lt;/h3&gt;
&lt;p&gt;An agent that declares a &lt;code&gt;tenant&lt;/code&gt; parameter and binds it into a bash tool’s
&lt;code&gt;tenant_id&lt;/code&gt; argument, so the model can call &lt;code&gt;query-invoices&lt;/code&gt; without ever
knowing — or choosing — which tenant it is querying:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;invoices-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;answers questions about a tenant&amp;#39;s invoices&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;You are an invoices assistant.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;parameters&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;session&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;bashToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileSystemDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Bindings&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;query-invoices&lt;/code&gt;’ schema, as the model sees it, has no &lt;code&gt;tenant_id&lt;/code&gt;
argument at all — it is indistinguishable from a tool that never had one.
Run it with a value for &lt;code&gt;tenant&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;agents-exe run --agent-file agent.json --set tenant=acme-corp --prompt &amp;quot;how many invoices are overdue?&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="declaring-parameters"&gt;Declaring parameters&lt;/h3&gt;
&lt;p&gt;An agent’s &lt;code&gt;parameters&lt;/code&gt; field is a list of named holes its author declares;
a caller supplies the value. Nothing here is visible to the model — a
parameter is plumbing, not a tool argument the LLM fills in.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;parameters&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;which tenant&amp;#39;s data to operate on&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;session&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;github_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;secret&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;process&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;EnvVar&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;GITHUB_TOKEN&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;Matched by &lt;code&gt;Param&lt;/code&gt; bindings, &lt;code&gt;--set&lt;/code&gt;/&lt;code&gt;--pin&lt;/code&gt;, &lt;code&gt;with&lt;/code&gt;, and the HTTP API.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;For the operator's own documentation; never shown to the model.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;secret&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The value is a string, and is never persisted, traced, or returned by any API — see [Secrets](#secrets).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;scope&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;"process"&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Who may supply it: &lt;code&gt;"process"&lt;/code&gt; (only the operator, at startup), &lt;code&gt;"session"&lt;/code&gt; or &lt;code&gt;"message"&lt;/code&gt; (a caller of &lt;code&gt;agents-server&lt;/code&gt;, see [Supplying values](#supplying-values)).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;required&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;&lt;td&gt;An unbound required parameter is an error before any LLM call — at startup for a process-scope parameter, at session creation or message post for the others.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;default&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Resolved once, at tree load, if nothing else supplies a value first. Reuses the same source shapes as a toolbox secret: &lt;code&gt;{"tag": "Given", "contents": "literal"}&lt;/code&gt;, &lt;code&gt;{"tag": "EnvVar", "contents": "NAME"}&lt;/code&gt;, &lt;code&gt;{"tag": "FileSystem", "contents": "/path"}&lt;/code&gt;, &lt;code&gt;{"tag": "Command", "contents": ["cmd", "arg1", "arg2"]}&lt;/code&gt;, or &lt;code&gt;{"tag": "ApiKey", "contents": "key-id"}&lt;/code&gt; (an entry of the &lt;code&gt;--api-keys&lt;/code&gt; file).&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Resolution order for one parameter, first hit wins: a pinned process value
(&lt;code&gt;--pin&lt;/code&gt;) short-circuits everything else; then a message-scope value; then
a session-scope value; then a process value (&lt;code&gt;--set&lt;/code&gt;/&lt;code&gt;--set-json&lt;/code&gt;/
&lt;code&gt;--params-file&lt;/code&gt;); then &lt;code&gt;default&lt;/code&gt;; otherwise it is unbound.&lt;/p&gt;
&lt;h3 id="supplying-values"&gt;Supplying values&lt;/h3&gt;
&lt;h4 id="agents-exe-process-scope"&gt;&lt;code&gt;agents-exe&lt;/code&gt; (process scope)&lt;/h4&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;agents-exe run --agent-file agent.json \
    --set tenant=acme-corp \
    --set-json max_results=10 \
    --pin region=eu-west-1 \
    --params-file ./params.json \
    --prompt &amp;quot;...&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Flag&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--set NAME=VALUE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Sets a parameter to a string value. Repeatable.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--set-json NAME=JSON&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Sets a parameter to any JSON value (number, bool, object...). Repeatable.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--pin NAME=VALUE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Like &lt;code&gt;--set&lt;/code&gt;, but the value cannot be overridden by a session- or message-scope value from &lt;code&gt;agents-server&lt;/code&gt; — useful to lock a container to one tenant. Repeatable.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--pin-json NAME=JSON&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The JSON form of &lt;code&gt;--pin&lt;/code&gt;. Repeatable.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--params-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A JSON file of &lt;code&gt;{"name": value, ...}&lt;/code&gt;. Flags win over a file's values.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;These flags work the same way on &lt;code&gt;agents-server&lt;/code&gt; (see
&lt;a href="/agents-exe/docs-agents-server.html#parameters"&gt;agents-server.md&lt;/a&gt;), where they set values
every session shares.&lt;/p&gt;
&lt;h4 id="agents-server-session-and-message-scope"&gt;&lt;code&gt;agents-server&lt;/code&gt; (session and message scope)&lt;/h4&gt;
&lt;p&gt;A session- or message-scope parameter is supplied per request, in the same
&lt;code&gt;params&lt;/code&gt; object used by &lt;code&gt;POST /v1/sessions&lt;/code&gt;, &lt;code&gt;.../messages&lt;/code&gt;, &lt;code&gt;.../resume&lt;/code&gt;,
and &lt;code&gt;POST /v1/continuations/:token&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;curl -sS localhost:8080/v1/sessions \
    -d '{&amp;quot;agent&amp;quot;: &amp;quot;invoices-agent&amp;quot;, &amp;quot;message&amp;quot;: {&amp;quot;text&amp;quot;: &amp;quot;how many invoices are overdue?&amp;quot;}, &amp;quot;params&amp;quot;: {&amp;quot;tenant&amp;quot;: &amp;quot;acme-corp&amp;quot;}}'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A session-scope value is kept in memory for the life of the session (a
client must resupply it after a restart or eviction); a message-scope value
lasts for that one run only. Neither is ever written to the session file —
see &lt;a href="/agents-exe/docs-agents-server.html#parameters"&gt;agents-server.md&lt;/a&gt; for the full request
shape and error responses, and for setting parameters over MCP-over-HTTP
via &lt;code&gt;Agents-Param-&amp;lt;name&amp;gt;&lt;/code&gt; headers.&lt;/p&gt;
&lt;h3 id="bindings"&gt;Bindings&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;Bindings&lt;/code&gt; list on a toolbox description ties one tool’s argument to a
fixed value or to a parameter. It is supported on bash toolboxes (both
&lt;code&gt;FileSystemDirectory&lt;/code&gt; and &lt;code&gt;SingleTool&lt;/code&gt;), OpenAPI toolboxes, and PostgREST
toolboxes:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileSystemDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;Path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;Bindings&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;github_token&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;export-*&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;format&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;csv&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tool&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(all tools)&lt;/td&gt;&lt;td&gt;A glob (&lt;code&gt;*&lt;/code&gt; matches any run of characters) against the tool's name, to bind the same argument differently across several tools.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;arg&lt;/code&gt;&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;The argument name, as the underlying tool declares it.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;value&lt;/code&gt;&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"tag": "Literal", "contents": &amp;lt;json&amp;gt;}&lt;/code&gt; for a fixed value chosen by the agent's author, or &lt;code&gt;{"tag": "Param", "contents": "&amp;lt;parameter name&amp;gt;"}&lt;/code&gt;, resolved fresh at call time.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;whenUnbound&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;"fail"&lt;/code&gt;&lt;/td&gt;&lt;td&gt;What happens if a &lt;code&gt;Param&lt;/code&gt; binding has no value at call time: &lt;code&gt;"fail"&lt;/code&gt; (the call fails with a message an operator can act on; the model just sees a generic "tool not found"), &lt;code&gt;"omit"&lt;/code&gt; (the argument is left out — only valid for an optional argument), or &lt;code&gt;"expose"&lt;/code&gt; (the argument reappears in the tool's schema for the model to fill in itself, for as long as it is unbound — see below).&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;A bound argument is removed from the tool’s schema entirely — indistinguishable
from a tool that never had it. If the model sends the argument’s name
anyway, the bound value wins.&lt;/p&gt;
&lt;p&gt;An agent itself can also carry a top-level &lt;code&gt;bindings&lt;/code&gt; list, applied after
every toolbox’s own bindings and matched by the tool’s final, LLM-visible
name — the one way to bind an argument on a tool from a toolbox that has no
per-tool &lt;code&gt;tool&lt;/code&gt; glob of its own (a bash tool, for instance):&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;bindings&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_query_invoices&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="whenunbound-expose"&gt;&lt;code&gt;whenUnbound: &amp;quot;expose&amp;quot;&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Most bindings should fail or omit when unbound: a tool the model can only
half-use is worse than one it cannot see. &lt;code&gt;&amp;quot;expose&amp;quot;&lt;/code&gt; is the deliberate
exception, for an argument that is &lt;em&gt;usually&lt;/em&gt; supplied for the model but
should fall back to letting the model choose when it is not: the tool’s
schema is a live function of whether the session currently has a value for
that parameter, updating as an &lt;code&gt;agents-server&lt;/code&gt; session’s parameters are set
— no agent rebuild, no restart. A secret parameter cannot use
&lt;code&gt;&amp;quot;expose&amp;quot;&lt;/code&gt;: it would just let the model retype the secret in plain text,
defeating the reason it was marked secret.&lt;/p&gt;
&lt;h3 id="secrets"&gt;Secrets&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;secret: true&lt;/code&gt; parameter’s value is a string, and:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is redacted (&lt;code&gt;&amp;quot;&amp;lt;secret&amp;gt;&amp;quot;&lt;/code&gt;) everywhere it might otherwise be printed,
logged, or traced;
&lt;/li&gt;
&lt;li&gt;is never persisted — a session’s stored parameters only ever include
non-secret ones; a secret session-scope value lives only in
&lt;code&gt;agents-server&lt;/code&gt;’s own memory, and is lost on restart or eviction;
&lt;/li&gt;
&lt;li&gt;is never returned by any &lt;code&gt;agents-server&lt;/code&gt; API response;
&lt;/li&gt;
&lt;li&gt;never appears in the conversation itself: a bound value is merged into
the tool call just before dispatch, after the model’s turn is already
decided, so it is not part of the session’s own history.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A bash tool argument bound to a secret parameter must use the bash &lt;code&gt;env&lt;/code&gt;
calling mode (&lt;code&gt;&amp;quot;mode&amp;quot;: &amp;quot;env&amp;quot;&lt;/code&gt;), which passes it as an environment variable
rather than on the command line — anything else would show up in &lt;code&gt;ps&lt;/code&gt; and
in traces regardless of how carefully the framework kept it from the model.
&lt;code&gt;agents-exe check&lt;/code&gt; refuses to load an agent that gets this wrong.&lt;/p&gt;
&lt;p&gt;An MCP server gets a secret through its &lt;code&gt;env&lt;/code&gt; map (&lt;code&gt;{&amp;quot;tag&amp;quot;: &amp;quot;Param&amp;quot;, &amp;quot;contents&amp;quot;: &amp;quot;name&amp;quot;}&lt;/code&gt;);
see &lt;a href="/agents-exe/docs-mcp.html"&gt;mcp.md&lt;/a&gt;. The server starts once per tree, so only process-scope
parameters can be used there.&lt;/p&gt;
&lt;h3 id="passing-parameters-to-sub-agents-with"&gt;Passing parameters to sub-agents (&lt;code&gt;with&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;Parameter &lt;em&gt;values&lt;/em&gt; never travel to a sub-agent implicitly — a name like
&lt;code&gt;tenant&lt;/code&gt; is not special, and a sub-agent that happens to declare the same
parameter name should not silently inherit whatever the caller set. An
&lt;code&gt;extraAgents&lt;/code&gt; reference’s &lt;code&gt;with&lt;/code&gt; field says explicitly which of the
sub-agent’s own parameters the caller fills, and from what:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;diff-reviewer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./diff-reviewer.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;with&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;repo_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;github_token&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;with&lt;/code&gt; is resolved against the caller’s own parameters when the sub-agent
is actually prompted, and is checked at load time: every key must be a
parameter the sub-agent declares, and every required session-scope
parameter of the sub-agent must be covered — by &lt;code&gt;with&lt;/code&gt;, or by the
sub-agent’s own process value or default.&lt;/p&gt;
&lt;h3 id="narrowing-sub-agents-at-call-time"&gt;Narrowing sub-agents at call time&lt;/h3&gt;
&lt;p&gt;Every sub-agent reachable through &lt;code&gt;extraAgents&lt;/code&gt; or a &lt;code&gt;toolDirectory&lt;/code&gt; gets a
&lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; tool. Two more things come with it, letting an agent
partially apply a sub-agent’s &lt;em&gt;own&lt;/em&gt; tools — or one of &lt;em&gt;its&lt;/em&gt; sub-agents’,
arbitrarily deep — for one call, without touching any file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;describe_agent {&amp;quot;slug&amp;quot;: &amp;quot;&amp;lt;helper&amp;gt;&amp;quot;}&lt;/code&gt;&lt;/strong&gt; — registered whenever an agent
has at least one helper. It shows, from the caller’s own position in the
chain, what is still open: the helper’s declared parameters (and whether
each is already bound), its tools’ still-open arguments, and the same
view recursively for its own helpers. A helper marked &lt;code&gt;narrowable: false&lt;/code&gt;
(see below) shows only its &lt;code&gt;announce&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;bindings&lt;/code&gt; and &lt;code&gt;with&lt;/code&gt; on the &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; call itself&lt;/strong&gt; — the
same shapes as a toolbox’s &lt;code&gt;Bindings&lt;/code&gt; and a reference’s &lt;code&gt;with&lt;/code&gt;, but
chosen by the calling model, for this one call:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;what&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;review this diff for security issues&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;bindings&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;repo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;backend&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;linter&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;strict&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;with&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;severity_threshold&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;high&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Each binding’s optional &lt;code&gt;agent&lt;/code&gt; field addresses where it applies:
omitted for the helper itself, a slash-separated path (&lt;code&gt;&amp;quot;linter&amp;quot;&lt;/code&gt;,
&lt;code&gt;&amp;quot;a/b&amp;quot;&lt;/code&gt;) for one of its own helpers, or &lt;code&gt;&amp;quot;**&amp;quot;&lt;/code&gt; for the helper and
everything below it. A binding not addressed at the helper itself
travels down, re-rooted, for the helper to apply in turn when &lt;em&gt;it&lt;/em&gt;
prompts one of its own helpers — so a grandparent can bind an argument
three levels down in one call. A call-time &lt;code&gt;with&lt;/code&gt; cannot refill a
parameter the reference’s own static &lt;code&gt;with&lt;/code&gt; already fills.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A helper’s &lt;code&gt;extraAgents&lt;/code&gt; reference can set &lt;code&gt;&amp;quot;narrowable&amp;quot;: false&lt;/code&gt; (default:
&lt;code&gt;true&lt;/code&gt;) to refuse all of this: &lt;code&gt;describe_agent&lt;/code&gt; shows only its &lt;code&gt;announce&lt;/code&gt;,
and any &lt;code&gt;bindings&lt;/code&gt;/&lt;code&gt;with&lt;/code&gt; on a call into it — direct or inherited from
above — is refused. Bound arguments stay bound either way: &lt;code&gt;narrowable&lt;/code&gt;
only controls whether &lt;em&gt;more&lt;/em&gt; can be bound from outside, not whether an
operator’s own bindings in the helper’s file are visible.&lt;/p&gt;
&lt;p&gt;Errors the calling model can act on — an unknown helper, no tool matching
a glob, no such open argument, a &lt;code&gt;narrowable: false&lt;/code&gt; target — are reported
before the helper runs, naming what is still open, so one retry usually
suffices. What is actually bound never appears in the response either way,
by the same rule as any other binding.&lt;/p&gt;
&lt;h3 id="naming-a-narrowing-derive_agent"&gt;Naming a narrowing (&lt;code&gt;derive_agent&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;Repeating the same &lt;code&gt;bindings&lt;/code&gt; on every call costs tokens and invites
inconsistency. &lt;code&gt;derive_agent&lt;/code&gt; saves one under a name for the rest of the
session:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;from&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;diff-reviewer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;backend-strict&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;bindings&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;repo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;backend&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;with&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;severity_threshold&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;high&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;and any later &lt;code&gt;prompt_agent_&amp;lt;from&amp;gt;&lt;/code&gt; call reuses it with &lt;code&gt;&amp;quot;as&amp;quot;: &amp;quot;&amp;lt;slug&amp;gt;&amp;quot;&lt;/code&gt;,
instead of repeating &lt;code&gt;bindings&lt;/code&gt;/&lt;code&gt;with&lt;/code&gt;. It is sugar, not a new mechanism —
nothing is stored beyond that &lt;code&gt;derive_agent&lt;/code&gt; call landing in the session’s
own history, folded back into a table the next time it is needed. An
unknown &lt;code&gt;as&lt;/code&gt; name tells the model to call &lt;code&gt;derive_agent&lt;/code&gt; first, and
&lt;code&gt;narrowable: false&lt;/code&gt; refuses &lt;code&gt;derive_agent&lt;/code&gt; and &lt;code&gt;as&lt;/code&gt; the same way it
refuses an inline &lt;code&gt;bindings&lt;/code&gt;/&lt;code&gt;with&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="design-notes"&gt;Design notes&lt;/h3&gt;
&lt;p&gt;A handful of decisions shape all of the above, in case they explain a
surprise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The author decides what is bindable, not the caller.&lt;/strong&gt; Otherwise any
client of &lt;code&gt;agents-server&lt;/code&gt; could pin any argument of any tool.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The schema is static&lt;/strong&gt;, except for &lt;code&gt;&amp;quot;expose&amp;quot;&lt;/code&gt;: a bound argument is
hidden whether or not a value is currently present, so the tool list
stays identical across sessions — simpler prompt caching, simpler
reasoning about what the model can do.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No templating.&lt;/strong&gt; A parameter never appears inside a system prompt or a
path string; it only ever fills a tool argument. Templating changes the
agent’s definition per session and puts values in front of the model,
which is a different feature with different risks.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Values live in the call context, never in the registration.&lt;/strong&gt; A
toolbox loads once and is shared across every session that uses it
(hot-reload, one MCP connection, one SQLite handle); rebuilding it per
session would mean re-describing every script and restarting every MCP
server.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;code&gt;todos/tool-partial-application.md&lt;/code&gt; in the repository for the full
design rationale and the phased implementation history, if you want the
“why” behind any of the above in more depth.&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-parameters-and-bindings.html" rel="alternate"/><summary type="text">Most agent frameworks give a tool's arguments to the model in full, or hide them entirely behind a wrapper script the author has to hand-maintain. This feature gives you a middle ground with no code: an agent's author declares a handful of</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-sessions.html</id><title type="text">Session Management</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/sessions.md"&gt;&lt;code&gt;documentation/sessions.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="session-management"&gt;Session Management&lt;/h2&gt;
&lt;p&gt;&lt;img src="/agents-exe/gen/images/session-lifecycle.dot.png" alt="The statuses of a session and what moves it from one to the next." /&gt;&lt;/p&gt;
&lt;p&gt;Session management provides persistent storage and retrieval of agent conversations, enabling conversation resumption, history analysis, and multi-modal content support. Sessions can now be stored across multiple locations with a unified read view.&lt;/p&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;p&gt;Sessions represent complete conversations between users and agents, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Session metadata&lt;/strong&gt;: IDs, timestamps, agent references, version info
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turn history&lt;/strong&gt;: Complete conversation turns
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool calls&lt;/strong&gt;: Records of tool invocations and results
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media attachments&lt;/strong&gt;: Base64-encoded images, documents, audio, video
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context&lt;/strong&gt;: Full conversation state for resumption
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The SessionStore now supports &lt;strong&gt;multi-location storage&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Write location&lt;/strong&gt;: Single directory where new sessions are written
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read locations&lt;/strong&gt;: Multiple directories searched for existing sessions
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deduplication&lt;/strong&gt;: First location wins when sessions exist in multiple places
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tilde expansion&lt;/strong&gt;: Paths like &lt;code&gt;~/.config/agents-exe/sessions/&lt;/code&gt; are resolved automatically
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                       Session                                │
├─────────────────────────────────────────────────────────────┤
│  SessionId: &amp;quot;uuid&amp;quot;                                          │
│  ConversationId: &amp;quot;uuid&amp;quot;                                     │
│  AgentSlug: &amp;quot;my-agent&amp;quot;                                      │
│  SessionVersion: 1                                          │
├─────────────────────────────────────────────────────────────┤
│  Turns:                                                      │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ Turn 1                                              │   │
│  │   User: &amp;quot;Hello!&amp;quot;                                    │   │
│  │   [📎 image.png]                                    │   │
│  │   Assistant: &amp;quot;Hi there!&amp;quot;                            │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ Turn 2                                              │   │
│  │   User: &amp;quot;List files&amp;quot;                                │   │
│  │   Tool: list_files -&amp;gt; [&amp;quot;a.txt&amp;quot;, &amp;quot;b.txt&amp;quot;]            │   │
│  │   [📎 screenshot.png]                               │   │
│  │   Assistant: &amp;quot;Found 2 files...&amp;quot;                     │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                  Multi-Location SessionStore                 │
├─────────────────────────────────────────────────────────────┤
│  Write Location: ./sessions/                                 │
│  Read Locations:                                             │
│    1. ./sessions/           (primary, write location)       │
│    2. ./.agents-sessions/   (project-local archive)         │
│    3. ~/.config/agents-exe/sessions/  (global storage)      │
├─────────────────────────────────────────────────────────────┤
│  Deduplication: First location wins by ConversationId       │
│  Priority: ./sessions/ &amp;gt; ./.agents-sessions/ &amp;gt; ~/.config/   │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="core-types"&gt;Core Types&lt;/h3&gt;
&lt;h4 id="session-types-systemagentssessiontypes"&gt;Session Types (&lt;code&gt;System.Agents.Session.Types&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | User query - can include text and media attachments.&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;UserQuery&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserQuery&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; queryText ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ The text query/prompt&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; queryMedia ::&lt;/span&gt; [&lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;]&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Optional media attachments (images, audio, video, etc.)&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Tool response from the user/agent system to the LLM.&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TextResponse&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                    &lt;span class="co"&gt;-- Plain UTF-8 text&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;JsonResponse&lt;/span&gt; &lt;span class="dt"&gt;Aeson.Value&lt;/span&gt;             &lt;span class="co"&gt;-- Structured JSON data&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaResponse&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;        &lt;span class="co"&gt;-- Single binary media (base64-encoded)&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MixedResponse&lt;/span&gt; [&lt;span class="dt"&gt;ContentPart&lt;/span&gt;]          &lt;span class="co"&gt;-- Multi-modal: alternating text and media&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Individual part of a mixed multi-modal response.&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ContentPart&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TextPart&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaPart&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | A media attachment containing base64-encoded binary data.&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; mediaMimeType ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;        &lt;span class="co"&gt;-- ^ MIME type (e.g., &amp;quot;image/png&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mediaBase64Data ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;      &lt;span class="co"&gt;-- ^ Base64-encoded content&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mediaFilename ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;  &lt;span class="co"&gt;-- ^ Optional filename&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Session with versioning for backwards compatibility.&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; sessionId ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; forkedFromSessionId ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;  &lt;span class="co"&gt;-- ^ For conversation forking&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; turnId ::&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; turns ::&lt;/span&gt; [&lt;span class="dt"&gt;Turn&lt;/span&gt;]&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sessionVersion ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Optional session version:&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;--   Nothing = legacy (pre-media)&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;--   Just 1 = media support enabled&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | User turn content including possible media.&lt;/span&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;UserTurnContent&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserTurnContent&lt;/span&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; userPrompt ::&lt;/span&gt; &lt;span class="dt"&gt;SystemPrompt&lt;/span&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; userTools ::&lt;/span&gt; [&lt;span class="dt"&gt;SystemTool&lt;/span&gt;]&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; userQuery ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UserQuery&lt;/span&gt;&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Query with optional media attachments&lt;/span&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; userToolResponses ::&lt;/span&gt; [(&lt;span class="dt"&gt;LlmToolCall&lt;/span&gt;, &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;)]&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Tool responses with multi-modal support&lt;/span&gt;&lt;/span&gt;
&lt;span id="51"&gt;&lt;a href="#51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="52"&gt;&lt;a href="#52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="53"&gt;&lt;a href="#53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Turn&lt;/span&gt;&lt;/span&gt;
&lt;span id="54"&gt;&lt;a href="#54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserTurn&lt;/span&gt; &lt;span class="dt"&gt;UserTurnContent&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;StepByteUsage&lt;/span&gt;)&lt;/span&gt;
&lt;span id="55"&gt;&lt;a href="#55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;LlmTurn&lt;/span&gt; &lt;span class="dt"&gt;LlmTurnContent&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;StepByteUsage&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="media-types-systemagentsmediatypes"&gt;Media Types (&lt;code&gt;System.Agents.Media.Types&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | High-level media type classification.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;MediaType&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;MediaImage&lt;/span&gt; &lt;span class="dt"&gt;ImageType&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaAudio&lt;/span&gt; &lt;span class="dt"&gt;AudioType&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaVideo&lt;/span&gt; &lt;span class="dt"&gt;VideoType&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaApplication&lt;/span&gt; &lt;span class="dt"&gt;ApplicationType&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaText&lt;/span&gt; &lt;span class="dt"&gt;TextSubtype&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ImageType&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ImagePNG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ImageJPEG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ImageGIF&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ImageWebP&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ImageSVG&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AudioType&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AudioMPEG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioWAV&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioOGG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioMP3&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioAAC&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioFLAC&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;VideoType&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;VideoMP4&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;VideoWebM&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;VideoOGG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;VideoAVI&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;VideoMOV&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ApplicationType&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AppPDF&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppJSON&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppXML&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppOctetStream&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppZip&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;TextSubtype&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TextPlain&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TextHTML&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TextCSS&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TextCSV&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TextMarkdown&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="session-versioning"&gt;Session Versioning&lt;/h3&gt;
&lt;p&gt;Sessions include a version field for backwards compatibility:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Version&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Nothing&lt;/code&gt; / missing&lt;/td&gt;&lt;td&gt;Legacy session (pre-media support)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Just 1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Full media support enabled&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="backwards-compatibility"&gt;Backwards Compatibility&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- JSON serialization handles both old and new formats&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;FromJSON&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    parseJSON &lt;span class="ot"&gt;=&lt;/span&gt; Aeson.withObject &lt;span class="st"&gt;&amp;quot;Session&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        mVersion &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; v &lt;span class="op"&gt;.:?&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sessionVersion&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;turns&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sessionId&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; v &lt;span class="op"&gt;.:?&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;forkedFromSessionId&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;turnId&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; mVersion&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;ToJSON&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    toJSON s &lt;span class="ot"&gt;=&lt;/span&gt; Aeson.object &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ &lt;span class="st"&gt;&amp;quot;turns&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; s&lt;span class="op"&gt;.&lt;/span&gt;turns&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="st"&gt;&amp;quot;sessionId&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; s&lt;span class="op"&gt;.&lt;/span&gt;sessionId&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="st"&gt;&amp;quot;forkedFromSessionId&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; s&lt;span class="op"&gt;.&lt;/span&gt;forkedFromSessionId&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="st"&gt;&amp;quot;turnId&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; s&lt;span class="op"&gt;.&lt;/span&gt;turnId&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;++&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;sessionVersion&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; v &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; v &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; [s&lt;span class="op"&gt;.&lt;/span&gt;sessionVersion]]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="media-attachments"&gt;Media Attachments&lt;/h3&gt;
&lt;h4 id="supported-media-types"&gt;Supported Media Types&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Category&lt;/th&gt;&lt;th&gt;Extensions&lt;/th&gt;&lt;th&gt;MIME Types&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Images&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.png&lt;/code&gt;, &lt;code&gt;.jpg&lt;/code&gt;, &lt;code&gt;.jpeg&lt;/code&gt;, &lt;code&gt;.gif&lt;/code&gt;, &lt;code&gt;.webp&lt;/code&gt;, &lt;code&gt;.svg&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;image/png&lt;/code&gt;, &lt;code&gt;image/jpeg&lt;/code&gt;, &lt;code&gt;image/gif&lt;/code&gt;, &lt;code&gt;image/webp&lt;/code&gt;, &lt;code&gt;image/svg+xml&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Documents&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.pdf&lt;/code&gt;, &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.md&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;, &lt;code&gt;.xml&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;application/pdf&lt;/code&gt;, &lt;code&gt;text/plain&lt;/code&gt;, &lt;code&gt;text/markdown&lt;/code&gt;, &lt;code&gt;application/json&lt;/code&gt;, &lt;code&gt;application/xml&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Audio&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.mp3&lt;/code&gt;, &lt;code&gt;.wav&lt;/code&gt;, &lt;code&gt;.ogg&lt;/code&gt;, &lt;code&gt;.aac&lt;/code&gt;, &lt;code&gt;.flac&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;audio/mp3&lt;/code&gt;, &lt;code&gt;audio/wav&lt;/code&gt;, &lt;code&gt;audio/ogg&lt;/code&gt;, &lt;code&gt;audio/aac&lt;/code&gt;, &lt;code&gt;audio/flac&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Video&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.mp4&lt;/code&gt;, &lt;code&gt;.webm&lt;/code&gt;, &lt;code&gt;.mov&lt;/code&gt;, &lt;code&gt;.avi&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;video/mp4&lt;/code&gt;, &lt;code&gt;video/webm&lt;/code&gt;, &lt;code&gt;video/quicktime&lt;/code&gt;, &lt;code&gt;video/avi&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="creating-media-attachments"&gt;Creating Media Attachments&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;Data.ByteString.Base64&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;B64&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;Data.Text.Encoding&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create a media attachment from file&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;createMediaAttachment ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;createMediaAttachment path &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    content &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; BS.readFile path&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; mimeType &lt;span class="ot"&gt;=&lt;/span&gt; detectMimeType path&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; base64Data &lt;span class="ot"&gt;=&lt;/span&gt; Text.decodeUtf8 &lt;span class="op"&gt;$&lt;/span&gt; B64.encode content&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Right&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { mediaMimeType &lt;span class="ot"&gt;=&lt;/span&gt; mimeType&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , mediaBase64Data &lt;span class="ot"&gt;=&lt;/span&gt; base64Data&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , mediaFilename &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; Text.pack &lt;span class="op"&gt;$&lt;/span&gt; takeFileName path&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Detect MIME type from file extension&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;detectMimeType ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;detectMimeType path &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; takeExtension path &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;.png&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;.jpg&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/jpeg&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;.jpeg&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/jpeg&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;.pdf&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;application/pdf&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ... etc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="using-media-in-queries"&gt;Using Media in Queries&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create a query with media attachments&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; query &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserQuery&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { queryText &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Describe this image&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , queryMedia &lt;span class="ot"&gt;=&lt;/span&gt; [imageAttachment, documentAttachment]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- The query is sent to the LLM with media included&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tool-responses-with-media"&gt;Tool Responses with Media&lt;/h4&gt;
&lt;p&gt;Tools can return media responses:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Tool returns an image&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; toolResponse &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;MediaResponse&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { mediaMimeType &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , mediaBase64Data &lt;span class="ot"&gt;=&lt;/span&gt; base64EncodedImageData&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , mediaFilename &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;chart.png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Tool returns mixed text and media&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; toolResponse &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;MixedResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ &lt;span class="dt"&gt;TextPart&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Here&amp;#39;s the analysis chart:&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="dt"&gt;MediaPart&lt;/span&gt; chartAttachment&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="dt"&gt;TextPart&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;As you can see, the trend is increasing.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="session-store"&gt;Session Store&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;SessionStore&lt;/code&gt; module provides persistent storage with multi-location support:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; sessionWritePrefix ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Directory where new sessions are written&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sessionReadPrefixes ::&lt;/span&gt; [&lt;span class="dt"&gt;FilePath&lt;/span&gt;]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Directories to search for existing sessions, in priority order&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="creating-a-sessionstore"&gt;Creating a SessionStore&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.SessionStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create with separate write and read locations&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;store &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; mkSessionStore&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;                              &lt;span class="co"&gt;-- Write location&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [&lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;~/.config/agents-exe/sessions/&amp;quot;&lt;/span&gt;]  &lt;span class="co"&gt;-- Read locations&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create simple single-location store (backwards compatible)&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;simpleStore &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; mkSimpleSessionStore &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Resolve tilde paths automatically&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;resolvedPath &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; resolveSessionPath &lt;span class="st"&gt;&amp;quot;~/.config/agents-exe/sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Returns: &amp;quot;/home/user/.config/agents-exe/sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="key-behaviors"&gt;Key Behaviors&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write Location&lt;/strong&gt;: All new sessions are written to &lt;code&gt;sessionWritePrefix&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Read Locations&lt;/strong&gt;: When reading sessions, all &lt;code&gt;sessionReadPrefixes&lt;/code&gt; are searched in order&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Auto-prepending&lt;/strong&gt;: If write location is not in read locations, it’s automatically prepended to ensure newly written sessions are immediately readable&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deduplication&lt;/strong&gt;: When listing sessions, if the same session ID exists in multiple locations, the first occurrence (highest priority) is kept&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tilde Expansion&lt;/strong&gt;: Paths starting with &lt;code&gt;~&lt;/code&gt; are automatically expanded to the user’s home directory&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="configuration"&gt;Configuration&lt;/h4&gt;
&lt;p&gt;Configure multi-location session storage in &lt;code&gt;agents-exe.cfg.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsConfigDir&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;~/.config/agents-exe&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsFiles&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;writeLocation&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;readLocations&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./.agents-sessions/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./task-sessions/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;~/.config/agents-exe/sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Configuration Fields:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Required&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sessions.writeLocation&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;FilePath&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Directory where new sessions are written&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sessions.readLocations&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[FilePath]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Directories to search for existing sessions&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Backwards Compatibility:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;sessions&lt;/code&gt; section is missing, falls back to &lt;code&gt;agentsLogs.logSessionsJsonPrefix&lt;/code&gt; (deprecated)
&lt;/li&gt;
&lt;li&gt;If no prefix is configured, uses &lt;code&gt;~/.config/agents-exe/sessions/&lt;/code&gt; as default
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="use-cases"&gt;Use Cases&lt;/h4&gt;
&lt;h5 id="personal--project-sessions"&gt;Personal + Project Sessions&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;writeLocation&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;readLocations&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;~/.config/agents-exe/sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;New sessions go to &lt;code&gt;./sessions/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Can access personal history from home directory
&lt;/li&gt;
&lt;li&gt;Project sessions take precedence if ID conflicts
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="task-based-organization"&gt;Task-Based Organization&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;writeLocation&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./task-sessions/current/&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;readLocations&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./task-sessions/current/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./task-sessions/archive/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Current task sessions in &lt;code&gt;current/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Archived tasks still searchable
&lt;/li&gt;
&lt;li&gt;General project sessions as fallback
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="team-shared-sessions"&gt;Team Shared Sessions&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;writeLocation&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./my-sessions/&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;readLocations&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./my-sessions/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./shared-sessions/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;~/.config/agents-exe/sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Personal work in &lt;code&gt;my-sessions/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Team-shared sessions in &lt;code&gt;shared-sessions/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Personal history available
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="file-naming"&gt;File Naming&lt;/h4&gt;
&lt;p&gt;Sessions are stored with the pattern &lt;code&gt;conv.&amp;lt;uuid&amp;gt;.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sessions/
├── conv.550e8400-e29b-41d4-a716-446655440000.json
├── conv.6ba7b810-9dad-11d1-80b4-00c04fd430c8.json
└── conv.6ba7b811-9dad-11d1-80b4-00c04fd430c8.json
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="session-store-operations"&gt;Session Store Operations&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Store a session (always writes to sessionWritePrefix)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;storeSession ::&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Read a session (searches all read locations in order)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;readSession ::&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- List all sessions (aggregates from all read locations, deduplicated)&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;listSessions ::&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [(&lt;span class="dt"&gt;FilePath&lt;/span&gt;, &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;, &lt;span class="dt"&gt;ConversationId&lt;/span&gt;)]&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Generate file path for a session&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sessionFilePath ::&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sessionWritePath ::&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="session-lifecycle"&gt;Session Lifecycle&lt;/h3&gt;
&lt;h4 id="creating-a-session"&gt;Creating a Session&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;newSession ::&lt;/span&gt; &lt;span class="dt"&gt;AgentSlug&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;newSession slug &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    sid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; UUID.nextRandom&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    cid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; UUID.nextRandom&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; UUID.nextRandom&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { sessionId &lt;span class="ot"&gt;=&lt;/span&gt; sid&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , forkedFromSessionId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , turnId &lt;span class="ot"&gt;=&lt;/span&gt; tid&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , turns &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , sessionVersion &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;  &lt;span class="co"&gt;-- New sessions use version 1&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="adding-a-turn"&gt;Adding a Turn&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;addUserTurn ::&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UserQuery&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;ToolCallRecord&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;addUserTurn session query calls &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; userContent &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserTurnContent&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            { userPrompt &lt;span class="ot"&gt;=&lt;/span&gt; currentPrompt&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , userTools &lt;span class="ot"&gt;=&lt;/span&gt; availableTools&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , userQuery &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; query&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , userToolResponses &lt;span class="ot"&gt;=&lt;/span&gt; calls&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; turn &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserTurn&lt;/span&gt; userContent &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; session { turns &lt;span class="ot"&gt;=&lt;/span&gt; turns session &lt;span class="op"&gt;++&lt;/span&gt; [turn] }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="conversation-loop"&gt;Conversation Loop&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;conversationLoop ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Runtime&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;conversationLoop store runtime session &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Get user input (possibly with media)&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (input, media) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getUserInput&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; query &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserQuery&lt;/span&gt; input media&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Call LLM with session context and media&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; messages &lt;span class="ot"&gt;=&lt;/span&gt; sessionToMessages session&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    response &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; callLLM runtime messages query&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Execute any tool calls&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    toolResults &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; executeToolCalls runtime (toolCalls response)&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Update session&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    newSession &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; addTurn session query toolResults&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Persist (always writes to write location)&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    storeSession store (conversationId newSession) newSession&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Continue&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    conversationLoop store runtime newSession&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="session-serialization"&gt;Session Serialization&lt;/h3&gt;
&lt;h4 id="json-format"&gt;JSON Format&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessionId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;550e8400-e29b-41d4-a716-446655440000&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;turnId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;6ba7b810-9dad-11d1-80b4-00c04fd430c8&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;forkedFromSessionId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;turns&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;UserTurn&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;userPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;You are helpful...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;userTools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="er"&gt;...&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;userQuery&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;What&amp;#39;s in this image?&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;media&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;mimeType&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;base64Data&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;iVBORw0KGgoAAAANSUhEUgAA...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;filename&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;screenshot.png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;userToolResponses&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;byteUsage&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;inputBytes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1234&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;outputBytes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;567&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;reasoningBytes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;totalBytes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1801&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;LlmTurn&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;llmResponse&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;I can see a chart showing...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;llmThinking&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;llmToolCalls&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessionVersion&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="usertoolresponse-json-formats"&gt;UserToolResponse JSON Formats&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;TextResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;The file contains...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;JsonResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;42&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;MediaResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;media&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;mimeType&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;base64Data&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;iVBORw0KGgoAAAANSUhEUgAA...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;filename&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;chart.png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;MixedResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;mixed&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;parts&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Here&amp;#39;s the chart:&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;media&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;mimeType&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;base64Data&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;As you can see...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="session-operations"&gt;Session Operations&lt;/h3&gt;
&lt;h4 id="resuming-a-session"&gt;Resuming a Session&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Start with existing session&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="at"&gt;--session-file&lt;/span&gt; session.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mainOneShot ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;  &lt;span class="co"&gt;-- Session file path&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;   &lt;span class="co"&gt;-- Pre-loaded session&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Props&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;            &lt;span class="co"&gt;-- Prompt&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [&lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="co"&gt;-- Media attachments&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;mainOneShot store mPath mSession props prompt media &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Load or create session&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    session &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; mSession &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Just&lt;/span&gt; s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;return&lt;/span&gt; s&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; mPath &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;Just&lt;/span&gt; path &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; fromMaybe (newSession props&lt;span class="op"&gt;.&lt;/span&gt;agentSlug) &lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                   &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; readSessionFromFile path&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; newSession props&lt;span class="op"&gt;.&lt;/span&gt;agentSlug&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create query with media&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; query &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserQuery&lt;/span&gt; prompt media&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Run conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Save session (to write location)&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    writeSession store updatedSession&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="session-printing-systemagentssessionprint"&gt;Session Printing (&lt;code&gt;System.Agents.SessionPrint&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;SessionPrint&lt;/code&gt; module provides rich markdown formatting for session files, including statistics visualization and configurable content display with media support.&lt;/p&gt;
&lt;h4 id="session-print-types"&gt;Session Print Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Preference for ordering session steps.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;OrderPreference&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Chronological&lt;/span&gt;      &lt;span class="co"&gt;-- Oldest first&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Antichronological&lt;/span&gt;  &lt;span class="co"&gt;-- Newest first&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Amount of content to print (lines or characters).&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;PrintAmount&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Lines&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Chars&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Visibility preference for displaying content.&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;PrintVisibility&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Hidden&lt;/span&gt;                    &lt;span class="co"&gt;-- Don&amp;#39;t show content&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Elided&lt;/span&gt; &lt;span class="dt"&gt;PrintAmount&lt;/span&gt; &lt;span class="dt"&gt;PrintAmount&lt;/span&gt;  &lt;span class="co"&gt;-- Show leading/trailing, elide middle&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ShownFull&lt;/span&gt;                 &lt;span class="co"&gt;-- Show complete content&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Options for controlling session print output.&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionPrintOptions&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionPrintOptions&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; sessionPrintFile ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; showToolCallResults ::&lt;/span&gt; &lt;span class="dt"&gt;PrintVisibility&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; showToolCallArguments ::&lt;/span&gt; &lt;span class="dt"&gt;PrintVisibility&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; nTurns ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; repeatSystemPrompt ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; repeatTools ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; orderPreference ::&lt;/span&gt; &lt;span class="dt"&gt;OrderPreference&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; noFunnyStamp ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Statistics about a session.&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionStatistics&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionStatistics&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; statTotalTurns ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; statUserTurns ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; statLlmTurns ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; statTotalToolCalls ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; statToolCallsByName ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; statInputBytes ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; statOutputBytes ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; statReasoningBytes ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; statTotalBytes ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; statMediaAttachments ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;  &lt;span class="co"&gt;-- NEW: Count of media attachments&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="cli-session-print-command"&gt;CLI: session-print Command&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Print full session&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print session.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Print with tool call results visible&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--show-tool-call-results&lt;/span&gt; shown session.json&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Show tool call arguments too&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--show-tool-call-results&lt;/span&gt; shown &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--show-tool-call-arguments&lt;/span&gt; shown &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    session.json&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Elide long outputs (show first/last 10 lines)&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--show-tool-call-results&lt;/span&gt; elided session.json&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Limit to N turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--n-turns&lt;/span&gt; 5 session.json&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Reverse chronological order&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--antichronological&lt;/span&gt; session.json&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Show system prompts and tools each turn&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--repeat-system-prompt&lt;/span&gt; &lt;span class="at"&gt;--repeat-tools&lt;/span&gt; session.json&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Skip the ASCII art logo&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--no-funny-stamp&lt;/span&gt; session.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="formatting-media-attachments"&gt;Formatting Media Attachments&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;formatToolResponse ::&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;formatToolResponse (&lt;span class="dt"&gt;TextResponse&lt;/span&gt; txt) &lt;span class="ot"&gt;=&lt;/span&gt; txt&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;formatToolResponse (&lt;span class="dt"&gt;JsonResponse&lt;/span&gt; val) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    Text.decodeUtf8 &lt;span class="op"&gt;$&lt;/span&gt; LByteString.toStrict &lt;span class="op"&gt;$&lt;/span&gt; Aeson.encodePretty val&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;formatToolResponse (&lt;span class="dt"&gt;MediaResponse&lt;/span&gt; media) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;[Media: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; media&lt;span class="op"&gt;.&lt;/span&gt;mediaMimeType &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;maybe&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;quot;&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;, &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt;) media&lt;span class="op"&gt;.&lt;/span&gt;mediaFilename &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;, &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; formatBytes (Text.length media&lt;span class="op"&gt;.&lt;/span&gt;mediaBase64Data &lt;span class="ot"&gt;`div`&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;) &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;]&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;formatToolResponse (&lt;span class="dt"&gt;MixedResponse&lt;/span&gt; parts) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    Text.intercalate &lt;span class="st"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; formatContentPart parts&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    formatContentPart (&lt;span class="dt"&gt;TextPart&lt;/span&gt; t) &lt;span class="ot"&gt;=&lt;/span&gt; t&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    formatContentPart (&lt;span class="dt"&gt;MediaPart&lt;/span&gt; m) &lt;span class="ot"&gt;=&lt;/span&gt; formatToolResponse (&lt;span class="dt"&gt;MediaResponse&lt;/span&gt; m)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="content-elision"&gt;Content Elision&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;elideDocument&lt;/code&gt; function intelligently handles content that’s too long:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Elide a document by keeping leading and trailing portions.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;elideDocument ::&lt;/span&gt; &lt;span class="dt"&gt;PrintAmount&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PrintAmount&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Examples:&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;elideDocument (&lt;span class="dt"&gt;Lines&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;) (&lt;span class="dt"&gt;Lines&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;) &lt;span class="st"&gt;&amp;quot;line1\nline2\n...\nline7&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Shows all 7 lines (no overlap)&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;elideDocument (&lt;span class="dt"&gt;Lines&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;) (&lt;span class="dt"&gt;Lines&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;) &lt;span class="st"&gt;&amp;quot;line1\nline2\nline3\nline4\nline5&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;quot;line1\nline2\n... (1 line elided) ...\nline4\nline5&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="statistics-visualization"&gt;Statistics Visualization&lt;/h4&gt;
&lt;p&gt;Session print includes visual bar charts for:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tool usage&lt;/strong&gt;: Bar chart showing which tools were called most
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Byte usage&lt;/strong&gt;: Input, output, and reasoning token breakdown
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media attachments&lt;/strong&gt;: Count and types of media
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;📊 Statistics

### 🔧 Tool Calls

Total Tool Calls: 15

`read-file`         8   ████████████████████████████████████████
`write-file`        4   ████████████████████
`grep-files`        3   ███████████████

### 💾 Byte Usage

`Input    `      2 KiB   ████████████████████████
`Output   `      5 KiB   ████████████████████████████████████████████████
`Reasoning`      1 KiB   ████████████

`Media    `     50 KiB   ████████████████████████████████████████████████████████████████████████████████████████████████████

Total: 58 KiB
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="session-content-injection-systemagentssessionprintinject"&gt;Session Content Injection (&lt;code&gt;System.Agents.SessionPrint.Inject&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;SessionInject&lt;/code&gt; module allows injecting session content into prompts with various verbosity levels.&lt;/p&gt;
&lt;h4 id="injection-verbosity-levels"&gt;Injection Verbosity Levels&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionInjectMode&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionXS&lt;/span&gt;   &lt;span class="co"&gt;-- Minimal: queries/responses only, skips tool-only turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionS&lt;/span&gt;    &lt;span class="co"&gt;-- Low: +thinking, +tool names&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionM&lt;/span&gt;    &lt;span class="co"&gt;-- Medium: +statistics&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionL&lt;/span&gt;    &lt;span class="co"&gt;-- High: +tool call results&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionXL&lt;/span&gt;   &lt;span class="co"&gt;-- Maximum: complete session&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="cli-session-injection-options"&gt;CLI: Session Injection Options&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Inject session at minimal verbosity&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--session-xs&lt;/span&gt; previous-session.json &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Continue...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Inject at low verbosity&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--session-s&lt;/span&gt; previous-session.json &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Continue...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Inject at medium verbosity&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--session-m&lt;/span&gt; previous-session.json &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Continue...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Inject at high verbosity (includes tool results)&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--session-l&lt;/span&gt; previous-session.json &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Continue...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Maximum verbosity&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--session-xl&lt;/span&gt; previous-session.json &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Continue...&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="programmatic-usage"&gt;Programmatic Usage&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.SessionPrint.Inject&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Load session content at specific verbosity&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;loadSessionForPrompt ::&lt;/span&gt; &lt;span class="dt"&gt;SessionInjectMode&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;loadSessionForPrompt mode session &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; mode &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SessionXS&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; formatMinimal session   &lt;span class="co"&gt;-- Just user queries and LLM responses&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SessionS&lt;/span&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; formatLow session       &lt;span class="co"&gt;-- + thinking process&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SessionM&lt;/span&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; formatMedium session    &lt;span class="co"&gt;-- + statistics&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SessionL&lt;/span&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; formatHigh session      &lt;span class="co"&gt;-- + tool call results&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SessionXL&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; formatComplete session  &lt;span class="co"&gt;-- Everything&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="session-edit"&gt;Session Edit&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;SessionEdit&lt;/code&gt; module provides operations for modifying session files.&lt;/p&gt;
&lt;h4 id="cli-session-edit-command"&gt;CLI: session-edit Command&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Take first N turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--take&lt;/span&gt; &lt;span class="at"&gt;--count&lt;/span&gt; 10 session.json &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; input.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; output.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Take last N turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--take-tail&lt;/span&gt; &lt;span class="at"&gt;--count&lt;/span&gt; 5 session.json &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; input.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; output.json&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Drop first N turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--drop&lt;/span&gt; &lt;span class="at"&gt;--count&lt;/span&gt; 2 session.json &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; input.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; output.json&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Drop last N turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--drop-tail&lt;/span&gt; &lt;span class="at"&gt;--count&lt;/span&gt; 1 session.json &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; input.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; output.json&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Remove all tool calls&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--censor-tool-calls&lt;/span&gt; session.json &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; input.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; output.json&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Remove thinking content&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--censor-thinking&lt;/span&gt; session.json &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; input.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; output.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="edit-operations"&gt;Edit Operations&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionEditOp&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionEditTake&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;       &lt;span class="co"&gt;-- Take first N turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionEditTakeTail&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;   &lt;span class="co"&gt;-- Take last N turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionEditDrop&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;       &lt;span class="co"&gt;-- Drop first N turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionEditDropTail&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;   &lt;span class="co"&gt;-- Drop last N turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionEditCensorToolCalls&lt;/span&gt;  &lt;span class="co"&gt;-- Remove tool calls&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionEditCensorThinking&lt;/span&gt;   &lt;span class="co"&gt;-- Remove thinking content&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;applyEdit ::&lt;/span&gt; &lt;span class="dt"&gt;SessionEditOp&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;applyEdit (&lt;span class="dt"&gt;SessionEditTake&lt;/span&gt; n) session &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    session { turns &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;take&lt;/span&gt; n (turns session) }&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;applyEdit (&lt;span class="dt"&gt;SessionEditDrop&lt;/span&gt; n) session &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    session { turns &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;drop&lt;/span&gt; n (turns session) }&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;applyEdit &lt;span class="dt"&gt;SessionEditCensorToolCalls&lt;/span&gt; session &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    session { turns &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; removeToolCalls (turns session) }&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- etc.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="session-search-systemagentssessionsearch"&gt;Session Search (&lt;code&gt;System.Agents.Session.Search&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;The Session Search subsystem provides fast fuzzy text search across session files using SQLite FTS5. It enables searching through conversation history with trigram-based fuzzy matching and metadata filtering.&lt;/p&gt;
&lt;h4 id="architecture"&gt;Architecture&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                    Session Search                            │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │    Types    │  │    Index    │  │    Query    │         │
│  │  (config)   │  │  (SQLite)   │  │  (search)   │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│        ▲                ▲                ▲                  │
│        └────────────────┴────────────────┘                  │
│                    CLI Handlers                              │
│              (session-index, session-search)                 │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="core-types-systemagentssessionsearchtypes"&gt;Core Types (&lt;code&gt;System.Agents.Session.Search.Types&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Configuration for the search index.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; indexDbPath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Path to the SQLite index database (default: .agents-search.db)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; indexSessionStore ::&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Session store to index (supports multi-location stores)&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; indexIncludeToolOutputs ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Whether to include tool outputs in the index&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Options for session search queries.&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SearchOptions&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SearchOptions&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; searchQuery ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Fuzzy search query text&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; searchDateFilter ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;DateFilter&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Optional date filter&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; searchTools ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Filter by tools used (any of these)&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; searchAgent ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Filter by agent slug&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; searchIncludeToolOutputs ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Include tool outputs in search&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; searchJsonOutput ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Output results as JSON&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; searchPreviewLines ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Number of context lines to show&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; searchLimit ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Maximum number of results&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; searchAutoUpdate ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Auto-update index if stale before searching&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Date filter for search queries.&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;DateFilter&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AfterDate&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;BeforeDate&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;BetweenDates&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Status of the search index.&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;IndexCurrent&lt;/span&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;IndexStale&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;  &lt;span class="co"&gt;-- (stale sessions, total sessions)&lt;/span&gt;&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;IndexMissing&lt;/span&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;IndexError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="search-result-types"&gt;Search Result Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Complete search results.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SearchResult&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SearchResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; resultItems ::&lt;/span&gt; [&lt;span class="dt"&gt;SearchResultItem&lt;/span&gt;]&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultTotalMatches ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultQueryTimeMs ::&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultIndexWasUpdated ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | A single search result item.&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SearchResultItem&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SearchResultItem&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; resultMetadata ::&lt;/span&gt; &lt;span class="dt"&gt;SearchResultMetadata&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultPreview ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultMatchedTerms ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Metadata about a search result.&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SearchResultMetadata&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SearchResultMetadata&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; resultSessionId ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultFilePath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultAgentSlug ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultTurnCount ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultFirstTurnAt ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultLastTurnAt ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultRank ::&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="index-schema-systemagentssessionsearchindex"&gt;Index Schema (&lt;code&gt;System.Agents.Session.Search.Index&lt;/code&gt;)&lt;/h4&gt;
&lt;p&gt;The search index uses SQLite with FTS5 (Full-Text Search version 5):&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Session metadata cache&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; session_index (&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    session_id TEXT &lt;span class="kw"&gt;PRIMARY&lt;/span&gt; &lt;span class="kw"&gt;KEY&lt;/span&gt;,&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    file_path TEXT &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    mtime &lt;span class="dt"&gt;INTEGER&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    agent_slug TEXT,&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    turn_count &lt;span class="dt"&gt;INTEGER&lt;/span&gt;,&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    first_turn_at &lt;span class="dt"&gt;TIMESTAMP&lt;/span&gt;,&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    last_turn_at &lt;span class="dt"&gt;TIMESTAMP&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;);&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- FTS5 virtual table for trigram search&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; VIRTUAL &lt;span class="kw"&gt;TABLE&lt;/span&gt; search_content &lt;span class="kw"&gt;USING&lt;/span&gt; fts5(&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    session_id,&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    content,&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tokenize&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;#39;trigram&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;);&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Tool call index for filtering&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; tool_index (&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    session_id TEXT &lt;span class="kw"&gt;REFERENCES&lt;/span&gt; session_index(session_id),&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tool_name TEXT &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    call_count &lt;span class="dt"&gt;INTEGER&lt;/span&gt; &lt;span class="kw"&gt;DEFAULT&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;,&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;PRIMARY&lt;/span&gt; &lt;span class="kw"&gt;KEY&lt;/span&gt; (session_id, tool_name)&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;);&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Index metadata&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; index_metadata (&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;key&lt;/span&gt; TEXT &lt;span class="kw"&gt;PRIMARY&lt;/span&gt; &lt;span class="kw"&gt;KEY&lt;/span&gt;,&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;value&lt;/span&gt; TEXT&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="index-operations"&gt;Index Operations&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Create a new search index, replacing any existing index.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Indexes sessions from ALL read locations in the SessionStore.&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;createSearchIndex ::&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Incrementally update the search index.&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;updateSearchIndex ::&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Check the status of the search index.&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;checkIndexStatus ::&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Remove the search index.&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;removeSearchIndex ::&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="search-execution-systemagentssessionsearchquery"&gt;Search Execution (&lt;code&gt;System.Agents.Session.Search.Query&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Execute a search query with the given options.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Searches across all indexed sessions from all locations.&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;executeSearchWithOptions ::&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SearchOptions&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;SearchResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Execute a search query against the index.&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;executeSearch ::&lt;/span&gt; &lt;span class="dt"&gt;SearchIndexConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SearchOptions&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;SearchResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Format search results for display.&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;formatResults ::&lt;/span&gt; &lt;span class="dt"&gt;SearchOptions&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SearchResult&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="fuzzy-matching"&gt;Fuzzy Matching&lt;/h4&gt;
&lt;p&gt;The search uses SQLite FTS5 with trigram tokenization:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigram tokenization&lt;/strong&gt;: Breaks text into 3-character sequences
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fuzzy matching&lt;/strong&gt;: “error” matches “errors”, “erroring”, “terror”
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefix matching&lt;/strong&gt;: “data” matches “database”, “datagram”
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Typo tolerance&lt;/strong&gt;: Small changes in query still find matches
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find sessions with fuzzy match to &amp;quot;error&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; session_id, &lt;span class="fu"&gt;rank&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; search_content &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; content MATCH &lt;span class="st"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; &lt;span class="fu"&gt;rank&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="cli-session-index-command"&gt;CLI: session-index Command&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Build the search index (includes all read locations)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--build&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Check index status&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--status&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Update index incrementally&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--update&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Remove the index&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--clean&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Build with tool outputs included&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--build&lt;/span&gt; &lt;span class="at"&gt;--include-tool-outputs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="cli-session-search-command"&gt;CLI: session-search Command&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Basic fuzzy search&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;database error&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Search with auto-update&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;migration&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--auto&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Include tool outputs in search&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;config.yaml&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--include-tool-outputs&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Filter by date and tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;auth&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--after&lt;/span&gt; 2024-01-01 &lt;span class="at"&gt;--tool&lt;/span&gt; write-file&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Filter by agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;refactor&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--agent&lt;/span&gt; my-coder&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# JSON output for scripting&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;TODO&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--json&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Show context lines&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;deploy&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--preview&lt;/span&gt; 5&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Combined filters&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;fix&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--after&lt;/span&gt; 2024-01-01 &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--before&lt;/span&gt; 2024-12-31 &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool&lt;/span&gt; bash_write-file &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="search-workflow-example"&gt;Search Workflow Example&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 1. Build the initial index (aggregates all locations)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--build&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 2. Search for sessions about errors&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;error&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--json&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;jq&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;.resultItems[] | .resultMetadata.resultFilePath&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 3. Find sessions using specific tools&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;database&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--tool&lt;/span&gt; write-file &lt;span class="at"&gt;--tool&lt;/span&gt; read-file&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 4. Update index after new sessions&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--update&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 5. Search with date filter&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;config&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--after&lt;/span&gt; 2024-06-01 &lt;span class="at"&gt;--preview&lt;/span&gt; 3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="context-window-management"&gt;Context Window Management&lt;/h3&gt;
&lt;p&gt;Sessions track context size for LLM limits:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;estimateTokens ::&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;estimateTokens session &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;sum&lt;/span&gt; [estimateMessageTokens m &lt;span class="op"&gt;|&lt;/span&gt; turn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; turns session&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                 , m &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; [userMessage turn, assistantMessage turn]]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;manageContext ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;manageContext maxTokens session&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; estimateTokens session &lt;span class="op"&gt;&amp;lt;=&lt;/span&gt; maxTokens &lt;span class="ot"&gt;=&lt;/span&gt; session&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; manageContext maxTokens (pruneOldestTurn session)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="byte-usage-tracking"&gt;Byte Usage Tracking&lt;/h3&gt;
&lt;p&gt;Sessions track byte usage for monitoring:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Calculate bytes for all response types&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;userToolResponseBytes ::&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;userToolResponseBytes (&lt;span class="dt"&gt;TextResponse&lt;/span&gt; txt) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    Text.length txt &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;  &lt;span class="co"&gt;-- UTF-8 max bytes per char&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;userToolResponseBytes (&lt;span class="dt"&gt;JsonResponse&lt;/span&gt; val) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;fromIntegral&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; LByteString.length &lt;span class="op"&gt;$&lt;/span&gt; Aeson.encode val&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;userToolResponseBytes (&lt;span class="dt"&gt;MediaResponse&lt;/span&gt; media) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    Text.length media&lt;span class="op"&gt;.&lt;/span&gt;mediaBase64Data  &lt;span class="co"&gt;-- Already base64 = ASCII&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;userToolResponseBytes (&lt;span class="dt"&gt;MixedResponse&lt;/span&gt; parts) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;sum&lt;/span&gt; (&lt;span class="fu"&gt;map&lt;/span&gt; contentPartBytes parts)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;contentPartBytes ::&lt;/span&gt; &lt;span class="dt"&gt;ContentPart&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;contentPartBytes (&lt;span class="dt"&gt;TextPart&lt;/span&gt; txt) &lt;span class="ot"&gt;=&lt;/span&gt; Text.length txt &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;contentPartBytes (&lt;span class="dt"&gt;MediaPart&lt;/span&gt; media) &lt;span class="ot"&gt;=&lt;/span&gt; Text.length media&lt;span class="op"&gt;.&lt;/span&gt;mediaBase64Data&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="tool-execution-context"&gt;Tool Execution Context&lt;/h3&gt;
&lt;p&gt;Sessions provide context for tool execution:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; ctxSessionId ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxTurnId ::&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxFullSession ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This allows tools to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access conversation history
&lt;/li&gt;
&lt;li&gt;Store tool-specific state
&lt;/li&gt;
&lt;li&gt;Make context-aware decisions
&lt;/li&gt;
&lt;li&gt;Return media responses
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="session-store-backends"&gt;Session Store Backends&lt;/h3&gt;
&lt;h4 id="file-store-default"&gt;File Store (Default)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;fileSessionStore ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;FilePath&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;fileSessionStore writePrefix readPrefixes &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { sessionWritePrefix &lt;span class="ot"&gt;=&lt;/span&gt; writePrefix&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , sessionReadPrefixes &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;if&lt;/span&gt; writePrefix &lt;span class="ot"&gt;`elem`&lt;/span&gt; readPrefixes&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;then&lt;/span&gt; readPrefixes&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;else&lt;/span&gt; writePrefix &lt;span class="op"&gt;:&lt;/span&gt; readPrefixes&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , readSession &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;sid &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Search through read prefixes in order&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;let&lt;/span&gt; paths &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; (&lt;span class="op"&gt;&amp;lt;/&amp;gt;&lt;/span&gt; sessionFileName sid) sessionReadPrefixes&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        findFirstExisting paths&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , writeSession &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;sess &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Always write to write prefix&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;let&lt;/span&gt; path &lt;span class="ot"&gt;=&lt;/span&gt; sessionWritePrefix &lt;span class="op"&gt;&amp;lt;/&amp;gt;&lt;/span&gt; sessionFileName (sessionId sess)&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        encodeFile path sess&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , listSessions &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Aggregate from all read prefixes, deduplicate&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        allSessions &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;concat&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;mapM&lt;/span&gt; listSessionsInDir sessionReadPrefixes&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;let&lt;/span&gt; deduplicated &lt;span class="ot"&gt;=&lt;/span&gt; dedupeBy sessionId allSessions&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        sortOn modificationTime deduplicated&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="memory-store-testing"&gt;Memory Store (Testing)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;memorySessionStore ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;memorySessionStore &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ref &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newIORef Map.empty&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { readSession &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;sid &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; Map.lookup sid &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; readIORef ref&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , writeSession &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;sess &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            modifyIORef ref (Map.insert (sessionId sess) sess)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="best-practices"&gt;Best Practices&lt;/h3&gt;
&lt;h4 id="session-hygiene"&gt;Session Hygiene&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Regular cleanup&lt;/strong&gt;: Delete old sessions to save space
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sensitive data&lt;/strong&gt;: Be careful with sessions containing secrets
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backup&lt;/strong&gt;: Sessions are JSON files - back them up
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Versioning&lt;/strong&gt;: Handle schema migrations for old sessions
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="conversation-design"&gt;Conversation Design&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Clear turn boundaries&lt;/strong&gt;: Each user input = one turn
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool call recording&lt;/strong&gt;: Always record for reproducibility
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error capture&lt;/strong&gt;: Record tool failures in the session
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timestamps&lt;/strong&gt;: Useful for debugging and auditing
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="performance"&gt;Performance&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Lazy loading&lt;/strong&gt;: Don’t load full history unless needed
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pagination&lt;/strong&gt;: For long sessions, load turns in chunks
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compression&lt;/strong&gt;: Consider gzip for large session files
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Search indexing&lt;/strong&gt;: Build index periodically for fast searching
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="search-best-practices"&gt;Search Best Practices&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Regular index updates&lt;/strong&gt;: Run &lt;code&gt;session-index --update&lt;/code&gt; periodically
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Include tool outputs&lt;/strong&gt;: Use &lt;code&gt;--include-tool-outputs&lt;/code&gt; for comprehensive search
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use filters&lt;/strong&gt;: Combine text search with &lt;code&gt;--tool&lt;/code&gt;, &lt;code&gt;--agent&lt;/code&gt;, or date filters
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSON output&lt;/strong&gt;: Use &lt;code&gt;--json&lt;/code&gt; for scripting and automation
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-update&lt;/strong&gt;: Use &lt;code&gt;--auto&lt;/code&gt; flag to ensure fresh results
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="multi-location-best-practices"&gt;Multi-Location Best Practices&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Write location priority&lt;/strong&gt;: Keep write location first in read locations for best performance
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Archive old sessions&lt;/strong&gt;: Move old sessions to archive directories instead of deleting
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shared sessions&lt;/strong&gt;: Use shared directories for team collaboration
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tilde expansion&lt;/strong&gt;: Use &lt;code&gt;~&lt;/code&gt; for portable home directory references
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deduplication awareness&lt;/strong&gt;: Understand that first location wins for duplicate IDs
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="media-best-practices"&gt;Media Best Practices&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Size limits&lt;/strong&gt;: Keep media attachments under 50MB
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MIME types&lt;/strong&gt;: Always declare correct MIME types
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Base64 encoding&lt;/strong&gt;: Use proper encoding for binary data
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mixed responses&lt;/strong&gt;: Use &lt;code&gt;MixedResponse&lt;/code&gt; for rich multi-modal output
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="example-session-analysis"&gt;Example: Session Analysis&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Count tool usage&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;toolUsageStats ::&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;toolUsageStats session &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    Map.fromListWith (&lt;span class="op"&gt;+&lt;/span&gt;) &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [(toolName tc, &lt;span class="dv"&gt;1&lt;/span&gt;) &lt;span class="op"&gt;|&lt;/span&gt; turn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; turns session&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                          , tc &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; toolCalls turn]&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Average response time&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;averageResponseTime ::&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;NominalDiffTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;averageResponseTime session &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;sum&lt;/span&gt; [toolDuration tc &lt;span class="op"&gt;|&lt;/span&gt; turn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; turns session&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                         , tc &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; toolCalls turn] &lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;/&lt;/span&gt; &lt;span class="fu"&gt;fromIntegral&lt;/span&gt; (&lt;span class="fu"&gt;length&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;concatMap&lt;/span&gt; toolCalls &lt;span class="op"&gt;$&lt;/span&gt; turns session)&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find turns with errors&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;errorTurns ::&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;Turn&lt;/span&gt;]&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;errorTurns session &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [turn &lt;span class="op"&gt;|&lt;/span&gt; turn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; turns session&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          , &lt;span class="fu"&gt;any&lt;/span&gt; (isLeft &lt;span class="op"&gt;.&lt;/span&gt; toolOutput) (toolCalls turn)]&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Count media attachments&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mediaAttachmentStats ::&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;Int&lt;/span&gt;, &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;)&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;mediaAttachmentStats session &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; attachments &lt;span class="ot"&gt;=&lt;/span&gt; collectAttachments session&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        byType &lt;span class="ot"&gt;=&lt;/span&gt; Map.fromListWith (&lt;span class="op"&gt;+&lt;/span&gt;) &lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            [(mediaMimeType m, &lt;span class="dv"&gt;1&lt;/span&gt;) &lt;span class="op"&gt;|&lt;/span&gt; m &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; attachments]&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;in&lt;/span&gt; (&lt;span class="fu"&gt;length&lt;/span&gt; attachments, byType)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="example-search-integration"&gt;Example: Search Integration&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Search.Types&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Search.Index&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Search.Query&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Search for sessions with specific patterns&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;searchSessions ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;SearchResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;searchSessions query &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create store with multi-location support&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    store &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; mkSessionStore &lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [&lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;~/.config/agents-exe/sessions/&amp;quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; config &lt;span class="ot"&gt;=&lt;/span&gt; defaultSearchIndexConfig store&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; opts &lt;span class="ot"&gt;=&lt;/span&gt; (defaultSearchOptions query)&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            { searchJsonOutput &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;False&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , searchPreviewLines &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , searchLimit &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dv"&gt;20&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    executeSearchWithOptions config opts&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find sessions that used specific tools&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;findToolUsage ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;SearchResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;findToolUsage tools &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    store &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; mkSimpleSessionStore &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; config &lt;span class="ot"&gt;=&lt;/span&gt; defaultSearchIndexConfig store&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; opts &lt;span class="ot"&gt;=&lt;/span&gt; (defaultSearchOptions &lt;span class="st"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            { searchTools &lt;span class="ot"&gt;=&lt;/span&gt; tools&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , searchJsonOutput &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;True&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    executeSearchWithOptions config opts&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="related-modules"&gt;Related Modules&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Module&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Media.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Media type definitions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Core session types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Base&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Session operations&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Loop&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Conversation loop&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Step&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Single turn execution&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Edit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Session editing operations&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.OpenAI&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OpenAI-specific session handling&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Compat&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Backwards compatibility&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Search.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Search configuration types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Search.Index&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Index building and maintenance&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Search.Query&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Search query execution&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.SessionStore&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Persistent storage with multi-location support&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.SessionPrint&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Markdown printing and statistics&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.SessionPrint.Inject&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Session content injection&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-sessions.html" rel="alternate"/><summary type="text">Session management provides persistent storage and retrieval of agent conversations, enabling conversation resumption, history analysis, and multi-modal content support. Sessions can now be stored across multiple locations with a unified re</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/commands.html</id><title type="text">Command reference</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/README.md"&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="command-reference"&gt;Command reference&lt;/h2&gt;
&lt;p&gt;The exact help text of each command, as printed by the binary this site was
produced with: &lt;a href="/agents-exe/gen/out/commands.cmark__help-agents-exe.txt"&gt;agents-exe –help&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-check.txt"&gt;check&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-config.txt"&gt;config&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-init.txt"&gt;init&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-run.txt"&gt;run&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-tui.txt"&gt;tui&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-serve.txt"&gt;serve&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-mcp-server.txt"&gt;mcp-server&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-session.txt"&gt;session&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-describe.txt"&gt;describe&lt;/a&gt;, &lt;a href="/agents-exe/gen/out/commands.cmark__help-new.txt"&gt;new&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="command-reference-1"&gt;Command Reference&lt;/h3&gt;
&lt;h4 id="global-options"&gt;Global Options&lt;/h4&gt;
&lt;p&gt;These options apply to all commands:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--api-keys FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/.config/agents-exe/secret-keys&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path to JSON file containing API keys&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--log-file LOGFILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;agents-logfile&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Raw log file for debugging&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--log-http URL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;HTTP endpoint for JSON log sink&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--log-json-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Local JSON file log sink&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--session-json-file-prefix PREFIX&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Prefix for session JSON files&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--agent-file AGENTFILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(auto-discovered)&lt;/td&gt;&lt;td&gt;Root agent description file(s). Can be specified multiple times. Defaults to &lt;code&gt;agent.json&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="commands"&gt;Commands&lt;/h4&gt;
&lt;h5 id="check"&gt;&lt;code&gt;check&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;Validates agent configuration files.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;agents-exe check
agents-exe check --agent-file custom-agent.json
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id="init"&gt;&lt;code&gt;init&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;Initializes a new agent project with a sample &lt;code&gt;agent.json&lt;/code&gt; and tools directory structure.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;agents-exe init
agents-exe init --agent-file my-agent.json
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id="tui---terminal-user-interface"&gt;&lt;code&gt;tui&lt;/code&gt; - Terminal User Interface&lt;/h5&gt;
&lt;p&gt;Launches an interactive terminal UI for chatting with agents.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;agents-exe tui
agents-exe tui --agent-file my-agent.json
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id="run---execute-a-one-shot-command"&gt;&lt;code&gt;run&lt;/code&gt; - Execute a One-Shot Command&lt;/h5&gt;
&lt;p&gt;Runs a single prompt through an agent and outputs the result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prompt Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Short&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--prompt TEXT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;-p&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Add a text paragraph to the prompt&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;-f&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Include contents of a file in the prompt&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--shell CMD&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Include stdout of a shell command in the prompt&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--sep4 SEP&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;-s&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Add a short separator (4 repetitions)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--sep40 SEP&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;-S&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Add a long separator (40 repetitions)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--session-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Resume from or save to a session file&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;# Simple prompt
agents-exe run --prompt &amp;quot;Hello, how are you?&amp;quot;

# Include file contents
agents-exe run --prompt &amp;quot;Summarize this:&amp;quot; --file README.md

# Include command output
agents-exe run -p &amp;quot;Explain this diff:&amp;quot; -s &amp;quot;---&amp;quot; --shell &amp;quot;git diff&amp;quot;

# Multiple prompts (concatenated with newlines)
agents-exe run -p &amp;quot;First part&amp;quot; -p &amp;quot;Second part&amp;quot;

# Resume a session
agents-exe run --session-file previous.json -p &amp;quot;Continue where we left off&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id="echo-prompt"&gt;&lt;code&gt;echo-prompt&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;Echoes the constructed prompt without sending it to the agent. Useful for debugging prompt construction.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;agents-exe echo-prompt -p &amp;quot;Hello&amp;quot; -f README.md
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id="describe"&gt;&lt;code&gt;describe&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;Outputs a JSON self-description of the tool interface. Useful when agents-exe is used as a sub-tool.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;agents-exe describe
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id="mcp-server"&gt;&lt;code&gt;mcp-server&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;Runs agents-exe as an MCP (Model Context Protocol) server, exposing agents as tools via stdin/stdout.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;agents-exe mcp-server
agents-exe mcp-server --agent-file agent1.json --agent-file agent2.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The MCP server exposes each configured agent as a callable tool to MCP clients like Claude Desktop.&lt;/p&gt;
&lt;h5 id="session-print"&gt;&lt;code&gt;session-print&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;Prints a session file in human-readable markdown format.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--show-tool-call-results&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Show the results of tool calls&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--n-turns N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Limit output to first N turns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--repeat-system-prompt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Repeat system prompt at each turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--repeat-tools&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Repeat available tools at each turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--antichronological&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Display newest turns first (default: oldest first)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;# Print entire session
agents-exe session-print my-session.json

# Print with tool results
agents-exe session-print --show-tool-call-results my-session.json

# Print last 10 turns only, newest first
agents-exe session-print --n-turns 10 --antichronological my-session.json
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/commands.html" rel="alternate"/><summary type="text">The global options and every agents-exe command, as the README lists them.</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-architecture.html</id><title type="text">Architecture</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/architecture.md"&gt;&lt;code&gt;documentation/architecture.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="architecture"&gt;Architecture&lt;/h2&gt;
&lt;p&gt;&lt;img src="/agents-exe/gen/images/architecture-layers.dot.png" alt="The layers: interfaces on top, the session runner and OS model, the agent tree, and the foundation they share." /&gt;&lt;/p&gt;
&lt;p&gt;This document describes the runtime architecture and core components of the Agents framework.&lt;/p&gt;
&lt;h3 id="core-architecture"&gt;Core Architecture&lt;/h3&gt;
&lt;p&gt;The framework is built around a layered architecture that separates concerns between agent definition, runtime execution, and user interfaces.&lt;/p&gt;
&lt;h4 id="layer-overview"&gt;Layer Overview&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────┐
│                    Interface Layer                              │
│  (CLI commands, TUI, MCP server, HTTP endpoints)                │
│  The TUI and the HTTP server (agents-server) are both clients   │
│  of an in-process SessionRunner (Host.Runner), driven through   │
│  the same RunnerClient interface -- see tui.md#architecture.    │
├────────────────────────────────────────────────────────────────┤
│                    OS Model Layer                               │
│  (Entity-Component-System, Resource Management,                 │
│   Conversation Tracking, Concurrent Access)                     │
├────────────────────────────────────────────────────────────────┤
│                    Agent Tree Layer                             │
│  (multi-agent hierarchy, reference validation, cycle detection) │
├────────────────────────────────────────────────────────────────┤
│                    Foundation Layer                             │
│  (sessions, tools, LLM integration, file loading)               │
└────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="os-model-architecture"&gt;OS Model Architecture&lt;/h3&gt;
&lt;p&gt;The OS Model provides a centralized, ECS-based architecture for managing agents, toolboxes, and resources.&lt;/p&gt;
&lt;h4 id="entity-component-system-ecs-pattern"&gt;Entity-Component-System (ECS) Pattern&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                         World                                    │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │  Component  │  │  Component  │  │  Component  │             │
│  │   Store 1   │  │   Store 2   │  │   Store N   │             │
│  │ (TVar Any)  │  │ (TVar Any)  │  │ (TVar Any)  │             │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘             │
│         │                │                │                     │
│         └────────────────┼────────────────┘                     │
│                          │                                      │
│                   HashMap ComponentTypeId                        │
└──────────────────────────┬──────────────────────────────────────┘
                           │
         ┌─────────────────┼─────────────────┐
         │                 │                 │
         ▼                 ▼                 ▼
    ┌─────────┐      ┌─────────┐      ┌─────────┐
    │ Entity  │      │ Entity  │      │ Entity  │
    │   1     │      │   2     │      │   N     │
    └────┬────┘      └────┬────┘      └────┬────┘
         │                │                │
    ┌────┴────┐      ┌────┴────┐      ┌────┴────┐
    │ Agent   │      │Toolbox  │      │ Conv    │
    │ Config  │      │ Config  │      │ Config  │
    │ Agent   │      │Toolbox  │      │ Conv    │
    │ State   │      │ State   │      │ State   │
    └─────────┘      └─────────┘      └─────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Key Design Principles:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Entities are just IDs&lt;/strong&gt;: Lightweight identifiers with phantom types for type safety
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Components are pure data&lt;/strong&gt;: Serializable, immutable data structures
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Systems are functions&lt;/strong&gt;: Operate on entities with specific component combinations
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage is heterogeneous&lt;/strong&gt;: Uses &lt;code&gt;TVar Any&lt;/code&gt; for type erasure with safe casting
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="component-types"&gt;Component Types&lt;/h4&gt;
&lt;h5 id="agent-components"&gt;Agent Components&lt;/h5&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Component&lt;/th&gt;&lt;th&gt;ID&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AgentConfig&lt;/code&gt;&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Static agent configuration (name, model, system prompt)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AgentState&lt;/code&gt;&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Runtime state (status, current conversation)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h5 id="toolbox-components"&gt;Toolbox Components&lt;/h5&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Component&lt;/th&gt;&lt;th&gt;ID&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ToolboxConfig&lt;/code&gt;&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Toolbox type and settings&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ToolboxState&lt;/code&gt;&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Runtime state and resource reference&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ToolboxBinding&lt;/code&gt;&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Agent-to-toolbox relationship&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h5 id="conversation-components"&gt;Conversation Components&lt;/h5&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Component&lt;/th&gt;&lt;th&gt;ID&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ConversationConfig&lt;/code&gt;&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;Conversation metadata&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ConversationState&lt;/code&gt;&lt;/td&gt;&lt;td&gt;31&lt;/td&gt;&lt;td&gt;Runtime status and timestamps&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AgentConversation&lt;/code&gt;&lt;/td&gt;&lt;td&gt;32&lt;/td&gt;&lt;td&gt;Agent-conversation relationship&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;TurnConfig&lt;/code&gt;&lt;/td&gt;&lt;td&gt;33&lt;/td&gt;&lt;td&gt;Turn structure (parent, conversation)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;TurnState&lt;/code&gt;&lt;/td&gt;&lt;td&gt;34&lt;/td&gt;&lt;td&gt;Turn execution state&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ToolCallConfig&lt;/code&gt;&lt;/td&gt;&lt;td&gt;35&lt;/td&gt;&lt;td&gt;Tool call specification&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ToolCallState&lt;/code&gt;&lt;/td&gt;&lt;td&gt;36&lt;/td&gt;&lt;td&gt;Tool call execution state&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Message&lt;/code&gt;&lt;/td&gt;&lt;td&gt;38&lt;/td&gt;&lt;td&gt;Chat messages&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="resource-lifecycle-flow"&gt;Resource Lifecycle Flow&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Program Startup
      │
      ▼
┌─────────────┐
│  Initialize │
│    World    │
└──────┬──────┘
       │
       ▼
┌─────────────┐     ┌─────────────┐
│   Create    │────&amp;gt;│  Register   │
│   Agents    │     │  Component  │
└──────┬──────┘     │   Stores    │
       │            └─────────────┘
       ▼
┌─────────────┐     ┌─────────────┐
│   Create    │────&amp;gt;│  Register   │
│  Toolboxes  │     │  Resources  │
└──────┬──────┘     └─────────────┘
       │
       ▼
┌─────────────┐
│    Bind     │
│   Agents    │
│  to Toolboxes│
└──────┬──────┘
       │
       ▼
    ┌────────┐
    │ RUNTIME │
    └────┬───┘
         │
    ┌────┴────┬──────────┬──────────┐
    │         │          │          │
    ▼         ▼          ▼          ▼
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
│ Agent │ │ Agent │ │Shared │ │ Shared│
│   1   │ │   2   │ │SQLite │ │  HTTP │
│       │ │       │ │  DB   │ │ Pool  │
└───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘
    │         │         │         │
    └─────────┴─────────┴─────────┘
              │
              ▼
       ┌─────────────┐
       │  Cleanup    │
       │   Scope     │
       │ (on destroy)│
       └─────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resource Scopes:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Program Scope&lt;/strong&gt;: Global resources (HTTP connection pools, shared caches)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent Scope&lt;/strong&gt;: Per-agent resources (sandbox directories, agent-specific state)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toolbox Scope&lt;/strong&gt;: Per-toolbox resources (SQLite connections, MCP clients)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Scope&lt;/strong&gt;: Per-conversation resources (isolated Lua states, temp files)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turn Scope&lt;/strong&gt;: Temporary resources (single turn execution context)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ToolCall Scope&lt;/strong&gt;: Single-use resources (tool call arguments, results)
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="concurrent-access-patterns"&gt;Concurrent Access Patterns&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────┐
│                    Access Patterns                            │
├──────────────────────────────────────────────────────────────┤
│                                                               │
│  Exclusive Access (TMVar)                                     │
│  ┌─────────┐     ┌─────────┐     ┌─────────┐                 │
│  │  Lock   │────&amp;gt;│ Execute │────&amp;gt;│ Release │                 │
│  └─────────┘     └─────────┘     └─────────┘                 │
│  Use: Lua interpreters, process handles                      │
│                                                               │
├──────────────────────────────────────────────────────────────┤
│                                                               │
│  Read-Write Access (RWLock)                                   │
│  ┌─────┐ ┌─────┐       ┌─────────┐      ┌─────┐ ┌─────┐      │
│  │Read │ │Read │──────&amp;gt;│  Data   │&amp;lt;─────│Write│     │      │
│  │  1  │ │  2  │       │         │      │     │     │      │
│  └─────┘ └─────┘       └─────────┘      └─────┘     │      │
│  Use: SQLite databases (especially WAL mode)                 │
│                                                               │
├──────────────────────────────────────────────────────────────┤
│                                                               │
│  Pool Access (TBQueue)                                        │
│  ┌─────────────────────────────────────────────────────┐     │
│  │  Pool: [Token] [Token] [Token] ... [Token]          │     │
│  └─────────────────────────────────────────────────────┘     │
│       ▲    │         ▲    │                                  │
│       │    └─────────┘    │                                  │
│    Acquire             Release                               │
│  Use: HTTP connection pools, DB connection pools             │
│                                                               │
├──────────────────────────────────────────────────────────────┤
│                                                               │
│  Stateless Access (No Lock)                                   │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐                        │
│  │ Access  │ │ Access  │ │ Access  │  (Concurrent, no sync) │
│  └─────────┘ └─────────┘ └─────────┘                        │
│  Use: Immutable data, thread-safe resources                  │
│                                                               │
└──────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="conversation-and-lineage-tracking"&gt;Conversation and Lineage Tracking&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Conversation Tree Structure

┌─────────────────┐
│ Conversation 1  │
│   (Entity)      │
└────────┬────────┘
         │
    ┌────┴────┐
    ▼         ▼
┌───────┐ ┌───────┐
│ Turn 1│ │ Turn 2│
│(Entity)│ │(Fork) │
└───┬───┘ └───┬───┘
    │         │
    ▼         ▼
┌───────┐ ┌───────┐
│ Call 1│ │ Call 1│
│       │ │       │
└───┬───┘ └───┬───┘
    │         │
    ▼         ▼
┌───────┐ ┌───────┐
│ Call 2│ │ Call 2│
│(Nested)│ │(Nested)│
└───────┘ └───────┘

Lineage Stack
┌─────────────────────────────────────┐
│ LineageFrame                        │
│ ├─ frameType: ToolCallFrame         │
│ ├─ frameEntityId: &amp;lt;tool-call-id&amp;gt;    │
│ └─ frameTimestamp: &amp;lt;time&amp;gt;           │
├─────────────────────────────────────┤
│ LineageFrame                        │
│ ├─ frameType: TurnFrame             │
│ ├─ frameEntityId: &amp;lt;turn-id&amp;gt;         │
│ └─ frameTimestamp: &amp;lt;time&amp;gt;           │
├─────────────────────────────────────┤
│ LineageFrame                        │
│ ├─ frameType: ConversationFrame     │
│ ├─ frameEntityId: &amp;lt;conversation-id&amp;gt; │
│ └─ frameTimestamp: &amp;lt;time&amp;gt;           │
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lineage provides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complete call chain for debugging
&lt;/li&gt;
&lt;li&gt;Recursion depth tracking
&lt;/li&gt;
&lt;li&gt;Audit trail for accounting
&lt;/li&gt;
&lt;li&gt;Context for subagent calls
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="persistence-layer"&gt;Persistence Layer&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────┐
│                    Persistence Backends                       │
├──────────────────────────────────────────────────────────────┤
│                                                               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐     │
│  │ In-Memory│  │   File   │  │  SQLite  │  │PostgreSQL│     │
│  │ (Dev/Test)│  │(Compat) │  │ (Local)  │  │(Production)    │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘     │
│       │             │             │             │            │
│       └─────────────┴──────┬──────┴─────────────┘            │
│                            │                                 │
│                            ▼                                 │
│                   ┌─────────────────┐                        │
│                   │  Unified API    │                        │
│                   │ (persist, load) │                        │
│                   └─────────────────┘                        │
│                                                               │
└──────────────────────────────────────────────────────────────┘

SQLite Schema (simplified)
┌──────────────────────────────────────────────────────────────┐
│  entities (id, entity_type, created_at)                      │
│  components (entity_id, component_type, data)                │
│  events (id, timestamp, type, data, entity_id)               │
│  messages (conversation_id, timestamp, role, content)        │
│  tool_calls (turn_id, timestamp, name, input, output)        │
└──────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="architecture-benefits"&gt;Architecture Benefits&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Shared Resources&lt;/strong&gt;: Multiple agents can share toolboxes (e.g., same SQLite database)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource Pooling&lt;/strong&gt;: HTTP connections pooled across all agents
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better Lifecycle Management&lt;/strong&gt;: Explicit scopes with predictable cleanup
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foundation for Web API&lt;/strong&gt;: Centralized state enables HTTP server interface
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Durable Persistence&lt;/strong&gt;: Built-in persistence layer with multiple backends
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thorough Lineage Tracking&lt;/strong&gt;: Complete call chains for debugging
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="core-types"&gt;Core Types&lt;/h3&gt;
&lt;h4 id="base-types-systemagentsbase"&gt;Base Types (&lt;code&gt;System.Agents.Base&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Unique identifiers&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;StepId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;StepId&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Agent configuration&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; slug ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                    &lt;span class="co"&gt;-- Unique identifier&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; apiKeyId ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                &lt;span class="co"&gt;-- Reference to API key&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; flavor ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                  &lt;span class="co"&gt;-- LLM provider (openai, etc.)&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; modelUrl ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                &lt;span class="co"&gt;-- API endpoint&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; modelName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;               &lt;span class="co"&gt;-- Model identifier&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; announce ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                &lt;span class="co"&gt;-- User-facing description&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; systemPrompt ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]          &lt;span class="co"&gt;-- System instructions&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolDirectory ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;       &lt;span class="co"&gt;-- Path to tools&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mcpServers ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; [&lt;span class="dt"&gt;McpServerDescription&lt;/span&gt;]&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; extraAgents ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; [&lt;span class="dt"&gt;ExtraAgentRef&lt;/span&gt;]&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; builtinToolboxes ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; [&lt;span class="dt"&gt;BuiltinToolboxDescription&lt;/span&gt;]&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="os-types-systemagentsoscore"&gt;OS Types (&lt;code&gt;System.Agents.OS.Core&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Phantom-typed entity IDs&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Agent components&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; agentName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentModel ::&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentSystemPrompt ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentToolboxBindings ::&lt;/span&gt; [&lt;span class="dt"&gt;ToolboxBindingSpec&lt;/span&gt;]&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentState&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; agentStatus ::&lt;/span&gt; &lt;span class="dt"&gt;AgentStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentCurrentConversation ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentCreatedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="agent-tree-system"&gt;Agent Tree System&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;AgentTree&lt;/code&gt; module manages multi-agent hierarchies and handles agent discovery, reference validation, and cycle detection.&lt;/p&gt;
&lt;h4 id="tree-structure"&gt;Tree Structure&lt;/h4&gt;
&lt;p&gt;Agents form a directed graph where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parent-child edges&lt;/strong&gt;: Discovered from tool directory hierarchy
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extra reference edges&lt;/strong&gt;: Explicit references via &lt;code&gt;extraAgents&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────┐
│  root-agent │
└──────┬──────┘
       │
   ┌───┴───┐
   ▼       ▼
┌──────┐ ┌──────┐
│tool-a│ │tool-b│
└──┬───┘ └──────┘
   │
   ▼
┌──────┐
│sub-1 │
└──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="subagent-wiring"&gt;Subagent Wiring&lt;/h4&gt;
&lt;p&gt;The Agent Tree system supports dynamic tool registration via STM TVars:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- OS-native agents use STM TVar for mutable tool storage&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;wireAgentTools ::&lt;/span&gt; &lt;span class="dt"&gt;Props&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AgentConfigGraph&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;AgentSlug&lt;/span&gt; &lt;span class="dt"&gt;OSAgentNode&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="conversation-flow"&gt;Conversation Flow&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   User      │────&amp;gt;│   Session   │────&amp;gt;│    LLM      │
│   Input     │     │   (turns)   │     │   (tools)   │
└─────────────┘     └──────┬──────┘     └──────┬──────┘
                           │                     │
                           │    ┌─────────────┐  │
                           └───&amp;gt;│ Tool Call   │&amp;lt;─┘
                                │ Execution   │
                                └──────┬──────┘
                                       │
                           ┌───────────┴───────────┐
                           ▼                       ▼
                    ┌─────────────┐        ┌─────────────┐
                    │  Bash Tool  │        │  MCP Tool   │
                    └─────────────┘        └─────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="tool-registration"&gt;Tool Registration&lt;/h3&gt;
&lt;p&gt;Tools are registered with the LLM via the &lt;code&gt;ToolRegistration&lt;/code&gt; type:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; toolName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolDescription ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolParameters ::&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;  &lt;span class="co"&gt;-- JSON Schema&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolExecutor ::&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ToolResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tool-sources"&gt;Tool Sources&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;BashToolbox&lt;/strong&gt;: Executable scripts in the tool directory
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;McpToolbox&lt;/strong&gt;: MCP servers providing dynamic tool lists
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenAPIToolbox&lt;/strong&gt;: REST API operations from OpenAPI specs
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IOTools&lt;/strong&gt;: Haskell functions embedded in the runtime
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SystemToolbox&lt;/strong&gt;: Builtin system information tools
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subagent Tools&lt;/strong&gt;: Other agents exposed as callable tools
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="libraries-and-executables"&gt;Libraries and executables&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;agents.cabal&lt;/code&gt; builds several components:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Component&lt;/th&gt;&lt;th&gt;Source&lt;/th&gt;&lt;th&gt;Contents&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents-lib&lt;/code&gt; (public library)&lt;/td&gt;&lt;td&gt;&lt;code&gt;src/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The core: agents, tools, sessions, storage, the OS layer, the MCP stdio server, CLI commands other than the TUI. No terminal-UI dependencies.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents-postgres&lt;/code&gt; (public library)&lt;/td&gt;&lt;td&gt;&lt;code&gt;postgres/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Session and continuation stores in Postgres, for &lt;code&gt;withHostStores&lt;/code&gt;. Kept apart so that &lt;code&gt;agents-lib&lt;/code&gt; does not need libpq.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents-tui&lt;/code&gt; (public library)&lt;/td&gt;&lt;td&gt;&lt;code&gt;tui/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The terminal UI (&lt;code&gt;System.Agents.TUI.*&lt;/code&gt;, &lt;code&gt;CLI.TUI&lt;/code&gt;, &lt;code&gt;CLI.Config&lt;/code&gt;, &lt;code&gt;CLI&lt;/code&gt;), on brick and vty.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents-exe&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;app/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The command-line tool, on both libraries.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents-server-internal&lt;/code&gt;, &lt;code&gt;agents-server&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;examples/agents-server/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The HTTP server (wai, warp). See [agents-server.md](/docs-agents-server.html).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agq&lt;/code&gt;, &lt;code&gt;durable-workflow-demo&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;agq/&lt;/code&gt;, &lt;code&gt;examples/durable-workflow-demo/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Other executables.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Programs that embed agents depend on &lt;code&gt;agents-lib&lt;/code&gt; only.&lt;/p&gt;
&lt;h3 id="module-dependencies"&gt;Module Dependencies&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Main
  ├── AgentTree
  │     ├── Base
  │     ├── FileLoader
  │     └── OS.Core
  ├── CLI.*
  │     └── AgentTree
  ├── TUI
  │     ├── Host, Host.Runner, Host.Client (RunnerClient)
  │     └── Session (pure views only: usage, signals, trajectory)
  ├── MCP.Server
  │     └── AgentTree
  └── ExportImport.*
  
OS Layer
  ├── OS.Core
  │     ├── OS.Core.Types
  │     └── OS.Core.World
  ├── OS.Resources
  │     ├── OS.Resources.Types
  │     ├── OS.Resources.Sqlite
  │     ├── OS.Resources.Lua
  │     └── OS.Resources.Http
  ├── OS.Concurrent
  │     ├── OS.Concurrent.Types
  │     └── OS.Concurrent.Locks
  ├── OS.Conversation
  │     ├── OS.Conversation.Types
  │     └── OS.Conversation.Lineage
  └── OS.Agents
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="key-design-decisions"&gt;Key Design Decisions&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;STM for Concurrency&lt;/strong&gt;: Tool reloading and subagent wiring use STM for thread-safe updates
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ECS Pattern&lt;/strong&gt;: Enables flexible composition and powerful queries
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explicit Resource Management&lt;/strong&gt;: Predictable cleanup with explicit scopes
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phantom Types&lt;/strong&gt;: Type safety for entity IDs without runtime overhead
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type Erasure&lt;/strong&gt;: &lt;code&gt;Any&lt;/code&gt; for heterogeneous storage with safe casting via Component typeclass
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tracer Pattern&lt;/strong&gt;: All side effects are traced for observability
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two-Phase Initialization&lt;/strong&gt;: Agent shells created first, then wired together to support cycles
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="tradeoffs"&gt;Tradeoffs&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ECS Complexity&lt;/strong&gt;: Adds indirection but enables powerful queries and flexible composition
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;STM Overhead&lt;/strong&gt;: Slight performance cost for composability
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage Overhead&lt;/strong&gt;: Component storage uses more memory than direct fields but enables dynamic extension
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type Erasure&lt;/strong&gt;: Using &lt;code&gt;Any&lt;/code&gt; requires careful casting but enables heterogeneous storage
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-architecture.html" rel="alternate"/><summary type="text">This document describes the runtime architecture and core components of the Agents framework. ## Core Architecture The framework is built around a layered architecture that separates concerns between agent definition, runtime execution, and</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-CHANGELOG-OS-MIGRATION.html</id><title type="text">Changelog: OS Model Migration</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/CHANGELOG-OS-MIGRATION.md"&gt;&lt;code&gt;documentation/CHANGELOG-OS-MIGRATION.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="changelog-os-model-migration"&gt;Changelog: OS Model Migration&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Date:&lt;/strong&gt; March 2026&lt;br /&gt;
&lt;strong&gt;Commits:&lt;/strong&gt; &lt;code&gt;0eb5263&lt;/code&gt; to &lt;code&gt;cb52af7&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="summary"&gt;Summary&lt;/h3&gt;
&lt;p&gt;This release introduces a major architectural refactoring of the agents-exe core, migrating from a Runtime-per-agent model to a centralized &lt;strong&gt;Entity-Component-System (ECS) based OS model&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="major-changes"&gt;Major Changes&lt;/h3&gt;
&lt;h4 id="new-architecture-ecs-based-os-model"&gt;New Architecture: ECS-Based OS Model&lt;/h4&gt;
&lt;p&gt;The framework now uses an Entity-Component-System (ECS) pattern at its core:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Entities&lt;/strong&gt;: Lightweight UUID-based identifiers (AgentId, ToolboxId, ConversationId, etc.)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Components&lt;/strong&gt;: Pure, serializable data attached to entities (AgentConfig, AgentState, ToolboxConfig)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Systems&lt;/strong&gt;: Functions that operate on entities with specific component combinations
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="new-modules-27-os-modules-added"&gt;New Modules (27 OS Modules Added)&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Module&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Main OS module, exports all OS functionality&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Core&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Core ECS types and World operations&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Core.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Component typeclass and entity ID types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Core.World&lt;/code&gt;&lt;/td&gt;&lt;td&gt;World storage with STM-based component stores&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Agents&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OS-native agent creation and management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.AgentTree&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OS-native agent tree initialization&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Concurrent&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Concurrent access patterns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Concurrent.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Access pattern types (Exclusive, Read-Write, Pool)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Concurrent.Locks&lt;/code&gt;&lt;/td&gt;&lt;td&gt;STM-based locking primitives&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Resources&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Resource lifecycle management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Resources.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Resource scope definitions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Resources.Sqlite&lt;/code&gt;&lt;/td&gt;&lt;td&gt;SQLite resource management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Resources.Lua&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Lua interpreter resources&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Resources.Http&lt;/code&gt;&lt;/td&gt;&lt;td&gt;HTTP connection pool resources&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Conversation&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Conversation and turn management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Conversation.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Turn, Message, Conversation components&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Conversation.Lineage&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Call chain tracking&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Compat&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Compatibility layer exports&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Compat.Runtime&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Runtime-to-OS bridge&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Interfaces&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Interface layer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Interfaces.TUI&lt;/code&gt;&lt;/td&gt;&lt;td&gt;TUI adaptation for OS&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Interfaces.OneShot&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OneShot adaptation for OS&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="migration-phases"&gt;Migration Phases&lt;/h4&gt;
&lt;p&gt;The migration follows a phased approach:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PhaseOldOnly (REMOVED) ──&amp;gt; PhaseDual ──&amp;gt; PhaseNewOnly
    (Legacy only)          (Both)        (OS only)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;March 2026 Update:&lt;/strong&gt; PhaseOldOnly has been removed. The system now operates in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PhaseDual&lt;/strong&gt; (default): Both Runtime and OS available
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PhaseNewOnly&lt;/strong&gt;: OS only, Runtime deprecated
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="key-new-capabilities"&gt;Key New Capabilities&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Shared Toolboxes&lt;/strong&gt;: Multiple agents can share the same SQLite database, HTTP connection pool, or other resources
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better Resource Management&lt;/strong&gt;: Explicit lifecycle scopes (Program, Agent, Toolbox, Conversation, Turn, ToolCall)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrent Access&lt;/strong&gt;: STM-based synchronization with multiple patterns:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ExclusiveAccess&lt;/code&gt;: Single accessor (TMVar) - for Lua interpreters
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ReadWriteAccess&lt;/code&gt;: Multiple readers/single writer (RWLock) - for SQLite
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PoolAccess&lt;/code&gt;: Bounded pool (TBQueue) - for HTTP connections
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StatelessAccess&lt;/code&gt;: No synchronization needed
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Durable Persistence&lt;/strong&gt;: Pluggable backends (SQLite, PostgreSQL, file-based)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complete Lineage Tracking&lt;/strong&gt;: Full call chains for debugging and accounting
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foundation for Web API&lt;/strong&gt;: Centralized state enables HTTP server interface
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="component-type-ids"&gt;Component Type IDs&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;ID&lt;/th&gt;&lt;th&gt;Component&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;AgentConfig&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;AgentState&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;ToolboxConfig&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;ToolboxState&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;ToolboxBinding&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;ConversationConfig&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;31&lt;/td&gt;&lt;td&gt;ConversationState&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;32&lt;/td&gt;&lt;td&gt;AgentConversation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;33&lt;/td&gt;&lt;td&gt;TurnConfig&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;34&lt;/td&gt;&lt;td&gt;TurnState&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;35&lt;/td&gt;&lt;td&gt;ToolCallConfig&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;36&lt;/td&gt;&lt;td&gt;ToolCallState&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;38&lt;/td&gt;&lt;td&gt;Message&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="new-cli-modules"&gt;New CLI Modules&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.CLI.Export&lt;/code&gt; - Export tools and agents
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.CLI.Import&lt;/code&gt; - Import tools and agents
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="new-documentation"&gt;New Documentation&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Document&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;documentation/architecture.md&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Updated with OS model architecture&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;documentation/OS-API.md&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Complete API reference for OS model&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;documentation/MIGRATION-OS.md&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Migration guide from Runtime to OS&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;documentation/MIGRATION-GUIDE.md&lt;/code&gt;&lt;/td&gt;&lt;td&gt;General migration guidance&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;documentation/advanced-configuration.md&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Advanced configuration options&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="new-tests"&gt;New Tests&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Test Module&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;test/OS/IntegrationTests.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;End-to-end OS scenarios&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;test/OS/CompatibilityTests.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Runtime/OS compatibility tests&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;test/OS/CoreTests.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ECS core functionality&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;test/OS/ConcurrentTests.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Concurrent access patterns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;test/OS/ResourcesTests.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Resource management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;test/OS/ConversationTests.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Conversation/lineage&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;test/OS/CompatTests.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Compatibility layer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;test/OS/InterfaceTests.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Interface layer&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="new-benchmarks"&gt;New Benchmarks&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Benchmark&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bench/OSBenchmarks.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OS model performance benchmarks&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="api-changes"&gt;API Changes&lt;/h3&gt;
&lt;h4 id="old-still-supported-via-compatibility-layer"&gt;Old (Still Supported via Compatibility Layer)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Legacy Runtime approach&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runtime &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newRuntime props agent tracer&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runWithRuntime runtime &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; listTools&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    callTool &lt;span class="st"&gt;&amp;quot;my-tool&amp;quot;&lt;/span&gt; args&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="new-os-model"&gt;New (OS Model)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- OS model approach&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Initialize world&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;world &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    w &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newWorld&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    w&amp;#39; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; registerComponentStore w (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentConfig&lt;/span&gt;)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    registerComponentStore w&amp;#39; (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentState&lt;/span&gt;)&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; config &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { agentName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentModel &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;url&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentSystemPrompt &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;You are helpful&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;agentId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createAgent world config&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="migration-path"&gt;Migration Path&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Current (PhaseDual)&lt;/strong&gt;: Use &lt;code&gt;System.Agents.OS.Compat.Runtime&lt;/code&gt; for gradual migration
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future (PhaseNewOnly)&lt;/strong&gt;: Direct OS model usage
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;See &lt;code&gt;documentation/MIGRATION-OS.md&lt;/code&gt; for detailed migration instructions.&lt;/p&gt;
&lt;h3 id="build-changes"&gt;Build Changes&lt;/h3&gt;
&lt;h4 id="new-dependencies"&gt;New Dependencies&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;deepseq&lt;/code&gt; - For benchmark strictness
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;criterion&lt;/code&gt; - Benchmarking framework
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;async&lt;/code&gt; - Concurrent test execution
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mtl&lt;/code&gt; - Monad transformers
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="cabal-updates"&gt;Cabal Updates&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added 27 new OS modules to library
&lt;/li&gt;
&lt;li&gt;Added new test modules
&lt;/li&gt;
&lt;li&gt;Added benchmark section
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="benefits"&gt;Benefits&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Shared Resources&lt;/strong&gt;: Multiple agents sharing toolboxes
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource Pooling&lt;/strong&gt;: HTTP connections pooled across agents
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better Lifecycle&lt;/strong&gt;: Explicit cleanup with scopes
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web API Ready&lt;/strong&gt;: Centralized state for HTTP interface
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Durable Persistence&lt;/strong&gt;: Multiple backend options
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lineage Tracking&lt;/strong&gt;: Complete call chains
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="tradeoffs"&gt;Tradeoffs&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ECS Complexity&lt;/strong&gt;: Adds indirection but enables flexible composition
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;STM Overhead&lt;/strong&gt;: Slight performance cost for composability
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dual Mode&lt;/strong&gt;: Maintenance burden during transition
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage Overhead&lt;/strong&gt;: More memory than direct fields
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="backward-compatibility"&gt;Backward Compatibility&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Full compatibility layer provided
&lt;/li&gt;
&lt;li&gt;Old Runtime interface still works
&lt;/li&gt;
&lt;li&gt;Gradual migration supported
&lt;/li&gt;
&lt;li&gt;Breaking changes documented in migration guide
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="related-issues"&gt;Related Issues&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;#348 - Core Entity and Component Types
&lt;/li&gt;
&lt;li&gt;#349 - Resource Management
&lt;/li&gt;
&lt;li&gt;#350 - Concurrent Access
&lt;/li&gt;
&lt;li&gt;#351 - Conversation and Lineage Tracking
&lt;/li&gt;
&lt;li&gt;#352 - OS Monad
&lt;/li&gt;
&lt;li&gt;#353 - Runtime Compatibility
&lt;/li&gt;
&lt;li&gt;#354 - TUI and OneShot Adaptation
&lt;/li&gt;
&lt;li&gt;#355 - Persistence Layer
&lt;/li&gt;
&lt;li&gt;#356 - Documentation and Integration (this release)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="contributors"&gt;Contributors&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Lucas DiCioccio
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;For questions about the migration, see &lt;code&gt;documentation/MIGRATION-OS.md&lt;/code&gt; or file an issue with the “migration” label.&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-CHANGELOG-OS-MIGRATION.html" rel="alternate"/><summary type="text">**Date:** March 2026 **Commits:** `0eb5263` to `cb52af7` ## Summary This release introduces a major architectural refactoring of the agents-exe core, migrating from a Runtime-per-agent model to a centralized **Entity-Component-System (ECS)</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-session-mailbox.html</id><title type="text">Spec: the session mailbox (agent-to-agent mail, suspended tool calls, interrupts, tool-call wrappers)</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/session-mailbox.md"&gt;&lt;code&gt;todos/session-mailbox.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="spec-the-session-mailbox-agent-to-agent-mail-suspended-tool-calls-interrupts-tool-call-wrappers"&gt;Spec: the session mailbox (agent-to-agent mail, suspended tool calls, interrupts, tool-call wrappers)&lt;/h2&gt;
&lt;p&gt;Status: proposal, 2026-09-22. Nothing implemented. Supersedes the designs in
issues #563 and #564, and most of #507 (see “What happens to the issues”).&lt;/p&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;
&lt;p&gt;One mechanism through which everything that happens &lt;em&gt;to&lt;/em&gt; a running session
reaches it: a user message, a message from another agent’s session, the result
of a tool call the LLM was told is “still running”, the result of a deferred
call, a timer, a pause request.&lt;/p&gt;
&lt;p&gt;Around it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(A2A) an agent can write to another session, running or idle, and get an
answer back, across sessions and (on &lt;code&gt;agents-server&lt;/code&gt;) across restarts;
&lt;/li&gt;
&lt;li&gt;(suspension) a slow tool call is suspended &lt;em&gt;inside the runtime&lt;/em&gt;: the LLM gets
&lt;code&gt;running, id = call_abc&lt;/code&gt; and takes its turn; it may then wait up to N seconds,
poll, cancel, or ignore the call;
&lt;/li&gt;
&lt;li&gt;(interrupts) while the runtime is blocked (on attached tool calls, on a
&lt;code&gt;wait&lt;/code&gt;, optionally on an LLM completion), higher-priority mail pre-empts the
wait;
&lt;/li&gt;
&lt;li&gt;(wrappers) tool calls are wrapped declaratively (timeout, retries, hooks that
may deny / defer / rewrite), which is the existing, currently inert,
&lt;code&gt;Decorator&lt;/code&gt; made real.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-os-picture"&gt;The OS picture&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;OS&lt;/th&gt;&lt;th&gt;here&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;CPU running user code&lt;/td&gt;&lt;td&gt;the LLM completing a turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;syscall&lt;/td&gt;&lt;td&gt;a tool call&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;blocking syscall&lt;/td&gt;&lt;td&gt;an &lt;em&gt;attached&lt;/em&gt; call: the step waits for it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SIGTSTP&lt;/code&gt; / &lt;code&gt;bg&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;detach&lt;/em&gt;: the call keeps running, the LLM gets a placeholder&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;wait(2)&lt;/code&gt;, &lt;code&gt;kill(2)&lt;/code&gt;, &lt;code&gt;/proc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;wait&lt;/code&gt;, &lt;code&gt;cancel-tool-call&lt;/code&gt;, &lt;code&gt;get-tool-call-status&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;interrupt controller + message queue&lt;/td&gt;&lt;td&gt;the mailbox&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;interrupt-enabled points&lt;/td&gt;&lt;td&gt;the receive points R1-R4 below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;syscall filter / LSM hooks&lt;/td&gt;&lt;td&gt;wrappers&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;scheduler run queue&lt;/td&gt;&lt;td&gt;&lt;code&gt;Host.Runner&lt;/code&gt;: a session with unread mail and no run is runnable&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="current-state"&gt;Current state&lt;/h3&gt;
&lt;p&gt;More of this exists than the issues assume. They predate &lt;code&gt;Session/Async*&lt;/code&gt;,
&lt;code&gt;Session/Wake.hs&lt;/code&gt; and &lt;code&gt;Host/Runner.hs&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="what-we-can-reuse-as-is"&gt;What we can reuse as-is&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Background calls: &lt;code&gt;RunAsync&lt;/code&gt;, the async engine, OS tool-call entities,
placeholder tool messages (&lt;code&gt;partialToolMessages&lt;/code&gt;), progress, cancellation of
the whole process group (&lt;code&gt;documentation/async-tool-calls.md&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt; (with &lt;code&gt;wait_for_completion&lt;/code&gt; + &lt;code&gt;timeout_seconds&lt;/code&gt;),
&lt;code&gt;list-running-tool-calls&lt;/code&gt;, &lt;code&gt;cancel-tool-call&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Deferred calls, continuation tokens, &lt;code&gt;wakeSessionWith&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Host.Runner&lt;/code&gt;: per-session lock, one run at a time, versioned writes
(&lt;code&gt;sbCompareAndStore&lt;/code&gt;), &lt;code&gt;SessionEvent&lt;/code&gt; broadcast + &lt;code&gt;subscribe&lt;/code&gt;, the HTTP event
stream, lineage (&lt;code&gt;smParent&lt;/code&gt;) and owners (&lt;code&gt;smOwner&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AsyncToolResponse = ToolComplete | ToolYield&lt;/code&gt;, which is the right result
type for a wrapper that wants to suspend a call.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="gaps"&gt;Gaps&lt;/h4&gt;
&lt;p&gt;G1. A session has &lt;strong&gt;half a dozen unrelated input channels&lt;/strong&gt;, each with its own
delivery rule:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;input&lt;/th&gt;&lt;th&gt;channel&lt;/th&gt;&lt;th&gt;"delivered once" is ensured by&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;user text&lt;/td&gt;&lt;td&gt;&lt;code&gt;usrQuery :: IO (Maybe UserQuery)&lt;/code&gt;, pulled&lt;/td&gt;&lt;td&gt;the caller&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;background result&lt;/td&gt;&lt;td&gt;STM over the OS entity (&lt;code&gt;awaitEntities&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;code&gt;tcDeliveredLate&lt;/code&gt; flag in the turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;deferred result&lt;/td&gt;&lt;td&gt;&lt;code&gt;lsInbox :: TVar [(token, result)]&lt;/code&gt; (&lt;code&gt;Runner.hs:204&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;code&gt;csComplete&lt;/code&gt; + &lt;code&gt;TokenAlreadyCompleted&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;user text, TUI&lt;/td&gt;&lt;td&gt;a &lt;code&gt;BChan&lt;/code&gt; per conversation + "buffered messages" in the core, drained by &lt;code&gt;usrQuery&lt;/code&gt; (&lt;code&gt;tui/…/Event/Conversation.hs&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;clearing the buffer on read&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;stop&lt;/td&gt;&lt;td&gt;&lt;code&gt;cancel&lt;/code&gt; of the run thread (&lt;code&gt;cancelRun&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;pause, TUI&lt;/td&gt;&lt;td&gt;&lt;code&gt;step&lt;/code&gt; polls &lt;code&gt;isConversationPaused&lt;/code&gt; every 200 ms&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;G2. &lt;strong&gt;A busy session cannot be talked to.&lt;/strong&gt; &lt;code&gt;postMessage&lt;/code&gt; answers
&lt;code&gt;RunInProgress&lt;/code&gt; / &lt;code&gt;NotAcceptingMessages&lt;/code&gt; (&lt;code&gt;Runner.hs:664&lt;/code&gt;). Nothing can be
addressed to a session by another session at all. This is the A2A blocker.&lt;/p&gt;
&lt;p&gt;G3. The one interrupt we have, &lt;code&gt;race agent.usrQuery (waitForRunningCalls …)&lt;/code&gt;
(&lt;code&gt;Step.hs:630&lt;/code&gt;), races two IO actions, so &lt;code&gt;usrQuery&lt;/code&gt; “must tolerate
cancellation”, and it only exists at one point (idle with background calls).
Attached calls, &lt;code&gt;wait_for_completion&lt;/code&gt; and LLM completions are not
interruptible.&lt;/p&gt;
&lt;p&gt;G4. Suspension is &lt;strong&gt;static&lt;/strong&gt;: a tool is &lt;code&gt;runAsync&lt;/code&gt; or it is not. There is no
“run it, and if it is still going after 10 s hand control back” per call;
&lt;code&gt;yieldOnTimeout&lt;/code&gt; is per agent and per step. And a &lt;code&gt;runSync&lt;/code&gt; call runs in the
step’s own thread, so it can never be detached.&lt;/p&gt;
&lt;p&gt;G5. &lt;strong&gt;Decorators are parsed, stored, and never applied.&lt;/strong&gt; &lt;code&gt;WithTimeout&lt;/code&gt;,
&lt;code&gt;WithRetries&lt;/code&gt;, &lt;code&gt;WithCache&lt;/code&gt;, &lt;code&gt;WithLabel&lt;/code&gt; (&lt;code&gt;Session/Types.hs:468&lt;/code&gt;) are flattened
into &lt;code&gt;ccDecorators&lt;/code&gt; (&lt;code&gt;Step.hs:347&lt;/code&gt;), which nobody reads; &lt;code&gt;Durable.hs&lt;/code&gt; binds
them to &lt;code&gt;_decorators&lt;/code&gt; four times. Policy rules match one exact tool name,
first match wins (&lt;code&gt;AgentConfig.hs:26&lt;/code&gt;), so a decorator cannot be applied
across tools.&lt;/p&gt;
&lt;p&gt;G6. “If the model reads a result with &lt;code&gt;get-tool-call-status&lt;/code&gt;, the delivery
notice repeats it once” (documented limit): a symptom of G1, there is no
notion of a message having been consumed.&lt;/p&gt;
&lt;h3 id="design"&gt;Design&lt;/h3&gt;
&lt;h4 id="1-the-mailbox"&gt;1. The mailbox&lt;/h4&gt;
&lt;p&gt;An envelope:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Envelope&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Envelope&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; envId       ::&lt;/span&gt; &lt;span class="dt"&gt;MessageId&lt;/span&gt;      &lt;span class="co"&gt;-- idempotency key; sender may supply it&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; envSeq      ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;            &lt;span class="co"&gt;-- assigned on accept; total order per session&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; envFrom     ::&lt;/span&gt; &lt;span class="dt"&gt;Sender&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; envPriority ::&lt;/span&gt; &lt;span class="dt"&gt;Priority&lt;/span&gt;       &lt;span class="co"&gt;-- Normal | Interrupt&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; envHops     ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;            &lt;span class="co"&gt;-- A2A loop guard, see §5&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; envSentAt   ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; envBody     ::&lt;/span&gt; &lt;span class="dt"&gt;MailBody&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Sender&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;FromUser&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;)                 &lt;span class="co"&gt;-- owner, when known&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;FromSession&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;)    &lt;span class="co"&gt;-- and its agent slug&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;FromToolCall&lt;/span&gt; &lt;span class="dt"&gt;ToolCallId&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;FromSystem&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                       &lt;span class="co"&gt;-- timers, watchers, the runner&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;MailBody&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserMessage&lt;/span&gt; &lt;span class="dt"&gt;UserQuery&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AgentMessage&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;MessageId&lt;/span&gt;) &lt;span class="dt"&gt;Bool&lt;/span&gt;      &lt;span class="co"&gt;-- text, in-reply-to, expects-reply&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallFinished&lt;/span&gt; &lt;span class="dt"&gt;ToolCallId&lt;/span&gt; &lt;span class="dt"&gt;ToolCallState&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ContinuationResult&lt;/span&gt; &lt;span class="dt"&gt;ContinuationToken&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;WatchedEvent&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Aeson.Value&lt;/span&gt;       &lt;span class="co"&gt;-- §7&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Control&lt;/span&gt; &lt;span class="dt"&gt;ControlMsg&lt;/span&gt;                            &lt;span class="co"&gt;-- Pause | Resume | CancelCalls [ToolCallId] | StopRun&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Progress is &lt;em&gt;not&lt;/em&gt; mail. It is state (the OS entity keeps the last 50 entries)
and is read, not delivered.&lt;/p&gt;
&lt;p&gt;The interface, a record of functions like &lt;code&gt;ContinuationStore&lt;/code&gt;, carried as
&lt;code&gt;ctxMailbox :: Maybe Mailbox&lt;/code&gt; on &lt;code&gt;Agent&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Mailbox&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Mailbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; mbSend   ::&lt;/span&gt; &lt;span class="dt"&gt;Outgoing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;SendError&lt;/span&gt; &lt;span class="dt"&gt;Receipt&lt;/span&gt;)  &lt;span class="co"&gt;-- any thread, any session&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mbUnread ::&lt;/span&gt; &lt;span class="dt"&gt;Cursor&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; [&lt;span class="dt"&gt;Envelope&lt;/span&gt;]                   &lt;span class="co"&gt;-- never removes anything&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mbTrim   ::&lt;/span&gt; &lt;span class="dt"&gt;Cursor&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()                            &lt;span class="co"&gt;-- GC at or below the cursor&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SendError&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UnknownRecipient&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MailboxFull&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;NotPermitted&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TooManyHops&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Receipt&lt;/span&gt;   &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Receipt&lt;/span&gt; {&lt;span class="ot"&gt; rcptId ::&lt;/span&gt; &lt;span class="dt"&gt;MessageId&lt;/span&gt;,&lt;span class="ot"&gt; rcptSeq ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;,&lt;span class="ot"&gt; rcptDuplicate ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Transactional&lt;/strong&gt; means three things, and only these:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Accept is atomic and idempotent.&lt;/em&gt; One STM transaction (in memory) or one
&lt;code&gt;INSERT … ON CONFLICT DO NOTHING&lt;/code&gt; (durable) assigns &lt;code&gt;envSeq&lt;/code&gt;. Resending the
same &lt;code&gt;envId&lt;/code&gt; returns the first receipt with &lt;code&gt;rcptDuplicate&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Reading does not consume.&lt;/em&gt; There is no &lt;code&gt;pop&lt;/code&gt;. A reader is a cursor.
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Consumption commits with its effect.&lt;/em&gt; &lt;code&gt;Session&lt;/code&gt; gains &lt;code&gt;mailCursor :: Int&lt;/code&gt;
(JSON default 0). A step that folds envelopes &lt;code&gt;≤ k&lt;/code&gt; into a turn returns a
session with &lt;code&gt;mailCursor = k&lt;/code&gt;; the versioned store of that session &lt;em&gt;is&lt;/em&gt; the
ack. A crash between reading and storing redelivers into a session that
does not contain the mail yet: exactly-once effect, no two-phase anything.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Point 3 is why #563’s &lt;code&gt;TQueue&lt;/code&gt; component is not enough (a &lt;code&gt;readTQueue&lt;/code&gt;
followed by a crash loses the message), and it removes &lt;code&gt;tcDeliveredLate&lt;/code&gt;-style
flags: “delivered” is &lt;code&gt;envSeq ≤ mailCursor&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because &lt;code&gt;mbUnread&lt;/code&gt; is STM, a blocking receive is &lt;code&gt;retry&lt;/code&gt;, a filtered receive
is a &lt;code&gt;filter&lt;/code&gt;, and a receive with alternatives is &lt;code&gt;orElse&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;awaitMail ::&lt;/span&gt; &lt;span class="dt"&gt;Mailbox&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Cursor&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;Envelope&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; [&lt;span class="dt"&gt;Envelope&lt;/span&gt;]&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;awaitMail mb cur p &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    es &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;filter&lt;/span&gt; p &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; mbUnread mb cur&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    when (&lt;span class="fu"&gt;null&lt;/span&gt; es) retry&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; es&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Two implementations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;in memory (&lt;code&gt;TVar (Seq Envelope)&lt;/code&gt;), for &lt;code&gt;run&lt;/code&gt;, the TUI, sub-agents, tests;
&lt;/li&gt;
&lt;li&gt;durable, for &lt;code&gt;Host&lt;/code&gt;: a &lt;code&gt;session_mail&lt;/code&gt; table next to the continuations
(&lt;code&gt;session_id, seq, id UNIQUE, from_json, priority, hops, body_json, accepted_at&lt;/code&gt;), SQLite and Postgres, fronted by the same &lt;code&gt;TVar&lt;/code&gt; so
&lt;code&gt;mbUnread&lt;/code&gt; stays STM. The runner is single-process per session already
(second writers are detected), so the &lt;code&gt;TVar&lt;/code&gt; front is sound; a multi-process
Postgres deployment fills it from &lt;code&gt;LISTEN/NOTIFY&lt;/code&gt; (&lt;code&gt;mbSync&lt;/code&gt;, with the
sequence numbers settled by the database).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bounded: &lt;code&gt;mailboxMaxUnread&lt;/code&gt; (default 256). A full mailbox refuses with
&lt;code&gt;MailboxFull&lt;/code&gt;; the sender’s tool call fails, which is the backpressure.
&lt;code&gt;Control&lt;/code&gt; and &lt;code&gt;ToolCallFinished&lt;/code&gt; are exempt.&lt;/p&gt;
&lt;h4 id="2-receive-points"&gt;2. Receive points&lt;/h4&gt;
&lt;p&gt;The stepper reads the mailbox at four points. Everything else in this spec is
a consequence of what each point does.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;when&lt;/th&gt;&lt;th&gt;blocking&lt;/th&gt;&lt;th&gt;reads&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;R1&lt;/td&gt;&lt;td&gt;building a user turn, before &lt;code&gt;AskLlmCompletion&lt;/code&gt;&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;all unread&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;R2&lt;/td&gt;&lt;td&gt;idle: the LLM issued no calls, or only detached/deferred calls remain&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;all unread&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;R3&lt;/td&gt;&lt;td&gt;blocked on attached calls, or inside the &lt;code&gt;wait&lt;/code&gt; tool&lt;/td&gt;&lt;td&gt;yes, as one arm of an &lt;code&gt;orElse&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Interrupt&lt;/code&gt; (R3a), any (R3b, &lt;code&gt;wait&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;R4&lt;/td&gt;&lt;td&gt;during an LLM completion (opt-in)&lt;/td&gt;&lt;td&gt;&lt;code&gt;race&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Interrupt&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;R1 generalises &lt;code&gt;collectLateResults&lt;/code&gt;; R2 replaces the &lt;code&gt;race&lt;/code&gt; in &lt;code&gt;askUserQuery&lt;/code&gt;
and the &lt;code&gt;block&lt;/code&gt; flag; both become:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- R2, no IO race, nothing to cancel&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; awaitMail mb cur (&lt;span class="fu"&gt;const&lt;/span&gt; &lt;span class="dt"&gt;True&lt;/span&gt;)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- R3a: attached calls vs. interrupts, one transaction&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; (&lt;span class="dt"&gt;Left&lt;/span&gt;  &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; awaitMail mb cur isInterrupt)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;`orElse`&lt;/span&gt; (&lt;span class="dt"&gt;Right&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; awaitEntities world &lt;span class="fu"&gt;any&lt;/span&gt; attached)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;A genuine &lt;code&gt;race&lt;/code&gt; (thread cancellation) remains only where an IO action must
be abandoned: R4, and an inline call under &lt;code&gt;StopRun&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What the LLM sees.&lt;/strong&gt; Providers want exactly one tool message per call, then
optionally a user message. So mail is folded into the &lt;code&gt;userQuery&lt;/code&gt; of the turn
being built, as &lt;code&gt;lateResultsQuery&lt;/code&gt; does today, one block per envelope with a
header the model can quote back:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[mail m-7f3a from session 9c1e (agent &amp;quot;reviewer&amp;quot;), expects reply]
The migration in your PR drops an index that report_daily depends on.

[mail m-7f3b: tool call call_abc (run_tests) completed]
42 tests passed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The raw envelopes are also kept on the turn (&lt;code&gt;userMail :: [Envelope]&lt;/code&gt;, new
optional field of &lt;code&gt;UserTurnContent&lt;/code&gt; / &lt;code&gt;PartialUserTurnContent&lt;/code&gt;), so the TUI,
the chat page and &lt;code&gt;session-print&lt;/code&gt; render senders properly instead of parsing
a blob, and the audit trail #563 wanted (&lt;code&gt;imSourceAgent&lt;/code&gt;) is in the session
file.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Control&lt;/code&gt; envelopes are consumed (cursor moves) but render nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compatibility.&lt;/strong&gt; &lt;code&gt;ctxMailbox = Nothing&lt;/code&gt; keeps today’s code paths, &lt;code&gt;usrQuery&lt;/code&gt;
included. With a mailbox, front-ends post &lt;code&gt;UserMessage&lt;/code&gt; instead of answering
&lt;code&gt;usrQuery&lt;/code&gt;: one-shot runs pre-load one envelope; the TUI’s message editor posts
to the selected conversation’s mailbox, which replaces both the per-conversation
&lt;code&gt;BChan&lt;/code&gt; and the buffered messages (typing at a busy conversation &lt;em&gt;is&lt;/em&gt; unread
mail), and the TUI’s pause becomes &lt;code&gt;Control Pause&lt;/code&gt; instead of a polling &lt;code&gt;step&lt;/code&gt;;
&lt;code&gt;postMessage&lt;/code&gt; posts. &lt;code&gt;usrQuery&lt;/code&gt; stays on the record for embedders.&lt;/p&gt;
&lt;h4 id="3-suspended-tool-calls-attach-and-detach"&gt;3. Suspended tool calls: attach and detach&lt;/h4&gt;
&lt;p&gt;In asynchronous mode &lt;strong&gt;every call that has an OS entity runs in the engine&lt;/strong&gt;.
A disposition no longer says &lt;em&gt;where&lt;/em&gt; a call runs but &lt;em&gt;how long the step stays
attached to it&lt;/em&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;config&lt;/th&gt;&lt;th&gt;meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{"tag":"runSync"}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;attached until done (today's behaviour, now detachable by an interrupt)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{"tag":"runAsync"}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;attached per the agent's &lt;code&gt;asyncYieldStrategy&lt;/code&gt; (unchanged)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{"tag":"runAsync","attachSeconds":10}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;attached for 10 s, then detached&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{"tag":"runAsync","attachSeconds":0}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;detached at once&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;attachSeconds&lt;/code&gt; is G4’s answer: fast calls look synchronous, slow ones suspend
themselves. The wait is R3a with one more &lt;code&gt;orElse&lt;/code&gt; arm per distinct deadline
(a &lt;code&gt;registerDelay&lt;/code&gt; TVar).&lt;/p&gt;
&lt;p&gt;Detaching is what &lt;code&gt;executeTrackedCalls&lt;/code&gt; already does when it emits a
&lt;code&gt;PartialUserTurn&lt;/code&gt; with &lt;code&gt;Running&lt;/code&gt; calls; the placeholder gains the reason:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;running&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;call_abc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;detached&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;still running after 10s&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Its result will arrive as mail. Use wait, get-tool-call-status or cancel-tool-call.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;On completion the engine posts &lt;code&gt;ToolCallFinished&lt;/code&gt; to the owning session’s
mailbox &lt;strong&gt;in the same STM transaction that marks the entity &lt;code&gt;TcCompleted&lt;/code&gt;&lt;/strong&gt;,
so a result can neither be lost nor observed by &lt;code&gt;get-tool-call-status&lt;/code&gt; before
it is mail. Fixing G6: when &lt;code&gt;get-tool-call-status&lt;/code&gt; returns a final result, the
stepper marks that envelope as read-by-tool on the turn, and R1 renders it as
a one-line &lt;code&gt;already read&lt;/code&gt; notice instead of repeating the payload.&lt;/p&gt;
&lt;p&gt;The LLM’s side, in the System Toolbox:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;capability&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;wait&lt;/code&gt; (new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"for": ["call_abc"] \| "any-call" \| "mail", "timeout_seconds": 30}&lt;/code&gt;. Returns on the first of: a named call is final, any mail, timeout. Says which. Peeks, never consumes: the mail it woke for is delivered by R1 in the same turn.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;unchanged; &lt;code&gt;wait_for_completion&lt;/code&gt; becomes sugar for &lt;code&gt;wait&lt;/code&gt; and gains interruptibility&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;cancel-tool-call&lt;/code&gt;, &lt;code&gt;list-running-tool-calls&lt;/code&gt;&lt;/td&gt;&lt;td&gt;unchanged&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;send-to-tool-call&lt;/code&gt; (later)&lt;/td&gt;&lt;td&gt;for a sub-agent call: mail to the child session (§5). For bash: stdin, not planned.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;wait&lt;/code&gt; needs the mailbox, so &lt;code&gt;ToolExecutionContext&lt;/code&gt; gains &lt;code&gt;ctxAwaitMail&lt;/code&gt;, a
hook like &lt;code&gt;ctxCancelToolCall&lt;/code&gt;. &lt;code&gt;wait&lt;/code&gt; always takes a timeout, capped by
&lt;code&gt;maxWaitSeconds&lt;/code&gt; (default 300): two agents waiting on each other time out
instead of deadlocking.&lt;/p&gt;
&lt;p&gt;Background calls still die with their process (orphaned on reload). Unchanged,
out of scope.&lt;/p&gt;
&lt;h4 id="4-interrupts"&gt;4. Interrupts&lt;/h4&gt;
&lt;p&gt;Priority is set by the sender and checked on accept: the user and &lt;code&gt;Control&lt;/code&gt;
may always interrupt; a session may interrupt its descendants; peers may not
(configurable, §5).&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;&lt;code&gt;Interrupt&lt;/code&gt; mail arrives while the step is…&lt;/th&gt;&lt;th&gt;effect&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;attached to engine calls (R3a)&lt;/td&gt;&lt;td&gt;all attached calls are detached; the LLM is asked at once, with the mail and placeholders. This is &lt;code&gt;^Z&lt;/code&gt; then talk.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;in the &lt;code&gt;wait&lt;/code&gt; tool (R3b)&lt;/td&gt;&lt;td&gt;&lt;code&gt;wait&lt;/code&gt; returns &lt;code&gt;{"woken_by": "mail"}&lt;/code&gt;; any priority does this&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;in an inline call (no entity, no engine)&lt;/td&gt;&lt;td&gt;nothing until it returns; &lt;code&gt;StopRun&lt;/code&gt; cancels the thread&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;in an LLM completion (R4), &lt;code&gt;interruptCompletions: true&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the completion is cancelled; the head &lt;code&gt;UserTurn&lt;/code&gt; is &lt;strong&gt;amended&lt;/strong&gt; with the mail (the LLM never answered it, so no turn is lost) and asked again&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;in an LLM completion, default&lt;/td&gt;&lt;td&gt;delivered at the next R1/R2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;idle (R2)&lt;/td&gt;&lt;td&gt;same as &lt;code&gt;Normal&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;Normal&lt;/code&gt; mail never pre-empts anything but &lt;code&gt;wait&lt;/code&gt; and R2.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Control&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Pause&lt;/code&gt;: the run stops at the next receive point, cursor committed, status
&lt;code&gt;paused&lt;/code&gt;; detached calls keep running unless &lt;code&gt;pauseCancelsCalls&lt;/code&gt;. &lt;code&gt;Resume&lt;/code&gt;
(or, by config, any mail) makes it runnable again.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CancelCalls&lt;/code&gt;: the engine’s cancel; results come back as
&lt;code&gt;ToolCallFinished … Failed&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StopRun&lt;/code&gt;: today’s &lt;code&gt;cancelRun&lt;/code&gt;, now reachable by mail.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-agent-to-agent"&gt;5. Agent-to-agent&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Address&lt;/strong&gt;: a &lt;code&gt;SessionId&lt;/code&gt;. Discovery is by the existing &lt;code&gt;list-sessions&lt;/code&gt; /
&lt;code&gt;search-sessions&lt;/code&gt;, plus &lt;code&gt;smAgent&lt;/code&gt;, &lt;code&gt;smParent&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Routing.&lt;/strong&gt; &lt;code&gt;mbSend&lt;/code&gt; needs to find the recipient’s mailbox, in every front-end
and not only on the server (helper agents are used extensively in the TUI). A
&lt;code&gt;MailRouter&lt;/code&gt; is the process’s table of live mailboxes:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;MailRouter&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;MailRouter&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; mrRegister ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;MailboxInfo&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Mailbox&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;IO&lt;/span&gt; ())  &lt;span class="co"&gt;-- returns unregister&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mrLookup   ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;MailboxInfo&lt;/span&gt;, &lt;span class="dt"&gt;Mailbox&lt;/span&gt;))&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mrList     ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [(&lt;span class="dt"&gt;SessionId&lt;/span&gt;, &lt;span class="dt"&gt;MailboxInfo&lt;/span&gt;)]   &lt;span class="co"&gt;-- agent slug, parent, status&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;front-end&lt;/th&gt;&lt;th&gt;router&lt;/th&gt;&lt;th&gt;a session is live…&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents-server&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Host.Runner&lt;/code&gt; (durable mail; unknown-but-stored sessions are loaded on demand)&lt;/td&gt;&lt;td&gt;always&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TUI&lt;/td&gt;&lt;td&gt;one per process, held next to &lt;code&gt;coreRef&lt;/code&gt;; every conversation registers, sub-calls included&lt;/td&gt;&lt;td&gt;while its conversation exists&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;run&lt;/code&gt;, MCP server&lt;/td&gt;&lt;td&gt;one per process; the root and every sub-agent session register&lt;/td&gt;&lt;td&gt;until its loop returns&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;It travels as &lt;code&gt;ctxMailRouter&lt;/code&gt; on &lt;code&gt;Agent&lt;/code&gt; and is handed down to sub-agents the
way &lt;code&gt;ctxWorld&lt;/code&gt; and &lt;code&gt;ctxEventQueue&lt;/code&gt; are, so a whole call tree shares one.
&lt;code&gt;mrList&lt;/code&gt; is what makes in-memory sessions discoverable (the “ongoing sessions”
#563 wanted to list): &lt;code&gt;list-sessions&lt;/code&gt; merges it with the persisted ones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scheduling rule&lt;/strong&gt;: &lt;em&gt;a session with unread mail, no run, and a status that
accepts mail is runnable.&lt;/em&gt; On the server the runner starts a run; in the TUI
and in &lt;code&gt;run&lt;/code&gt; a session’s loop is simply parked at R2 and wakes by itself.&lt;/p&gt;
&lt;p&gt;Which mail wakes an &lt;strong&gt;idle&lt;/strong&gt; session is a per-agent option, &lt;code&gt;wakeOn&lt;/code&gt;, a list
among &lt;code&gt;user&lt;/code&gt;, &lt;code&gt;tool&lt;/code&gt;, &lt;code&gt;parent&lt;/code&gt;, &lt;code&gt;child&lt;/code&gt;, &lt;code&gt;peer&lt;/code&gt;. Mail that does not wake is
still queued and delivered with the next thing that does. Default
&lt;code&gt;[&amp;quot;user&amp;quot;, &amp;quot;tool&amp;quot;, &amp;quot;parent&amp;quot;, &amp;quot;child&amp;quot;]&lt;/code&gt;, deliberately a config knob and not a
rule of the design: it is too early to know what peers should be allowed to do
to each other (D10). The rule also replaces the special case in
&lt;code&gt;completeCall&lt;/code&gt;: &lt;code&gt;autoResume&lt;/code&gt; becomes “post &lt;code&gt;ContinuationResult&lt;/code&gt;”, and &lt;code&gt;lsInbox&lt;/code&gt;
goes away.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;postMessage&lt;/code&gt; during a run stops failing: it posts &lt;code&gt;UserMessage&lt;/code&gt; and returns
the receipt (HTTP 202 with &lt;code&gt;message_id&lt;/code&gt;, &lt;code&gt;seq&lt;/code&gt;), optionally
&lt;code&gt;&amp;quot;interrupt&amp;quot;: true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt; (System Toolbox capabilities):&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;capability&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;send-message&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"to": "&amp;lt;session&amp;gt;", "text": …, "in_reply_to": "m-…", "expects_reply": true, "interrupt": false}&lt;/code&gt; → receipt + the recipient's status (&lt;code&gt;running&lt;/code&gt;, &lt;code&gt;idle&lt;/code&gt;, &lt;code&gt;paused&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;spawn-session&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"agent": "&amp;lt;slug&amp;gt;", "message": …}&lt;/code&gt; → the new session's id. A session that is a child in lineage but &lt;em&gt;not&lt;/em&gt; call/return: it outlives the tool call that created it, and answers by mail. &lt;code&gt;&amp;lt;slug&amp;gt;&lt;/code&gt; is one of the caller's helpers, as for &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt;, with the same &lt;code&gt;with&lt;/code&gt; / &lt;code&gt;bindings&lt;/code&gt; narrowing.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;wait&lt;/code&gt;&lt;/td&gt;&lt;td&gt;§3, with &lt;code&gt;"for": "mail"&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;spawn-session&lt;/code&gt; exists in every front-end:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;server: &lt;code&gt;createSessionAs&lt;/code&gt;, durable, survives restarts;
&lt;/li&gt;
&lt;li&gt;TUI: a new conversation, created the way sub-calls are today
(&lt;code&gt;OSEvent_SubcallStarted&lt;/code&gt;, &lt;code&gt;conversationParentId&lt;/code&gt;), so it shows up in the
conversation list, the user can open it and type into it, and its mailbox is
what the message editor posts to. It lives until the user closes it or its
parent conversation goes away;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run&lt;/code&gt;: a thread with an in-memory mailbox, cancelled with the root like
background calls are (&lt;code&gt;withEngineShutdown&lt;/code&gt;). A root that stops while
spawned sessions still work loses them; an agent that wants their answers
calls &lt;code&gt;wait&lt;/code&gt; (D11).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Call/return sub-agents (&lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt;) are unchanged, but when they run
detached their placeholder and status report the &lt;strong&gt;child session id&lt;/strong&gt;, so the
parent can &lt;code&gt;send-message&lt;/code&gt; to a helper that is still working, and the helper’s
final answer arrives as &lt;code&gt;ToolCallFinished&lt;/code&gt;. “Interacting with a running tool
call” and “agent-to-agent chat” are the same mechanism.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Permissions&lt;/strong&gt;: #563’s scope, checked in &lt;code&gt;mbSend&lt;/code&gt;, per sending agent:
&lt;code&gt;mailScope: own | children | subtree | all&lt;/code&gt; (default &lt;code&gt;subtree&lt;/code&gt;), and
&lt;code&gt;interruptScope&lt;/code&gt; (default &lt;code&gt;children&lt;/code&gt;). Through the HTTP API the existing owner
check applies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Loops&lt;/strong&gt;: a reply carries &lt;code&gt;envHops = hops of the mail being answered + 1&lt;/code&gt;
(the stepper knows which mail the current turn consumed); &lt;code&gt;maxMailHops&lt;/code&gt;
(default 16) refuses with &lt;code&gt;TooManyHops&lt;/code&gt;. User mail resets to 0. Together with
&lt;code&gt;MailboxFull&lt;/code&gt; and the &lt;code&gt;wait&lt;/code&gt; cap, two agents cannot ping-pong or deadlock
forever.&lt;/p&gt;
&lt;h4 id="6-wrappers"&gt;6. Wrappers&lt;/h4&gt;
&lt;p&gt;Decorators become middleware over the executor, applied in one place
(&lt;code&gt;executeCall&lt;/code&gt;, which both the inline path and the engine already go through):&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;Exec&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LlmToolCall&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;AsyncToolResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;ToolMiddleware&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Exec&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Exec&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;interpretDecorator ::&lt;/span&gt; &lt;span class="dt"&gt;WrapperEnv&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Decorator&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolMiddleware&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Decorate [d1, d2] base  ==&amp;gt;  d1 (d2 exec): first listed is outermost&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;AsyncToolResponse&lt;/code&gt; rather than &lt;code&gt;UserToolResponse&lt;/code&gt; so that a wrapper can
answer &lt;code&gt;ToolYield&lt;/code&gt;: that is how a &lt;code&gt;before&lt;/code&gt; hook turns a call into a deferred
one (an approval gate) from inside the engine, without blocking the step.&lt;/p&gt;
&lt;p&gt;Config: &lt;code&gt;rules&lt;/code&gt; keep choosing the base disposition (first match). A new
&lt;code&gt;wrappers&lt;/code&gt; list contributes decorators; &lt;strong&gt;every&lt;/strong&gt; match applies, in file
order, outermost first. The result is still one &lt;code&gt;Decorate […] base&lt;/code&gt;, recorded
in &lt;code&gt;AppliedPolicy&lt;/code&gt;, so the session file shows what wrapped each call.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;toolCallPolicyConfig&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runSync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;run_tests&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;disposition&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runAsync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;attachSeconds&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;wrappers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;match&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;        &lt;span class="dt"&gt;&amp;quot;decorators&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;truncate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;maxBytes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;65536&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;match&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;http_*&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;   &lt;span class="dt"&gt;&amp;quot;decorators&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;retries&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;backoffMs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;500&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                                   &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;timeout&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;seconds&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;30&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;match&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;deploy_*&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;decorators&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;before&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;hook&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;command&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;hooks/approve-deploy&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                                   &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;after&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;  &lt;span class="dt"&gt;&amp;quot;hook&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;audit_log&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;match&lt;/code&gt;: &lt;code&gt;tool&lt;/code&gt; (glob on the LLM-visible name), &lt;code&gt;toolbox&lt;/code&gt;, later &lt;code&gt;args&lt;/code&gt; (a
JSON predicate). Decorators:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;tag&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;timeout&lt;/code&gt;, &lt;code&gt;retries&lt;/code&gt;, &lt;code&gt;cache&lt;/code&gt;, &lt;code&gt;label&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the existing four, now applied. Per-call &lt;code&gt;timeout&lt;/code&gt; wins over &lt;code&gt;asyncCallTimeoutSeconds&lt;/code&gt;; each retry reports progress.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;truncate&lt;/code&gt;&lt;/td&gt;&lt;td&gt;cap the result, say so to the model&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;before&lt;/code&gt;&lt;/td&gt;&lt;td&gt;hook sees &lt;code&gt;{tool, arguments, session_id, tool_call_id, agent}&lt;/code&gt;; answers &lt;code&gt;continue&lt;/code&gt; (optionally &lt;code&gt;arguments&lt;/code&gt; rewritten), &lt;code&gt;deny {message}&lt;/code&gt; (the message is the tool result, the tool does not run), &lt;code&gt;defer {reason}&lt;/code&gt; (→ &lt;code&gt;ToolYield&lt;/code&gt;, a continuation token, the usual external completion), &lt;code&gt;answer {result}&lt;/code&gt; (short-circuit)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;after&lt;/code&gt;&lt;/td&gt;&lt;td&gt;hook sees the above plus &lt;code&gt;result&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;duration_ms&lt;/code&gt;; answers &lt;code&gt;continue&lt;/code&gt; (optionally &lt;code&gt;result&lt;/code&gt; rewritten), &lt;code&gt;annotate {text}&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;A hook target is &lt;code&gt;{&amp;quot;command&amp;quot;: path}&lt;/code&gt; (JSON on stdin, JSON on stdout, the
isolation-envelope conventions, non-zero exit = &lt;code&gt;deny&lt;/code&gt; for &lt;code&gt;before&lt;/code&gt;, ignored
with a trace for &lt;code&gt;after&lt;/code&gt;), or &lt;code&gt;{&amp;quot;tool&amp;quot;: name}&lt;/code&gt;: any tool registered on the
agent, visible to the LLM or not, &lt;strong&gt;including a sub-agent&lt;/strong&gt;, which gives
LLM-as-guard for free and lets hooks use bindings and secrets like any tool.&lt;/p&gt;
&lt;p&gt;Two rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hooks see what the LLM sent. Bindings are merged inside &lt;code&gt;toolRun&lt;/code&gt;, below
&lt;code&gt;executeCall&lt;/code&gt;, so bound values, secrets included, never reach a hook, and a
&lt;code&gt;before&lt;/code&gt; rewrite cannot override a binding.
&lt;/li&gt;
&lt;li&gt;A hook failure (crash, timeout, bad JSON) is &lt;code&gt;deny&lt;/code&gt; for &lt;code&gt;before&lt;/code&gt; (“fail
closed”) and &lt;code&gt;continue&lt;/code&gt; for &lt;code&gt;after&lt;/code&gt;, both traced.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="7-watching-other-sessions"&gt;7. Watching other sessions&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Host.Runner&lt;/code&gt; already broadcasts &lt;code&gt;SessionEvent&lt;/code&gt; and serves it over HTTP. No
subscription registry, no filter algebra: a &lt;strong&gt;watch&lt;/strong&gt; forwards matching events
of one session into the watcher’s mailbox as &lt;code&gt;WatchedEvent&lt;/code&gt;, and &lt;code&gt;wait&lt;/code&gt; is the
only blocking primitive.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;watch-session {&amp;quot;session&amp;quot;: …, &amp;quot;events&amp;quot;: [&amp;quot;run.stopped&amp;quot;, &amp;quot;tool.completed&amp;quot;], &amp;quot;tool&amp;quot;: &amp;quot;deploy_*&amp;quot;, &amp;quot;ttl_seconds&amp;quot;: 600}&lt;/code&gt;,
&lt;code&gt;unwatch-session&lt;/code&gt;. Watches are in-memory, scoped like mail, capped per session,
and die with their TTL or either session. &lt;code&gt;SessionEvent&lt;/code&gt; gains the two
tool-call events (&lt;code&gt;tool.started&lt;/code&gt;, &lt;code&gt;tool.completed&lt;/code&gt;); the rest of #563’s event
list is already covered by &lt;code&gt;SessionUpdated&lt;/code&gt; carrying the head turn.&lt;/p&gt;
&lt;h3 id="what-happens-to-the-issues"&gt;What happens to the issues&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;issue&lt;/th&gt;&lt;th&gt;kept&lt;/th&gt;&lt;th&gt;changed&lt;/th&gt;&lt;th&gt;dropped&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;amp;#35;563 ph.1 inbox&lt;/td&gt;&lt;td&gt;inject a message, pause, cancel calls, scopes, audit of the sender&lt;/td&gt;&lt;td&gt;an &lt;code&gt;Agent&lt;/code&gt;-level interface with a cursor in the session, not an ECS &lt;code&gt;TQueue&lt;/code&gt; component: the server path does not keep sessions in the World, and a queue pop is not transactional with the session store&lt;/td&gt;&lt;td&gt;&lt;code&gt;InjectSystemInstruction&lt;/code&gt;; &lt;code&gt;ForkConversation&lt;/code&gt; (belongs with §5.2 of the partial-application spec)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;amp;#35;563 ph.2 event history&lt;/td&gt;&lt;td&gt;tool-call events&lt;/td&gt;&lt;td&gt;extend &lt;code&gt;Host.Runner.SessionEvent&lt;/code&gt;; history = the stored session versions&lt;/td&gt;&lt;td&gt;a second &lt;code&gt;SessionEvent&lt;/code&gt; type, the &lt;code&gt;TBQueue&lt;/code&gt; ring&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;amp;#35;564 ph.3 subscriptions&lt;/td&gt;&lt;td&gt;watching a session&lt;/td&gt;&lt;td&gt;events → mail (§7)&lt;/td&gt;&lt;td&gt;registry, &lt;code&gt;FilterCombinator&lt;/code&gt;, quotas per subscriber&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;amp;#35;564 ph.4 wait-for&lt;/td&gt;&lt;td&gt;blocking with a timeout&lt;/td&gt;&lt;td&gt;&lt;code&gt;wait&lt;/code&gt; on one's own mailbox (§3)&lt;/td&gt;&lt;td&gt;&lt;code&gt;EventCondition&lt;/code&gt; DSL. Note the sketch's &lt;code&gt;readTQueue&lt;/code&gt; then &lt;code&gt;retry&lt;/code&gt; on a non-match never progresses: &lt;code&gt;retry&lt;/code&gt; undoes the read, so a non-matching head blocks the queue forever.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;amp;#35;507 suspend&lt;/td&gt;&lt;td&gt;suspended = no run, mail accumulates, cursor committed; &lt;code&gt;Pause&lt;/code&gt;/&lt;code&gt;Resume&lt;/code&gt;&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;&lt;code&gt;ManagedResource&lt;/code&gt; tracking: engine shutdown, process groups and &lt;code&gt;evictIdle&lt;/code&gt; already release what a run holds. Reopen if a toolbox leaks.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="phases"&gt;Phases&lt;/h3&gt;
&lt;p&gt;Each phase ships alone and leaves &lt;code&gt;ctxMailbox = Nothing&lt;/code&gt; agents untouched.
Phases 0, 3 and 5 depend on nothing but Phase 1 (Phase 0 not even on that);
Phase 4 needs Phases 1-2 and, for its server part only, Phase 3.&lt;/p&gt;
&lt;h4 id="phase-0-decorators-are-real"&gt;Phase 0: decorators are real&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;interpretDecorator&lt;/code&gt; for the existing four + &lt;code&gt;truncate&lt;/code&gt;; applied in
&lt;code&gt;executeCall&lt;/code&gt; from &lt;code&gt;tcPolicy&lt;/code&gt;; &lt;code&gt;wrappers&lt;/code&gt; with glob matching. Independent of
everything else. Closes G5.&lt;/p&gt;
&lt;h4 id="phase-1-the-mailbox-in-memory"&gt;Phase 1: the mailbox, in memory&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Mailbox&lt;/code&gt;, &lt;code&gt;Envelope&lt;/code&gt;, &lt;code&gt;mailCursor&lt;/code&gt;, &lt;code&gt;userMail&lt;/code&gt;; R1 and R2; the engine posts
&lt;code&gt;ToolCallFinished&lt;/code&gt;; late results and the &lt;code&gt;usrQuery&lt;/code&gt; race ported; TUI and
one-shot post &lt;code&gt;UserMessage&lt;/code&gt;. Visible change: typing during a busy run is
accepted and delivered at the next R1. Closes G1, G6.&lt;/p&gt;
&lt;h4 id="phase-2-attach--detach"&gt;Phase 2: attach / detach&lt;/h4&gt;
&lt;p&gt;All entity-backed calls through the engine in async mode; &lt;code&gt;attachSeconds&lt;/code&gt;;
R3a with interrupt-detaches; &lt;code&gt;wait&lt;/code&gt; and &lt;code&gt;ctxAwaitMail&lt;/code&gt;; an interrupt key in
the TUI. Closes G3 (except R4), G4.&lt;/p&gt;
&lt;h4 id="phase-3-durable-mail-on-the-server"&gt;Phase 3: durable mail on the server&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;session_mail&lt;/code&gt; on both backends; &lt;code&gt;lsInbox&lt;/code&gt; and the &lt;code&gt;completeCall&lt;/code&gt; special case
replaced; the runnable rule and &lt;code&gt;wakeOn&lt;/code&gt;; &lt;code&gt;postMessage&lt;/code&gt; during a run → 202;
&lt;code&gt;Control&lt;/code&gt; by mail; mail in the event stream and on the chat page (plain text,
as that page is on purpose). Closes G2.&lt;/p&gt;
&lt;h4 id="phase-4-agent-to-agent"&gt;Phase 4: agent-to-agent&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;MailRouter&lt;/code&gt; in the TUI, &lt;code&gt;run&lt;/code&gt; and the server; &lt;code&gt;send-message&lt;/code&gt;, &lt;code&gt;spawn-session&lt;/code&gt;
in all three, scopes, hops, &lt;code&gt;wakeOn&lt;/code&gt;; detached sub-agent calls expose the child
session id; &lt;code&gt;list-sessions&lt;/code&gt; shows live in-memory sessions. The TUI comes first:
it is where helpers are used most and where a spawned session can be watched
and typed into, which is the cheapest way to find out what peers should be
allowed to do (D10).&lt;/p&gt;
&lt;h4 id="phase-5-hooks"&gt;Phase 5: hooks&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;before&lt;/code&gt; / &lt;code&gt;after&lt;/code&gt;, command and tool targets, &lt;code&gt;deny&lt;/code&gt; / &lt;code&gt;defer&lt;/code&gt; / &lt;code&gt;answer&lt;/code&gt; /
rewrite.&lt;/p&gt;
&lt;h4 id="phase-6-watches-r4-pause"&gt;Phase 6: watches, R4, pause&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;watch-session&lt;/code&gt;, &lt;code&gt;tool.*&lt;/code&gt; events, &lt;code&gt;interruptCompletions&lt;/code&gt;, &lt;code&gt;Pause&lt;/code&gt;/&lt;code&gt;Resume&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="decisions-proposed"&gt;Decisions (proposed)&lt;/h3&gt;
&lt;p&gt;D1. &lt;strong&gt;The cursor lives in the session&lt;/strong&gt;, so the versioned session store is the
ack. No per-message delivered flags, no separate consumer table.&lt;/p&gt;
&lt;p&gt;D2. &lt;strong&gt;Mail is rendered into the user query, and kept raw beside it.&lt;/strong&gt; The only
shape every provider accepts after tool messages; the raw copy is for UIs and
audit.&lt;/p&gt;
&lt;p&gt;D3. &lt;strong&gt;Reads never consume; only the stepper advances the cursor.&lt;/strong&gt; Tools
(&lt;code&gt;wait&lt;/code&gt;, status) peek. One consumer per mailbox, so no claim/lease protocol.&lt;/p&gt;
&lt;p&gt;D4. &lt;strong&gt;In async mode, &lt;code&gt;runSync&lt;/code&gt; means “attached forever”, not “in the step’s
thread”.&lt;/strong&gt; Otherwise an interrupt cannot detach it. Calls without an entity
stay inline and uninterruptible, as today.&lt;/p&gt;
&lt;p&gt;D5. &lt;strong&gt;Interrupting a completion amends the unanswered head turn&lt;/strong&gt; rather than
stacking a second user turn or keeping a truncated LLM turn. Opt-in, because a
cancelled completion is paid for.&lt;/p&gt;
&lt;p&gt;D6. &lt;strong&gt;Wrappers are data in the disposition&lt;/strong&gt;, not a second mechanism: one
&lt;code&gt;Decorate&lt;/code&gt;, visible in &lt;code&gt;AppliedPolicy&lt;/code&gt;. Wrappers compose (all matches); base
dispositions do not (first match).&lt;/p&gt;
&lt;p&gt;D7. &lt;strong&gt;Hooks never see bound values&lt;/strong&gt;, and &lt;code&gt;before&lt;/code&gt; fails closed.&lt;/p&gt;
&lt;p&gt;D8. &lt;strong&gt;Events become mail; &lt;code&gt;wait&lt;/code&gt; is the only blocking primitive.&lt;/strong&gt; One thing
to make interruptible, time-bounded and deadlock-free, instead of three.&lt;/p&gt;
&lt;p&gt;D9. &lt;strong&gt;Progress is state, not mail.&lt;/strong&gt; It would drown the mailbox and the
context window; a tool that wants the model’s attention can finish, or a
later &lt;code&gt;notify&lt;/code&gt; progress level can post mail.&lt;/p&gt;
&lt;p&gt;D10. &lt;strong&gt;What wakes an idle session is configuration (&lt;code&gt;wakeOn&lt;/code&gt;), not design.&lt;/strong&gt;
Decided 2026-09-22: too early to settle what peers may do to each other, so
the mechanism stays neutral and the default conservative. Same reasoning for
&lt;code&gt;mailScope&lt;/code&gt; / &lt;code&gt;interruptScope&lt;/code&gt;: knobs, with defaults we expect to revisit once
the TUI has been used with spawned sessions for a while.&lt;/p&gt;
&lt;p&gt;D11. &lt;strong&gt;A run never lingers for a reply.&lt;/strong&gt; It stops when the LLM is done, no
background call runs and nothing is unread, whatever &lt;code&gt;expects_reply&lt;/code&gt; messages
are outstanding. An agent that wants the answer calls &lt;code&gt;wait&lt;/code&gt;. &lt;code&gt;expects_reply&lt;/code&gt;
is a hint to the recipient, never a runtime obligation.&lt;/p&gt;
&lt;p&gt;D12. &lt;strong&gt;Peer sessions exist in every front-end&lt;/strong&gt;, not only on the server
(decided 2026-09-22: helpers are used extensively in the TUI). Hence the
&lt;code&gt;MailRouter&lt;/code&gt;, and &lt;code&gt;spawn-session&lt;/code&gt; as a TUI conversation. Durability is the
only thing the server adds.&lt;/p&gt;
&lt;h3 id="related-docs"&gt;Related docs&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;documentation/async-tool-calls.md&lt;/code&gt;, &lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt;,
&lt;code&gt;documentation/agents-server.md&lt;/code&gt;, &lt;code&gt;todos/async-tool-calls.md&lt;/code&gt;,
&lt;code&gt;todos/tool-partial-application.md&lt;/code&gt; (bindings, §5.2 fork).&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-session-mailbox.html" rel="alternate"/><summary type="text">Status: proposal, 2026-09-22. Nothing implemented. Supersedes the designs in</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-tool-partial-application.html</id><title type="text">Spec: partial application of tool arguments</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/tool-partial-application.md"&gt;&lt;code&gt;todos/tool-partial-application.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="spec-partial-application-of-tool-arguments"&gt;Spec: partial application of tool arguments&lt;/h2&gt;
&lt;p&gt;Status: Phases 1-7 and §8.4 (&lt;code&gt;derive_agent&lt;/code&gt;) done as of 2026-09-21. Phase 1 done
(&lt;code&gt;97961e0&lt;/code&gt;). Phase 2 done
except MCP server &lt;code&gt;env&lt;/code&gt; (G4); the tool-cache key (G8) is done too, see below (&lt;code&gt;03783fb&lt;/code&gt;,
&lt;code&gt;b0c53a5&lt;/code&gt;): parameters, &lt;code&gt;ctxParams&lt;/code&gt; (now actually wired at runtime, not
just in tests), &lt;code&gt;--set&lt;/code&gt;/&lt;code&gt;--set-json&lt;/code&gt;/&lt;code&gt;--pin&lt;/code&gt;/&lt;code&gt;--pin-json&lt;/code&gt;/&lt;code&gt;--params-file&lt;/code&gt;,
process-scope resolution, secret-argv-mode load-time guard (G7).
Phase 3 done (&lt;code&gt;8a41cd8&lt;/code&gt;): OpenAPI/PostgREST argument bindings via the
generic combinator, &lt;code&gt;ParamSource&lt;/code&gt; secrets resolved per request.&lt;/p&gt;
&lt;p&gt;Phase 4 (session-level parameters in &lt;code&gt;agents-server&lt;/code&gt;) done for the core
mechanics, live-verified end to end against a real LLM: &lt;code&gt;params&lt;/code&gt; on
&lt;code&gt;POST /v1/sessions&lt;/code&gt;, &lt;code&gt;/messages&lt;/code&gt;, &lt;code&gt;/resume&lt;/code&gt; and &lt;code&gt;POST /v1/continuations/:token&lt;/code&gt;;
the validation table (&lt;code&gt;422 unknown_params&lt;/code&gt;, &lt;code&gt;403 forbidden_params&lt;/code&gt;,
&lt;code&gt;422 invalid_params&lt;/code&gt;, &lt;code&gt;422 params_required&lt;/code&gt;); a &lt;code&gt;params&lt;/code&gt; column and
migration on both the SQLite and Postgres session backends (&lt;code&gt;SessionMeta. smParams&lt;/code&gt;, non-secret only); secret session values kept only in the
in-memory &lt;code&gt;LiveSession&lt;/code&gt; (&lt;code&gt;Host/Runner.hs&lt;/code&gt;’s new &lt;code&gt;lsParams&lt;/code&gt;), never
persisted; message-scope values applied for one run only, never stored;
&lt;code&gt;agentView&lt;/code&gt;’s &lt;code&gt;&amp;quot;parameters&amp;quot;&lt;/code&gt; self-description (&lt;code&gt;bound&lt;/code&gt;/&lt;code&gt;pinned&lt;/code&gt;, never a
value); &lt;code&gt;agents-server --set&lt;/code&gt;/&lt;code&gt;--set-json&lt;/code&gt;/&lt;code&gt;--pin&lt;/code&gt;/&lt;code&gt;--pin-json&lt;/code&gt; (mirroring
&lt;code&gt;agents-exe&lt;/code&gt;) so an operator can lock a container to one tenant. Not done
from Phase 4: the chat page’s parameter form, and the generated OpenAPI
document’s request/response schemas (&lt;code&gt;AgentsServer/Types.hs&lt;/code&gt;/&lt;code&gt;Routes.hs&lt;/code&gt;
are a separate hand-maintained layer used only for &lt;code&gt;/openapi.json&lt;/code&gt; and
were not updated with the new fields — the real handlers in &lt;code&gt;Api.hs&lt;/code&gt; are
fully wired and correct; this is a documentation-only gap).
&lt;code&gt;recoverOnStartup&lt;/code&gt; marks the running calls of a session whose required
parameters are no longer bound as failed with a &lt;code&gt;params_required&lt;/code&gt; message
(§5’s documented recovery behaviour; done 2026-09-25, which also made the
persisted non-secret session values seed the live session back after a
restart or an eviction, as §5 always said they would). &lt;code&gt;seal&lt;/code&gt; and session
tokens (§5.1) are done: &lt;code&gt;seal&lt;/code&gt;/&lt;code&gt;session_token&lt;/code&gt; on &lt;code&gt;POST /v1/sessions&lt;/code&gt;, a
&lt;code&gt;security&lt;/code&gt; column (sealed flag and token SHA-256 digest, never the token) on
both backends, session-token routing limited to its own session’s read,
messages, events and cancel, and &lt;code&gt;DELETE /v1/sessions/:id/token&lt;/code&gt;. Deviations:
the token is only honoured on &lt;code&gt;/v1/sessions/:id/...&lt;/code&gt; paths of its own session
(anything else is a 401, so no probing); &lt;code&gt;seal&lt;/code&gt; exempts the owner as §5.1 says,
so today it only matters against session-token holders, who never may set
parameters anyway; a fork or child does not inherit either. Since then:
&lt;code&gt;PUT /v1/sessions/:id/params&lt;/code&gt;, &lt;code&gt;409 params_required&lt;/code&gt; on a message or resume
to an existing session, and &lt;code&gt;params&lt;/code&gt; on &lt;code&gt;POST /v1/sessions/:id/fork&lt;/code&gt; (which
lacks §5.2’s &lt;code&gt;fork&lt;/code&gt; on session creation and the CLI’s &lt;code&gt;--fork&lt;/code&gt;; required
parameters are not enforced at fork time).&lt;/p&gt;
&lt;p&gt;Phase 5 (sub-agents and MCP over HTTP) done, checked live with &lt;code&gt;agents-exe check&lt;/code&gt; against fixture agents and with an &lt;code&gt;agents-server&lt;/code&gt; integration
test: &lt;code&gt;ExtraAgentRef&lt;/code&gt; gains &lt;code&gt;with&lt;/code&gt; (§7), a map from the &lt;em&gt;child’s&lt;/em&gt;
parameter names to &lt;code&gt;BindingValue&lt;/code&gt;s in the &lt;em&gt;parent’s&lt;/em&gt; scope;
&lt;code&gt;AgentConfigNode.nodeExtraWith&lt;/code&gt; carries it from discovery through to
&lt;code&gt;wireAgentTools&lt;/code&gt;, which checks it at load time (every &lt;code&gt;with&lt;/code&gt; key must be
a declared parameter of the child; every required session-scope parameter
of the child must be covered by &lt;code&gt;with&lt;/code&gt; or by the child’s own process
value/default) and reports failures through the existing
&lt;code&gt;LoadingError&lt;/code&gt;/&lt;code&gt;OtherError&lt;/code&gt; path. &lt;code&gt;Props.agentToTool&lt;/code&gt; and
&lt;code&gt;turnAgentRuntimeIntoIOTool&lt;/code&gt; gained a &lt;code&gt;Maybe (Map ParamName BindingValue)&lt;/code&gt;
argument (&lt;code&gt;Nothing&lt;/code&gt; for a child reached through a toolDirectory, which has
no reference site to hang a &lt;code&gt;with&lt;/code&gt; on); &lt;code&gt;runSubAgent&lt;/code&gt; resolves it against
the caller’s &lt;code&gt;ctxParams&lt;/code&gt; at call time (&lt;code&gt;OneShotTool.hs&lt;/code&gt;’s new
&lt;code&gt;resolveWith&lt;/code&gt;) and overlays the result onto the child’s own resolved
params, so the child’s own process values and defaults still apply
underneath. A &lt;code&gt;Literal&lt;/code&gt; in &lt;code&gt;with&lt;/code&gt; is never secret; a &lt;code&gt;Param&lt;/code&gt; inherits
secrecy from the caller’s value. MCP over HTTP (&lt;code&gt;AgentsServer/Mcp.hs&lt;/code&gt;,
&lt;code&gt;Api.hs&lt;/code&gt;) gained &lt;code&gt;Agents-Param-&amp;lt;name&amp;gt;&lt;/code&gt; request headers (always strings)
and &lt;code&gt;_meta.&amp;quot;agents-exe/params&amp;quot;&lt;/code&gt; on a &lt;code&gt;tools/call&lt;/code&gt; (any JSON, overrides the
headers by name); each call is one run, so session and message scope
coincide there, and both go through the same validation table as the REST
API.&lt;/p&gt;
&lt;p&gt;Phase 6 (narrowing helpers down the call chain) done, checked with the
&lt;code&gt;agents-tests&lt;/code&gt; suite (&lt;code&gt;NarrowingTests.hs&lt;/code&gt;: the &lt;code&gt;AgentAddress&lt;/code&gt; algebra, and
&lt;code&gt;describe_agent&lt;/code&gt; end to end against a loaded three-level tree) and with
&lt;code&gt;agents-exe check&lt;/code&gt; against fixture agents: &lt;code&gt;Agent&lt;/code&gt; gains a top-level
&lt;code&gt;bindings&lt;/code&gt; list (§8.1), applied in &lt;code&gt;loadAgentToolboxes&lt;/code&gt; after every
toolbox’s own bindings, matching by the LLM-visible tool name across
toolboxes (bash tools have no toolbox name of their own to hang a
toolbox-level binding on). &lt;code&gt;ExtraAgentRef&lt;/code&gt; gains &lt;code&gt;narrowable&lt;/code&gt; (default
&lt;code&gt;True&lt;/code&gt;); &lt;code&gt;AgentConfigNode.nodeExtraNarrowable&lt;/code&gt; carries it alongside
&lt;code&gt;nodeExtraWith&lt;/code&gt;. &lt;code&gt;describe_agent&lt;/code&gt; (§8.2) is registered by &lt;code&gt;wireAgentTools&lt;/code&gt;
next to &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; for any agent with at least one helper; it
recurses over &lt;code&gt;nodeChildren&lt;/code&gt;/&lt;code&gt;nodeExtraRefs&lt;/code&gt;, cut at &lt;code&gt;maxDescribeDepth&lt;/code&gt; and
at cycles, shows each declared parameter with a &lt;code&gt;bound&lt;/code&gt; flag (already
resolved, or covered by the reference’s &lt;code&gt;with&lt;/code&gt;) and each tool’s still-open
arguments (its current, already-bound-reduced schema minus anything the
caller’s inherited bindings already cover), and reports only &lt;code&gt;announce&lt;/code&gt;
for a &lt;code&gt;narrowable: false&lt;/code&gt; reference. &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; gains optional
&lt;code&gt;bindings&lt;/code&gt; and &lt;code&gt;with&lt;/code&gt; arguments (§8.3): &lt;code&gt;AgentBinding&lt;/code&gt;/&lt;code&gt;ScopedBinding&lt;/code&gt;/
&lt;code&gt;AgentAddress&lt;/code&gt; (&lt;code&gt;Bindings/Types.hs&lt;/code&gt;) represent a binding addressed at the
prompted helper (&lt;code&gt;Here&lt;/code&gt;), one of its own helpers (a slash-separated
&lt;code&gt;AgentPath&lt;/code&gt;), or all of them (&lt;code&gt;&amp;quot;**&amp;quot;&lt;/code&gt;/&lt;code&gt;Everywhere&lt;/code&gt;); &lt;code&gt;descendAddress&lt;/code&gt;/
&lt;code&gt;reRootBindings&lt;/code&gt; re-root an address (or a whole list of &lt;code&gt;ScopedBinding&lt;/code&gt;s)
one level down when a call descends into a named child. &lt;code&gt;runSubAgent&lt;/code&gt;
resolves the call’s own &lt;code&gt;bindings&lt;/code&gt; against the caller’s &lt;code&gt;ctxParams&lt;/code&gt;
(&lt;code&gt;resolveCallBindings&lt;/code&gt;; an unresolvable required &lt;code&gt;Param&lt;/code&gt; fails the call
with a message the calling model can act on, per D8), combines them with
the caller’s own &lt;code&gt;ctxInheritedBindings&lt;/code&gt; re-rooted at the prompted helper,
applies whatever is addressed at the helper itself to a &lt;em&gt;fresh&lt;/em&gt; copy of
its &lt;code&gt;osNodeTools&lt;/code&gt; (&lt;code&gt;applyBindings&lt;/code&gt;, scoped to this call only — the shared,
loaded toolboxes are never mutated) via a throwaway &lt;code&gt;OSAgentNode&lt;/code&gt; passed to
&lt;code&gt;buildAgent&lt;/code&gt;, and carries the rest into the sub-agent’s own
&lt;code&gt;SessionBase.ctxInheritedBindings&lt;/code&gt; for it to apply, in turn, when it
prompts its own helpers. &lt;code&gt;ToolExecutionContext&lt;/code&gt;/&lt;code&gt;Session.Base.Agent&lt;/code&gt; both
gained &lt;code&gt;ctxInheritedBindings :: [ScopedBinding]&lt;/code&gt;, threaded through
&lt;code&gt;buildContext&lt;/code&gt; like &lt;code&gt;ctxParams&lt;/code&gt;; &lt;code&gt;ToolExecutionContextSnapshot&lt;/code&gt; keeps only
its non-secret entries, same as &lt;code&gt;tecsParams&lt;/code&gt;. A call-time &lt;code&gt;with&lt;/code&gt; cannot
refill a parameter the reference’s own static &lt;code&gt;with&lt;/code&gt; (§7) already fills. A
&lt;code&gt;narrowable: false&lt;/code&gt; reference refuses any &lt;code&gt;bindings&lt;/code&gt;/&lt;code&gt;with&lt;/code&gt; on the call
that reaches it, and any inherited binding addressed at it or below,
rather than applying them.&lt;/p&gt;
&lt;p&gt;Phase 7 (&lt;code&gt;Expose&lt;/code&gt;) done, checked with the &lt;code&gt;agents-tests&lt;/code&gt; suite
(&lt;code&gt;BindingsTests.hs&lt;/code&gt;’s new “Expose bindings (§7)” group) and live with
&lt;code&gt;agents-exe check&lt;/code&gt; against fixture agents (an &lt;code&gt;Expose&lt;/code&gt;-bound bash argument
stays in the schema when its parameter is a session-scope parameter that
&lt;code&gt;check&lt;/code&gt; never resolves; a secret parameter bound with &lt;code&gt;whenUnbound: &amp;quot;expose&amp;quot;&lt;/code&gt; is a load-time &lt;code&gt;ExposedSecretParameter&lt;/code&gt; error). A binding whose
&lt;code&gt;whenUnbound&lt;/code&gt; is &lt;code&gt;&amp;quot;expose&amp;quot;&lt;/code&gt; is left out of &lt;code&gt;applyBindings&lt;/code&gt;’s &lt;em&gt;static&lt;/em&gt;
schema reduction entirely (D3’s opt-in exception): the shared registration
keeps the argument declared, so it is never hidden or shown by mistake for
every session at once. &lt;code&gt;Bindings.narrowExposedSchema :: Params -&amp;gt; [Binding] -&amp;gt; ToolRegistration -&amp;gt; ToolRegistration&lt;/code&gt; re-hides it when the parameter
happens to resolve in a given snapshot; &lt;code&gt;System.Agents.Combinators. ProgressiveDisclosure.agentEvaluateActiveTools&lt;/code&gt; calls it fresh on every
read of the tool list — the same “read fresh on every access” pattern it
already used for activation — against a new &lt;code&gt;IO Params&lt;/code&gt; action
(&lt;code&gt;AgentFactory.AgentDeps.adLiveParams&lt;/code&gt;) read only when the node has at
least one &lt;code&gt;Expose&lt;/code&gt; binding. Outside &lt;code&gt;agents-server&lt;/code&gt;, &lt;code&gt;adLiveParams&lt;/code&gt;
defaults to &lt;code&gt;pure mempty&lt;/code&gt;: an &lt;code&gt;Expose&lt;/code&gt;d argument then behaves like a
process-scope-only binding, decided once from &lt;code&gt;osNodeParams&lt;/code&gt;, since there
is no notion of a session distinct from the process. &lt;code&gt;agents-server&lt;/code&gt;’s
&lt;code&gt;Host/Runner.newAgent&lt;/code&gt; overrides it with &lt;code&gt;readTVarIO live.lsParams&lt;/code&gt;, so the
tool list a session sees updates the moment &lt;code&gt;prepareParams&lt;/code&gt; writes a new
session-scope value in — no agent rebuild, no registration mutation. A
message-scope value (this run only, never written to &lt;code&gt;lsParams&lt;/code&gt;) is not
seen by this mechanism and so is treated as unbound for schema-visibility
purposes; the value itself is still merged correctly at call time
regardless, since that path (&lt;code&gt;wrapTool&lt;/code&gt;, unchanged) already reads
&lt;code&gt;ctxParams&lt;/code&gt; fresh per call. &lt;code&gt;AgentTree.loadAgentToolboxes&lt;/code&gt; collects every
&lt;code&gt;Expose&lt;/code&gt; binding for a node (toolbox-level, returned out of
&lt;code&gt;ToolLoader.loadAgentTools&lt;/code&gt;/&lt;code&gt;loadBashTools&lt;/code&gt;/&lt;code&gt;loadOpenAPIToolboxes&lt;/code&gt;/
&lt;code&gt;loadPostgRESToolboxes&lt;/code&gt;; and agent-level, from &lt;code&gt;Agent.bindings&lt;/code&gt;) into a new
&lt;code&gt;OSAgentNode.osNodeExposeBindings&lt;/code&gt; TVar, and rejects any of them bound to a
declared &lt;code&gt;secret&lt;/code&gt; parameter (&lt;code&gt;Bindings.exposedSecretBindings&lt;/code&gt;, a new
&lt;code&gt;ExposedSecretParameter&lt;/code&gt; &lt;code&gt;LoadingError&lt;/code&gt;): exposing a secret back to the
model would just let it retype the value in plain text.&lt;/p&gt;
&lt;p&gt;§8.4 (&lt;code&gt;derive_agent&lt;/code&gt;) done, checked with the &lt;code&gt;agents-tests&lt;/code&gt; suite
(&lt;code&gt;BindingsTests.hs&lt;/code&gt;’s &lt;code&gt;deriveAgentTable&lt;/code&gt; group; &lt;code&gt;NarrowingTests.hs&lt;/code&gt;’s
&lt;code&gt;derive_agent&lt;/code&gt; group against the loaded three-level tree) and live with
&lt;code&gt;agents-exe check&lt;/code&gt;. &lt;code&gt;derive_agent {from, slug, bindings, with}&lt;/code&gt; is a new
tool, registered by &lt;code&gt;wireAgentTools&lt;/code&gt; alongside &lt;code&gt;describe_agent&lt;/code&gt; for any
agent with at least one helper: it checks &lt;code&gt;from&lt;/code&gt; names a known, narrowable
direct helper and, if so, echoes back &lt;code&gt;{&amp;quot;stored&amp;quot;: true, &amp;quot;from&amp;quot;, &amp;quot;slug&amp;quot;}&lt;/code&gt; —
nothing else happens, and nothing is stored beyond that call landing in the
session’s own history. &lt;code&gt;prompt_agent_&amp;lt;from&amp;gt;&lt;/code&gt; gains an optional &lt;code&gt;as&lt;/code&gt;
argument; at call time, &lt;code&gt;System.Agents.Tools.Bindings.deriveAgentTable&lt;/code&gt;
folds the &lt;em&gt;current&lt;/em&gt; session’s turns (matching successful &lt;code&gt;derive_agent&lt;/code&gt;
calls by function name and response, the same “recomputed fresh, not
persisted” treatment as &lt;code&gt;ctxSessionToolCalls&lt;/code&gt;) into a &lt;code&gt;Map (from, slug) DerivedNarrowing&lt;/code&gt;, exposed on a new &lt;code&gt;ToolExecutionContext. ctxDerivedNarrowings&lt;/code&gt; field set in &lt;code&gt;Session/Step.buildContext&lt;/code&gt; — so this
works for every front-end without any wiring, no &lt;code&gt;includeFullSession&lt;/code&gt; op-
in needed. &lt;code&gt;runSubAgent&lt;/code&gt; looks up &lt;code&gt;(helper, as)&lt;/code&gt;; an unknown name is an
error the calling model can retry (naming &lt;code&gt;derive_agent&lt;/code&gt;, per D8). When
found, the derived &lt;code&gt;bindings&lt;/code&gt; apply before the call’s own explicit ones,
and the derived &lt;code&gt;with&lt;/code&gt; fills what the call’s own &lt;code&gt;with&lt;/code&gt; and the
reference’s static &lt;code&gt;with&lt;/code&gt; (§7) do not. A &lt;code&gt;narrowable: false&lt;/code&gt; helper refuses
&lt;code&gt;derive_agent&lt;/code&gt; and &lt;code&gt;as&lt;/code&gt; the same way it already refuses &lt;code&gt;bindings&lt;/code&gt;/&lt;code&gt;with&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;
&lt;p&gt;Let whoever &lt;em&gt;runs&lt;/em&gt; an agent pin down some arguments of its tools, so that the
LLM neither sees nor chooses them. The motivating case: one bundled agent
(say, a docker image with &lt;code&gt;agents-server&lt;/code&gt; and a bash toolbox) serves several
tenants, and each session carries its own &lt;code&gt;tenant-id&lt;/code&gt; and API token.&lt;/p&gt;
&lt;p&gt;The primitive is partial application, on purpose. A tool is a function from a
JSON object to a result:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;query-invoices : { tenant_id, token, since } -&amp;gt; Result
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Binding &lt;code&gt;tenant_id&lt;/code&gt; and &lt;code&gt;token&lt;/code&gt; gives a smaller function, and that smaller
function is the tool the LLM gets:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;query-invoices' : { since } -&amp;gt; Result
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things follow, and they are the whole feature:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Schema&lt;/strong&gt;: a bound argument disappears from the tool’s JSON schema. The
model is not told that it ever existed. That is the point: with most
arguments already given, the model has less to reason about locally.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Call&lt;/strong&gt;: the bound value is merged into the LLM’s argument object just
before dispatch. The bound value always wins.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The deliverable is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;a generic combinator on &lt;code&gt;ToolRegistration&lt;/code&gt; in &lt;code&gt;agents-lib&lt;/code&gt;, so every kind
of toolbox (bash, MCP, OpenAPI, PostgREST, builtin, sub-agents) gets the
feature at once;
&lt;/li&gt;
&lt;li&gt;a way to &lt;em&gt;declare&lt;/em&gt; an agent’s parameters and to &lt;em&gt;bind&lt;/em&gt; tool arguments to
them in the agent file;
&lt;/li&gt;
&lt;li&gt;ways to &lt;em&gt;supply&lt;/em&gt; parameter values: at process start (&lt;code&gt;agents-exe&lt;/code&gt;,
&lt;code&gt;agents-server&lt;/code&gt;) and transiently per session (&lt;code&gt;agents-server&lt;/code&gt;);
&lt;/li&gt;
&lt;li&gt;a changed interface for helper agents exposed as tools, so that a parent
can &lt;em&gt;discover&lt;/em&gt; the open tool arguments of a helper and &lt;em&gt;bind&lt;/em&gt; some of them
when it prompts it, all the way down a chain of sub-agents (§8).
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="scenarios"&gt;Scenarios&lt;/h3&gt;
&lt;p&gt;The design is checked against these three.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;S1. One container, one tenant.&lt;/strong&gt; A docker image holds &lt;code&gt;agents-server&lt;/code&gt;, an
agent file and a bash toolbox. The operator starts it with
&lt;code&gt;-e BILLING_TOKEN=…&lt;/code&gt; and &lt;code&gt;--pin tenant=acme&lt;/code&gt;. Nobody who talks to the
container can change either. (§4)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;S2. A backend mints a credential and leads a chat.&lt;/strong&gt; A product API
receives “open an assistant on project 42” from a logged-in user. It mints a
credential that is valid for project 42 only, creates a session on
&lt;code&gt;agents-server&lt;/code&gt; with &lt;code&gt;params: {project_id: &amp;quot;42&amp;quot;, callback_token: &amp;quot;…&amp;quot;}&lt;/code&gt; and
&lt;code&gt;seal: true&lt;/code&gt;, and hands the browser a session token. The agent’s tools are
callbacks into the product API, with &lt;code&gt;project_id&lt;/code&gt; and the &lt;code&gt;Authorization&lt;/code&gt;
header bound. Three defences stack up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the model cannot hallucinate a project id: the argument is not in any
schema, and a bound value wins over anything the model sends;
&lt;/li&gt;
&lt;li&gt;a prompt injection cannot retarget the tools, for the same reason;
&lt;/li&gt;
&lt;li&gt;enumeration fails even if the two above were bypassed, because the minted
credential opens one project. The end user, who only holds the session
token, cannot re-parameterise the session either.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(§3.3, §5, §5.1)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;S3. A parent narrows its helpers, down the chain.&lt;/strong&gt; A root agent splits a
job and prompts a helper with extra bindings for that part (one repository,
one date range), routing secrets by parameter name without ever seeing them.
The helper may have helpers of its own: the root can bind arguments of tools
anywhere below it, each agent on the way can narrow further, and none can
undo what an ancestor bound. (§8)&lt;/p&gt;
&lt;h3 id="non-goals-for-this-spec"&gt;Non-goals (for this spec)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Sandboxing. A bound token still reaches a bash script that the agent
author wrote; we do not defend the value against the tool itself.
&lt;/li&gt;
&lt;li&gt;A general templating language in agent files (&lt;code&gt;${…}&lt;/code&gt; expansion in
prompts, paths, URLs). Parameters bind tool arguments, nothing else.
See &lt;a href="#decisions"&gt;Decisions&lt;/a&gt;, D7.
&lt;/li&gt;
&lt;li&gt;Per-tenant &lt;em&gt;agent definitions&lt;/em&gt;. The agent stays one static definition; only
parameter values change between sessions.
&lt;/li&gt;
&lt;li&gt;Encrypting values at rest. Secret values are simply never written.
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="current-state"&gt;Current state&lt;/h3&gt;
&lt;h4 id="what-we-can-reuse-as-is"&gt;What we can reuse as-is&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Piece&lt;/th&gt;&lt;th&gt;Where&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;One shape for all tools&lt;/td&gt;&lt;td&gt;&lt;code&gt;ToolRegistration{innerTool, declareTool, findTool, toolActivation}&lt;/code&gt; (&lt;code&gt;ToolRegistration.hs:154&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;Schema is &lt;code&gt;declareTool.toolDescriptionParamProperties&lt;/code&gt;; the call receives an &lt;code&gt;Aeson.Value&lt;/code&gt;. A wrapper can rewrite both without knowing the toolbox kind.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;A per-call context, already threaded everywhere&lt;/td&gt;&lt;td&gt;&lt;code&gt;ToolExecutionContext&lt;/code&gt; (&lt;code&gt;Tools/Context.hs:238&lt;/code&gt;), built per step in &lt;code&gt;Session/Step.hs:855&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The run function of every tool gets it.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;A serializable part of that context&lt;/td&gt;&lt;td&gt;&lt;code&gt;ToolExecutionContextSnapshot&lt;/code&gt; (&lt;code&gt;Tools/Context.hs:422&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;Persisted with deferred and async calls.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Value sources&lt;/td&gt;&lt;td&gt;&lt;code&gt;SecretSource = Given \| ApiKeySource \| FileSystem \| EnvVar \| Command&lt;/code&gt; (&lt;code&gt;Tools/Secrets.hs:105&lt;/code&gt;) and &lt;code&gt;resolveSecretSource&lt;/code&gt; (&lt;code&gt;:343&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;Exactly what a parameter &lt;em&gt;default&lt;/em&gt; needs.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Header/query serializers&lt;/td&gt;&lt;td&gt;&lt;code&gt;SecretSerializer&lt;/code&gt; (&lt;code&gt;Secrets.hs:161&lt;/code&gt;), &lt;code&gt;applySecretsToHeaders&lt;/code&gt; (&lt;code&gt;:464&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;Applied per request already; only the &lt;em&gt;resolution&lt;/em&gt; is load-time.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bash argument marshalling&lt;/td&gt;&lt;td&gt;&lt;code&gt;translateArguments&lt;/code&gt; (&lt;code&gt;ScriptTypes.hs:186&lt;/code&gt;), &lt;code&gt;flattenArguments&lt;/code&gt;/&lt;code&gt;flattenInput&lt;/code&gt; (&lt;code&gt;Bash.hs:272&lt;/code&gt;, &lt;code&gt;:284&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;Reads declared args from a JSON object. Merging bound values upstream needs no change here.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Single env funnel for bash tools&lt;/td&gt;&lt;td&gt;&lt;code&gt;buildToolEnvironment&lt;/code&gt; (&lt;code&gt;Bash.hs:356&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Session metadata row with reserved columns&lt;/td&gt;&lt;td&gt;&lt;code&gt;SessionMeta&lt;/code&gt; (&lt;code&gt;SessionStore.hs:192&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;Home for non-secret session parameters.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Per-session entry points&lt;/td&gt;&lt;td&gt;&lt;code&gt;Runner.createSessionAs&lt;/code&gt; (&lt;code&gt;Host/Runner.hs:510&lt;/code&gt;), &lt;code&gt;postMessage&lt;/code&gt; (&lt;code&gt;:530&lt;/code&gt;), &lt;code&gt;Api.createH&lt;/code&gt; (&lt;code&gt;Api.hs:340&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Server self-description&lt;/td&gt;&lt;td&gt;&lt;code&gt;agentView&lt;/code&gt; (&lt;code&gt;Api.hs:279&lt;/code&gt;), &lt;code&gt;GET /openapi.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Where clients learn which parameters an agent wants.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="gaps"&gt;Gaps&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;G1. Nothing flows from the caller to a tool call.&lt;/strong&gt; &lt;code&gt;agents-server&lt;/code&gt; reads
&lt;code&gt;agent&lt;/code&gt;, &lt;code&gt;prompt&lt;/code&gt;, &lt;code&gt;media&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt; and the bearer token; none of it reaches
&lt;code&gt;ToolExecutionContext&lt;/code&gt;. The CLI has no &lt;code&gt;--set&lt;/code&gt;-like flag.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G2. Toolboxes are frozen at tree load.&lt;/strong&gt; &lt;code&gt;osNodeTools :: TVar [ToolRegistration]&lt;/code&gt; is built once per agent tree and shared by all sessions.
Any per-session value must therefore arrive through the call context, not
through the registration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G3. HTTP toolbox secrets resolve once.&lt;/strong&gt; &lt;code&gt;OpenAPIToolbox.initializeToolbox&lt;/code&gt;
(&lt;code&gt;OpenAPIToolbox.hs:323&lt;/code&gt;) calls &lt;code&gt;resolveSecrets&lt;/code&gt; at load. A per-session token
is impossible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G4. MCP servers cannot receive configuration.&lt;/strong&gt;
&lt;code&gt;McpSimpleBinaryConfiguration&lt;/code&gt; has &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;executable&lt;/code&gt;, &lt;code&gt;args&lt;/code&gt; and no &lt;code&gt;env&lt;/code&gt;.
&lt;code&gt;mcpTool&lt;/code&gt; (&lt;code&gt;ToolRegistration.hs:1699&lt;/code&gt;) ignores the context entirely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G5. Bash arguments are always &lt;code&gt;required&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;mapArg&lt;/code&gt;
(&lt;code&gt;ToolRegistration.hs:262&lt;/code&gt;) sets &lt;code&gt;propertyRequired = True&lt;/code&gt; and ignores
&lt;code&gt;argTypeArity&lt;/code&gt;. The skills toolbox already honours arity
(&lt;code&gt;Skills/Toolbox.hs:333&lt;/code&gt;). Not caused by this feature, but it makes “leave an
optional argument out” impossible to express, so it is fixed here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G6. Bash tools only take values through argv or stdin.&lt;/strong&gt; A token in argv
shows in &lt;code&gt;ps&lt;/code&gt; and in traces. There is no calling mode that passes an argument
as an environment variable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G7. Traces record argv.&lt;/strong&gt; &lt;code&gt;RunCommandStart path args&lt;/code&gt; (&lt;code&gt;Bash.hs:193&lt;/code&gt;)
logs the full command line. A bound secret would land in log files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G8. The tool cache ignores everything but the LLM’s arguments.&lt;/strong&gt;
&lt;code&gt;computeCacheKey&lt;/code&gt; hashes tool name + LLM arguments (&lt;code&gt;Tools/Cache.hs:71&lt;/code&gt;,
&lt;code&gt;Session/Async.hs:335&lt;/code&gt;). With bindings, tenant A’s cached result would answer
tenant B’s identical call.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G9. Sub-agents receive nothing from their caller&lt;/strong&gt; except the call stack
and the OS world (&lt;code&gt;OneShotTool.hs:191&lt;/code&gt;). A child agent with its own tenant-aware
toolbox has no way to learn the tenant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G10. A parent cannot narrow a helper.&lt;/strong&gt; Helpers are the agents exposed to
a parent as &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; tools
(&lt;code&gt;OneShotTool.turnAgentRuntimeIntoIOTool&lt;/code&gt;, wired by
&lt;code&gt;AgentTree.wireAgentTools&lt;/code&gt;, &lt;code&gt;AgentTree.hs:724&lt;/code&gt;). The tool takes one argument,
&lt;code&gt;what&lt;/code&gt; (&lt;code&gt;OneShotTool.hs:95&lt;/code&gt;). The parent cannot learn which tools a helper
has or what arguments they take, and cannot fix any of them for a call. With
a chain root → A → B, the root has even less say over B. One would expect
narrowing to compose along the chain naturally; today there is nothing to
compose. (The developer toolbox’s &lt;code&gt;create-agent&lt;/code&gt; is unrelated: it bootstraps
agent JSON &lt;em&gt;files&lt;/em&gt; for a human and is left alone by this spec.)&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="design"&gt;Design&lt;/h3&gt;
&lt;h4 id="overview"&gt;Overview&lt;/h4&gt;
&lt;p&gt;Three separate notions, kept apart deliberately:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  agent file                                  caller
  ──────────                                  ──────
  parameters:   declares names       ◄─────   supplies values
     tenant, api_token                         (process start, or per session)
        ▲
        │ refers to
  bindings:     tool argument := parameter | literal
     query-*.tenant_id := tenant
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;parameter&lt;/strong&gt; is a named hole in the &lt;em&gt;agent&lt;/em&gt;. The agent author declares
it. An agent with parameters is a function &lt;code&gt;Params -&amp;gt; Agent&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;binding&lt;/strong&gt; ties one &lt;em&gt;tool argument&lt;/em&gt; to a parameter or to a literal. The
agent author writes it, next to the toolbox.
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;value&lt;/strong&gt; is supplied by the caller for a &lt;em&gt;parameter&lt;/em&gt;, never directly
for a tool argument.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The indirection matters for safety: a remote client can fill &lt;code&gt;tenant&lt;/code&gt;, and
only &lt;code&gt;tenant&lt;/code&gt;. It cannot decide to bind the &lt;code&gt;path&lt;/code&gt; argument of some other
tool. What is bindable is the author’s decision; what it is bound &lt;em&gt;to&lt;/em&gt; is the
caller’s.&lt;/p&gt;
&lt;h4 id="1-parameters"&gt;1. Parameters&lt;/h4&gt;
&lt;p&gt;New optional field on &lt;code&gt;Agent&lt;/code&gt; (&lt;code&gt;Base.hs:1595&lt;/code&gt;):&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;parameters&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Tenant identifier, as in the billing system&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;session&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;api_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Bearer token for the billing API&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;secret&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;session&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;EnvVar&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;BILLING_TOKEN&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;region&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;process&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Given&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;eu-west-1&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ParameterDecl&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ParameterDecl&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; paramName ::&lt;/span&gt; &lt;span class="dt"&gt;ParamName&lt;/span&gt;            &lt;span class="co"&gt;-- [a-z][a-z0-9_]*&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; paramDescription ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; paramSecret ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;               &lt;span class="co"&gt;-- default False&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; paramScope ::&lt;/span&gt; &lt;span class="dt"&gt;ParamScope&lt;/span&gt;          &lt;span class="co"&gt;-- default ScopeProcess&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; paramRequired ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;             &lt;span class="co"&gt;-- default True&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; paramDefault ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SecretSource&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ParamScope&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ScopeProcess&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ScopeSession&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ScopeMessage&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;scope: &amp;quot;process&amp;quot;&lt;/code&gt;: only the operator can set it (CLI flag, environment,
default). An HTTP client that tries gets &lt;code&gt;403&lt;/code&gt;. This is the docker case
where the operator pins a tenant for the whole container.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scope: &amp;quot;session&amp;quot;&lt;/code&gt;: a client may also set it per session; the value lasts
as long as the session. Process-level values still act as the fallback.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scope: &amp;quot;message&amp;quot;&lt;/code&gt;: a client may set it with a request that starts a run
(create, message, resume, continuation); the value lasts for that run only
and is dropped when the run blocks or completes. Meant for short-lived
tokens. It is never persisted, secret or not (§5).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;secret: true&lt;/code&gt;: the value must be a string; it is never persisted, never
traced, never returned by the API (§6).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default&lt;/code&gt; reuses &lt;code&gt;SecretSource&lt;/code&gt;, so a default can be a literal, an env var,
a file, a command, or an entry of the API-keys file.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Values are JSON (&lt;code&gt;Aeson.Value&lt;/code&gt;), because MCP and OpenAPI arguments are not
always strings. Bash arguments need strings (§3.1).&lt;/p&gt;
&lt;p&gt;Resolution order for one parameter, first hit wins:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;pinned process value (&lt;code&gt;--pin&lt;/code&gt;, §4): nothing below is looked at;
&lt;/li&gt;
&lt;li&gt;message value (only if &lt;code&gt;scope = message&lt;/code&gt;);
&lt;/li&gt;
&lt;li&gt;session value (only if &lt;code&gt;scope = session&lt;/code&gt;);
&lt;/li&gt;
&lt;li&gt;process value (&lt;code&gt;--set&lt;/code&gt;, &lt;code&gt;--params-file&lt;/code&gt;);
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default&lt;/code&gt;, resolved once at tree load;
&lt;/li&gt;
&lt;li&gt;unbound.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;An unbound &lt;code&gt;required&lt;/code&gt; parameter is an error &lt;em&gt;before&lt;/em&gt; any LLM call:
at startup for a process-scope parameter, at session creation or message post
for a session-scope or message-scope one (§5).&lt;/p&gt;
&lt;h4 id="2-bindings"&gt;2. Bindings&lt;/h4&gt;
&lt;p&gt;Every toolbox description gains an optional &lt;code&gt;Bindings&lt;/code&gt; list (same
prefix-stripping convention as &lt;code&gt;Activation&lt;/code&gt;). Example for a bash toolbox:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileSystemDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;Path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;Bindings&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;     &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;api_token&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;export-*&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;format&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;csv&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Binding&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Binding&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; bindTool ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ToolGlob&lt;/span&gt;     &lt;span class="co"&gt;-- matched against the toolbox-local name; default: all&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; bindArg ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; bindValue ::&lt;/span&gt; &lt;span class="dt"&gt;BindingValue&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; bindWhenUnbound ::&lt;/span&gt; &lt;span class="dt"&gt;WhenUnbound&lt;/span&gt; &lt;span class="co"&gt;-- default Fail&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;BindingValue&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Param&lt;/span&gt; &lt;span class="dt"&gt;ParamName&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Literal&lt;/span&gt; &lt;span class="dt"&gt;Aeson.Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;WhenUnbound&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Fail&lt;/span&gt;     &lt;span class="co"&gt;-- the call fails with a clear error (cannot happen for required params)&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Omit&lt;/span&gt;     &lt;span class="co"&gt;-- the argument is left out; only for optional arguments&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Expose&lt;/span&gt;   &lt;span class="co"&gt;-- (later, Phase 7) the argument goes back to the LLM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Literal&lt;/code&gt; is the degenerate case and is useful on its own: specialise a
generic third-party tool without writing a wrapper script.&lt;/p&gt;
&lt;p&gt;Load-time checks, all of them errors in &lt;code&gt;agents-exe check&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;Param&lt;/code&gt; names an undeclared parameter;
&lt;/li&gt;
&lt;li&gt;a binding matches no tool, or no matched tool has that argument (typo
guard). For MCP, whose tool list arrives late and may refresh, this is a
warning trace at each &lt;code&gt;ToolsRefreshed&lt;/code&gt;;
&lt;/li&gt;
&lt;li&gt;two bindings hit the same (tool, argument);
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Omit&lt;/code&gt; on a required argument;
&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;secret&lt;/code&gt; parameter bound to a bash argument whose mode is &lt;code&gt;positional&lt;/code&gt;,
&lt;code&gt;dashdashspace&lt;/code&gt; or &lt;code&gt;dashdashequal&lt;/code&gt; (it would show in &lt;code&gt;ps&lt;/code&gt;): an error,
pointing to the &lt;code&gt;env&lt;/code&gt; mode of §3.1.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-the-combinator"&gt;3. The combinator&lt;/h4&gt;
&lt;p&gt;In a new module &lt;code&gt;System.Agents.Tools.Bindings&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;applyBindings ::&lt;/span&gt; [&lt;span class="dt"&gt;ResolvedBinding&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;declareTool&lt;/code&gt;: drop bound &lt;code&gt;ParamProperty&lt;/code&gt;s from
&lt;code&gt;toolDescriptionParamProperties&lt;/code&gt;, and nothing else. No “pre-set” note, no
trace of the argument: what the model gets is indistinguishable from a tool
that never had it (D8). A tool whose prose description talks about an
argument that the author then binds is the author’s to reword; &lt;code&gt;check&lt;/code&gt;
warns when a bound argument’s name appears in the tool description.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;innerTool&lt;/code&gt; / &lt;code&gt;findTool&lt;/code&gt;: wrap the run function. At call time it reads
parameter values from the context, builds the bound object, and calls the
original with &lt;code&gt;bound &amp;lt;&amp;gt; llmArgs&lt;/code&gt; (left-biased: bound wins). If the LLM sends
a bound key anyway, it is dropped and a trace is emitted.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is applied in &lt;code&gt;ToolLoader.loadAgentTools&lt;/code&gt; (&lt;code&gt;ToolLoader.hs:127&lt;/code&gt;), once per
toolbox, after the toolbox produced its registrations. Because values come
from the context at call time, the registrations stay shared across sessions
(G2) and the schema stays static.&lt;/p&gt;
&lt;p&gt;The context gains one field:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { …&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxParams ::&lt;/span&gt; &lt;span class="dt"&gt;Params&lt;/span&gt;   &lt;span class="co"&gt;-- Map ParamName ParamValue&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ParamValue&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ParamValue&lt;/span&gt; {&lt;span class="ot"&gt; pvValue ::&lt;/span&gt; &lt;span class="dt"&gt;Aeson.Value&lt;/span&gt;,&lt;span class="ot"&gt; pvSecret ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Show&lt;/code&gt; and &lt;code&gt;ToJSON&lt;/code&gt; of &lt;code&gt;ParamValue&lt;/code&gt; print &lt;code&gt;&amp;quot;&amp;lt;secret&amp;gt;&amp;quot;&lt;/code&gt; when &lt;code&gt;pvSecret&lt;/code&gt;.
&lt;code&gt;Session/Step.buildContext&lt;/code&gt; fills &lt;code&gt;ctxParams&lt;/code&gt; from the agent runtime
(process values and defaults) overlaid with the session’s values (§5).&lt;/p&gt;
&lt;p&gt;The session itself is unchanged: it records the call as the LLM made it, so
bound values never enter the conversation history, never go back to the
model, and do not show in &lt;code&gt;session-print&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id="31-bash-tools"&gt;3.1 Bash tools&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;New calling mode &lt;code&gt;env&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;ScriptArgCallingMode&lt;/code&gt; gains &lt;code&gt;Env&lt;/code&gt;. An argument
&lt;code&gt;{&amp;quot;name&amp;quot;: &amp;quot;token&amp;quot;, &amp;quot;mode&amp;quot;: &amp;quot;env&amp;quot;}&lt;/code&gt; is passed as the environment variable
&lt;code&gt;TOKEN&lt;/code&gt; (upper-cased, &lt;code&gt;-&lt;/code&gt; to &lt;code&gt;_&lt;/code&gt;), not in argv. &lt;code&gt;flattenArguments&lt;/code&gt; and
&lt;code&gt;flattenInput&lt;/code&gt; ignore it; a new &lt;code&gt;flattenEnv&lt;/code&gt; feeds &lt;code&gt;buildToolEnvironment&lt;/code&gt;.
Partial application stays a single concept (everything is an argument);
the mode only picks the transport. This closes G6 and is useful without
bindings too.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arity (G5).&lt;/strong&gt; &lt;code&gt;mapArg&lt;/code&gt; sets &lt;code&gt;propertyRequired = (argTypeArity == Single)&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strings only.&lt;/strong&gt; A value bound to a bash argument must be a JSON string;
numbers and booleans are rendered with their JSON text; objects and arrays
are a load-time error for &lt;code&gt;Literal&lt;/code&gt;, a call-time error for &lt;code&gt;Param&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tracing (G7).&lt;/strong&gt; &lt;code&gt;runValue&lt;/code&gt; gets the set of secret argument names from the
wrapper and replaces their values with &lt;code&gt;&amp;lt;secret&amp;gt;&lt;/code&gt; in &lt;code&gt;RunCommandStart&lt;/code&gt; /
&lt;code&gt;RunCommandStopped&lt;/code&gt;. With the load-time check of §2, secrets are env-only
anyway; the redaction is the second line of defence.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/binary-tool.md&lt;/code&gt; and &lt;code&gt;agents-exe spec bash-tools&lt;/code&gt; document the &lt;code&gt;env&lt;/code&gt;
mode.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="32-mcp-toolboxes"&gt;3.2 MCP toolboxes&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Argument bindings work through the generic combinator; &lt;code&gt;adaptSchema&lt;/code&gt;
(&lt;code&gt;ToolRegistration.hs:2600&lt;/code&gt;) output is filtered like any other.
&lt;/li&gt;
&lt;li&gt;Separately, close G4: &lt;code&gt;McpSimpleBinaryConfiguration&lt;/code&gt; gains
&lt;code&gt;env :: Maybe (Map Text BindingValue)&lt;/code&gt;. The server process is started once
per tree, so only &lt;code&gt;Literal&lt;/code&gt; and &lt;strong&gt;process-scope&lt;/strong&gt; &lt;code&gt;Param&lt;/code&gt;s are accepted
here; a session-scope parameter is a load-time error with a message that
says why.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="33-openapi-and-postgrest-toolboxes"&gt;3.3 OpenAPI and PostgREST toolboxes&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Argument bindings (path, query and body parameters) work through the
generic combinator.
&lt;/li&gt;
&lt;li&gt;Headers and tokens are not tool arguments, so they go through the existing
secrets. &lt;code&gt;SecretSource&lt;/code&gt; gains &lt;code&gt;ParamSource ParamName&lt;/code&gt;. Secrets with that
source are skipped by the load-time &lt;code&gt;resolveSecrets&lt;/code&gt; and resolved per
request from &lt;code&gt;ctxParams&lt;/code&gt;, then serialized by the unchanged
&lt;code&gt;applySecretsToHeaders&lt;/code&gt; / &lt;code&gt;applySecretsToQueryString&lt;/code&gt;. This closes G3.
&lt;/li&gt;
&lt;li&gt;Fetching the spec at load time cannot use a session-scope secret. If the
spec endpoint needs auth, use a process-scope parameter or a plain secret
for it; the loader says so when it fails.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="34-builtin-toolboxes-and-sub-agents"&gt;3.4 Builtin toolboxes and sub-agents&lt;/h5&gt;
&lt;p&gt;Builtins need nothing special. For sub-agents see §7.&lt;/p&gt;
&lt;h4 id="4-supplying-values-process-level"&gt;4. Supplying values: process level&lt;/h4&gt;
&lt;p&gt;Shared by &lt;code&gt;agents-exe&lt;/code&gt; (all subcommands that load a tree) and
&lt;code&gt;agents-server&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--set NAME=VALUE          string value; repeatable
--set-json NAME=JSON      any JSON value
--params-file FILE        {&amp;quot;tenant&amp;quot;: &amp;quot;acme&amp;quot;, &amp;quot;api_token&amp;quot;: &amp;quot;…&amp;quot;}
--pin NAME=VALUE          like --set, and clients cannot override it
--pin-json NAME=JSON
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;They feed a new &lt;code&gt;processParams :: Map ParamName ProcessValue&lt;/code&gt; in
&lt;code&gt;AgentTree.Props&lt;/code&gt; (&lt;code&gt;AgentTree.hs:384&lt;/code&gt;), where a &lt;code&gt;ProcessValue&lt;/code&gt; is a value
plus a &lt;code&gt;pinned&lt;/code&gt; flag. &lt;code&gt;--params-file&lt;/code&gt; entries may be written
&lt;code&gt;{&amp;quot;value&amp;quot;: …, &amp;quot;pinned&amp;quot;: true}&lt;/code&gt; to the same effect.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--set&lt;/code&gt; on a session- or message-scope parameter gives a &lt;em&gt;fallback&lt;/em&gt; that a
client may override. &lt;code&gt;--pin&lt;/code&gt; gives a value that a client may not: for the
lifetime of the process the parameter behaves as if it were declared
&lt;code&gt;scope: &amp;quot;process&amp;quot;&lt;/code&gt;. This is how an operator takes a multi-tenant agent
file and locks one container to one tenant without editing the file. On a
process-scope parameter &lt;code&gt;--pin&lt;/code&gt; and &lt;code&gt;--set&lt;/code&gt; mean the same.
&lt;/li&gt;
&lt;li&gt;A name that no loaded agent declares is an error (typo guard).
&lt;/li&gt;
&lt;li&gt;For secrets, prefer a &lt;code&gt;default&lt;/code&gt; with &lt;code&gt;EnvVar&lt;/code&gt; / &lt;code&gt;FileSystem&lt;/code&gt;, or
&lt;code&gt;--params-file&lt;/code&gt;: &lt;code&gt;--set&lt;/code&gt; shows in &lt;code&gt;ps&lt;/code&gt;. The docs say so.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-exe check&lt;/code&gt; prints each agent’s parameters and how each one
resolved (&lt;code&gt;set&lt;/code&gt;, &lt;code&gt;default:EnvVar&lt;/code&gt;, &lt;code&gt;unbound&lt;/code&gt;), never the values of secret
ones.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-exe describe&lt;/code&gt; and &lt;code&gt;describe-tool&lt;/code&gt; show the &lt;em&gt;reduced&lt;/em&gt; schema, with
the bound arguments listed apart (this output is for the operator, not for
the model).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-exe tool-call&lt;/code&gt; and &lt;code&gt;replay-tool-call&lt;/code&gt; go through the wrapped
registration, so they apply bindings too.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the docker case this is all that is needed: the image holds the agent
file, the operator runs it with &lt;code&gt;-e BILLING_TOKEN=… &lt;/code&gt; and &lt;code&gt;--pin tenant=acme&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="5-supplying-values-session-level-agents-server"&gt;5. Supplying values: session level (&lt;code&gt;agents-server&lt;/code&gt;)&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Create.&lt;/strong&gt; &lt;code&gt;POST /v1/sessions&lt;/code&gt; accepts &lt;code&gt;params&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;billing&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;prompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;params&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;acme&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;api_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;s3cr3t&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Follow-ups.&lt;/strong&gt; &lt;code&gt;POST /v1/sessions/:id/messages&lt;/code&gt;, &lt;code&gt;/resume&lt;/code&gt; and
&lt;code&gt;POST /v1/continuations/:token&lt;/code&gt; accept the same field. It is merged over the
session’s current values; &lt;code&gt;null&lt;/code&gt; removes a value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Validation&lt;/strong&gt;, before the run starts:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Case&lt;/th&gt;&lt;th&gt;Answer&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;name not declared by the agent&lt;/td&gt;&lt;td&gt;&lt;code&gt;422&lt;/code&gt;, lists the unknown names&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;scope: "process"&lt;/code&gt; parameter, or one pinned with &lt;code&gt;--pin&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;403&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;scope: "message"&lt;/code&gt; parameter on a request that starts no run&lt;/td&gt;&lt;td&gt;&lt;code&gt;422&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;secret&lt;/code&gt; with a non-string value&lt;/td&gt;&lt;td&gt;&lt;code&gt;422&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a required session or message parameter still unbound after merging&lt;/td&gt;&lt;td&gt;&lt;code&gt;422&lt;/code&gt;, lists the missing names&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Storage.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Non-secret values: a new &lt;code&gt;params&lt;/code&gt; JSON column on the sessions table (both
SQLite and Postgres backends; &lt;code&gt;SessionMeta.smParams&lt;/code&gt;), written through the
same versioned store as the rest of the metadata. They survive restarts and
live-session eviction.
&lt;/li&gt;
&lt;li&gt;Secret values: only in the &lt;code&gt;LiveSession&lt;/code&gt; (&lt;code&gt;Host/Runner.hs:178&lt;/code&gt;), in memory.
After a restart or after &lt;code&gt;--live-session-ttl&lt;/code&gt; evicts the session, the next
message must carry them again, or gets the &lt;code&gt;422&lt;/code&gt; above. This is the
“transient” in the goal, and it keeps tokens out of the database with no
encryption story to design.
&lt;/li&gt;
&lt;li&gt;Message-scope values, secret or not: only in the run’s state inside the
&lt;code&gt;LiveSession&lt;/code&gt;, cleared when the run ends (blocked, completed, failed or
cancelled). A required message-scope parameter must therefore come with
&lt;em&gt;every&lt;/em&gt; request that starts a run, including &lt;code&gt;/resume&lt;/code&gt; and
&lt;code&gt;POST /v1/continuations/:token&lt;/code&gt; when it resumes. They are never in
snapshots either.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolExecutionContextSnapshot&lt;/code&gt; gains &lt;code&gt;tecsParams&lt;/code&gt;, holding non-secret
values only. A deferred or async call that is re-hydrated in another
process sees non-secret parameters; if its tool needs a secret one, the
re-hydrated call fails with &lt;code&gt;parameter api_token is not bound&lt;/code&gt;.
&lt;code&gt;recoverOnStartup&lt;/code&gt; (&lt;code&gt;Runner.hs:700&lt;/code&gt;) therefore marks such running calls as
failed rather than retrying blind.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Self-description.&lt;/strong&gt; &lt;code&gt;agentView&lt;/code&gt; adds&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;parameters&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;session&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;secret&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;bound&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;region&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;process&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;bound&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;bound&lt;/code&gt; tells a client whether the process already supplies the value;
&lt;code&gt;&amp;quot;pinned&amp;quot;: true&lt;/code&gt; says that it cannot be overridden (and the chat page then
hides the field). No values are ever returned. &lt;code&gt;GET /v1/sessions/:id&lt;/code&gt; returns the non-secret
session values and the &lt;em&gt;names&lt;/em&gt; of the secret ones currently held.
&lt;code&gt;Routes.hs&lt;/code&gt; and the generated OpenAPI document follow. The chat page gets a
small plain form for session parameters, shown when the chosen agent has
unbound ones (password inputs for secret ones).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stored agents.&lt;/strong&gt; &lt;code&gt;parameters&lt;/code&gt; is a normal field for database agents
(&lt;code&gt;Host.putStoredAgent&lt;/code&gt;). &lt;code&gt;Bindings&lt;/code&gt; lives inside toolbox descriptions, so it
follows whatever &lt;code&gt;fileBasedFields&lt;/code&gt; already allows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MCP over HTTP&lt;/strong&gt; (&lt;code&gt;POST /mcp&lt;/code&gt;, the &lt;code&gt;ask_&amp;lt;slug&amp;gt;&lt;/code&gt; tools). MCP clients are
usually configured with static headers, which is exactly the pin-down case:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Agents-Param-&amp;lt;name&amp;gt;: &amp;lt;value&amp;gt;&lt;/code&gt; request headers, string values;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_meta: {&amp;quot;agents-exe/params&amp;quot;: {…}}&lt;/code&gt; on &lt;code&gt;tools/call&lt;/code&gt;, any JSON, wins over
headers.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Same validation as above, reported as a JSON-RPC error. Each &lt;code&gt;tools/call&lt;/code&gt; is
one run, so session and message scope coincide here.&lt;/p&gt;
&lt;h5 id="51-sealed-sessions-and-delegated-chat-s2"&gt;5.1 Sealed sessions and delegated chat (S2)&lt;/h5&gt;
&lt;p&gt;In S2 two different principals talk to the same session: the backend, which
is trusted to choose &lt;code&gt;project_id&lt;/code&gt;, and the end user’s browser, which is not.
Today the server knows one kind of caller, the bearer-token owner
(&lt;code&gt;AgentsServer/Auth.hs&lt;/code&gt;), and the backend cannot give its token to a
browser. Without more, the backend has to proxy every chat message and SSE
stream. Three additions remove that need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;seal: true&lt;/code&gt;&lt;/strong&gt; on &lt;code&gt;POST /v1/sessions&lt;/code&gt;. After creation, &lt;code&gt;params&lt;/code&gt; on
&lt;code&gt;/messages&lt;/code&gt;, &lt;code&gt;/resume&lt;/code&gt; and continuations is refused with &lt;code&gt;403&lt;/code&gt;, for every
caller but the owner. The parameters of a sealed session are those its
creator chose.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session tokens.&lt;/strong&gt; &lt;code&gt;POST /v1/sessions&lt;/code&gt; with &lt;code&gt;&amp;quot;session_token&amp;quot;: true&lt;/code&gt;
returns a random token bound to that session. &lt;code&gt;Authorization: Bearer &amp;lt;session token&amp;gt;&lt;/code&gt; allows exactly: post a message, read the session and its
events, cancel a run, on that one session. It cannot set or read &lt;code&gt;params&lt;/code&gt;,
list sessions, complete continuations, or touch agents. Tokens are stored
hashed, next to the session, and die with it; the owner can revoke one with
&lt;code&gt;DELETE /v1/sessions/:id/token&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;PUT /v1/sessions/:id/params&lt;/code&gt;&lt;/strong&gt;, owner only, sets session-scope values
without starting a run. The backend uses it to rotate a minted credential
before it expires, and to re-supply secrets after a restart or an eviction
(secrets are memory-only, §5). When a message arrives on a session whose
required parameters are no longer all bound, the answer is
&lt;code&gt;409 params_required&lt;/code&gt; with the missing names; a browser holding a session
token relays that to its backend, which calls this endpoint.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="52-forking-a-session-with-new-values"&gt;5.2 Forking a session with new values&lt;/h5&gt;
&lt;p&gt;A credential that expires in the middle of a long run is not handled: the
tool calls fail, the model reports the failure, the run ends. No blocking,
no refresh protocol (D14). The way forward is a new session that starts from
the old one’s history with a fresh value pinned:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;POST&lt;/span&gt; &lt;span class="er"&gt;/v1/sessions&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;fork&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;lt;session id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;params&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;callback_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…fresh…&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;seal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;session_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;prompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;The credential was renewed, please carry on.&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The new session gets a copy of the turns of the source, a new session id,
and &lt;code&gt;forkedFromSessionId&lt;/code&gt; set (the field exists already,
&lt;code&gt;Session/Types.hs:1385&lt;/code&gt;). &lt;code&gt;agent&lt;/code&gt; is taken from the source; &lt;code&gt;prompt&lt;/code&gt; is
optional, and without it the session is created idle.
&lt;/li&gt;
&lt;li&gt;Parameters are &lt;strong&gt;not&lt;/strong&gt; shared with the source at run time. The new
session starts from the source’s persisted (non-secret) values, overlaid
with the request’s &lt;code&gt;params&lt;/code&gt;, and is validated like any creation; secrets
always have to be given again. &lt;code&gt;seal&lt;/code&gt; and session tokens are not inherited
either.
&lt;/li&gt;
&lt;li&gt;This is sound because bound values never enter the history (§3): the
copied turns hold no trace of the old token or of any bound argument, so
nothing in them contradicts the new values. Changing &lt;code&gt;project_id&lt;/code&gt; in a
fork is therefore &lt;em&gt;possible&lt;/em&gt; and is the owner’s call; it is refused to
session-token holders, who cannot fork at all.
&lt;/li&gt;
&lt;li&gt;Pending deferred calls and running async calls of the source are not
copied. The fork’s last turn is closed the way a cancelled run closes it,
so the history stays well-formed for the LLM.
&lt;/li&gt;
&lt;li&gt;Narrowed helper calls (§8) need nothing: their bindings are arguments of
&lt;code&gt;prompt_agent_*&lt;/code&gt; calls in the copied history, and a &lt;code&gt;Param&lt;/code&gt; in a future
call resolves against the fork’s values, which is the intent.
&lt;/li&gt;
&lt;li&gt;Only the owner of the source (or an admin owner) may fork it.
&lt;/li&gt;
&lt;li&gt;On the CLI the same thing is &lt;code&gt;agents-exe session start --fork &amp;lt;id&amp;gt;&lt;/code&gt; with
the usual &lt;code&gt;--set&lt;/code&gt; / &lt;code&gt;--pin&lt;/code&gt; flags.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The callback tools themselves need nothing new. With an OpenAPI toolbox
pointing at the product API:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAPIServer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;SpecUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.example.com/agent-callbacks/openapi.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;BaseUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.example.com/agent-callbacks&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;Secrets&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;source&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;ParamSource&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;callback_token&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;decoder&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Clear&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;serializer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Header&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Authorization&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Bearer {{secret}}&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;Bindings&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;project_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;project_id&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Every operation that has a &lt;code&gt;project_id&lt;/code&gt; path or query parameter loses it;
the model sees &lt;code&gt;list_tasks {status}&lt;/code&gt; instead of &lt;code&gt;list_tasks {project_id, status}&lt;/code&gt;. The same works with bash tools that &lt;code&gt;curl&lt;/code&gt; the API, with &lt;code&gt;token&lt;/code&gt;
in &lt;code&gt;env&lt;/code&gt; mode.&lt;/p&gt;
&lt;p&gt;One thing stays with the product API: its error bodies go back to the model
verbatim. An API that answers “project 43 belongs to another account” leaks
through any amount of binding.&lt;/p&gt;
&lt;h4 id="6-secrecy-rules"&gt;6. Secrecy rules&lt;/h4&gt;
&lt;p&gt;One list, because they are scattered over the sections above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A secret value is never written: not in the session JSON, not in the
metadata, not in continuation snapshots, not in the tool cache.
&lt;/li&gt;
&lt;li&gt;A secret value is never traced. &lt;code&gt;ParamValue&lt;/code&gt; redacts itself; bash argv is
redacted (§3.1); the HTTP toolboxes already keep secret headers out of
&lt;code&gt;--log-http&lt;/code&gt; and that path is reused.
&lt;/li&gt;
&lt;li&gt;A secret value is never returned by the API nor shown by &lt;code&gt;check&lt;/code&gt; /
&lt;code&gt;describe&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;A secret value never reaches bash argv (§2 load-time check).
&lt;/li&gt;
&lt;li&gt;None of this protects the value from the tool that receives it. A tool
that echoes its token sends it to the LLM. That is the tool author’s
responsibility and the docs say so.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Tool cache (G8), done.&lt;/strong&gt; Implemented as &lt;code&gt;CacheScope&lt;/code&gt;/&lt;code&gt;cacheScopeOf&lt;/code&gt; in
&lt;code&gt;Tools/Cache.hs&lt;/code&gt;: a call’s key also depends on the digest of the agent’s
non-secret parameter values and inherited narrowing bindings (the context’s
&lt;code&gt;ctxParams&lt;/code&gt;/&lt;code&gt;ctxInheritedBindings&lt;/code&gt;, at every cache call site), and a call
with any secret one is not cached. Deviation: this looks at &lt;em&gt;all&lt;/em&gt; the agent’s
parameters, not only those a tool binds (the registrations’ bindings are closed
over in the tools and invisible where the cache is consulted), so it can only
cost hits, never share a result across bound values. Argument hashes are now
SHA-256 (the old length + 60-character prefix could collide). As designed:
&lt;code&gt;computeCacheKey&lt;/code&gt; takes the bound values of the call:
non-secret values are hashed into &lt;code&gt;ckArgumentsHash&lt;/code&gt; together with the LLM
arguments. A call with any secret binding is &lt;strong&gt;not cached at all&lt;/strong&gt;: hashing a
token into a persisted key is a needless oracle, and results obtained with
one credential should not be replayed for another.&lt;/p&gt;
&lt;h4 id="7-sub-agents"&gt;7. Sub-agents&lt;/h4&gt;
&lt;p&gt;Lexical, not dynamic: a child sees only what the parent passes explicitly.
&lt;code&gt;ExtraAgentRef&lt;/code&gt; (&lt;code&gt;Base.hs:93&lt;/code&gt;) gains &lt;code&gt;with&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;invoice-expert&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;invoice-expert.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;with&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;mode&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt;   &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-only&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Keys are the &lt;em&gt;child’s&lt;/em&gt; parameter names; values are &lt;code&gt;BindingValue&lt;/code&gt;s in the
&lt;em&gt;parent’s&lt;/em&gt; scope.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;runSubAgent&lt;/code&gt; (&lt;code&gt;OneShotTool.hs:191&lt;/code&gt;) evaluates &lt;code&gt;with&lt;/code&gt; against the caller’s
&lt;code&gt;ctxParams&lt;/code&gt;, at call time, so a message-scope value of the parent is passed
like any other, and hands the result to the child as its session-level values;
the child’s own process values and defaults still apply underneath.
Secrecy is inherited: a value that is secret in the parent is secret in
the child, whatever the child declares.
&lt;/li&gt;
&lt;li&gt;Children discovered through a tool directory have no reference site, so
they get process values and defaults only. List them in &lt;code&gt;extraAgents&lt;/code&gt; to
pass something.
&lt;/li&gt;
&lt;li&gt;The check phase verifies that &lt;code&gt;with&lt;/code&gt; keys exist in the child and that the
child’s required session parameters are covered.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="8-narrowing-helpers-down-the-call-chain"&gt;8. Narrowing helpers, down the call chain&lt;/h4&gt;
&lt;p&gt;The scenario (S3): a parent splits a job and prompts a helper whose tools are
already pinned to one part of it, so that the helper’s model has nothing left
to choose. This is partial application done by a model instead of an
operator, and it composes: the operator binds &lt;code&gt;tenant&lt;/code&gt;, the root binds
&lt;code&gt;repo&lt;/code&gt;, helper A binds &lt;code&gt;branch&lt;/code&gt;, helper B only picks &lt;code&gt;path&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This concerns helper agents exposed as tools, and only them. Their interface
changes in two ways: (a) a parent can discover the open arguments below a
helper, (b) a parent can bind some of them when it prompts the helper.&lt;/p&gt;
&lt;h5 id="81-agent-level-bindings"&gt;8.1 Agent-level bindings&lt;/h5&gt;
&lt;p&gt;Toolbox-level bindings (§2) need a toolbox to hang on, and bash toolboxes
have no name. So &lt;code&gt;Agent&lt;/code&gt; also gets a top-level &lt;code&gt;bindings&lt;/code&gt; list, where &lt;code&gt;tool&lt;/code&gt;
globs match the LLM-visible names (&lt;code&gt;bash_query-*&lt;/code&gt;, &lt;code&gt;mcp_billing_*&lt;/code&gt;). They are
applied after the toolbox-level ones. §8.3 uses the same shape at run time.&lt;/p&gt;
&lt;p&gt;Successive application is monotone by construction: a later binding can only
name an argument that is &lt;em&gt;still open&lt;/em&gt;. There is no “unbind” and no override.&lt;/p&gt;
&lt;h5 id="82-a-discovery-describe_agent"&gt;8.2 (a) Discovery: &lt;code&gt;describe_agent&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;One new tool next to the &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; family, registered by
&lt;code&gt;wireAgentTools&lt;/code&gt; for any agent that has helpers:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;describe_agent&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;repo-worker&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;repo-worker&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;works on one git repository&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;parameters&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gh_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;bound&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_git-log&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;repo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;since&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;helpers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;diff-reviewer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_git-diff&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                   &lt;span class="dt"&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;repo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="er"&gt;…&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;rev&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="er"&gt;…&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;helpers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;It shows &lt;strong&gt;open&lt;/strong&gt; arguments only, as seen from the caller’s position in
the chain: what the agent file bound, what the operator bound, and what any
ancestor of the caller bound for this call are all absent. A parent
discovers exactly what is left for it to decide, in keeping with D8.
&lt;/li&gt;
&lt;li&gt;It is recursive over &lt;code&gt;helpers&lt;/code&gt;, cut at the configured max depth and at
cycles (&lt;code&gt;isAgentInCallStack&lt;/code&gt;, &lt;code&gt;Tools/Context.hs:767&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Parameters are listed by name and description, never by value.
&lt;/li&gt;
&lt;li&gt;It is a read of the loaded tree, not an LLM call. The answer is the same
for the whole run, so it caches well.
&lt;/li&gt;
&lt;li&gt;An author can opt a helper out with &lt;code&gt;&amp;quot;narrowable&amp;quot;: false&lt;/code&gt; on its
&lt;code&gt;extraAgents&lt;/code&gt; entry: &lt;code&gt;describe_agent&lt;/code&gt; then shows only its announce, and
bindings that target it or anything below it are refused.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="83-b-binding-prompt_agent_slug-takes-bindings"&gt;8.3 (b) Binding: &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; takes &lt;code&gt;bindings&lt;/code&gt;&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;prompt_agent_repo-worker&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;what&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Summarise last week&amp;#39;s changes to the session runner.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;bindings&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_git-*&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;repo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;lucasdicioccio/agents-exe&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;diff-reviewer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_git-diff&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;repo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;lucasdicioccio/agents-exe&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;**&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_gh-*&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arg&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gh_token&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;with&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;bindings&lt;/code&gt; and &lt;code&gt;with&lt;/code&gt; are optional; the schema of the tool is static (D3)
and a parent that ignores them sees today’s behaviour.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Addressing.&lt;/strong&gt; &lt;code&gt;agent&lt;/code&gt; is a path of slugs &lt;em&gt;below the prompted helper&lt;/em&gt;:
absent means the helper itself, &lt;code&gt;diff-reviewer&lt;/code&gt; its helper of that name,
&lt;code&gt;a/b&lt;/code&gt; a grandchild, &lt;code&gt;**&lt;/code&gt; the helper and everything below. &lt;code&gt;tool&lt;/code&gt; and &lt;code&gt;arg&lt;/code&gt;
are as in §2.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Values are resolved at the call site.&lt;/strong&gt; &lt;code&gt;Literal&lt;/code&gt; is what the parent’s
model wrote. &lt;code&gt;Param&lt;/code&gt; names a parameter of the &lt;em&gt;calling&lt;/em&gt; agent and is
resolved against its &lt;code&gt;ctxParams&lt;/code&gt; when the call is made (lexical, as in §7);
secrecy travels with the value. The parent’s model routes a token it has
never seen. &lt;code&gt;with&lt;/code&gt; fills the helper’s parameters as in §7, and cannot
refill one that the &lt;code&gt;extraAgents&lt;/code&gt; entry already fills.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How they travel.&lt;/strong&gt; &lt;code&gt;ToolExecutionContext&lt;/code&gt; gains
&lt;code&gt;ctxInheritedBindings :: [ScopedBinding]&lt;/code&gt;, a resolved binding plus the
remaining agent path. &lt;code&gt;runSubAgent&lt;/code&gt; (&lt;code&gt;OneShotTool.hs:191&lt;/code&gt;):
&lt;ol&gt;
&lt;li&gt;takes the caller’s inherited bindings, re-rooted at the helper, and adds
the ones from this call;
&lt;/li&gt;
&lt;li&gt;applies those addressed to the helper itself, wrapping the helper’s
registrations with &lt;code&gt;applyBindings&lt;/code&gt; for this call only. The loaded
toolboxes stay shared: no script is re-described, no MCP server
restarted;
&lt;/li&gt;
&lt;li&gt;puts the rest in the helper’s context, from where step 1 picks them up
when the helper prompts &lt;em&gt;its&lt;/em&gt; helpers.
The non-secret part goes in &lt;code&gt;ToolExecutionContextSnapshot&lt;/code&gt;, like
parameters.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The chain composes, and only narrows.&lt;/strong&gt; Every agent on the way may add
bindings for what is below it. It can only name arguments that are still
open from its position, which is all &lt;code&gt;describe_agent&lt;/code&gt; shows it. If a
model names an argument that an ancestor already bound (it cannot know
about it, so this is a hallucination), the ancestor’s value stays, the new
binding is dropped, and a trace is emitted; the call goes on (D8).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Errors the parent’s model can fix are told to it&lt;/strong&gt;: unknown agent path,
no tool matching the glob, no such open argument, wrong value type, a
&lt;code&gt;narrowable: false&lt;/code&gt; target. The call fails before the helper runs, with
a message that names the open arguments, so one retry suffices.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Literals bound to &lt;code&gt;env&lt;/code&gt;-mode arguments are allowed.&lt;/strong&gt; Nothing makes a
model-chosen literal secret.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Knowing parameter names is not knowing arguments.&lt;/strong&gt; D8 is about the
surface of the tools an agent &lt;em&gt;calls&lt;/em&gt;. An agent that narrows other agents
works one level up and sees configuration: names and descriptions, never
values. An operator who does not want even that pre-binds the argument in
the helper’s file: bound arguments are not shown.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recovery.&lt;/strong&gt; The bindings of a call are in the parent’s history, as the
arguments of its &lt;code&gt;prompt_agent_*&lt;/code&gt; call, so a resumed or forked (§5.2)
parent re-issues them as they were; &lt;code&gt;Param&lt;/code&gt; values resolve against the
current values, which is the intent after a fork.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool cache.&lt;/strong&gt; Inherited non-secret bindings enter the helper’s cache
keys as in §6; any secret one disables caching for the calls it touches.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="84-naming-a-narrowing-optional-convenience"&gt;8.4 Naming a narrowing (optional convenience)&lt;/h5&gt;
&lt;p&gt;Repeating the same &lt;code&gt;bindings&lt;/code&gt; on ten prompts costs tokens and invites
inconsistency. &lt;code&gt;derive_agent {from, slug, bindings, with}&lt;/code&gt; stores a
narrowing under a slug for the session, and &lt;code&gt;prompt_agent_&amp;lt;from&amp;gt;&lt;/code&gt; accepts
&lt;code&gt;&amp;quot;as&amp;quot;: &amp;quot;&amp;lt;slug&amp;gt;&amp;quot;&lt;/code&gt; to use it. It is sugar over §8.3 and adds no power: the
stored thing is the same data, the table is a fold over the session’s
successful &lt;code&gt;derive_agent&lt;/code&gt; calls (in the manner of &lt;code&gt;ToolboxSessionState&lt;/code&gt;,
&lt;code&gt;Tools/Activation.hs:75&lt;/code&gt;), so nothing new is stored. To be built only if
§8.3 proves verbose in practice.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="phases"&gt;Phases&lt;/h3&gt;
&lt;p&gt;Each phase is shippable and leaves &lt;code&gt;agents-exe check&lt;/code&gt; and the test suite
green.&lt;/p&gt;
&lt;h4 id="phase-1-the-combinator-literals-bash-fixes"&gt;Phase 1: the combinator, literals, bash fixes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Tools.Bindings&lt;/code&gt;: &lt;code&gt;Binding&lt;/code&gt;, &lt;code&gt;BindingValue&lt;/code&gt;, &lt;code&gt;applyBindings&lt;/code&gt;,
schema reduction, argument merge.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Bindings&lt;/code&gt; field on all toolbox descriptions; &lt;code&gt;Literal&lt;/code&gt; only.
&lt;/li&gt;
&lt;li&gt;Bash: arity in &lt;code&gt;mapArg&lt;/code&gt; (G5), &lt;code&gt;env&lt;/code&gt; calling mode (G6).
&lt;/li&gt;
&lt;li&gt;Load-time checks of §2 that do not involve parameters.
&lt;/li&gt;
&lt;li&gt;Tests: schema reduction; bound wins over an LLM-sent key; glob matching;
&lt;code&gt;env&lt;/code&gt; mode end to end with a fixture script.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-2-parameters-at-process-level"&gt;Phase 2: parameters at process level&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ParameterDecl&lt;/code&gt;, &lt;code&gt;parameters&lt;/code&gt; on &lt;code&gt;Agent&lt;/code&gt;, &lt;code&gt;Param&lt;/code&gt; binding values.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctxParams&lt;/code&gt;, &lt;code&gt;ParamValue&lt;/code&gt; with redaction, &lt;code&gt;buildContext&lt;/code&gt; wiring.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--set&lt;/code&gt;, &lt;code&gt;--set-json&lt;/code&gt;, &lt;code&gt;--params-file&lt;/code&gt;, &lt;code&gt;--pin&lt;/code&gt;, &lt;code&gt;--pin-json&lt;/code&gt;;
&lt;code&gt;Props.processParams&lt;/code&gt;; defaults
through &lt;code&gt;resolveSecretSource&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;check&lt;/code&gt;, &lt;code&gt;describe&lt;/code&gt;, &lt;code&gt;describe-tool&lt;/code&gt;, &lt;code&gt;tool-call&lt;/code&gt; output.
&lt;/li&gt;
&lt;li&gt;Bash argv redaction (G7) and the secret-in-argv check.
&lt;/li&gt;
&lt;li&gt;Cache key (G8).
&lt;/li&gt;
&lt;li&gt;MCP &lt;code&gt;env&lt;/code&gt; (G4).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After this phase the docker use case works with one tenant per container.&lt;/p&gt;
&lt;h4 id="phase-3-http-toolboxes"&gt;Phase 3: HTTP toolboxes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ParamSource&lt;/code&gt; in &lt;code&gt;SecretSource&lt;/code&gt;, per-request resolution (G3).
&lt;/li&gt;
&lt;li&gt;Same for PostgREST.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-4-session-level-parameters-in-agents-server"&gt;Phase 4: session-level parameters in &lt;code&gt;agents-server&lt;/code&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;params&lt;/code&gt; on create / messages / resume / continuations, validation table.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;params&lt;/code&gt; column and migration (SQLite and Postgres), &lt;code&gt;smParams&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Secrets in &lt;code&gt;LiveSession&lt;/code&gt; only; &lt;code&gt;tecsParams&lt;/code&gt;; recovery behaviour.
&lt;/li&gt;
&lt;li&gt;Message scope: per-run values, cleared at run end.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;seal&lt;/code&gt;, session tokens, &lt;code&gt;PUT /v1/sessions/:id/params&lt;/code&gt;,
&lt;code&gt;409 params_required&lt;/code&gt; (§5.1).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fork&lt;/code&gt; on session creation and &lt;code&gt;session start --fork&lt;/code&gt; (§5.2).
&lt;/li&gt;
&lt;li&gt;Pinned parameters refused with &lt;code&gt;403&lt;/code&gt;; &lt;code&gt;pinned&lt;/code&gt; in &lt;code&gt;agentView&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agentView&lt;/code&gt;, session view, OpenAPI document, &lt;code&gt;documentation/agents-server.md&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Chat page form.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After this phase one container serves many tenants.&lt;/p&gt;
&lt;h4 id="phase-5-sub-agents-and-mcp-over-http"&gt;Phase 5: sub-agents and MCP over HTTP&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;with&lt;/code&gt; on &lt;code&gt;ExtraAgentRef&lt;/code&gt;, evaluation in &lt;code&gt;runSubAgent&lt;/code&gt;, checks (G9).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Agents-Param-*&lt;/code&gt; headers and &lt;code&gt;_meta&lt;/code&gt; on &lt;code&gt;/mcp&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-6-narrowing-helpers"&gt;Phase 6: narrowing helpers&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Agent-level &lt;code&gt;bindings&lt;/code&gt; (§8.1), with the still-open check.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;describe_agent&lt;/code&gt; (§8.2), recursive, position-aware; &lt;code&gt;narrowable&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bindings&lt;/code&gt; and &lt;code&gt;with&lt;/code&gt; on &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt;; &lt;code&gt;ctxInheritedBindings&lt;/code&gt;;
per-call wrapping in &lt;code&gt;runSubAgent&lt;/code&gt;; snapshot; cache keys (§8.3).
&lt;/li&gt;
&lt;li&gt;Tests on a three-level chain: root binds for the grandchild; the middle
agent narrows further; the middle agent cannot rebind; &lt;code&gt;describe_agent&lt;/code&gt;
from the middle does not show what the root bound; resume and fork.
&lt;/li&gt;
&lt;li&gt;Later, if needed: &lt;code&gt;derive_agent&lt;/code&gt; (§8.4).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Depends on Phases 1, 2 and 5 (&lt;code&gt;with&lt;/code&gt;).&lt;/p&gt;
&lt;h4 id="phase-7-optional-expose"&gt;Phase 7 (optional): &lt;code&gt;Expose&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;whenUnbound: &amp;quot;expose&amp;quot;&lt;/code&gt; puts the argument back in the schema when the
parameter is unbound for this session. It makes the tool list a function of
the session, which the progressive-disclosure machinery
(&lt;code&gt;Combinators/ProgressiveDisclosure.hs&lt;/code&gt;) already does for activation, so the
hook exists. Deferred until a real use shows up.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="decisions"&gt;Decisions&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;D1. Callers fill parameters, not tool arguments.&lt;/strong&gt; The author decides what
is bindable. Otherwise any client of &lt;code&gt;agents-server&lt;/code&gt; could pin any argument
of any tool, and every toolbox would need its own allow-list.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D2. Values travel in the call context, not in the registration.&lt;/strong&gt; Toolboxes
load once per tree and are shared (G2). Rebuilding a toolbox per session
would mean re-running &lt;code&gt;describe&lt;/code&gt; on every script and restarting MCP servers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D3. The schema is static.&lt;/strong&gt; A bound argument is hidden whether or not a
value is present; a missing value is an error, not a fallback to the LLM.
It keeps the tool list identical across sessions (prompt caching, simpler
reasoning about what the model can do). &lt;code&gt;Expose&lt;/code&gt; is the opt-in exception,
postponed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D4. &lt;code&gt;env&lt;/code&gt; is a calling mode, not a second kind of binding.&lt;/strong&gt; One concept
(arguments) with a transport choice, rather than “argument bindings” plus
“environment bindings” with different rules. The exception is the MCP server
process environment, which is not a tool argument at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D5. Secrets are never persisted.&lt;/strong&gt; The cost is that clients re-send them
after eviction or restart. The alternative needs key management, and an
&lt;code&gt;agents-server&lt;/code&gt; database that holds customer tokens is a much more sensitive
asset than one that does not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D6. Sub-agent passing is explicit.&lt;/strong&gt; Dynamic scoping (“the child inherits
every parameter with the same name”) is shorter to write and leaks a token
to any child that happens to declare the same name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D7. No templating.&lt;/strong&gt; &lt;code&gt;${tenant}&lt;/code&gt; in a system prompt or a path is tempting
and is a different feature: it changes the agent definition per session and
puts values in front of the model. Parameters here are deliberately
invisible to the LLM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D8. The model does not know.&lt;/strong&gt; A partially applied argument leaves no
mark in what the model sees: not in the schema, not as a “pre-set” note in
the description, not in error messages. The purpose of the feature is to
shrink the local reasoning a call requires; telling the model about a key it
cannot use, or a tenant it cannot choose, adds reasoning back and invites it
to try. Consequently, if the LLM sends a bound key anyway, the call proceeds
with the bound value and only a trace is emitted; and the error for an
unbound parameter at call time goes to the operator’s trace, while the model
gets a generic “tool unavailable” failure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D9. Pinning is an operator flag, not an agent-file field.&lt;/strong&gt; The agent file
says what &lt;em&gt;may&lt;/em&gt; vary per session; the deployment says what &lt;em&gt;does&lt;/em&gt;. The same
file then serves both the shared server and the one-tenant container.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D10. Message scope means one run.&lt;/strong&gt; Not one HTTP request, not one LLM
turn: a run is the unit after which control goes back to the client, which
is the only moment a client can supply a fresh token.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D11. Narrowing composes along the chain, and only narrows.&lt;/strong&gt; Each agent
may bind what is still open below it; none may rebind. Whatever a narrowed
helper can do, the un-narrowed one could, so giving this power to a model
cannot widen anything, which is why it is on by default (&lt;code&gt;narrowable: false&lt;/code&gt;
opts out).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D12. Bindings ride on the call, not on a new kind of agent.&lt;/strong&gt; The helper
interface gains discovery and a &lt;code&gt;bindings&lt;/code&gt; argument, rather than a registry
of derived agents. A call is self-describing, lives in the parent’s history,
and needs no lifetime rules. Naming a narrowing (§8.4) is sugar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D13. Session tokens belong to this spec.&lt;/strong&gt; They look like a separate
authentication feature, but without them S2 either proxies everything
through the backend or hands the browser a token that can re-parameterise
the session, which undoes the point of binding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D14. An expired credential is a failed run, and the remedy is a fork.&lt;/strong&gt;
No mid-run refresh, no “blocked on credential” state. &lt;code&gt;PUT …/params&lt;/code&gt; covers
rotation &lt;em&gt;between&lt;/em&gt; runs, and a fork with a fresh value covers a run that
died. Forking is cheap to specify precisely because bound values are absent
from the history.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D15. No saved narrowings for now.&lt;/strong&gt; It is kept possible, not planned: a
narrowing is plain serializable data (helper slug, scoped &lt;code&gt;bindings&lt;/code&gt;,
&lt;code&gt;with&lt;/code&gt;) and has the shape of an agent-level &lt;code&gt;bindings&lt;/code&gt; list (§8.1), so a
later “save this helper” writes that data to the agent store and resolves
the reference at load. Nothing here should tie a narrowing to the in-memory
identity of a session. It stays secondary to a good experience for the user
and for the model.&lt;/p&gt;
&lt;h3 id="nice-to-have-later"&gt;Nice to have, later&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Saving a narrowed helper as a stored agent (D15).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;derive_agent&lt;/code&gt;, naming a narrowing within a session (§8.4).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;whenUnbound: &amp;quot;expose&amp;quot;&lt;/code&gt; (Phase 7).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="related-docs"&gt;Related docs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;documentation/binary-tool.md&lt;/code&gt;: bash tool protocol, to be extended with &lt;code&gt;env&lt;/code&gt; mode.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/tools.md&lt;/code&gt;, &lt;code&gt;documentation/advanced-configuration.md&lt;/code&gt;: toolbox configuration.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/agents-server.md&lt;/code&gt;: HTTP API.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;todos/web-server-embedding.md&lt;/code&gt;: the host, the runner, session metadata.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;todo&lt;/code&gt;: “partial-application of tool values”.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-tool-partial-application.html" rel="alternate"/><summary type="text">Status: Phases 1-7 and §8.4 (`derive_agent`) done as of 2026-09-21. Phase 1 done</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-durable-workflows.progress.html</id><title type="text">Durable Workflows — Implementation Progress</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/durable-workflows.progress.md"&gt;&lt;code&gt;todos/durable-workflows.progress.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="durable-workflows--implementation-progress"&gt;Durable Workflows — Implementation Progress&lt;/h2&gt;
&lt;p&gt;Progress tracker for &lt;code&gt;todos/durable-workflows.md&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="phase-1--core-primitives-types--interfaces-white_check_mark-complete"&gt;Phase 1 — Core primitives (types &amp;amp; interfaces) ✅ COMPLETE&lt;/h3&gt;
&lt;h4 id="11-rich-tool-call-state-inside-a-turn"&gt;1.1 Rich tool-call state inside a turn&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added durable workflow primitives to &lt;code&gt;System.Agents.Session.Types&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ToolCallId&lt;/code&gt; — stable UUID-based identifier for matching external results
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolCallState&lt;/code&gt; — &lt;code&gt;Ready | Running | Deferred | Completed | Failed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TrackedToolCall&lt;/code&gt; — wraps &lt;code&gt;LlmToolCall&lt;/code&gt; with id, state, result, continuation token, and applied policy
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AppliedPolicy&lt;/code&gt; — records the policy decision applied to a call
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Refactored &lt;code&gt;PartialUserTurnContent&lt;/code&gt; to hold &lt;code&gt;[TrackedToolCall]&lt;/code&gt; instead of separate completed/pending/continuation lists.
&lt;/li&gt;
&lt;li&gt;Added backward-compatible JSON parsing for legacy sessions and helper views:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;partialCompletedResponses&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;partialPendingCalls&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;partialPendingContinuations&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cacheKeyForTrackedCall&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Updated dependent modules (&lt;code&gt;Session.Step&lt;/code&gt;, &lt;code&gt;Session.Loop&lt;/code&gt;, &lt;code&gt;Session.OpenAI&lt;/code&gt;, &lt;code&gt;Session.Search.Index&lt;/code&gt;, &lt;code&gt;Session.Edit&lt;/code&gt;) to use the new model.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="12-tool-call-policy--decorator"&gt;1.2 Tool-call policy / decorator&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added to &lt;code&gt;System.Agents.Session.Types&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ToolCallDisposition&lt;/code&gt; — &lt;code&gt;RunSync | RunAsync | RunIsolated IsolationSpec | Defer Reason | Decorate [Decorator] ToolCallDisposition&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IsolationSpec&lt;/code&gt; — &lt;code&gt;Docker Text | LocalProcess FilePath | FunctionRunner Text&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Reason&lt;/code&gt; — human-readable reason for defer/isolation
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Decorator&lt;/code&gt; — &lt;code&gt;WithTimeout | WithRetries | WithCache | WithLabel&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;ToolCallPolicy&lt;/code&gt; type alias in new &lt;code&gt;System.Agents.Session.Durable&lt;/code&gt; module.
&lt;/li&gt;
&lt;li&gt;Provided &lt;code&gt;defaultToolCallPolicy = const $ const RunSync&lt;/code&gt; for backward compatibility.
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;flattenDisposition&lt;/code&gt; helper to extract decorators from a disposition tree.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="13-pluggable-executor-interface"&gt;1.3 Pluggable executor interface&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Created &lt;code&gt;System.Agents.Session.Durable&lt;/code&gt; with:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ToolExecutor&lt;/code&gt; record (&lt;code&gt;execSync&lt;/code&gt; / &lt;code&gt;execAsync&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inProcessExecutor&lt;/code&gt; — current behavior
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yieldingExecutor&lt;/code&gt; — always returns &lt;code&gt;ToolYield&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cachingExecutor&lt;/code&gt; — cache wrapper
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isolatedExecutor&lt;/code&gt; — delegates &lt;code&gt;RunIsolated&lt;/code&gt; calls to a &lt;code&gt;DeploymentRunner&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DeploymentRunner&lt;/code&gt; and &lt;code&gt;IsolationError&lt;/code&gt; abstractions
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Updated &lt;code&gt;System.Agents.Session.Base.Agent&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;ctxToolCallPolicy&lt;/code&gt;, &lt;code&gt;ctxToolExecutor&lt;/code&gt;, &lt;code&gt;ctxContinuationStore&lt;/code&gt;, &lt;code&gt;ctxDeploymentRunner&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Removed &lt;code&gt;ctxAsyncToolCall&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Added combinators: &lt;code&gt;withToolCallPolicy&lt;/code&gt;, &lt;code&gt;withToolExecutor&lt;/code&gt;, &lt;code&gt;withContinuationStore&lt;/code&gt;, &lt;code&gt;withDeploymentRunner&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Updated all agent construction sites (&lt;code&gt;OneShot&lt;/code&gt;, &lt;code&gt;MCP.Server&lt;/code&gt;, &lt;code&gt;AgentTree.OneShotTool&lt;/code&gt;) to initialize the new fields.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Test suite &lt;code&gt;agents-tests&lt;/code&gt; passes.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-2--async-scheduler-in-the-session-loop-white_check_mark-complete"&gt;Phase 2 — Async scheduler in the session loop ✅ COMPLETE&lt;/h3&gt;
&lt;h4 id="21-policy-driven-async-scheduler"&gt;2.1 Policy-driven async scheduler&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Updated &lt;code&gt;runStepMAsync&lt;/code&gt; / &lt;code&gt;executeTrackedCalls&lt;/code&gt; in &lt;code&gt;System.Agents.Session.Step&lt;/code&gt; to:
&lt;ul&gt;
&lt;li&gt;classify every &lt;code&gt;Ready&lt;/code&gt; &lt;code&gt;TrackedToolCall&lt;/code&gt; via &lt;code&gt;Agent.ctxToolCallPolicy&lt;/code&gt;;
&lt;/li&gt;
&lt;li&gt;execute all &lt;code&gt;RunSync&lt;/code&gt; / &lt;code&gt;RunIsolated&lt;/code&gt; calls in one batch (with cache lookup);
&lt;/li&gt;
&lt;li&gt;move &lt;code&gt;RunAsync&lt;/code&gt; and &lt;code&gt;Defer&lt;/code&gt; calls to the &lt;code&gt;Deferred&lt;/code&gt; state, generate continuation tokens, and store snapshots.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If all calls complete, the scheduler emits a full &lt;code&gt;UserTurn&lt;/code&gt;; otherwise it yields a &lt;code&gt;PartialUserTurn&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Updated &lt;code&gt;naiveStep&lt;/code&gt; and &lt;code&gt;naiveTilNoToolCallStep&lt;/code&gt; so partial turns with remaining ready/deferred calls continue via &lt;code&gt;AskUserPrompt&lt;/code&gt; rather than prematurely asking the LLM.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="22-serializable-continuation-snapshots"&gt;2.2 Serializable continuation snapshots&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;ToolExecutionContextSnapshot&lt;/code&gt; to &lt;code&gt;System.Agents.Tools.Context&lt;/code&gt; containing only serialisable fields (&lt;code&gt;ctxSessionId&lt;/code&gt;, &lt;code&gt;ctxConversationId&lt;/code&gt;, &lt;code&gt;ctxTurnId&lt;/code&gt;, &lt;code&gt;ctxCallStack&lt;/code&gt;, &lt;code&gt;ctxAllowedTools&lt;/code&gt;, &lt;code&gt;ctxParentConversation&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;ToolContinuationSnapshot&lt;/code&gt; to &lt;code&gt;System.Agents.Session.Async&lt;/code&gt; and a helper &lt;code&gt;mkToolContinuationSnapshot&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Deduplicated &lt;code&gt;ContinuationToken&lt;/code&gt; by re-exporting the one from &lt;code&gt;System.Agents.Session.Types&lt;/code&gt; in &lt;code&gt;System.Agents.Session.Async&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="23-wake--resume-primitives"&gt;2.3 Wake / resume primitives&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Created &lt;code&gt;System.Agents.Session.Wake&lt;/code&gt; with:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wakeSession :: Session -&amp;gt; [(ContinuationToken, UserToolResponse)] -&amp;gt; IO Session&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wakeSessionWithCache :: Maybe ToolCache -&amp;gt; Session -&amp;gt; [(ContinuationToken, UserToolResponse)] -&amp;gt; IO Session&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resumeSession :: ConversationId -&amp;gt; Agent r -&amp;gt; Session -&amp;gt; IO (Either r Session)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wakeSession&lt;/code&gt; finds the latest &lt;code&gt;PartialUserTurn&lt;/code&gt;, matches deferred calls by token, moves them to &lt;code&gt;Completed&lt;/code&gt;, updates the cache when provided, and converts the turn to a full &lt;code&gt;UserTurn&lt;/code&gt; when every call is complete.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resumeSession&lt;/code&gt; runs the agent step-by-step until it either completes (&lt;code&gt;Left r&lt;/code&gt;) or yields again because deferred calls remain (&lt;code&gt;Right Session&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="24-sqlite-continuationstore-loadlist"&gt;2.4 SQLite &lt;code&gt;ContinuationStore&lt;/code&gt; load/list&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Finished &lt;code&gt;sqliteLoadContinuation&lt;/code&gt; and &lt;code&gt;sqliteListPending&lt;/code&gt; with proper JSON round-tripping of &lt;code&gt;ToolContinuationSnapshot&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Changed &lt;code&gt;ContinuationStore&lt;/code&gt; to store/load &lt;code&gt;ToolContinuationSnapshot&lt;/code&gt; instead of the in-memory &lt;code&gt;ToolContinuation&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Updated &lt;code&gt;resumeAsyncToolCall&lt;/code&gt; to use the snapshot’s cache key.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-1"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Test suite &lt;code&gt;agents-tests&lt;/code&gt; passes, including new &lt;code&gt;DurableWorkflowTests&lt;/code&gt; covering policy classification, continuation-store round-tripping, wake/resume, cache integration, and snapshot serialisation.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-3--durable-session-storage-white_check_mark-complete"&gt;Phase 3 — Durable session storage ✅ COMPLETE&lt;/h3&gt;
&lt;h4 id="31-generalized-sessionbackend-interface"&gt;3.1 Generalized &lt;code&gt;SessionBackend&lt;/code&gt; interface&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;SessionBackend&lt;/code&gt; record to &lt;code&gt;System.Agents.SessionStore&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sbStore :: SessionId -&amp;gt; Session -&amp;gt; IO ()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sbLoad :: SessionId -&amp;gt; IO (Maybe Session)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sbList :: IO [(SessionId, UTCTime)]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sbDelete :: SessionId -&amp;gt; IO ()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;sessionIdToConversationId&lt;/code&gt; / &lt;code&gt;conversationIdToSessionId&lt;/code&gt; conversion helpers.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="32-concrete-backends"&gt;3.2 Concrete backends&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FileSessionStore FilePath&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Newtype wrapper and &lt;code&gt;mkFileSessionStore&lt;/code&gt; constructor.
&lt;/li&gt;
&lt;li&gt;Implements &lt;code&gt;SessionBackend&lt;/code&gt; by reusing the existing file-based &lt;code&gt;SessionStore&lt;/code&gt; logic (&lt;code&gt;mkSimpleSessionStore&lt;/code&gt;, &lt;code&gt;storeSession&lt;/code&gt;, &lt;code&gt;readSession&lt;/code&gt;, &lt;code&gt;findSessionFiles&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SqliteSessionStore Connection&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Newtype wrapper and &lt;code&gt;mkSqliteSessionStore&lt;/code&gt; constructor.
&lt;/li&gt;
&lt;li&gt;Stores sessions as JSON in a &lt;code&gt;sessions&lt;/code&gt; table with &lt;code&gt;session_id&lt;/code&gt;, &lt;code&gt;created_at&lt;/code&gt;, &lt;code&gt;updated_at&lt;/code&gt;, and &lt;code&gt;json&lt;/code&gt; columns.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initializeSessionSchema&lt;/code&gt; creates the table and an index on &lt;code&gt;updated_at&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CompositeSessionStore [SessionBackend]&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Newtype wrapper and &lt;code&gt;mkCompositeSessionStore&lt;/code&gt; constructor.
&lt;/li&gt;
&lt;li&gt;Reads fall back across all backends in order.
&lt;/li&gt;
&lt;li&gt;Writes (store/delete) go to the first backend only (primary target).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="33-agent-integration"&gt;3.3 &lt;code&gt;Agent&lt;/code&gt; integration&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;ctxSessionBackend :: Maybe SessionBackend&lt;/code&gt; to &lt;code&gt;Agent&lt;/code&gt; in &lt;code&gt;System.Agents.Session.Base&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;withSessionBackend :: SessionBackend -&amp;gt; Agent r -&amp;gt; Agent r&lt;/code&gt; combinator.
&lt;/li&gt;
&lt;li&gt;Updated &lt;code&gt;System.Agents.Combinators.StoreSessionProgress&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;backendStoreCallback&lt;/code&gt; for storing progress via a &lt;code&gt;SessionBackend&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agentStoreSession&lt;/code&gt; now uses &lt;code&gt;ctxSessionBackend&lt;/code&gt; when present, falling back to the provided file &lt;code&gt;SessionStore&lt;/code&gt; when absent.
&lt;/li&gt;
&lt;li&gt;The optional explicit &lt;code&gt;FilePath&lt;/code&gt; still receives an additional copy in both cases.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Updated all &lt;code&gt;Agent&lt;/code&gt; construction sites (&lt;code&gt;OneShot&lt;/code&gt;, &lt;code&gt;MCP.Server&lt;/code&gt;, &lt;code&gt;AgentTree.OneShotTool&lt;/code&gt;) and the test helper to initialize &lt;code&gt;ctxSessionBackend = Nothing&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="34-tests"&gt;3.4 Tests&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Extended &lt;code&gt;DurableWorkflowTests&lt;/code&gt; with a Phase 3 group covering:
&lt;ul&gt;
&lt;li&gt;File backend store/load/delete/list round-trip.
&lt;/li&gt;
&lt;li&gt;SQLite backend store/load/delete/list round-trip.
&lt;/li&gt;
&lt;li&gt;Composite backend read fallback, primary-only write, primary-only delete, and aggregated listing.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withSessionBackend&lt;/code&gt; + &lt;code&gt;agentStoreSession&lt;/code&gt; integration ensuring the backend is used and the file store is bypassed.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-2"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Test suite &lt;code&gt;agents-tests&lt;/code&gt; passes, including all Phase 2 and Phase 3 durable-workflow tests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-4--wake--resume-api-white_check_mark-complete"&gt;Phase 4 — Wake / resume API ✅ COMPLETE&lt;/h3&gt;
&lt;h4 id="41-inject-external-results"&gt;4.1 Inject external results&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wakeSession&lt;/code&gt; and &lt;code&gt;wakeSessionWithCache&lt;/code&gt; are implemented in &lt;code&gt;System.Agents.Session.Wake&lt;/code&gt; (introduced in Phase 2).
&lt;/li&gt;
&lt;li&gt;They find the latest &lt;code&gt;PartialUserTurn&lt;/code&gt;, match deferred calls by token, move them to &lt;code&gt;Completed&lt;/code&gt;, update the cache, and convert the turn to a full &lt;code&gt;UserTurn&lt;/code&gt; when all calls are complete.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="42-resume-execution"&gt;4.2 Resume execution&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;resumeSession&lt;/code&gt; is implemented in &lt;code&gt;System.Agents.Session.Wake&lt;/code&gt; (introduced in Phase 2).
&lt;/li&gt;
&lt;li&gt;It resumes a session from a partial or completed user turn, running the scheduler until completion or until deferred calls remain.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="43-complete-continuations-from-external-workers"&gt;4.3 Complete continuations from external workers&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;resumeAsyncToolCall&lt;/code&gt; uses the SQLite &lt;code&gt;ContinuationStore&lt;/code&gt; with proper JSON round-tripping of &lt;code&gt;ToolContinuationSnapshot&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;csLoad&lt;/code&gt; / &lt;code&gt;csListPending&lt;/code&gt; implementations are complete (Phase 2).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="note"&gt;Note&lt;/h4&gt;
&lt;p&gt;Phase 4’s core functions were already implemented during Phase 2. CLI exposure (Phase 7) is out of scope for this phase.&lt;/p&gt;
&lt;h4 id="verification-3"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Test suite &lt;code&gt;agents-tests&lt;/code&gt; passes, including Phase 2 wake/resume tests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-5--isolated-deployment-primitives-white_check_mark-complete"&gt;Phase 5 — Isolated deployment primitives ✅ COMPLETE&lt;/h3&gt;
&lt;h4 id="51-deploymentrunner-abstraction"&gt;5.1 &lt;code&gt;DeploymentRunner&lt;/code&gt; abstraction&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Moved &lt;code&gt;DeploymentRunner&lt;/code&gt; and &lt;code&gt;IsolationError&lt;/code&gt; to a new module &lt;code&gt;System.Agents.Session.Isolation&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Changed &lt;code&gt;DeploymentRunner&lt;/code&gt; to accept a stable &lt;code&gt;IsolationEnvelope&lt;/code&gt; instead of raw &lt;code&gt;IsolationSpec&lt;/code&gt; + &lt;code&gt;LlmToolCall&lt;/code&gt;, so external workers receive a language-agnostic document.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Durable&lt;/code&gt; re-exports the runner/error types and the new envelope helpers for backward compatibility.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="52-serialization-contract-for-isolated-calls"&gt;5.2 Serialization contract for isolated calls&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added stable envelope types in &lt;code&gt;System.Agents.Session.Isolation&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IsolationEnvelope&lt;/code&gt; — input envelope with &lt;code&gt;token&lt;/code&gt;, &lt;code&gt;toolCall&lt;/code&gt;, &lt;code&gt;contextSnapshot&lt;/code&gt;, &lt;code&gt;policy&lt;/code&gt;, and optional &lt;code&gt;reason&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IsolationResultEnvelope&lt;/code&gt; — result envelope with &lt;code&gt;token&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt; (&lt;code&gt;success&lt;/code&gt;/&lt;code&gt;error&lt;/code&gt;), &lt;code&gt;result&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IsolationResultStatus&lt;/code&gt; — &lt;code&gt;IsolationSuccess&lt;/code&gt; / &lt;code&gt;IsolationFailure&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Added helpers:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mkIsolationEnvelope&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mkIsolationSuccessEnvelope&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mkIsolationErrorEnvelope&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parseIsolationResultEnvelope&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parseIsolationResultEnvelopeLBS&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Documented the JSON shapes in Haddock comments.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="53-concrete-runners"&gt;5.3 Concrete runners&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;localProcessRunner :: FilePath -&amp;gt; DeploymentRunner&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Serialises the envelope to compact JSON.
&lt;/li&gt;
&lt;li&gt;Forks the worker process and writes the envelope to its stdin.
&lt;/li&gt;
&lt;li&gt;Reads stdout and parses the result envelope.
&lt;/li&gt;
&lt;li&gt;Validates that the result token matches the input token.
&lt;/li&gt;
&lt;li&gt;Returns &lt;code&gt;IsolationError&lt;/code&gt; for non-zero exit codes, unparseable output, or token mismatches.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dockerRunner :: Text -&amp;gt; DeploymentRunner&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Runs &lt;code&gt;docker run --rm -i &amp;lt;image&amp;gt;&lt;/code&gt; with the envelope on stdin.
Reads stdout and parses the result envelope.
&lt;/li&gt;
&lt;li&gt;Returns &lt;code&gt;IsolationError&lt;/code&gt; if Docker is unavailable or the container fails.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;functionRunner :: DeploymentRunner&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Documented placeholder for future serverless/FaaS execution.
&lt;/li&gt;
&lt;li&gt;Always returns &lt;code&gt;IsolationError &amp;quot;functionRunner is a future placeholder ...&amp;quot;&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="54-integration-with-the-policy-driven-scheduler"&gt;5.4 Integration with the policy-driven scheduler&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Updated &lt;code&gt;isolatedExecutor&lt;/code&gt; in &lt;code&gt;System.Agents.Session.Durable&lt;/code&gt; to build an &lt;code&gt;IsolationEnvelope&lt;/code&gt; for each isolated call (fresh continuation token + serialisable context snapshot).
&lt;/li&gt;
&lt;li&gt;Updated &lt;code&gt;executeCall&lt;/code&gt; in &lt;code&gt;System.Agents.Session.Step&lt;/code&gt; so that when an agent has &lt;code&gt;ctxDeploymentRunner&lt;/code&gt; configured but no explicit &lt;code&gt;ctxToolExecutor&lt;/code&gt;, isolated calls are dispatched through the runner and non-isolated calls fall back to the agent’s &lt;code&gt;toolCall&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;This makes &lt;code&gt;RunIsolated&lt;/code&gt; policy decisions transparent to the session loop.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="55-example-isolation-by-tool-name-policy"&gt;5.5 Example isolation-by-tool-name policy&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;isolatedToolNamePolicyTest&lt;/code&gt; showing:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bash_command&lt;/code&gt; isolated via &lt;code&gt;localProcessRunner&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Other tools executed synchronously in-process.
&lt;/li&gt;
&lt;li&gt;The scheduler produces a full &lt;code&gt;UserTurn&lt;/code&gt; containing both responses.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="56-tests"&gt;5.6 Tests&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Extended &lt;code&gt;DurableWorkflowTests&lt;/code&gt; with a Phase 5 group covering:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IsolationEnvelope&lt;/code&gt; JSON round-trip.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IsolationResultEnvelope&lt;/code&gt; JSON round-trip and parser helpers.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;localProcessRunner&lt;/code&gt; with a simple bash worker script.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dockerRunner&lt;/code&gt; envelope construction (execution skipped when Docker is unavailable).
&lt;/li&gt;
&lt;li&gt;Integration test for isolation-by-tool-name policy.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-4"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Test suite &lt;code&gt;agents-tests&lt;/code&gt; passes, including all Phase 2, Phase 3, Phase 4, and Phase 5 durable-workflow tests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-6--integration--agent-combinators-white_check_mark-complete"&gt;Phase 6 — Integration &amp;amp; agent combinators ✅ COMPLETE&lt;/h3&gt;
&lt;h4 id="61-agent-record-defaults"&gt;6.1 &lt;code&gt;Agent&lt;/code&gt; record defaults&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Verified that &lt;code&gt;System.Agents.Session.Base.Agent&lt;/code&gt; exposes all durable-workflow fields:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ctxToolCallPolicy :: ToolCallPolicy&lt;/code&gt; (defaults to &lt;code&gt;defaultToolCallPolicy&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctxToolExecutor :: Maybe ToolExecutor&lt;/code&gt; (defaults to &lt;code&gt;Nothing&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctxContinuationStore :: Maybe ContinuationStore&lt;/code&gt; (defaults to &lt;code&gt;Nothing&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctxDeploymentRunner :: Maybe DeploymentRunner&lt;/code&gt; (defaults to &lt;code&gt;Nothing&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctxSessionBackend :: Maybe SessionBackend&lt;/code&gt; (defaults to &lt;code&gt;Nothing&lt;/code&gt;)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Confirmed all existing agent construction sites (&lt;code&gt;OneShot&lt;/code&gt;, &lt;code&gt;MCP.Server&lt;/code&gt;, &lt;code&gt;AgentTree.OneShotTool&lt;/code&gt;) still compile unchanged and initialise every field.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="62-agent-combinators"&gt;6.2 Agent combinators&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added/verified all requested combinators in &lt;code&gt;System.Agents.Session.Base&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;withToolCallPolicy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withToolExecutor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withContinuationStore&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withDeploymentRunner&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withSessionBackend&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Convenience &lt;code&gt;withDurableWorkflows :: SessionBackend -&amp;gt; ContinuationStore -&amp;gt; Agent r -&amp;gt; Agent r&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Convenience &lt;code&gt;withAsyncConfig :: ExecutionMode -&amp;gt; Maybe ToolCache -&amp;gt; ToolCallPolicy -&amp;gt; Agent r -&amp;gt; Agent r&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Convenience &lt;code&gt;withDurableExecutor :: Maybe ToolCache -&amp;gt; Maybe DeploymentRunner -&amp;gt; Agent r -&amp;gt; Agent r&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="63-progress--storage-helpers"&gt;6.3 Progress / storage helpers&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;backendWithCallbackStoreCallback :: SessionBackend -&amp;gt; OnSessionProgress -&amp;gt; OnSessionProgress&lt;/code&gt; to &lt;code&gt;System.Agents.Combinators.StoreSessionProgress&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;Stores each progress event via the configured backend and then forwards the event to an additional user-supplied callback.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Verified &lt;code&gt;agentStoreSession&lt;/code&gt; still correctly wires &lt;code&gt;ctxSessionBackend&lt;/code&gt;, file fallback, and optional extra file copy.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="64-durable-executor-helpers"&gt;6.4 Durable executor helpers&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Verified &lt;code&gt;System.Agents.Session.Durable&lt;/code&gt; provides:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mkDurableExecutor&lt;/code&gt; — cache + runner + native tool call
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cachedInProcessExecutor&lt;/code&gt; — in-process execution with caching
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;composeExecutors&lt;/code&gt; — conditional dispatch by disposition
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="65-integration-tests"&gt;6.5 Integration tests&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Fixed and extended &lt;code&gt;test/DurableWorkflowTests.hs&lt;/code&gt; Phase 6 group:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;durableWorkflowIntegrationTest&lt;/code&gt; — end-to-end session with a policy that defers calls, a continuation store, a SQLite session backend, and a cache; verifies yield, persistence, wake, cache population, and resume.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withDurableWorkflowsTest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withAsyncConfigTest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mkDurableExecutorTest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cachedInProcessExecutorTest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;composeExecutorsTest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agentStoreSessionWithCallbackTest&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-5"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Test suite &lt;code&gt;agents-tests&lt;/code&gt; passes, including all Phase 2, Phase 3, Phase 4, Phase 5, and Phase 6 durable-workflow tests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-7--cli--operator-api-white_check_mark-complete"&gt;Phase 7 — CLI / operator API ✅ COMPLETE&lt;/h3&gt;
&lt;h4 id="71-new-session-subcommand-group"&gt;7.1 New &lt;code&gt;session&lt;/code&gt; subcommand group&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;System.Agents.CLI.SessionDurable&lt;/code&gt; module with:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SessionDurableOptions&lt;/code&gt; and &lt;code&gt;SessionDurableCommand&lt;/code&gt; types.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handleSessionDurable&lt;/code&gt; dispatcher.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Integrated the new command group into &lt;code&gt;app/Main.hs&lt;/code&gt; under &lt;code&gt;agents session &amp;lt;subcommand&amp;gt;&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;uuid&lt;/code&gt; to the &lt;code&gt;agents-exe&lt;/code&gt; executable build-depends for parsing session/token UUID arguments.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="72-agents-session-pause-session-id"&gt;7.2 &lt;code&gt;agents session pause &amp;lt;session-id&amp;gt;&lt;/code&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Loads the session from the configured file-based &lt;code&gt;SessionStore&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Loads the first supplied agent file (same mechanism as one-shot) and sets execution mode to &lt;code&gt;Asynchronous&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Runs one step via &lt;code&gt;runStepM&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Persists the resulting session (completed or yielded) back to the &lt;code&gt;SessionStore&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Prints the yielded state and any deferred continuation tokens.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="73-agents-session-resume-session-id"&gt;7.3 &lt;code&gt;agents session resume &amp;lt;session-id&amp;gt;&lt;/code&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Loads the session and agent as above.
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;resumeSession&lt;/code&gt; from &lt;code&gt;System.Agents.Session.Wake&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Runs until completion or until the session yields again, persisting after each yield.
&lt;/li&gt;
&lt;li&gt;Prints the final LLM response or the yielded partial-turn summary.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="74-agents-session-pending-session-id"&gt;7.4 &lt;code&gt;agents session pending &amp;lt;session-id&amp;gt;&lt;/code&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Loads the session from the &lt;code&gt;SessionStore&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Finds the latest &lt;code&gt;PartialUserTurn&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Lists all deferred &lt;code&gt;TrackedToolCall&lt;/code&gt;s with their &lt;code&gt;ToolCallId&lt;/code&gt;, &lt;code&gt;ContinuationToken&lt;/code&gt;, tool name, and policy/disposition.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="75-agents-session-complete-token-result-file"&gt;7.5 &lt;code&gt;agents session complete &amp;lt;token&amp;gt; &amp;lt;result-file&amp;gt;&lt;/code&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Reads the result file. If it parses as a &lt;code&gt;UserToolResponse&lt;/code&gt; JSON value, that value is used; otherwise the raw file contents are treated as a plain-text response.
&lt;/li&gt;
&lt;li&gt;Scans all sessions in the &lt;code&gt;SessionStore&lt;/code&gt; to locate the session containing the matching continuation token.
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;wakeSession&lt;/code&gt; with the token/result pair.
&lt;/li&gt;
&lt;li&gt;Persists the updated session.
&lt;/li&gt;
&lt;li&gt;Prints whether the turn is now complete or still partial.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="76-agents-session-run-isolated-session-id-optional"&gt;7.6 &lt;code&gt;agents session run-isolated &amp;lt;session-id&amp;gt;&lt;/code&gt; (optional)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Loads the session and agent.
&lt;/li&gt;
&lt;li&gt;Finds deferred calls whose disposition is &lt;code&gt;RunIsolated&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;If the agent has a configured &lt;code&gt;ctxDeploymentRunner&lt;/code&gt;, executes those calls through the runner and injects the results via &lt;code&gt;wakeSession&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Persists the updated session and prints per-call results/errors.
&lt;/li&gt;
&lt;li&gt;If no runner is configured, reports the number of deferred isolated calls found.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="77-pure-helpers-and-tests"&gt;7.7 Pure helpers and tests&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Exported pure helpers from &lt;code&gt;System.Agents.CLI.SessionDurable&lt;/code&gt; for testing:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;formatContinuationToken&lt;/code&gt; / &lt;code&gt;parseContinuationToken&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parseResultFile&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;extractDeferredCalls&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;extractIsolatedCalls&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;test/SessionDurableTests.hs&lt;/code&gt; with unit tests for:
&lt;ul&gt;
&lt;li&gt;Continuation token formatting/parsing round-trip.
&lt;/li&gt;
&lt;li&gt;Result-file parsing for JSON and plain-text responses.
&lt;/li&gt;
&lt;li&gt;Deferred-call extraction from partial turns.
&lt;/li&gt;
&lt;li&gt;Isolated-call extraction from manually constructed partial turns.
&lt;/li&gt;
&lt;li&gt;Pending/complete integration test via a temporary file session store.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Registered the new test module in &lt;code&gt;test/Main.hs&lt;/code&gt; and &lt;code&gt;agents.cabal&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-6"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Executable &lt;code&gt;agents-exe&lt;/code&gt; builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Test suite &lt;code&gt;agents-tests&lt;/code&gt; passes, including all Phase 2–6 durable-workflow tests and the new Phase 7 &lt;code&gt;SessionDurableTests&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="next-phase-8--testing-strategy"&gt;Next: Phase 8 — Testing strategy&lt;/h3&gt;
&lt;p&gt;Remaining work from the plan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Policy classification tests (already covered in Phase 2 &lt;code&gt;DurableWorkflowTests&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Partial turn serialization through SQLite/file backends (already covered in Phase 3).
&lt;/li&gt;
&lt;li&gt;Wake/resume tests (already covered in Phase 2/4).
&lt;/li&gt;
&lt;li&gt;Cache integration tests (already covered in Phase 2).
&lt;/li&gt;
&lt;li&gt;Isolation contract tests (already covered in Phase 5).
&lt;/li&gt;
&lt;li&gt;Determinism/resume-twice tests (can be added as part of Phase 8).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-8--testing-strategy-white_check_mark-complete"&gt;Phase 8 — Testing strategy ✅ COMPLETE&lt;/h3&gt;
&lt;h4 id="81-review-of-existing-phase-27-tests"&gt;8.1 Review of existing Phase 2–7 tests&lt;/h4&gt;
&lt;p&gt;Verified that the durable-workflow tests already covered the first five Phase 8
categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Policy classification (Phase 2 &lt;code&gt;policyClassificationTest&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Partial turn serialization through SQLite/file backends (Phase 3
&lt;code&gt;fileBackendRoundTripTest&lt;/code&gt;, &lt;code&gt;sqliteBackendRoundTripTest&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Wake/resume (Phase 2 &lt;code&gt;wakeAndResumeTest&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Cache integration (Phase 2 &lt;code&gt;cacheIntegrationTest&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Isolation contract (Phase 5 &lt;code&gt;localProcessRunnerTest&lt;/code&gt;,
&lt;code&gt;isolatedToolNamePolicyTest&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Updated the Haddock header of &lt;code&gt;test/DurableWorkflowTests.hs&lt;/code&gt; to explicitly map
each existing test group to the Phase 8 category it covers, and to reference the
new Phase 8 determinism/edge-case tests in
&lt;code&gt;test/DurableWorkflowDeterminismTests.hs&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="82-determinism--resume-twice-tests"&gt;8.2 Determinism / resume-twice tests&lt;/h4&gt;
&lt;p&gt;Added &lt;code&gt;test/DurableWorkflowDeterminismTests.hs&lt;/code&gt; with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;determinismTest&lt;/code&gt;: constructs a yielded session with one sync and two deferred
calls, wakes both deferred calls, then resumes the identical woken session
twice.  Asserts that both resumes produce the same semantic outcome by comparing
LLM turn content and turn history while ignoring generated &lt;code&gt;turnId&lt;/code&gt; values.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wakeIdempotenceTest&lt;/code&gt;: wakes a session once, then wakes the resulting session
again with the same token/result pair, asserting the session state is unchanged.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="83-edge-case-tests"&gt;8.3 Edge-case tests&lt;/h4&gt;
&lt;p&gt;Added focused edge-case tests in &lt;code&gt;DurableWorkflowDeterminismTests&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wakeNoPartialTurnTest&lt;/code&gt;: &lt;code&gt;wakeSession&lt;/code&gt; on a session without a partial turn is
a no-op.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;completeLastDeferredTest&lt;/code&gt;: completing the single remaining deferred call
converts a &lt;code&gt;PartialUserTurn&lt;/code&gt; into a full &lt;code&gt;UserTurn&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;compositeBackendDeduplicationTest&lt;/code&gt;: a composite backend’s &lt;code&gt;sbList&lt;/code&gt; returns
only one entry when the same session is stored in multiple backends.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Implemented the deduplication behavior in &lt;code&gt;src/System/Agents/SessionStore.hs&lt;/code&gt;:
&lt;code&gt;mkCompositeSessionStore&lt;/code&gt; now applies &lt;code&gt;dedupeBy fst&lt;/code&gt; to the concatenated backend
lists so the primary backend’s entry wins.  Updated the composite backend
Haddock to document this.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Registered &lt;code&gt;DurableWorkflowDeterminismTests&lt;/code&gt; in &lt;code&gt;test/Main.hs&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;DurableWorkflowDeterminismTests&lt;/code&gt; to the &lt;code&gt;other-modules&lt;/code&gt; of the
&lt;code&gt;agents-tests&lt;/code&gt; test suite in &lt;code&gt;agents.cabal&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-7"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Also added the missing &lt;code&gt;default-language: Haskell2010&lt;/code&gt; field to the &lt;code&gt;agq&lt;/code&gt;
executable stanza in &lt;code&gt;agents.cabal&lt;/code&gt;; without it the executable defaulted to
Haskell98 and failed to compile under the current GHC/cabal setup.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Library builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Test suite &lt;code&gt;agents-tests&lt;/code&gt; passes, including all Phase 2–7 durable-workflow
tests and the new Phase 8 determinism/edge-case tests.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="addendum--user-facing-how-to-and-demonstrator-white_check_mark-complete"&gt;Addendum — User-facing how-to and demonstrator ✅ COMPLETE&lt;/h3&gt;
&lt;p&gt;After completing the implementation phases, a runnable demonstrator and a
user-facing how-to were added so the durable-workflow mode can be exercised
without writing custom code first.&lt;/p&gt;
&lt;h4 id="additions"&gt;Additions&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;examples/durable-workflow-demo/Main.hs&lt;/code&gt; — self-contained executable that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;simulates an LLM turn with three tool calls (&lt;code&gt;fetch_local&lt;/code&gt;,
&lt;code&gt;fetch_remote_a&lt;/code&gt;, &lt;code&gt;fetch_remote_b&lt;/code&gt;);
&lt;/li&gt;
&lt;li&gt;uses a &lt;code&gt;ToolCallPolicy&lt;/code&gt; that runs the local call synchronously and defers
the two remote calls;
&lt;/li&gt;
&lt;li&gt;prints the yielded partial turn with continuation tokens;
&lt;/li&gt;
&lt;li&gt;wakes the session with external results for the deferred calls;
&lt;/li&gt;
&lt;li&gt;resumes the session and prints the final LLM response.
&lt;/li&gt;
&lt;li&gt;Uses a mock LLM, so it needs no API keys and runs deterministically.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt; — guide covering:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;how to run the demonstrator;
&lt;/li&gt;
&lt;li&gt;core durable-workflow concepts (execution mode, policy, executor,
persistence, wake/resume);
&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;agents session pause|resume|pending|complete|run-isolated&lt;/code&gt; CLI
commands;
&lt;/li&gt;
&lt;li&gt;how to build a custom durable agent in Haskell;
&lt;/li&gt;
&lt;li&gt;how to add durable storage, caching, and isolated execution.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;documentation/README.md&lt;/code&gt; — updated the documentation index to link to the new how-to
and mention durable workflows in the overview and quick-start sections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;agents.cabal&lt;/code&gt; — registered the new &lt;code&gt;durable-workflow-demo&lt;/code&gt; executable and
fixed the pre-existing missing &lt;code&gt;System.Agents.TUI.Clipboard&lt;/code&gt; entry in the
library’s &lt;code&gt;exposed-modules&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-8"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;durable-workflow-demo&lt;/code&gt; executable builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The full test suite &lt;code&gt;agents-tests&lt;/code&gt; passes.
&lt;/li&gt;
&lt;li&gt;Library, &lt;code&gt;agents-exe&lt;/code&gt;, and &lt;code&gt;agq&lt;/code&gt; executables all build with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="summary--what-we-gained"&gt;Summary — What we gained&lt;/h3&gt;
&lt;p&gt;Implementing all eight phases of the durable-workflows plan turned agents-exe from a purely synchronous, in-process runner into a &lt;strong&gt;durable, resumable, and isolatable workflow engine&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id="capabilities-delivered"&gt;Capabilities delivered&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Per-call execution policy&lt;/strong&gt;: &lt;code&gt;ToolCallPolicy&lt;/code&gt; lets an agent decide, for every tool call, whether to run it synchronously, defer it, yield it for external completion, or run it in isolation (Docker/subprocess).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tracked tool-call lifecycle&lt;/strong&gt;: &lt;code&gt;TrackedToolCall&lt;/code&gt; gives every call a stable ID and explicit state (&lt;code&gt;Ready&lt;/code&gt; / &lt;code&gt;Running&lt;/code&gt; / &lt;code&gt;Deferred&lt;/code&gt; / &lt;code&gt;Completed&lt;/code&gt; / &lt;code&gt;Failed&lt;/code&gt;), enabling external systems to match results to calls.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Yield and wake&lt;/strong&gt;: a session can pause mid-turn, persist, and later resume when external results arrive via &lt;code&gt;wakeSession&lt;/code&gt; / &lt;code&gt;resumeSession&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pluggable executors&lt;/strong&gt;: &lt;code&gt;ToolExecutor&lt;/code&gt;, &lt;code&gt;DeploymentRunner&lt;/code&gt;, and concrete runners (&lt;code&gt;localProcessRunner&lt;/code&gt;, &lt;code&gt;dockerRunner&lt;/code&gt;) make &lt;em&gt;how&lt;/em&gt; a call runs independent of the session loop.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Durable session storage&lt;/strong&gt;: &lt;code&gt;SessionBackend&lt;/code&gt; abstracts file, SQLite, and composite backends so sessions can survive process restarts and be shared across machines.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operator CLI&lt;/strong&gt;: &lt;code&gt;agents session pause|resume|pending|complete|run-isolated&lt;/code&gt; gives operators direct control over durable executions.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runnable demonstrator and how-to&lt;/strong&gt;: users can exercise the canonical flow immediately with &lt;code&gt;cabal run durable-workflow-demo&lt;/code&gt; and follow &lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt; to build their own durable agents.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="architectural-gains"&gt;Architectural gains&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Separation of concerns&lt;/strong&gt;: policy, execution, persistence, and isolation are now distinct, composable layers.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backward compatibility&lt;/strong&gt;: existing synchronous agents continue to work unchanged; durable features are opt-in via combinators.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testability&lt;/strong&gt;: 848 tests cover policy classification, serialization, wake/resume, caching, isolation envelopes, backend round-trips, CLI helpers, and determinism.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="new-modules-and-examples"&gt;New modules and examples&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Durable&lt;/code&gt; — policy/executor primitives
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Isolation&lt;/code&gt; — isolated execution envelopes and runners
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Wake&lt;/code&gt; — wake/resume API
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.CLI.SessionDurable&lt;/code&gt; — operator CLI
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test/DurableWorkflowTests.hs&lt;/code&gt;, &lt;code&gt;test/SessionDurableTests.hs&lt;/code&gt;, &lt;code&gt;test/DurableWorkflowDeterminismTests.hs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;examples/durable-workflow-demo/Main.hs&lt;/code&gt; — runnable mock-LLM demonstrator
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt; — user-facing how-to guide
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The codebase now supports the requested example flow end-to-end: an agent issues three tool calls, executes one and defers two, yields, persists, wakes with the two results, and resumes to completion.&lt;/p&gt;
&lt;h3 id="follow-up--phase-2-scheduler-compilation-fix"&gt;Follow-up — Phase 2 scheduler compilation fix&lt;/h3&gt;
&lt;p&gt;A subsequent review found that &lt;code&gt;src/System/Agents/Session/Step.hs&lt;/code&gt; had drifted
into a non-compiling state despite the Phase 2 completion note. The following
fixes were applied to make the async scheduler build and the test suite pass
again:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added missing imports:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Base&lt;/code&gt; (agent/session/action types)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Async&lt;/code&gt; (&lt;code&gt;mkToolContinuationSnapshot&lt;/code&gt;, &lt;code&gt;storeContinuation&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Compat&lt;/code&gt; (&lt;code&gt;parseToolCallFromLlmToolCall&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Types&lt;/code&gt; (&lt;code&gt;StepByteUsage&lt;/code&gt;, &lt;code&gt;calculateStepByteUsage&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Media.Types&lt;/code&gt; (&lt;code&gt;ContentPart&lt;/code&gt;, &lt;code&gt;MediaAttachment&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.OS.Core.World&lt;/code&gt; (&lt;code&gt;getComponent&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Control.Concurrent.STM&lt;/code&gt; (&lt;code&gt;atomically&lt;/code&gt;)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Qualified the &lt;code&gt;System.Agents.OS.Conversation&lt;/code&gt; import as &lt;code&gt;OSConv&lt;/code&gt; and updated
&lt;code&gt;pollRunningCall&lt;/code&gt; to use &lt;code&gt;OSConv.ToolCallState&lt;/code&gt;, &lt;code&gt;OSConv.tcStatus&lt;/code&gt;, and the
&lt;code&gt;OSConv.TcCompleted&lt;/code&gt; / &lt;code&gt;OSConv.TcFailed&lt;/code&gt; / &lt;code&gt;OSConv.TcCancelled&lt;/code&gt; constructors,
resolving name clashes with the session-layer &lt;code&gt;ToolCallState&lt;/code&gt; / &lt;code&gt;tcResult&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Removed the dead import of &lt;code&gt;System.Agents.Session.Async.Engine&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Enabled &lt;code&gt;TypeApplications&lt;/code&gt; so &lt;code&gt;getComponent @OSConv.ToolCallState&lt;/code&gt; is valid.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-9"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Executable &lt;code&gt;agents-exe&lt;/code&gt; builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Executable &lt;code&gt;durable-workflow-demo&lt;/code&gt; builds with &lt;code&gt;-Wall -Werror&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Test suite &lt;code&gt;agents-tests&lt;/code&gt; passes, including all durable-workflow tests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-durable-workflows.progress.html" rel="alternate"/><summary type="text">Status: no status line yet</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-AI-CONTEXT.html</id><title type="text">AI Context - Working on the Agents Framework</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/AI-CONTEXT.md"&gt;&lt;code&gt;documentation/AI-CONTEXT.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="ai-context---working-on-the-agents-framework"&gt;AI Context - Working on the Agents Framework&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;READ THIS FIRST&lt;/strong&gt; when invoked on this codebase.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="immediate-first-steps"&gt;Immediate First Steps&lt;/h3&gt;
&lt;p&gt;When you’re invoked on this project, run these queries immediately:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 1. What is this project?&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="kw"&gt;FROM&lt;/span&gt; project_overview;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 2. What docs exist?&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; doc_path, title &lt;span class="kw"&gt;FROM&lt;/span&gt; docs_index &lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; doc_path;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 3. What&amp;#39;s the module structure?&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; module_name, purpose, documented_in &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; filepath;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 4. Check for recent changes&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; module_name &lt;span class="kw"&gt;LIKE&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;%OS%&amp;#39;&lt;/span&gt; &lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; filepath;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="project-snapshot"&gt;Project Snapshot&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Agents&lt;/strong&gt; is a Haskell framework for AI agent orchestration with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NEW (2026-03)&lt;/strong&gt;: ECS-based OS Model for agent management
&lt;/li&gt;
&lt;li&gt;Multi-agent hierarchies (agents can call other agents as tools)
&lt;/li&gt;
&lt;li&gt;Tool system: bash scripts, MCP servers, OpenAPI specs
&lt;/li&gt;
&lt;li&gt;Session persistence
&lt;/li&gt;
&lt;li&gt;TUI + CLI + MCP server interfaces
&lt;/li&gt;
&lt;li&gt;OpenAI-compatible LLM integration
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="architecture-overview"&gt;Architecture Overview&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────┐
│                    Interface Layer                              │
│  (CLI commands, TUI, MCP server, HTTP endpoints)                │
├────────────────────────────────────────────────────────────────┤
│                    OS Model Layer     [NEW]                     │
│  (Entity-Component-System, Resource Management,                 │
│   Conversation Tracking, Concurrent Access)                     │
├────────────────────────────────────────────────────────────────┤
│                    Agent Tree Layer                             │
│  (multi-agent hierarchy, reference validation, cycle detection) │
├────────────────────────────────────────────────────────────────┤
│                    Foundation Layer                             │
│  (sessions, tools, LLM integration, file loading)               │
└────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Key architectural pattern&lt;/strong&gt;: The &lt;strong&gt;OS Model&lt;/strong&gt; (Entity-Component-System) now manages agents, toolboxes, and resources, replacing the legacy Runtime-per-agent model.&lt;/p&gt;
&lt;h3 id="critical-files"&gt;Critical Files&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;File&lt;/th&gt;&lt;th&gt;Why It Matters&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/OS.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;NEW&lt;/strong&gt;: Main OS module, exports ECS-based agent management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/OS/Core.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;NEW&lt;/strong&gt;: Core ECS types: &lt;code&gt;World&lt;/code&gt;, &lt;code&gt;EntityId&lt;/code&gt;, &lt;code&gt;Component&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/OS/Agents.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;NEW&lt;/strong&gt;: OS-native agent creation and management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/OS/Compat/Runtime.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;NEW&lt;/strong&gt;: Migration bridge from old Runtime to new OS&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/Base.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Core types: &lt;code&gt;Agent&lt;/code&gt;, &lt;code&gt;AgentId&lt;/code&gt;, &lt;code&gt;ConversationId&lt;/code&gt;, &lt;code&gt;ExtraAgentRef&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/AgentTree.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Multi-agent discovery, cycle detection, reference validation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/Runtime/Runtime.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Legacy Runtime (deprecated, use OS model)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;app/Main.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;CLI entry point - all commands defined here&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents.cabal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Dependencies, build config&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="documentation-map"&gt;Documentation Map&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;documentation/
├── README.md              # Start here for overview
├── architecture.md        # System design, data flow, module relationships
├── OS-API.md              # [NEW] OS Model API reference
├── MIGRATION-OS.md        # [NEW] Migration guide: Runtime -&amp;gt; OS
├── CHANGELOG-OS-MIGRATION.md # [NEW] Recent changes summary
├── tools.md               # Tool registration (bash/MCP/OpenAPI/IO)
├── mcp.md                 # Model Context Protocol integration
├── sessions.md            # Session persistence and lifecycle
├── tui.md                 # Terminal UI (Brick library)
├── cli-commands.md        # All CLI commands reference
├── export-import.md       # Tool sharing (tar.gz/git)
├── file-loader.md         # JSON loading, section extraction
├── AI-CONTEXT.md          # This file
└── ai-assistant-guidelines.md # Detailed reference
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="the-os-model-entity-component-system"&gt;The OS Model (Entity-Component-System)&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;OS Model&lt;/strong&gt; is the new architectural foundation (Phase 2+):&lt;/p&gt;
&lt;h4 id="core-concepts"&gt;Core Concepts&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Entity: Just a unique ID&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Component: Pure data attached to entities&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; agentName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentModel ::&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentSystemPrompt ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentToolboxBindings ::&lt;/span&gt; [&lt;span class="dt"&gt;ToolboxBindingSpec&lt;/span&gt;]&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentState&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; agentStatus ::&lt;/span&gt; &lt;span class="dt"&gt;AgentStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentCurrentConversation ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentCreatedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- World: Container for all component stores&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; componentStores ::&lt;/span&gt; &lt;span class="dt"&gt;HashMap&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt; (&lt;span class="dt"&gt;TVar&lt;/span&gt; &lt;span class="dt"&gt;Any&lt;/span&gt;) &lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="basic-usage"&gt;Basic Usage&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Initialize world with component stores&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;world &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    w &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newWorld&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    w&amp;#39; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; registerComponentStore w (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentConfig&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    registerComponentStore w&amp;#39; (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentState&lt;/span&gt;)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; config &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { agentName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentModel &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;url&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentSystemPrompt &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;You are helpful&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createAgent world config&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="migration-phases"&gt;Migration Phases&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;PhaseOldOnly (REMOVED) ──&amp;gt; PhaseDual ──&amp;gt; PhaseNewOnly
    (Legacy only)          (Both)        (OS only)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Current&lt;/strong&gt;: PhaseDual is the default, with PhaseNewOnly available.&lt;/p&gt;
&lt;h4 id="resource-scopes"&gt;Resource Scopes&lt;/h4&gt;
&lt;p&gt;Resources have explicit lifetimes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Program Scope&lt;/strong&gt;: Global resources (HTTP pools)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent Scope&lt;/strong&gt;: Per-agent resources
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toolbox Scope&lt;/strong&gt;: Per-toolbox resources (SQLite)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Scope&lt;/strong&gt;: Per-conversation resources
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turn Scope&lt;/strong&gt;: Temporary turn resources
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ToolCall Scope&lt;/strong&gt;: Single-use resources
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="concurrent-access-patterns"&gt;Concurrent Access Patterns&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Use Case&lt;/th&gt;&lt;th&gt;Implementation&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ExclusiveAccess&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Lua interpreters&lt;/td&gt;&lt;td&gt;TMVar&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ReadWriteAccess&lt;/code&gt;&lt;/td&gt;&lt;td&gt;SQLite (WAL mode)&lt;/td&gt;&lt;td&gt;RWLock&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;PoolAccess&lt;/code&gt;&lt;/td&gt;&lt;td&gt;HTTP connections&lt;/td&gt;&lt;td&gt;TBQueue&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;StatelessAccess&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Immutable data&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="knowledge-base-schema"&gt;Knowledge Base Schema&lt;/h3&gt;
&lt;p&gt;The SQLite knowledge base (&lt;code&gt;agents_kb.sqlite&lt;/code&gt;) tracks state:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Key tables:&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--   project_overview  - project metadata&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--   code_index        - 108 Haskell modules with docs linkage&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--   docs_index        - 15+ documentation files&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--   commits_seen      - git commits already processed&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Common queries:&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find OS modules:&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;span class="kw"&gt;WHERE&lt;/span&gt; filepath &lt;span class="kw"&gt;LIKE&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;%OS%&amp;#39;&lt;/span&gt;;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find where a module is documented:&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; documented_in &lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; module_name &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;System.Agents.OS.Core&amp;#39;&lt;/span&gt;;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check documentation coverage:&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;COUNT&lt;/span&gt;(&lt;span class="op"&gt;*&lt;/span&gt;) &lt;span class="kw"&gt;as&lt;/span&gt; total_modules,&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;SUM&lt;/span&gt;(&lt;span class="cf"&gt;CASE&lt;/span&gt; &lt;span class="cf"&gt;WHEN&lt;/span&gt; documented_in &lt;span class="kw"&gt;IS&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt; &lt;span class="cf"&gt;THEN&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt; &lt;span class="cf"&gt;ELSE&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt; &lt;span class="cf"&gt;END&lt;/span&gt;) &lt;span class="kw"&gt;as&lt;/span&gt; documented&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; code_index;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="module-to-doc-mapping"&gt;Module-to-Doc Mapping&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;If working on...&lt;/th&gt;&lt;th&gt;Update...&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/OS-API.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Compat*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/MIGRATION-OS.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Base&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/architecture.md&lt;/code&gt;, &lt;code&gt;documentation/README.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Runtime*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/architecture.md&lt;/code&gt; (legacy)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.AgentTree*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/architecture.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/tools.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.MCP.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/mcp.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/sessions.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.TUI.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/tui.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.CLI.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/cli-commands.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;app/Main.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/cli-commands.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.ExportImport*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/export-import.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.FileLoader*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;documentation/file-loader.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="code-patterns-to-recognize"&gt;Code Patterns to Recognize&lt;/h3&gt;
&lt;h4 id="pattern-ecs-component-definition"&gt;Pattern: ECS Component Definition&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Define component type&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt; {&lt;span class="ot"&gt; unComponentTypeId ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; }&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;class&lt;/span&gt; &lt;span class="dt"&gt;Component&lt;/span&gt; a &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;    componentId ::&lt;/span&gt; &lt;span class="dt"&gt;Proxy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create a component&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;Component&lt;/span&gt; &lt;span class="dt"&gt;MyComponent&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    componentId _ &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt; &lt;span class="dv"&gt;100&lt;/span&gt;  &lt;span class="co"&gt;-- Unique ID&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Use with world&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world eid myComponent&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    mComp &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;MyComponent&lt;/span&gt; world eid&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-os-agent-creation"&gt;Pattern: OS Agent Creation&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- OS model approach&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createAgent world &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { agentName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentModel &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;url&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentSystemPrompt &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;You are helpful&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; result &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Left&lt;/span&gt; err &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; handleError err&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Right&lt;/span&gt; agentId &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Agent created successfully&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-resource-management"&gt;Pattern: Resource Management&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Resources&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create registry&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;registry &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically newResourceRegistry&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; ctx &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ResourceContext&lt;/span&gt; [&lt;span class="dt"&gt;ProgramScope&lt;/span&gt;] registry&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create resource&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;rid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createResource ctx (&lt;span class="dt"&gt;SqliteResource&lt;/span&gt; config) &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;rid &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    conn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; openConnection config&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&gt;ResourceHandle&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { handleId &lt;span class="ot"&gt;=&lt;/span&gt; rid&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , handleCleanup &lt;span class="ot"&gt;=&lt;/span&gt; closeConnection conn&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , handleAccess &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;f &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; f (&lt;span class="dt"&gt;SqliteAccessor&lt;/span&gt; conn)&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Cleanup&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;cleanupScope registry (&lt;span class="dt"&gt;AgentScope&lt;/span&gt; agentId)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-migration-compatibility"&gt;Pattern: Migration Compatibility&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- During migration, use compatibility layer&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Compat.Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initializeWithMigration defaultMigrationConfig&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; result &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Right&lt;/span&gt; os &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Use new OS with compatibility bridge&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        bridge &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newRuntimeBridge agentId os&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        runWithBridge bridge &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            tools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; listTools&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            callTool &lt;span class="st"&gt;&amp;quot;my-tool&amp;quot;&lt;/span&gt; args&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Migration not configured&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-tracer-usage"&gt;Pattern: Tracer Usage&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- All operations are traced&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Prod.Tracer&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;MyTrace&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Started&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Completed&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Failed&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;myFunction ::&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;MyTrace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;myFunction tracer &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    runTracer tracer &lt;span class="dt"&gt;Started&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; try operation&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; result &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Right&lt;/span&gt; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; runTracer tracer &lt;span class="dt"&gt;Completed&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Left&lt;/span&gt; e  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; runTracer tracer (&lt;span class="dt"&gt;Failed&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt; e)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-concurrent-access-with-stm"&gt;Pattern: Concurrent Access with STM&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- SQLite with concurrent reads (WAL mode)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runResourceM ctx &lt;span class="op"&gt;$&lt;/span&gt; withRead rid &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    queryDatabase sql&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Lua with exclusive access&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runResourceM ctx &lt;span class="op"&gt;$&lt;/span&gt; withExclusive luaRid &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    runLuaScript script&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- HTTP with connection pool&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runResourceM ctx &lt;span class="op"&gt;$&lt;/span&gt; withPooled httpRid &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    makeHttpRequest req&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="key-types-reference"&gt;Key Types Reference&lt;/h3&gt;
&lt;h4 id="os-model-types"&gt;OS Model Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- ECS Core&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Agent Components&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; agentName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentModel ::&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentSystemPrompt ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentToolboxBindings ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentState&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; agentStatus ::&lt;/span&gt; &lt;span class="dt"&gt;AgentStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentCurrentConversation ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentCreatedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Resource Management&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ResourceScope&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ScopeGlobal&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ScopeAgent&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ScopeConversation&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AccessPattern&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ExclusiveAccess&lt;/span&gt;      &lt;span class="co"&gt;-- TMVar&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ReadWriteAccess&lt;/span&gt;      &lt;span class="co"&gt;-- RWLock&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PoolAccess&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;       &lt;span class="co"&gt;-- TBQueue&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StatelessAccess&lt;/span&gt;      &lt;span class="co"&gt;-- No lock&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="legacy-types-still-supported"&gt;Legacy Types (Still Supported)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Original Runtime types&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; slug ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; apiKeyId ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; flavor ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; modelUrl ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; modelName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; systemPrompt ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolDirectory ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mcpServers ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; [&lt;span class="dt"&gt;McpServerDescription&lt;/span&gt;]&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; extraAgents ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; [&lt;span class="dt"&gt;ExtraAgentRef&lt;/span&gt;]&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ExtraAgentRef&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ExtraAgentRef&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; extraAgentSlug ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; extraAgentPath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="git-workflow"&gt;Git Workflow&lt;/h3&gt;
&lt;p&gt;When documentation work spans multiple invocations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;First invocation&lt;/strong&gt;: Plan, gather info, create initial docs
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intermediate&lt;/strong&gt;: Continue where left off, check &lt;code&gt;commits_seen&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Final&lt;/strong&gt;: Update all indices, ensure consistency
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Always include a summary line as the &lt;strong&gt;first line of response&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="testing-documentation"&gt;Testing Documentation&lt;/h3&gt;
&lt;p&gt;Verify docs are correct by checking:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Type definitions match source code
&lt;/li&gt;
&lt;li&gt;File paths in examples exist
&lt;/li&gt;
&lt;li&gt;JSON examples are valid
&lt;/li&gt;
&lt;li&gt;Module names are correct (use &lt;code&gt;bash_grep-files&lt;/code&gt; to verify)
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="running-tests"&gt;Running Tests&lt;/h4&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;# All tests
cabal test

# OS-specific tests
cabal test --test-option=--pattern=&amp;quot;OS&amp;quot;

# Benchmarks
cabal bench
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="red-flags"&gt;Red Flags&lt;/h3&gt;
&lt;p&gt;Watch for these issues:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Issue&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Undocumented OS modules&lt;/td&gt;&lt;td&gt;Add to &lt;code&gt;code_index&lt;/code&gt;, update &lt;code&gt;documentation/OS-API.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Docs referencing wrong modules&lt;/td&gt;&lt;td&gt;Update &lt;code&gt;docs_index.related_modules&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Missing migration guidance&lt;/td&gt;&lt;td&gt;Update &lt;code&gt;documentation/MIGRATION-OS.md&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Broken code examples&lt;/td&gt;&lt;td&gt;Fix or mark as "illustrative"&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;New CLI commands not in &lt;code&gt;cli-commands.md&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Add with examples&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Commits not tracked&lt;/td&gt;&lt;td&gt;Process and insert to &lt;code&gt;commits_seen&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="quick-queries"&gt;Quick Queries&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find all OS-related modules:&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; module_name, filepath &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; module_name &lt;span class="kw"&gt;LIKE&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;%OS%&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;OR&lt;/span&gt; filepath &lt;span class="kw"&gt;LIKE&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;%OS%&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; filepath;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find all documentation:&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; doc_path, title &lt;span class="kw"&gt;FROM&lt;/span&gt; docs_index &lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; doc_path;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check documentation coverage:&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;COUNT&lt;/span&gt;(&lt;span class="op"&gt;*&lt;/span&gt;) &lt;span class="kw"&gt;as&lt;/span&gt; total,&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;SUM&lt;/span&gt;(&lt;span class="cf"&gt;CASE&lt;/span&gt; &lt;span class="cf"&gt;WHEN&lt;/span&gt; documented_in &lt;span class="kw"&gt;IS&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt; &lt;span class="cf"&gt;THEN&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt; &lt;span class="cf"&gt;ELSE&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt; &lt;span class="cf"&gt;END&lt;/span&gt;) &lt;span class="kw"&gt;as&lt;/span&gt; documented,&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;ROUND&lt;/span&gt;(&lt;span class="fl"&gt;100.0&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="fu"&gt;SUM&lt;/span&gt;(&lt;span class="cf"&gt;CASE&lt;/span&gt; &lt;span class="cf"&gt;WHEN&lt;/span&gt; documented_in &lt;span class="kw"&gt;IS&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt; &lt;span class="cf"&gt;THEN&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt; &lt;span class="cf"&gt;ELSE&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt; &lt;span class="cf"&gt;END&lt;/span&gt;) &lt;span class="op"&gt;/&lt;/span&gt; &lt;span class="fu"&gt;COUNT&lt;/span&gt;(&lt;span class="op"&gt;*&lt;/span&gt;), &lt;span class="dv"&gt;1&lt;/span&gt;) &lt;span class="kw"&gt;as&lt;/span&gt; pct&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; code_index;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find modules by documentation file:&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; module_name, filepath &lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; documented_in &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;documentation/OS-API.md&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; module_name;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="working-with-cabal"&gt;Working with Cabal&lt;/h3&gt;
&lt;p&gt;The project uses &lt;code&gt;agents.cabal&lt;/code&gt;. Key stanzas:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Library exports modules under System.Agents&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;library&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;exposed-modules&lt;/span&gt;:&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        System.Agents&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        System.Agents.OS           &lt;span class="co"&gt;-- NEW&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        System.Agents.OS.Core      &lt;span class="co"&gt;-- NEW&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        System.Agents.OS.Agents    &lt;span class="co"&gt;-- NEW&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        System.Agents.Base&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        System.Agents.Runtime&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ...&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Executable is app/Main.hs&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;executable&lt;/span&gt; agents-exe&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;main-is&lt;/span&gt;: Main.hs&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;hs-source-dirs&lt;/span&gt;: app&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;build-depends&lt;/span&gt;: agents, ...&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Test suite&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;test-suite&lt;/span&gt;&lt;span class="at"&gt; agents-tests&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;other-modules&lt;/span&gt;:&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        OS.CoreTests&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        OS.IntegrationTests&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        OS.CompatibilityTests&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ...&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Benchmarks&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;benchmark&lt;/span&gt;&lt;span class="at"&gt; os-benchmarks&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;main-is&lt;/span&gt;: OSBenchmarks.hs&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;hs-source-dirs&lt;/span&gt;: bench&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="common-import-patterns"&gt;Common Import Patterns&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- OS Model (New)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Core&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Agents&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Compat.Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Core types&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Base&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Legacy Runtime (being deprecated)&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Runtime.Runtime&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Agent tree&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.AgentTree&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;AgentTree&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.AgentTree&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;OSAgentTree&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Tools&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Tools.Bash&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;Bash&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Tools.BashToolbox&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;BashToolbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Sessions&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Base&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Tracing&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Prod.Tracer&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- STM for concurrency&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Control.Concurrent.STM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="summary-checklist"&gt;Summary Checklist&lt;/h3&gt;
&lt;p&gt;Before finishing work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ ] Summary line included (first line of response)
&lt;/li&gt;
&lt;li&gt;[ ] Knowledge base tables updated if needed
&lt;/li&gt;
&lt;li&gt;[ ] New OS modules added to &lt;code&gt;code_index&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] New documentation files added to &lt;code&gt;docs_index&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Documentation created/updated for changes
&lt;/li&gt;
&lt;li&gt;[ ] Cross-references checked
&lt;/li&gt;
&lt;li&gt;[ ] Code examples verified
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="emergency-contacts"&gt;Emergency Contacts&lt;/h3&gt;
&lt;p&gt;If completely lost:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read &lt;code&gt;documentation/README.md&lt;/code&gt; for overview
&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;documentation/CHANGELOG-OS-MIGRATION.md&lt;/code&gt; for recent changes
&lt;/li&gt;
&lt;li&gt;Read &lt;code&gt;documentation/MIGRATION-OS.md&lt;/code&gt; for migration guidance
&lt;/li&gt;
&lt;li&gt;Look at &lt;code&gt;src/System/Agents/OS.hs&lt;/code&gt; for OS entry point
&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;app/Main.hs&lt;/code&gt; for current command structure
&lt;/li&gt;
&lt;li&gt;Query &lt;code&gt;code_index&lt;/code&gt; for module purposes
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember: This is a well-structured Haskell project in transition from Runtime-per-agent to ECS-based OS model. Follow the types, follow the imports, and you’ll find your way.&lt;/p&gt;
&lt;h3 id="recent-changes-march-2026"&gt;Recent Changes (March 2026)&lt;/h3&gt;
&lt;p&gt;See &lt;code&gt;documentation/CHANGELOG-OS-MIGRATION.md&lt;/code&gt; for detailed change log.&lt;/p&gt;
&lt;p&gt;Key highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;27 new OS modules&lt;/strong&gt; added for ECS-based architecture
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PhaseOldOnly removed&lt;/strong&gt; - now only PhaseDual and PhaseNewOnly
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full compatibility layer&lt;/strong&gt; for gradual migration
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New documentation&lt;/strong&gt;: OS-API.md, MIGRATION-OS.md
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New tests&lt;/strong&gt;: Integration, Compatibility, benchmarks
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-AI-CONTEXT.html" rel="alternate"/><summary type="text">&gt; **READ THIS FIRST** when invoked on this codebase. ## Immediate First Steps When you're invoked on this project, run these queries immediately: ```sql -- 1. What is this project? SELECT * FROM project_overview; -- 2. What docs exist? SELE</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-salmon-preview-deployment.html</id><title type="text">Spec: a salmon-driven preview deployment of agents-server</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/salmon-preview-deployment.md"&gt;&lt;code&gt;todos/salmon-preview-deployment.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="spec-a-salmon-driven-preview-deployment-of-agents-server"&gt;Spec: a salmon-driven preview deployment of agents-server&lt;/h2&gt;
&lt;p&gt;Status: proposal, 2026-10-03. Nothing implemented. A design pass with a
recommendation; the points marked &lt;strong&gt;Decide&lt;/strong&gt; need the owner before any
phase starts.&lt;/p&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;
&lt;p&gt;Run the &lt;em&gt;built&lt;/em&gt; &lt;code&gt;agents-server&lt;/code&gt; as it would run in production (its own
process, its files on disk, a real database, later a real init system),
check it over the network, and tear it down. The same recipe, left up
instead of torn down, is a preview of a branch.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/lucasdicioccio/salmon"&gt;salmon&lt;/a&gt; is the tool that brings
the deployment up and down: it expresses the deployment as a graph of
idempotent ops with &lt;code&gt;up&lt;/code&gt;/&lt;code&gt;down&lt;/code&gt;/&lt;code&gt;check&lt;/code&gt;, and it already has the pieces this
needs (podman containers, systemd units, postgres, qemu VMs, files).&lt;/p&gt;
&lt;h3 id="where-things-stand"&gt;Where things stand&lt;/h3&gt;
&lt;p&gt;What is tested today, and how:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;What&lt;/th&gt;&lt;th&gt;Where&lt;/th&gt;&lt;th&gt;How real&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Runtime, sessions, tools&lt;/td&gt;&lt;td&gt;&lt;code&gt;agents-tests&lt;/code&gt; (&lt;code&gt;test/&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;in-process, in-memory persistence&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP API, auth, events, mail&lt;/td&gt;&lt;td&gt;&lt;code&gt;agents-server-tests&lt;/code&gt; (&lt;code&gt;examples/agents-server/test&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;in-process WAI application on a free port, the LLM replaced by a Haskell function, a temporary SQLite file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Postgres store, leases, takeover&lt;/td&gt;&lt;td&gt;&lt;code&gt;agents-postgres-tests&lt;/code&gt; (&lt;code&gt;postgres/test&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;a real cluster from &lt;code&gt;initdb&lt;/code&gt;/&lt;code&gt;pg_ctl&lt;/code&gt; (or &lt;code&gt;AGENTS_TEST_POSTGRES_URL&lt;/code&gt;); skipped when neither is there&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TUI against a real binary&lt;/td&gt;&lt;td&gt;&lt;code&gt;checks/*-e2e&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the built &lt;code&gt;agents-exe&lt;/code&gt; under a pty, with &lt;code&gt;checks/lib/fake_llm.py&lt;/code&gt; as an OpenAI-compatible LLM&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;What none of them runs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;agents-server&lt;/code&gt; executable itself: its option parser, its startup
order, its exit codes, its JSON log lines;
&lt;/li&gt;
&lt;li&gt;the units in &lt;code&gt;bundling/systemd/&lt;/code&gt; (&lt;code&gt;User=&lt;/code&gt;, &lt;code&gt;StateDirectory=&lt;/code&gt;,
&lt;code&gt;TimeoutStopSec&lt;/code&gt; against &lt;code&gt;--shutdown-grace&lt;/code&gt;, &lt;code&gt;Restart=on-failure&lt;/code&gt;);
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SIGTERM&lt;/code&gt; and &lt;code&gt;SIGKILL&lt;/code&gt; on a real process, and what a restart finds;
&lt;/li&gt;
&lt;li&gt;a database written by one version and opened by the next;
&lt;/li&gt;
&lt;li&gt;two server processes on one Postgres, one of them killed;
&lt;/li&gt;
&lt;li&gt;a client on another machine: &lt;code&gt;--bind&lt;/code&gt;, &lt;code&gt;--auth-tokens&lt;/code&gt;, &lt;code&gt;--cors-origin&lt;/code&gt;,
&lt;code&gt;agents-exe tui --attach URL&lt;/code&gt;;
&lt;/li&gt;
&lt;li&gt;the binary on a machine other than the one that built it.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;salmon is not used by this repository. The two mentions are incidental
(&lt;code&gt;dbs/README.md&lt;/code&gt;, &lt;code&gt;website/README.md&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id="what-salmon-provides"&gt;What salmon provides&lt;/h3&gt;
&lt;p&gt;Read from salmon’s README and &lt;code&gt;resources/howto-ops.md&lt;/code&gt; (section 10); none of
it has been run for this spec.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Builtin nodes for &lt;code&gt;Podman&lt;/code&gt; (and quadlets), &lt;code&gt;Systemd&lt;/code&gt;, &lt;code&gt;Postgres&lt;/code&gt;, &lt;code&gt;Qemu&lt;/code&gt;,
&lt;code&gt;Filesystem&lt;/code&gt;, &lt;code&gt;Cabal&lt;/code&gt;, &lt;code&gt;Daemon&lt;/code&gt; (a process salmon keeps running where
there is no systemd), &lt;code&gt;Certificates&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;A binary built on salmon speaks &lt;code&gt;config &amp;lt;seed&amp;gt; | run up&lt;/code&gt;, &lt;code&gt;run down&lt;/code&gt;,
&lt;code&gt;run tree&lt;/code&gt;. Teardown is the graph walked backwards.
&lt;/li&gt;
&lt;li&gt;Its own tests are in four layers by cost: graph shape only (0), temporary
directories (1), disposable podman containers (2), a qemu VM for systemd
as PID 1 and real interfaces (3). Layers 2 and 3 skip loudly when podman
or the VM privileges are missing.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SreBox.Gcp.PreviewEnvironment&lt;/code&gt; groups several Cloud Run deploys into one
node per branch. It is the precedent for “one thing to point &lt;code&gt;run up&lt;/code&gt; and
&lt;code&gt;run down&lt;/code&gt; at”, on a host this spec does not propose.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;salmon-core&lt;/code&gt;, &lt;code&gt;salmon-ops&lt;/code&gt; and &lt;code&gt;salmon-ops-recipes&lt;/code&gt; are on Hackage. The
test harness (&lt;code&gt;Test.Harness&lt;/code&gt;: &lt;code&gt;withContainer&lt;/code&gt;, &lt;code&gt;withVm&lt;/code&gt;, &lt;code&gt;sshToVm&lt;/code&gt;, …)
is in salmon’s test tree, not in a library, so it cannot be imported from
here as it is.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="recommendation"&gt;Recommendation&lt;/h3&gt;
&lt;p&gt;Build one salmon recipe, in this repository, that describes an
agents-server deployment, and use it two ways: a test driver runs &lt;code&gt;up&lt;/code&gt;,
checks, &lt;code&gt;down&lt;/code&gt;; an operator runs &lt;code&gt;up&lt;/code&gt; and keeps it. Start with a container
and SQLite, and add Postgres and a VM as later phases. Do not make it a
tier of &lt;code&gt;cabal test&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="one-graph-two-uses"&gt;One graph, two uses&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;agents-preview config --name NAME --host container|vm --db sqlite|postgres ...
    | agents-preview run up        # or: run down, run tree
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The graph, from the leaves:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the &lt;code&gt;agents-server&lt;/code&gt; binary for the target (see “The binary” below);
&lt;/li&gt;
&lt;li&gt;the host: a podman container, or a qemu VM;
&lt;/li&gt;
&lt;li&gt;files on the host: agent file, keys file, token file, and for the VM the
unit from &lt;code&gt;bundling/systemd/&lt;/code&gt;, copied as it is shipped;
&lt;/li&gt;
&lt;li&gt;the LLM: &lt;code&gt;checks/lib/fake_llm.py&lt;/code&gt; with a script, listening next to the
server; the agent file’s &lt;code&gt;modelUrl&lt;/code&gt; points at it, as &lt;code&gt;checks/lib/e2e.py&lt;/code&gt;
already does. No API key, so no secret is involved;
&lt;/li&gt;
&lt;li&gt;optionally Postgres and its database;
&lt;/li&gt;
&lt;li&gt;the server process (container command or &lt;code&gt;Daemon&lt;/code&gt; in the container,
the systemd unit in the VM);
&lt;/li&gt;
&lt;li&gt;a last node whose &lt;code&gt;check&lt;/code&gt; is &lt;code&gt;GET /healthz&lt;/code&gt; answering &lt;code&gt;200&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;run up&lt;/code&gt; prints where the server listens and a token. A preview is this,
left standing; &lt;code&gt;run down&lt;/code&gt; removes it.&lt;/p&gt;
&lt;h4 id="where-it-lives"&gt;Where it lives&lt;/h4&gt;
&lt;p&gt;A separate cabal package, &lt;code&gt;preview/&lt;/code&gt;, with its own project file
(&lt;code&gt;cabal.preview.project&lt;/code&gt;), depending on &lt;code&gt;salmon-ops&lt;/code&gt; and
&lt;code&gt;salmon-ops-recipes&lt;/code&gt; from Hackage and on &lt;code&gt;agents-lib&lt;/code&gt; for the HTTP client.
The repository has no &lt;code&gt;cabal.project&lt;/code&gt; today, only a freeze file, so the
default build and &lt;code&gt;cabal test&lt;/code&gt; are untouched and nobody needs salmon, podman
or qemu to work on agents-exe. This is what salmon does for its own
experimental packages (&lt;code&gt;cabal.perso.project&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Not recommended:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;A new test-suite in &lt;code&gt;agents.cabal&lt;/code&gt;&lt;/em&gt;. It would put salmon and all its
dependencies in the freeze file of every build, for tests that most
machines skip.
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The recipe in the salmon repository&lt;/em&gt;. agents-server’s flags and files
change here; the recipe must change in the same commit.
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;A shell script around &lt;code&gt;podman&lt;/code&gt;&lt;/em&gt;. It would work for phase 1. It gives no
&lt;code&gt;down&lt;/code&gt; that matches &lt;code&gt;up&lt;/code&gt;, no &lt;code&gt;check&lt;/code&gt;, and nothing to reuse for the VM.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="the-checks"&gt;The checks&lt;/h4&gt;
&lt;p&gt;Written in Haskell in the same package, against the address &lt;code&gt;run up&lt;/code&gt;
printed, with &lt;code&gt;System.Agents.Host.Client.Http&lt;/code&gt; (the client the TUI attaches
with). They take a URL and a token and nothing else, so they also run
against a server deployed by other means.&lt;/p&gt;
&lt;p&gt;Phase 1, container and SQLite:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;/healthz&lt;/code&gt; answers; the &lt;code&gt;server.started&lt;/code&gt; log line says
&lt;code&gt;authentication: bearer&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;A request without a token is refused; one owner cannot read another’s
session.
&lt;/li&gt;
&lt;li&gt;A scripted run: create a session with a prompt, wait, read the answer
the fake LLM was scripted to give, with one tool call on the way.
&lt;/li&gt;
&lt;li&gt;The events stream of that run carries &lt;code&gt;run.started&lt;/code&gt; … &lt;code&gt;run.stopped&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SIGTERM&lt;/code&gt; during a run: the process exits within &lt;code&gt;--shutdown-grace&lt;/code&gt;, the
session is stored.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SIGKILL&lt;/code&gt; during a run, then start: &lt;code&gt;sessions.recovered&lt;/code&gt; names the
session, its status is the one its turns imply, &lt;code&gt;resume&lt;/code&gt; continues it.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-exe tui --attach URL&lt;/code&gt; from outside the container (the existing
&lt;code&gt;checks/phase4-attach-e2e&lt;/code&gt;, given a URL).
&lt;/li&gt;
&lt;li&gt;Upgrade: bring up the binary built from &lt;code&gt;main&lt;/code&gt;, run check 3, replace the
binary with the branch’s, start on the same database, read the old
session and run check 3 again.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Phase 2, Postgres:&lt;/p&gt;
&lt;ol start="9"&gt;
&lt;li&gt;The server creates its tables in an empty database.
&lt;/li&gt;
&lt;li&gt;Two servers on one database: a message sent to one reaches a run on the
other; kill the owner, and the other logs &lt;code&gt;sessions.taken_over&lt;/code&gt; after
the lease expires.
&lt;/li&gt;
&lt;li&gt;Check 8 with Postgres.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Phase 3, a VM with systemd:&lt;/p&gt;
&lt;ol start="12"&gt;
&lt;li&gt;&lt;code&gt;bundling/systemd/agents-server.service&lt;/code&gt;, installed as the
documentation says, starts as the &lt;code&gt;agents-server&lt;/code&gt; user and creates its
state directory.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl stop&lt;/code&gt; during a run ends cleanly, before &lt;code&gt;TimeoutStopSec&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;A killed server is restarted by systemd and recovers its sessions.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;journalctl -u agents-server -o cat&lt;/code&gt; is one JSON object per line.
&lt;/li&gt;
&lt;li&gt;The VM reboots; the service comes back with its sessions.
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="the-binary"&gt;The binary&lt;/h4&gt;
&lt;p&gt;A binary built on the developer’s machine is linked against that machine’s
glibc and libraries, and may not start in a &lt;code&gt;debian:bookworm&lt;/code&gt; container.
Two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;build inside a container of the target’s distribution and copy the binary
out (&lt;code&gt;bundling/Containerfile.build&lt;/code&gt; does this for &lt;code&gt;agents-exe&lt;/code&gt;, from a
clone of GitHub rather than the working tree, and on &lt;code&gt;haskell:9.8.4&lt;/code&gt;
while &lt;code&gt;agents.cabal&lt;/code&gt; asks for &lt;code&gt;base &amp;gt;=4.20&lt;/code&gt;: it looks out of date, and
was not built for this spec);
&lt;/li&gt;
&lt;li&gt;choose the container image to match the host that builds.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first is right for a preview that must be like production and slow
(a full build, once per image, cached after). The second is enough for
phase 1 on the owner’s machine. Phase 1 takes the path of a binary as a
seed argument, so the choice can be made later.&lt;/p&gt;
&lt;h4 id="phases"&gt;Phases&lt;/h4&gt;
&lt;p&gt;Each is useful alone and can stop there.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Phase&lt;/th&gt;&lt;th&gt;Adds&lt;/th&gt;&lt;th&gt;Needs on the machine&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;the &lt;code&gt;preview/&lt;/code&gt; package, the graph with a container and no server (&lt;code&gt;run tree&lt;/code&gt;, &lt;code&gt;up&lt;/code&gt;, &lt;code&gt;down&lt;/code&gt;), a graph-shape test&lt;/td&gt;&lt;td&gt;podman&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;server, fake LLM, SQLite, checks 1 to 8&lt;/td&gt;&lt;td&gt;podman, python3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Postgres, a second server, checks 9 to 11&lt;/td&gt;&lt;td&gt;podman&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;VM host, the shipped unit, checks 12 to 16&lt;/td&gt;&lt;td&gt;qemu, root or the &lt;code&gt;setcap&lt;/code&gt; grants salmon's harness documents&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;a preview on a host other than this machine&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Decide&lt;/strong&gt;: see below&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Phase 3 depends on salmon’s VM harness being usable from outside salmon’s
test tree. That is a change in salmon and is not part of this work: ask for
it there, or copy the few functions needed here until it exists.&lt;/p&gt;
&lt;h3 id="the-other-reading-salmon-as-a-feature"&gt;The other reading: salmon as a feature&lt;/h3&gt;
&lt;p&gt;The request also said “or integrate as a new feature”. Two candidates were
considered, and neither is recommended now.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Agents that operate salmon&lt;/em&gt;. &lt;code&gt;salmon run serve --http&lt;/code&gt; has an HTTP API
with an OpenAPI description (&lt;code&gt;salmon-ops/openapi/serve-api.openapi.json&lt;/code&gt;),
and agents-exe has an OpenAPI toolbox. An agent that lists, converges and
inspects a salmon world may need no code at all, only an agent file and a
page of documentation. Worth one experiment after phase 1, when there is
a salmon graph in this repository to point it at.
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;salmon as the way to install agents-server&lt;/em&gt;. The units in
&lt;code&gt;bundling/systemd/&lt;/code&gt; and a page of documentation do this today. A salmon
recipe for production installs is the phase 1 graph with a real host, and
should wait until the preview has shown the graph is right.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="not-in-scope"&gt;Not in scope&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Deploying anywhere but the machine that runs the recipe (until phase 4 is
decided).
&lt;/li&gt;
&lt;li&gt;TLS, a reverse proxy, DNS. The server binds a plain port; the
documentation puts a proxy in front. A later check, not a first one.
&lt;/li&gt;
&lt;li&gt;A real LLM. Every check uses the fake one. A preview an operator keeps
may be given real keys by hand; the recipe does not handle them.
&lt;/li&gt;
&lt;li&gt;CI. The repository has no CI configuration; this spec adds none.
&lt;/li&gt;
&lt;li&gt;Changes to the salmon repository.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="decide"&gt;Decide&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Scope of the first step.&lt;/strong&gt; Recommended: phases 0 and 1 (container,
SQLite), then stop and look. The alternative is to go straight to
Postgres and systemd, which is closer to production and much more
work before the first result.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host.&lt;/strong&gt; Recommended: podman container first, qemu VM in phase 3 for
systemd. The alternative is the VM from the start (one host kind, but
every run needs VM privileges and a rootfs).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Package location.&lt;/strong&gt; Recommended: &lt;code&gt;preview/&lt;/code&gt; with its own project
file. Is a second cabal project in this repository acceptable?
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The checks’ language.&lt;/strong&gt; Recommended: Haskell with the existing HTTP
client. The alternative is Python next to &lt;code&gt;checks/lib&lt;/code&gt;, which reuses
&lt;code&gt;fake_llm.py&lt;/code&gt;’s conventions and adds no Haskell dependency, but
duplicates the client.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 4.&lt;/strong&gt; Is a preview on another host wanted at all (a URL to open
per branch), and if so on what: a machine of the owner’s over ssh, or
Cloud Run as salmon’s &lt;code&gt;PreviewEnvironment&lt;/code&gt; does? This one involves real
hosts, credentials and cost, and nothing is proposed until it is
answered.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The salmon harness.&lt;/strong&gt; May the VM helpers move from salmon’s test tree
to a library, or should phase 3 copy them?
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;bundling/Containerfile.build&lt;/code&gt;.&lt;/strong&gt; Fix it as part of phase 1 (build
from the working tree, a GHC that satisfies &lt;code&gt;base &amp;gt;=4.20&lt;/code&gt;, also produce
&lt;code&gt;agents-server&lt;/code&gt;), or leave it?
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-salmon-preview-deployment.html" rel="alternate"/><summary type="text">Status: proposal, 2026-10-03. Nothing implemented. A design pass with a</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-async-tool-calls.html</id><title type="text">Asynchronous / Interruptible Tool Calls</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/async-tool-calls.md"&gt;&lt;code&gt;todos/async-tool-calls.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="asynchronous--interruptible-tool-calls"&gt;Asynchronous / Interruptible Tool Calls&lt;/h2&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;
&lt;p&gt;Make tool calls in a TUI/oneshot session truly interruptible and inspectable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tool calls can execute concurrently instead of blocking the whole turn.
&lt;/li&gt;
&lt;li&gt;The LLM can receive &lt;em&gt;partial&lt;/em&gt; answers as soon as individual calls finish.
&lt;/li&gt;
&lt;li&gt;The LLM can later query the status of a still-running or previously-yielded tool call.
&lt;/li&gt;
&lt;li&gt;Tool calls become first-class entities in the ECS-style OS, visible to the rest of the system.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today the flow is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;LLM turn emits tool calls.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-exe&lt;/code&gt; schedules them synchronously:
&lt;ul&gt;
&lt;li&gt;tool call 1 runs
&lt;/li&gt;
&lt;li&gt;tool call 2 runs
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-exe&lt;/code&gt; returns the LLM turn.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We want:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;LLM turn emits tool calls.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-exe&lt;/code&gt; promotes each call to an OS entity and starts them concurrently.
&lt;/li&gt;
&lt;li&gt;As soon as at least one call has a useful partial result, the scheduler can yield a partial user turn back to the LLM.
&lt;/li&gt;
&lt;li&gt;The LLM can continue the conversation, optionally calling a system capability to inspect any call it is interested in.
&lt;/li&gt;
&lt;li&gt;When all calls for the turn are complete, the turn finalizes normally.
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="current-state"&gt;Current State&lt;/h3&gt;
&lt;p&gt;There is already async scaffolding in place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Types&lt;/code&gt; defines &lt;code&gt;TrackedToolCall&lt;/code&gt;, &lt;code&gt;ToolCallState&lt;/code&gt; (&lt;code&gt;Ready&lt;/code&gt;, &lt;code&gt;Running&lt;/code&gt;, &lt;code&gt;Deferred&lt;/code&gt;, &lt;code&gt;Completed&lt;/code&gt;, &lt;code&gt;Failed&lt;/code&gt;), &lt;code&gt;ToolCallDisposition&lt;/code&gt; (&lt;code&gt;RunSync&lt;/code&gt;, &lt;code&gt;RunAsync&lt;/code&gt;, &lt;code&gt;RunIsolated&lt;/code&gt;, &lt;code&gt;Defer&lt;/code&gt;, &lt;code&gt;Decorate&lt;/code&gt;), &lt;code&gt;ContinuationToken&lt;/code&gt;, etc.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Async&lt;/code&gt; provides continuation tokens, snapshots, and a &lt;code&gt;ContinuationStore&lt;/code&gt; (SQLite-backed).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Step&lt;/code&gt; has &lt;code&gt;runStepMAsync&lt;/code&gt;, which classifies calls via &lt;code&gt;ctxToolCallPolicy&lt;/code&gt; and can defer calls.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Loop&lt;/code&gt; has &lt;code&gt;runAsync&lt;/code&gt; / &lt;code&gt;runAsyncWithProgress&lt;/code&gt; that pause when a &lt;code&gt;PartialUserTurn&lt;/code&gt; is present.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What is missing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RunAsync&lt;/code&gt; / &lt;code&gt;Running&lt;/code&gt; are mostly nominal. Calls are still executed sequentially in one batch; &lt;code&gt;RunAsync&lt;/code&gt; just defers them.
&lt;/li&gt;
&lt;li&gt;There is no real concurrent execution engine.
&lt;/li&gt;
&lt;li&gt;There is no way for the LLM to ask “what is the status of tool-call X?” while it is running.
&lt;/li&gt;
&lt;li&gt;Tool calls are not yet represented as ECS entities with runtime components.
&lt;/li&gt;
&lt;li&gt;Partial answers are not surfaced: a call is either done or deferred.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="design-overview"&gt;Design Overview&lt;/h3&gt;
&lt;p&gt;We introduce three layers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ECS OS layer&lt;/strong&gt; — every tool call becomes an &lt;code&gt;EntityId&lt;/code&gt; with &lt;code&gt;ToolCallConfig&lt;/code&gt; and &lt;code&gt;ToolCallState&lt;/code&gt; components. The OS is the source of truth for status.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Async execution engine&lt;/strong&gt; — a small scheduler that runs approved calls concurrently, updates OS components, and emits heartbeat/partial progress.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System-toolbox introspection capability&lt;/strong&gt; — a new &lt;code&gt;get-tool-call-status&lt;/code&gt; capability (and possibly &lt;code&gt;list-running-tool-calls&lt;/code&gt;) that any agent can invoke.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key idea is that the existing &lt;code&gt;PartialUserTurn&lt;/code&gt; mechanism is extended so that a turn can be yielded &lt;em&gt;before&lt;/em&gt; all calls are complete, carrying intermediate responses. The LLM can then decide whether to keep waiting, do something else, or inspect a specific call.&lt;/p&gt;
&lt;h3 id="ecs-integration"&gt;ECS Integration&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;System.Agents.OS.Conversation.Types&lt;/code&gt; already has the right component shapes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ToolCallConfig&lt;/code&gt; — static info: turn, tool name, input args, parent call.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolCallState&lt;/code&gt; — runtime status, timestamps, result value.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We extend them with async-specific fields:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolCallConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCallConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; tcTurnId ::&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tcToolName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tcToolInput ::&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tcParentCallId ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ToolCallId&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tcSessionId ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;          &lt;span class="co"&gt;-- NEW: which session owns this call&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tcConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="co"&gt;-- NEW&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolCallState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCallState&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; tcStatus ::&lt;/span&gt; &lt;span class="dt"&gt;ToolCallStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tcStartedAt ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;      &lt;span class="co"&gt;-- NEW: was required, now optional until actually started&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tcCompletedAt ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tcResult ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tcProgress ::&lt;/span&gt; [&lt;span class="dt"&gt;ToolCallProgress&lt;/span&gt;]  &lt;span class="co"&gt;-- NEW: ordered structured partial updates&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- NEW component-like value stored inside ToolCallState.&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- All progress payloads are structured JSON.&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolCallProgress&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCallProgress&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; progressAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; progressKind ::&lt;/span&gt; &lt;span class="dt"&gt;ProgressKind&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; progressPayload ::&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ProgressKind&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ProgressStarted&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ProgressLog&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;          &lt;span class="co"&gt;-- free-form log line (still wrapped in JSON)&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ProgressPartial&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;     &lt;span class="co"&gt;-- structured partial result&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ProgressHeartbeat&lt;/span&gt;         &lt;span class="co"&gt;-- &amp;quot;still alive&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;When the scheduler receives tool calls from an LLM turn, it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Creates one OS entity per call.
&lt;/li&gt;
&lt;li&gt;Attaches &lt;code&gt;ToolCallConfig&lt;/code&gt; and &lt;code&gt;ToolCallState { TcPending }&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Links the call back to the current &lt;code&gt;TurnId&lt;/code&gt; and &lt;code&gt;ConversationId&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Returns a lightweight &lt;code&gt;ToolCallHandle&lt;/code&gt; (entity id + &lt;code&gt;ToolCallId&lt;/code&gt;) to the session layer.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The existing &lt;code&gt;TrackedToolCall&lt;/code&gt; keeps its &lt;code&gt;ToolCallId&lt;/code&gt; but gains a &lt;code&gt;tcEntityId :: Maybe EntityId&lt;/code&gt; so the session can map back to the OS.&lt;/p&gt;
&lt;h3 id="async-execution-engine"&gt;Async Execution Engine&lt;/h3&gt;
&lt;p&gt;A new module &lt;code&gt;System.Agents.Session.Async.Engine&lt;/code&gt; provides:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AsyncEngine&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AsyncEngine&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; aeWorld ::&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; aeExecutor ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LlmToolCall&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; aeMaxConcurrency ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Start executing a batch of calls concurrently.&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Returns handles and, if some calls already completed synchronously, their results.&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;startAsyncBatch ::&lt;/span&gt; &lt;span class="dt"&gt;AsyncEngine&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;TrackedToolCall&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;AsyncBatch&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Block until at least one call in the batch makes progress, then return.&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;waitForProgress ::&lt;/span&gt; &lt;span class="dt"&gt;AsyncBatch&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;AsyncBatchUpdate&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Finalize any completed calls into UserToolResponses.&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;finalizeCompleted ::&lt;/span&gt; &lt;span class="dt"&gt;AsyncBatch&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [(&lt;span class="dt"&gt;ToolCallId&lt;/span&gt;, &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;)]&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Cancel all still-running calls (best effort).&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;cancelAsyncBatch ::&lt;/span&gt; &lt;span class="dt"&gt;AsyncBatch&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Cancel a single running call by its handle.&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;cancelToolCall ::&lt;/span&gt; &lt;span class="dt"&gt;AsyncEngine&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolCallId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The engine uses &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;Async&lt;/code&gt; (or &lt;code&gt;forkIO&lt;/code&gt; + &lt;code&gt;TVar&lt;/code&gt;) to run calls. For each call:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It sets the OS state to &lt;code&gt;TcExecuting&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;It runs the call in a background thread.
&lt;/li&gt;
&lt;li&gt;The call can emit progress via a callback injected into &lt;code&gt;ToolExecutionContext&lt;/code&gt;:
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ctxProgressCallback ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;Value&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ())&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;All payloads passed to this callback must be valid JSON values.
&lt;/li&gt;
&lt;li&gt;On completion it sets the OS state to &lt;code&gt;TcCompleted result&lt;/code&gt; (or &lt;code&gt;TcFailed err&lt;/code&gt; / &lt;code&gt;TcCancelled&lt;/code&gt;).
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Policy integration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RunSync&lt;/code&gt; calls are still executed inline.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RunAsync&lt;/code&gt; calls go to the engine.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RunIsolated&lt;/code&gt; calls are delegated to the configured deployment runner but also tracked as OS entities.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Defer&lt;/code&gt; calls stay in &lt;code&gt;TcPending&lt;/code&gt; with a continuation token.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="partial-answers"&gt;Partial Answers&lt;/h3&gt;
&lt;p&gt;A tool can emit a partial answer by calling the progress callback if the tool supports streaming. For tools that do not support streaming, the engine can still yield after each individual call finishes, so the LLM gets &lt;em&gt;some&lt;/em&gt; responses earlier.&lt;/p&gt;
&lt;p&gt;When the session stepper asks for a user turn, the scheduler can produce a &lt;code&gt;PartialUserTurn&lt;/code&gt; with the subset of calls that have completed so far. The LLM then sees:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;completed&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;and for still-running calls:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;running&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;progress&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;at&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;kind&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;payload&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;downloading...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;at&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;kind&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;partial&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;payload&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;percent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;50&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The LLM can choose to continue immediately (if the completed answers are enough) or call &lt;code&gt;get_tool_call_status&lt;/code&gt; for more detail.&lt;/p&gt;
&lt;h3 id="tool-call-status-system-capability"&gt;Tool-Call Status System Capability&lt;/h3&gt;
&lt;p&gt;Add new capabilities to &lt;code&gt;SystemToolCapability&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SystemToolGetToolCallStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SystemToolListRunningToolCalls&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SystemToolCancelToolCall&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;and expose them through &lt;code&gt;System.Agents.Tools.SystemToolbox&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="get_tool_call_status"&gt;&lt;code&gt;get_tool_call_status&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Input schema:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;include_progress&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;wait_for_completion&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;timeout_seconds&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Output schema:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;pending|running|completed|failed|cancelled|orphaned&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tool_name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;started_at&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;completed_at&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;progress&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="er"&gt;...&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;is_final&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Status values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pending&lt;/code&gt; — call is queued but has not started.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;running&lt;/code&gt; — call is executing.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;completed&lt;/code&gt; — call finished successfully.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;failed&lt;/code&gt; — call finished with an error.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancelled&lt;/code&gt; — call was cancelled before completion.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;orphaned&lt;/code&gt; — the call is referenced in the chat history but no longer exists in the OS (process restarted, entity was dropped, etc.). This is the clear “task no longer exists” status.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If &lt;code&gt;wait_for_completion&lt;/code&gt; is true, the tool blocks up to &lt;code&gt;timeout_seconds&lt;/code&gt; and returns the final result when available. This lets an LLM poll efficiently.&lt;/p&gt;
&lt;h4 id="list_running_tool_calls"&gt;&lt;code&gt;list_running_tool_calls&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Returns calls filtered by the current session/conversation scope (reusing the existing session-introspection scope rules). Useful for the LLM to discover what it can inspect.&lt;/p&gt;
&lt;h4 id="cancel_tool_call"&gt;&lt;code&gt;cancel_tool_call&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Input schema:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;user request&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Output schema:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;cancelled&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;previous_status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;running&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Cancellation is best-effort. If the call is already final, the capability returns &lt;code&gt;cancelled: false&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="changes-to-session-step--loop"&gt;Changes to Session Step / Loop&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;runStepMAsync&lt;/code&gt; currently defers &lt;code&gt;RunAsync&lt;/code&gt; calls. We change it to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Classify calls.
&lt;/li&gt;
&lt;li&gt;Execute &lt;code&gt;RunSync&lt;/code&gt; calls inline.
&lt;/li&gt;
&lt;li&gt;Hand &lt;code&gt;RunAsync&lt;/code&gt; calls to the async engine.
&lt;/li&gt;
&lt;li&gt;If &lt;em&gt;all&lt;/em&gt; calls complete quickly, produce a normal &lt;code&gt;UserTurn&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Otherwise produce a &lt;code&gt;PartialUserTurn&lt;/code&gt; and yield.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a new agent configuration field:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ctxAsyncYieldStrategy ::&lt;/span&gt; &lt;span class="dt"&gt;AsyncYieldStrategy&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AsyncYieldStrategy&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;YieldOnAnyProgress&lt;/span&gt;       &lt;span class="co"&gt;-- yield as soon as one call finishes&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;YieldWhenAllDone&lt;/span&gt;         &lt;span class="co"&gt;-- DEFAULT: yield only once every synchronous and asynchronous call in the batch has reached a final state&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;YieldOnTimeout&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;       &lt;span class="co"&gt;-- yield after N milliseconds even if nothing finished&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The default is &lt;code&gt;YieldWhenAllDone&lt;/code&gt; for backward compatibility with the existing synchronous mental model.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On resume (&lt;code&gt;continuePartialTurn&lt;/code&gt;), the stepper checks the OS for calls that have completed since the last step and finalizes them. Any still-running calls remain in the &lt;code&gt;PartialUserTurn&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When the LLM invokes &lt;code&gt;get_tool_call_status&lt;/code&gt; and the call is still running, the stepper does not block the whole session; it returns the current snapshot. If the call completed, the result is copied back into the &lt;code&gt;TrackedToolCall&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="sub-conversations-and-lineage"&gt;Sub-Conversations and Lineage&lt;/h3&gt;
&lt;p&gt;Lineage remains important. Tool-call entities already carry &lt;code&gt;tcParentCallId&lt;/code&gt; for nested calls. Sub-conversations will eventually need richer primitives so that one conversation can ask another conversation for more information. The work described here is a prerequisite: once a tool-call result can be replaced by a later status update, the LLM can treat a long-running sub-conversation as an “interruptible” tool call. For now we keep the existing call-stack/lineage plumbing and ensure child tool-call entities are created with the correct parent reference.&lt;/p&gt;
&lt;h3 id="tui--oneshot-integration"&gt;TUI / OneShot Integration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The TUI already has a buffered-message queue and pause mechanism (&lt;code&gt;ConversationStatus_Paused&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;When a partial turn is yielded, the TUI should render running tool calls with a spinner/progress indicator.
&lt;/li&gt;
&lt;li&gt;The TUI event loop should listen for &lt;code&gt;AppEvent_ToolCallProgress&lt;/code&gt; events emitted by the async engine and refresh the conversation view.
&lt;/li&gt;
&lt;li&gt;OneShot mode should support a &lt;code&gt;--wait-for-async&lt;/code&gt; flag; without it, oneshot exits with a JSON description of pending calls and a continuation token.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="lifecycle-state-machine"&gt;Lifecycle State Machine&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Pending -&amp;gt; Executing -&amp;gt; Completed
        -&amp;gt; Executing -&amp;gt; Failed
        -&amp;gt; Executing -&amp;gt; Cancelled
        -&amp;gt; Deferred   -&amp;gt; Pending  (wake/resume)
        -&amp;gt; Deferred   -&amp;gt; Completed (external completion)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a session resumes after a process restart, any tool call referenced in the chat history that has no corresponding OS entity is reported as &lt;code&gt;orphaned&lt;/code&gt; by &lt;code&gt;get_tool_call_status&lt;/code&gt;. No in-progress call persistence is required; the LLM is responsible for deciding what to do with an orphaned call.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ready&lt;/code&gt; / &lt;code&gt;Running&lt;/code&gt; / &lt;code&gt;Deferred&lt;/code&gt; / &lt;code&gt;Completed&lt;/code&gt; / &lt;code&gt;Failed&lt;/code&gt; from &lt;code&gt;ToolCallState&lt;/code&gt; map cleanly to ECS &lt;code&gt;ToolCallStatus&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Session &lt;code&gt;ToolCallState&lt;/code&gt;&lt;/th&gt;&lt;th&gt;ECS &lt;code&gt;ToolCallStatus&lt;/code&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Ready&lt;/td&gt;&lt;td&gt;TcPending&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Running&lt;/td&gt;&lt;td&gt;TcExecuting&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Deferred&lt;/td&gt;&lt;td&gt;TcPending (with continuation token)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Completed&lt;/td&gt;&lt;td&gt;TcCompleted&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Failed&lt;/td&gt;&lt;td&gt;TcFailed&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Cancelled session calls become &lt;code&gt;TcCancelled&lt;/code&gt;. Missing OS entities become the &lt;code&gt;orphaned&lt;/code&gt; status in the capability response.&lt;/p&gt;
&lt;h3 id="new-modules--files"&gt;New Modules / Files&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Async.Engine&lt;/code&gt; — concurrent execution engine.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.OS.Conversation.ToolCalls&lt;/code&gt; — helpers to create/update/query tool-call entities.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Tools.SystemToolbox.ToolCallStatus&lt;/code&gt; — implementation of the new capabilities.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.TUI.Event.ToolCallProgress&lt;/code&gt; — TUI event handling for progress updates.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="modified-modules"&gt;Modified Modules&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.OS.Conversation.Types&lt;/code&gt; — add progress, session/conversation ids to tool-call components; add &lt;code&gt;TcCancelled&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Types&lt;/code&gt; — add &lt;code&gt;tcEntityId&lt;/code&gt; to &lt;code&gt;TrackedToolCall&lt;/code&gt;; add &lt;code&gt;AsyncYieldStrategy&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Step&lt;/code&gt; — integrate the async engine and partial-yield logic.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Loop&lt;/code&gt; — handle resume from partial turns with running background calls.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Async&lt;/code&gt; — reuse continuation store; add progress-related helpers.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Base&lt;/code&gt; — add new &lt;code&gt;SystemToolCapability&lt;/code&gt; constructors.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Tools.SystemToolbox.Core&lt;/code&gt; — register new capabilities.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Tools.SystemToolbox.Types&lt;/code&gt; — add query/error types for tool-call status.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.TUI.Types&lt;/code&gt; — add events for tool-call progress.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="implementation-phases"&gt;Implementation Phases&lt;/h3&gt;
&lt;h4 id="phase-1-ecs-tool-call-entities"&gt;Phase 1: ECS Tool-Call Entities&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Promote tool-call creation from session layer to OS layer.
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;tcEntityId&lt;/code&gt; to &lt;code&gt;TrackedToolCall&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Ensure every tool call in a session has a corresponding OS entity.
&lt;/li&gt;
&lt;li&gt;Write tests in &lt;code&gt;test/OS/ConversationTests.hs&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-2-async-engine"&gt;Phase 2: Async Engine&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Implement &lt;code&gt;AsyncEngine&lt;/code&gt; with background threads and progress callbacks.
&lt;/li&gt;
&lt;li&gt;Integrate engine into &lt;code&gt;runStepMAsync&lt;/code&gt; for &lt;code&gt;RunAsync&lt;/code&gt; calls.
&lt;/li&gt;
&lt;li&gt;Keep &lt;code&gt;RunSync&lt;/code&gt; behavior unchanged.
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;AsyncYieldStrategy&lt;/code&gt; with default &lt;code&gt;YieldWhenAllDone&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-3-system-capability"&gt;Phase 3: System Capability&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;SystemToolGetToolCallStatus&lt;/code&gt;, &lt;code&gt;SystemToolListRunningToolCalls&lt;/code&gt;, and &lt;code&gt;SystemToolCancelToolCall&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Implement lookup by &lt;code&gt;ToolCallId&lt;/code&gt; / entity id from the OS &lt;code&gt;World&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;wait_for_completion&lt;/code&gt; optional blocking.
&lt;/li&gt;
&lt;li&gt;Implement cancellation and the &lt;code&gt;orphaned&lt;/code&gt; status.
&lt;/li&gt;
&lt;li&gt;Expose capabilities in agent configs.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-4-tui--oneshot-ux"&gt;Phase 4: TUI / OneShot UX&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Render running calls and progress in the TUI.
&lt;/li&gt;
&lt;li&gt;Add progress events to the TUI event channel.
&lt;/li&gt;
&lt;li&gt;Add oneshot &lt;code&gt;--wait-for-async&lt;/code&gt; / continuation-token resume.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-5-cleanup--hardening"&gt;Phase 5: Cleanup &amp;amp; Hardening&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Cancellation on session abort.
&lt;/li&gt;
&lt;li&gt;Expiration of stale running calls.
&lt;/li&gt;
&lt;li&gt;Rate limiting / max concurrency enforcement.
&lt;/li&gt;
&lt;li&gt;Ensure orphaned status is returned consistently after process restart.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="open-questions"&gt;Open Questions&lt;/h3&gt;
&lt;p&gt;None remaining. Decisions from review:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Progress payloads are structured JSON.
&lt;/li&gt;
&lt;li&gt;Cancellation capability is included.
&lt;/li&gt;
&lt;li&gt;Lineage is preserved; sub-conversation primitives will be built later on top of interruptible tool calls.
&lt;/li&gt;
&lt;li&gt;In-progress calls are not persisted; missing OS entities are reported as &lt;code&gt;orphaned&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Default &lt;code&gt;AsyncYieldStrategy&lt;/code&gt; is &lt;code&gt;YieldWhenAllDone&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="success-criteria"&gt;Success Criteria&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[ ] Two long-running tool calls issued in one LLM turn execute concurrently.
&lt;/li&gt;
&lt;li&gt;[ ] The LLM receives a partial user turn as soon as the first call finishes (when &lt;code&gt;YieldOnAnyProgress&lt;/code&gt; is configured).
&lt;/li&gt;
&lt;li&gt;[ ] The LLM can call &lt;code&gt;get_tool_call_status&lt;/code&gt; for any call and see current structured progress or final result.
&lt;/li&gt;
&lt;li&gt;[ ] The LLM can call &lt;code&gt;cancel_tool_call&lt;/code&gt; to stop a running call.
&lt;/li&gt;
&lt;li&gt;[ ] Tool calls appear as ECS entities in the OS &lt;code&gt;World&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;[ ] Existing synchronous behavior is unchanged when &lt;code&gt;ExecutionMode = Synchronous&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;get_tool_call_status&lt;/code&gt; returns &lt;code&gt;orphaned&lt;/code&gt; for calls referenced in history that no longer exist.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-async-tool-calls.html" rel="alternate"/><summary type="text">Status: no status line yet</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-web-server-embedding.html</id><title type="text">Spec: embedding agents-exe in a web server</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/web-server-embedding.md"&gt;&lt;code&gt;todos/web-server-embedding.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="spec-embedding-agents-exe-in-a-web-server"&gt;Spec: embedding agents-exe in a web server&lt;/h2&gt;
&lt;p&gt;Status: proposed (2026-09-18)&lt;/p&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;
&lt;p&gt;Run agents from a long-lived HTTP server, with no TUI and no CLI, where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;every session lives in a database, not in &lt;code&gt;conv.&amp;lt;uuid&amp;gt;.json&lt;/code&gt; files;
&lt;/li&gt;
&lt;li&gt;a client can start a session, send follow-up messages, watch progress live,
list and complete deferred tool calls, resume, and cancel;
&lt;/li&gt;
&lt;li&gt;the server can restart at any time without losing or corrupting sessions.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The deliverable is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;a small library API in &lt;code&gt;agents-lib&lt;/code&gt; for hosting agents, with no HTTP
dependencies;
&lt;/li&gt;
&lt;li&gt;a reference HTTP server, &lt;code&gt;agents-server&lt;/code&gt;, built on that API.
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="non-goals-for-this-spec"&gt;Non-goals (for this spec)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Multi-tenancy: per-user isolation, per-user API keys, and sandboxing of bash
or MCP tools. The data model reserves an &lt;code&gt;owner&lt;/code&gt; column so this can come
later without a migration (see &lt;a href="#milestone-2-the-later-work"&gt;Milestone 2&lt;/a&gt;).
&lt;/li&gt;
&lt;li&gt;A Postgres backend. The interfaces below are designed so it can be added as
a separate backend.
&lt;/li&gt;
&lt;li&gt;Streaming LLM tokens. Clients get updates at step granularity.
&lt;/li&gt;
&lt;li&gt;Agent definitions stored in the database. Agents still come from JSON files
loaded at startup.
&lt;/li&gt;
&lt;li&gt;Splitting the library to drop the &lt;code&gt;brick&lt;/code&gt;/&lt;code&gt;vty&lt;/code&gt; dependencies.
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="current-state"&gt;Current state&lt;/h3&gt;
&lt;h4 id="what-we-can-reuse-as-is"&gt;What we can reuse as-is&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Piece&lt;/th&gt;&lt;th&gt;Where&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Loading the agent tree once, sharing it across concurrent runs&lt;/td&gt;&lt;td&gt;&lt;code&gt;AgentTree.withAgentTree&lt;/code&gt;; used by &lt;code&gt;MCP/Server.hs:127&lt;/code&gt; and &lt;code&gt;:222&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The MCP server already runs one &lt;code&gt;async&lt;/code&gt; per request over a shared tree.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Stepping a session&lt;/td&gt;&lt;td&gt;&lt;code&gt;Session.Step.runStepM&lt;/code&gt;, &lt;code&gt;Session.Loop.runUntilBlocked&lt;/code&gt; (&lt;code&gt;Loop.hs:105&lt;/code&gt;), &lt;code&gt;Session.Wake.resumeSession&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;runUntilBlocked&lt;/code&gt; returns the session when it waits only on deferred calls.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Injecting external results&lt;/td&gt;&lt;td&gt;&lt;code&gt;Session.Wake.wakeSession&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Pure load, modify, return.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Session storage interface&lt;/td&gt;&lt;td&gt;&lt;code&gt;SessionStore.SessionBackend&lt;/code&gt; (&lt;code&gt;SessionStore.hs:97&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;store / load / list / delete; file, SQLite, and composite versions.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Continuation index&lt;/td&gt;&lt;td&gt;&lt;code&gt;Session.Async.ContinuationStore&lt;/code&gt; (&lt;code&gt;Async.hs:248&lt;/code&gt;), SQLite table &lt;code&gt;tool_continuations&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Written by the scheduler (&lt;code&gt;Step.hs:490&lt;/code&gt;, &lt;code&gt;:728&lt;/code&gt;).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Declarative policy per agent&lt;/td&gt;&lt;td&gt;&lt;code&gt;toolCallPolicyConfig&lt;/code&gt;, &lt;code&gt;executionMode&lt;/code&gt;, etc.; applied by &lt;code&gt;Session.AgentConfig.applyAgentDurableConfig&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Progress hook&lt;/td&gt;&lt;td&gt;&lt;code&gt;Combinators.StoreSessionProgress.agentWithSessionProgress&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Fires &lt;code&gt;SessionUpdated&lt;/code&gt; before every step.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Restart handling for background calls&lt;/td&gt;&lt;td&gt;&lt;code&gt;Step.pollRunningCall&lt;/code&gt; (&lt;code&gt;Step.hs:505&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;A &lt;code&gt;Running&lt;/code&gt; call whose process is gone becomes &lt;code&gt;Failed&lt;/code&gt; ("orphaned").&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Background execution&lt;/td&gt;&lt;td&gt;&lt;code&gt;Session.Base.withAsyncEngine&lt;/code&gt;; on-demand World at &lt;code&gt;Step.hs:917&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Needs an OS &lt;code&gt;World&lt;/code&gt; plus an &lt;code&gt;AsyncEngine&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="gaps"&gt;Gaps&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;G1. A backend set on an agent after construction is ignored for progress
storage.&lt;/strong&gt; &lt;code&gt;OneShot.nodeToAgent&lt;/code&gt; wraps the agent with &lt;code&gt;agentStoreSession&lt;/code&gt;
while &lt;code&gt;ctxSessionBackend = Nothing&lt;/code&gt;. &lt;code&gt;agentStoreSession&lt;/code&gt;
(&lt;code&gt;StoreSessionProgress.hs:130&lt;/code&gt;) checks &lt;code&gt;ctxSessionBackend&lt;/code&gt; on the agent it
receives when it wraps, not at store time. So
&lt;code&gt;withSessionBackend backend =&amp;lt;&amp;lt; nodeToAgent …&lt;/code&gt; still writes every step to the
file store.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G2. Agent construction is copied three times&lt;/strong&gt; with small differences:
&lt;code&gt;OneShot.nodeToAgentWithThinking&lt;/code&gt; (&lt;code&gt;OneShot.hs:293&lt;/code&gt;),
&lt;code&gt;AgentTree.OneShotTool.nodeToAgent&lt;/code&gt; (&lt;code&gt;OneShotTool.hs:511&lt;/code&gt;, used for
sub-agents), and the MCP server (&lt;code&gt;MCP/Server.hs:~300&lt;/code&gt;). The one-shot copy also
prints thinking to stdout/stderr. Progressive-disclosure tool filtering
(&lt;code&gt;agentEvaluateActiveTools&lt;/code&gt;) is applied only on the one-shot path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G3. Sub-agent sessions always go to the file store.&lt;/strong&gt; &lt;code&gt;OneShotTool.nodeToAgent&lt;/code&gt;
takes the file &lt;code&gt;SessionStore&lt;/code&gt;, generates a fresh &lt;code&gt;ConversationId&lt;/code&gt;, and records
no link to the parent session.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G4. Session-reading tools and search read only the file store&lt;/strong&gt; (tools
fixed in Phase 3; the search index is CLI-only and stays on files). The
&lt;code&gt;SystemToolbox&lt;/code&gt; session tools (&lt;code&gt;Tools/SystemToolbox/Session.hs&lt;/code&gt;, via
&lt;code&gt;SessionIntrospectionConfig.introspectionStore&lt;/code&gt;) and the search index
(&lt;code&gt;Session/Search/Index.hs&lt;/code&gt;, via &lt;code&gt;indexSessionStore&lt;/code&gt;) call
&lt;code&gt;SessionStore.listSessions&lt;/code&gt; / &lt;code&gt;readSession&lt;/code&gt; directly. &lt;code&gt;Props.sessionStore&lt;/code&gt;
passes this down from &lt;code&gt;AgentTree&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G5. Sessions have two keys.&lt;/strong&gt; The file store is keyed by &lt;code&gt;ConversationId&lt;/code&gt;,
durable commands by &lt;code&gt;SessionId&lt;/code&gt;, and the two are generated separately
(&lt;code&gt;SessionDurable.hs&lt;/code&gt; &lt;code&gt;handleStart&lt;/code&gt;). &lt;code&gt;runOneShotWithConfig&lt;/code&gt; stores a paused
session under both.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G6. No concurrency control.&lt;/strong&gt; Every mutation is load, modify, store. Two
concurrent requests on one session (two &lt;code&gt;complete&lt;/code&gt; calls, or &lt;code&gt;complete&lt;/code&gt; during
a run) silently lose an update.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G7. Continuation table and sessions drift apart.&lt;/strong&gt; &lt;code&gt;wakeSession&lt;/code&gt; never calls
&lt;code&gt;csComplete&lt;/code&gt;, so &lt;code&gt;tool_continuations&lt;/code&gt; rows stay pending forever. Finding a
session from a token scans every session (&lt;code&gt;findSessionForToken&lt;/code&gt; in
&lt;code&gt;SessionDurable.hs&lt;/code&gt;) even though &lt;code&gt;tool_continuations.session_id&lt;/code&gt; already maps
it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G8. Background calls only live as long as one loop call.&lt;/strong&gt; The loops
create an engine on demand and shut it down on exit (&lt;code&gt;withEngineShutdown&lt;/code&gt;,
&lt;code&gt;Loop.hs:88&lt;/code&gt;). A server that pauses and resumes over several HTTP requests
needs a World and engine per live session that outlive a single request.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G9. No metadata beyond the JSON blob.&lt;/strong&gt; The &lt;code&gt;sessions&lt;/code&gt; table has only
&lt;code&gt;session_id&lt;/code&gt;, &lt;code&gt;created_at&lt;/code&gt;, &lt;code&gt;updated_at&lt;/code&gt;, &lt;code&gt;json&lt;/code&gt;. Listing sessions by agent or
status, or finding ones interrupted by a restart, means decoding every blob.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;G10. The prompt-to-first-turn code lives in the CLI.&lt;/strong&gt; &lt;code&gt;handleStart&lt;/code&gt; builds
the initial &lt;code&gt;UserTurn&lt;/code&gt; inside &lt;code&gt;CLI/SessionDurable.hs&lt;/code&gt;, so the library has no
reusable version.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="design"&gt;Design&lt;/h3&gt;
&lt;h4 id="overview"&gt;Overview&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;                 +-------------------------------------------+
  HTTP / SSE --&amp;gt; | agents-server (wai + warp)                |   examples/agents-server/
                 +---------------------+---------------------+
                                       |
                 +---------------------v---------------------+
                 | System.Agents.Host.Runner                 |   per-session lock, live runs,
                 |   SessionRunner                           |   events, cancellation, recovery
                 +---------+-------------------+-------------+
                           |                   |
        +------------------v-----+     +-------v----------------------+
        | System.Agents.Host     |     | SessionBackend (extended)    |
        |   Host, on top of      |     | ContinuationStore            |
        |   AgentFactory         |     | SQLite, one database file    |
        +------------------------+     +------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The library adds three modules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.AgentFactory&lt;/code&gt;: the single agent factory (done).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Host&lt;/code&gt;: loaded agents, database, and stores.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Host.Runner&lt;/code&gt;: session lifecycle on top of a &lt;code&gt;Host&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of them imports anything HTTP-related. The HTTP layer is a new executable.&lt;/p&gt;
&lt;h4 id="1-keys-one-id-per-session"&gt;1. Keys: one id per session&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt; a session’s &lt;code&gt;SessionId&lt;/code&gt; is its only key. Wherever a
&lt;code&gt;ConversationId&lt;/code&gt; is needed for the same session, it is
&lt;code&gt;sessionIdToConversationId sid&lt;/code&gt;. The Host API never generates a separate
&lt;code&gt;ConversationId&lt;/code&gt; for a session.&lt;/p&gt;
&lt;p&gt;Sub-agent sessions get their own &lt;code&gt;SessionId&lt;/code&gt; and record their parent (§3).&lt;/p&gt;
&lt;h4 id="2-the-agent-factory-and-the-host"&gt;2. The agent factory and the Host&lt;/h4&gt;
&lt;h5 id="21-systemagentsagentfactory-implemented-phases-12"&gt;2.1 &lt;code&gt;System.Agents.AgentFactory&lt;/code&gt; (implemented, Phases 1–2)&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentDeps&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentDeps&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; adApiKeys           ::&lt;/span&gt; &lt;span class="dt"&gt;LoadedApiKeys&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; adSessionSink       ::&lt;/span&gt; &lt;span class="dt"&gt;SessionSink&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; adContinuationStore ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ContinuationStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; adToolCache         ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ToolCache&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; adCompletion        ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;OSAgentNode&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Completion&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Replaces the LLM call (tests pass a mock).&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;defaultAgentDeps ::&lt;/span&gt; &lt;span class="dt"&gt;LoadedApiKeys&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AgentDeps&lt;/span&gt;               &lt;span class="co"&gt;-- SinkNone&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;fileAgentDeps    ::&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LoadedApiKeys&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AgentDeps&lt;/span&gt;  &lt;span class="co"&gt;-- SinkFiles&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentRole&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RootAgent&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SubAgent&lt;/span&gt; {&lt;span class="ot"&gt; subParentConversation ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;,&lt;span class="ot"&gt; subCallStack ::&lt;/span&gt; [&lt;span class="dt"&gt;CallStackEntry&lt;/span&gt;] }&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | The only way to turn an OSAgentNode into a runnable Agent.&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;buildAgent ::&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AgentDeps&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AgentRole&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OSAgentNode&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;           &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Agent&lt;/span&gt; (&lt;span class="dt"&gt;LlmTurnContent&lt;/span&gt;, &lt;span class="dt"&gt;Session&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;buildAgent&lt;/code&gt; takes a &lt;code&gt;ConversationId&lt;/code&gt;, not a &lt;code&gt;SessionId&lt;/code&gt;: the CLI and TUI key
their file store by conversation ID, and changing that is not part of this
work. Callers that follow the §1 rule pass &lt;code&gt;sessionIdToConversationId sid&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What &lt;code&gt;buildAgent&lt;/code&gt; does, in this order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Builds the base &lt;code&gt;Agent&lt;/code&gt; record: prompt, tools, &lt;code&gt;toolCall&lt;/code&gt;, &lt;code&gt;toolPortal&lt;/code&gt;,
and &lt;code&gt;complete&lt;/code&gt; (from &lt;code&gt;adCompletion&lt;/code&gt;, or else the agent’s OpenAI config).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Applies &lt;code&gt;applyAgentDurableConfig&lt;/code&gt; for the node’s JSON config, and installs
&lt;code&gt;adContinuationStore&lt;/code&gt;, &lt;code&gt;adToolCache&lt;/code&gt;, and (for &lt;code&gt;SinkBackend&lt;/code&gt;) the backend.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Applies &lt;code&gt;agentEvaluateActiveTools&lt;/code&gt; (progressive disclosure) to every agent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wraps the agent with &lt;code&gt;agentPersistSession adSessionSink convId&lt;/code&gt; &lt;strong&gt;last&lt;/strong&gt;
(fixes G1). &lt;code&gt;SessionSink&lt;/code&gt; lives in &lt;code&gt;Combinators.StoreSessionProgress&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionSink&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SinkBackend&lt;/span&gt; &lt;span class="dt"&gt;SessionBackend&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SinkFiles&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SinkNone&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;agentPersistSession ::&lt;/span&gt; &lt;span class="dt"&gt;SessionSink&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;agentStoreSession&lt;/code&gt; keeps its old behaviour for existing callers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Never writes to stdout or stderr. &lt;code&gt;OneShot.nodeToAgentWithThinking&lt;/code&gt; adds
the thinking printer, the media injection, and the extra &lt;code&gt;--session-file&lt;/code&gt;
copy as decorators on the result.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All front-ends use it: one-shot &lt;code&gt;run&lt;/code&gt; and the TUI (through
&lt;code&gt;OneShot.nodeToAgent&lt;/code&gt;), sub-agent tools, the MCP server, and the durable
&lt;code&gt;session&lt;/code&gt; commands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sub-agents:&lt;/strong&gt; &lt;code&gt;turnAgentRuntimeIntoIOTool&lt;/code&gt; takes an &lt;code&gt;AgentDeps&lt;/code&gt; instead of a
&lt;code&gt;SessionStore&lt;/code&gt; and API keys. It builds the sub-agent with
&lt;code&gt;SubAgent parentConvId stack&lt;/code&gt; and the same conversation ID it uses for the
call stack and the OS World entity. That ID now also names the stored
sub-session; it used to be an unrelated random ID. The parent link is kept at
runtime (&lt;code&gt;ctxParentConversation&lt;/code&gt;), and backends store it as
&lt;code&gt;parent_session_id&lt;/code&gt; (Phase 3).&lt;/p&gt;
&lt;h5 id="22-systemagentshost-implemented-phase-5"&gt;2.2 &lt;code&gt;System.Agents.Host&lt;/code&gt; (implemented, Phase 5)&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Host&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Host&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; hostAgents         ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;OSAgentNode&lt;/span&gt;   &lt;span class="co"&gt;-- root agents, by slug&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; hostDeps           ::&lt;/span&gt; &lt;span class="dt"&gt;AgentDeps&lt;/span&gt;              &lt;span class="co"&gt;-- root agents: SinkNone, the runner stores&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; hostSubAgentDeps   ::&lt;/span&gt; &lt;span class="dt"&gt;AgentDeps&lt;/span&gt;              &lt;span class="co"&gt;-- sub-agents: SinkBackend hostBackend&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; hostBackend        ::&lt;/span&gt; &lt;span class="dt"&gt;SessionBackend&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; hostContinuations  ::&lt;/span&gt; &lt;span class="dt"&gt;ContinuationStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; hostTracer         ::&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;HostTrace&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; hostLiveSessionTtl ::&lt;/span&gt; &lt;span class="dt"&gt;NominalDiffTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;HostConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;HostConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; hcAgentFiles ::&lt;/span&gt; [&lt;span class="dt"&gt;FilePath&lt;/span&gt;],&lt;span class="ot"&gt; hcApiKeysFile ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;,&lt;span class="ot"&gt; hcDatabasePath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; hcCompletion ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;OSAgentNode&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Completion&lt;/span&gt;),&lt;span class="ot"&gt; hcLiveSessionTtl ::&lt;/span&gt; &lt;span class="dt"&gt;NominalDiffTime&lt;/span&gt; }&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;defaultHostConfig ::&lt;/span&gt; [&lt;span class="dt"&gt;FilePath&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;HostConfig&lt;/span&gt;   &lt;span class="co"&gt;-- TTL 15 minutes&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withHost ::&lt;/span&gt; &lt;span class="dt"&gt;HostConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;HostTrace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;Host&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;withHost&lt;/code&gt; opens the database with &lt;code&gt;journal_mode = WAL&lt;/code&gt; and
&lt;code&gt;busy_timeout = 5000&lt;/code&gt;, runs the session and continuation migrations, loads
each agent file (sub-agent tools get &lt;code&gt;hostSubAgentDeps&lt;/code&gt;, and session tools a
&lt;code&gt;backendCatalog&lt;/code&gt;), and refuses duplicate root slugs (&lt;code&gt;HostError&lt;/code&gt;). Both
dependency sets share the continuation store and the completion override.
The bundled SQLite is built with &lt;code&gt;THREADSAFE=1&lt;/code&gt; (serialized), so one
connection is shared by all threads; no statement sequence relies on
&lt;code&gt;changes()&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="3-storage"&gt;3. Storage&lt;/h4&gt;
&lt;h5 id="31-extended-sessionbackend-implemented-phase-3"&gt;3.1 Extended &lt;code&gt;SessionBackend&lt;/code&gt; (implemented, Phase 3)&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;SessionStatus&lt;/code&gt;, &lt;code&gt;sessionStatusOf&lt;/code&gt;, &lt;code&gt;isBlockedOnDeferredCalls&lt;/code&gt;, and
&lt;code&gt;hasBackgroundCalls&lt;/code&gt; live in &lt;code&gt;Session.Types&lt;/code&gt; (pure, re-exported by
&lt;code&gt;Session.Base&lt;/code&gt;); the metadata types live in &lt;code&gt;SessionStore&lt;/code&gt;.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionStatus&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;StatusIdle&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StatusReady&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StatusRunning&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StatusWaitingExternal&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StatusFailed&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionLabels&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionLabels&lt;/span&gt;   &lt;span class="co"&gt;-- Nothing keeps the stored value&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; slAgent ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;,&lt;span class="ot"&gt; slParent ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;,&lt;span class="ot"&gt; slOwner ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; smSessionId    ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smAgent        ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smParent       ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smOwner        ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;          &lt;span class="co"&gt;-- reserved, unused for now&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smStatus       ::&lt;/span&gt; &lt;span class="dt"&gt;SessionStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smStatusDetail ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;          &lt;span class="co"&gt;-- why it failed&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smVersion      ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;                 &lt;span class="co"&gt;-- incremented on every write; 0 = never stored&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , smCreatedAt,&lt;span class="ot"&gt; smUpdatedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionQuery&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionQuery&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; sqAgent ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;,&lt;span class="ot"&gt; sqStatuses ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; [&lt;span class="dt"&gt;SessionStatus&lt;/span&gt;],&lt;span class="ot"&gt; sqParent ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sqUpdatedBefore ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;,&lt;span class="ot"&gt; sqLimit ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; }&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;VersionConflict&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;VersionConflict&lt;/span&gt; {&lt;span class="ot"&gt; vcSessionId ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;, vcExpected,&lt;span class="ot"&gt; vcActual ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; }&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionBackend&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionBackend&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; sbStore  ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()     &lt;span class="co"&gt;-- unconditional&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sbLoad   ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;)&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sbList   ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [(&lt;span class="dt"&gt;SessionId&lt;/span&gt;, &lt;span class="dt"&gt;UTCTime&lt;/span&gt;)]&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sbDelete ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sbStoreLabelled   ::&lt;/span&gt; &lt;span class="dt"&gt;SessionLabels&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sbLoadMeta        ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;Session&lt;/span&gt;, &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;))&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sbCompareAndStore ::&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;VersionConflict&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;)&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; sbQuery           ::&lt;/span&gt; &lt;span class="dt"&gt;SessionQuery&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [&lt;span class="dt"&gt;SessionMeta&lt;/span&gt;]&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Unconditional stores (&lt;code&gt;sbStore&lt;/code&gt;, &lt;code&gt;sbStoreLabelled&lt;/code&gt;) increment the version,
keep stored labels where the new ones are &lt;code&gt;Nothing&lt;/code&gt;, and set the status from
&lt;code&gt;sessionStatusOf&lt;/code&gt;, unless the stored status is &lt;code&gt;StatusRunning&lt;/code&gt;.
&lt;code&gt;sbCompareAndStore&lt;/code&gt; writes the given metadata exactly, only if the stored
version equals &lt;code&gt;smVersion&lt;/code&gt; (a missing session counts as 0).&lt;/p&gt;
&lt;p&gt;Backend implementations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQLite&lt;/strong&gt;: compare-and-store is one conditional statement
(&lt;code&gt;UPDATE … WHERE version = ? RETURNING …&lt;/code&gt;, or an upsert with
&lt;code&gt;DO UPDATE … WHERE sessions.version = 0&lt;/code&gt; for version 0), so it is atomic
without a lock. Rows from before the migration have version 0.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File&lt;/strong&gt;: metadata in a sidecar &lt;code&gt;meta.&amp;lt;uuid&amp;gt;.json&lt;/code&gt; (not &lt;code&gt;conv.*&lt;/code&gt;, so session
listings ignore it). A session file without a sidecar reads as version 0.
Compare-and-store is read-compare-write, not atomic across processes.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composite&lt;/strong&gt;: writes and queries go to the primary backend; loads fall
back in order.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;AgentFactory&lt;/code&gt; stores through &lt;code&gt;sbStoreLabelled&lt;/code&gt; with the agent’s slug and,
for sub-agents, the parent session. A sub-agent’s session ID is its
conversation ID, so its own sub-agents name it correctly as their parent.&lt;/p&gt;
&lt;h5 id="32-sqlite-schema-and-migrations-implemented-phase-3"&gt;3.2 SQLite schema and migrations (implemented, Phase 3)&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;SessionStore.runMigrations conn component migrations&lt;/code&gt; applies each
not-yet-applied &lt;code&gt;Migration&lt;/code&gt; in a transaction and records it in
&lt;code&gt;schema_migrations(component, version, applied_at)&lt;/code&gt;, so the continuation
store and tool cache can have their own migration lists later.
&lt;code&gt;initializeSessionSchema&lt;/code&gt; (called by &lt;code&gt;mkSqliteSessionStore&lt;/code&gt;) runs the
&lt;code&gt;sessions&lt;/code&gt; migrations:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- migration 1: the original table and index (CREATE IF NOT EXISTS)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- migration 2&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ALTER&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; sessions &lt;span class="kw"&gt;ADD&lt;/span&gt; &lt;span class="kw"&gt;COLUMN&lt;/span&gt; agent_slug TEXT;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ALTER&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; sessions &lt;span class="kw"&gt;ADD&lt;/span&gt; &lt;span class="kw"&gt;COLUMN&lt;/span&gt; parent_session_id TEXT;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ALTER&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; sessions &lt;span class="kw"&gt;ADD&lt;/span&gt; &lt;span class="kw"&gt;COLUMN&lt;/span&gt; owner TEXT;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ALTER&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; sessions &lt;span class="kw"&gt;ADD&lt;/span&gt; &lt;span class="kw"&gt;COLUMN&lt;/span&gt; status TEXT &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt; &lt;span class="kw"&gt;DEFAULT&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;ready&amp;#39;&lt;/span&gt;;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ALTER&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; sessions &lt;span class="kw"&gt;ADD&lt;/span&gt; &lt;span class="kw"&gt;COLUMN&lt;/span&gt; status_detail TEXT;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ALTER&lt;/span&gt; &lt;span class="kw"&gt;TABLE&lt;/span&gt; sessions &lt;span class="kw"&gt;ADD&lt;/span&gt; &lt;span class="kw"&gt;COLUMN&lt;/span&gt; version &lt;span class="dt"&gt;INTEGER&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt; &lt;span class="kw"&gt;DEFAULT&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; &lt;span class="kw"&gt;INDEX&lt;/span&gt; &lt;span class="cf"&gt;IF&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;EXISTS&lt;/span&gt; idx_sessions_status &lt;span class="kw"&gt;ON&lt;/span&gt; sessions(status, updated_at);&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;CREATE&lt;/span&gt; &lt;span class="kw"&gt;INDEX&lt;/span&gt; &lt;span class="cf"&gt;IF&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;EXISTS&lt;/span&gt; idx_sessions_parent &lt;span class="kw"&gt;ON&lt;/span&gt; sessions(parent_session_id);&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- then each existing row&amp;#39;s status is derived from its JSON&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;tool_continuations(session_id, completed_at)&lt;/code&gt; index belongs to the
continuation store’s migrations (Phase 4). Connection settings
(&lt;code&gt;journal_mode=WAL&lt;/code&gt;, &lt;code&gt;busy_timeout&lt;/code&gt;) are set by &lt;code&gt;withHost&lt;/code&gt;
when it opens the database (Phase 5), not by the library backends, which
work on connections their callers own.&lt;/p&gt;
&lt;h5 id="33-reading-sessions-from-tools-g4-implemented-phase-3"&gt;3.3 Reading sessions from tools (G4, implemented, Phase 3)&lt;/h5&gt;
&lt;p&gt;A read-only interface both stores implement:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;CatalogEntry&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;CatalogEntry&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; ceConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;,&lt;span class="ot"&gt; ceUpdatedAt ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ceSession ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;   &lt;span class="co"&gt;-- Nothing when unreadable (locked file)&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ceBusy ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; }             &lt;span class="co"&gt;-- locked file, or status running&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionCatalog&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionCatalog&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; catList ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [&lt;span class="dt"&gt;CatalogEntry&lt;/span&gt;],&lt;span class="ot"&gt; catRead ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;) }&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;fileCatalog    ::&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionCatalog&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;backendCatalog ::&lt;/span&gt; &lt;span class="dt"&gt;SessionBackend&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionCatalog&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Entries are keyed by conversation ID, the vocabulary of the session tools
(and the same UUID as the session ID in a backend).
&lt;code&gt;SessionIntrospectionConfig.introspectionCatalog&lt;/code&gt; and
&lt;code&gt;AgentTree.Props.sessionCatalog&lt;/code&gt; take a catalog; the CLI and TUI pass
&lt;code&gt;fileCatalog store&lt;/code&gt;, and the Host will pass &lt;code&gt;backendCatalog&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The search index (&lt;code&gt;Session/Search&lt;/code&gt;) stays on the file &lt;code&gt;SessionStore&lt;/code&gt;: only
the &lt;code&gt;session-index&lt;/code&gt; and &lt;code&gt;session-search&lt;/code&gt; CLI commands use it, and it is built
around file paths and modification times.&lt;/p&gt;
&lt;h5 id="34-continuations-stay-consistent-g7-implemented-phase-4"&gt;3.4 Continuations stay consistent (G7, implemented, Phase 4)&lt;/h5&gt;
&lt;p&gt;The session JSON is the source of truth. &lt;code&gt;tool_continuations&lt;/code&gt; is an index
from token to session.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ContinuationStore.csFindSession :: ContinuationToken -&amp;gt; IO (Maybe SessionId)&lt;/code&gt;
answers for pending and completed tokens (&lt;code&gt;csLoad&lt;/code&gt; only returns pending
ones, so it cannot tell a completed token from an unknown one).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Session.Wake.wakeSessionWith :: Maybe ContinuationStore -&amp;gt; Maybe ToolCache -&amp;gt; Session -&amp;gt; [(ContinuationToken, UserToolResponse)] -&amp;gt; IO WakeOutcome&lt;/code&gt;
reports, per token, whether it was applied, already completed, or unknown,
and calls &lt;code&gt;csComplete&lt;/code&gt; for the applied ones. A token is already completed
when a call of the session still carries it but is no longer deferred, or
when the store knows it for this session (once a turn is complete, the
session no longer holds its tokens). &lt;code&gt;wakeSession&lt;/code&gt; and
&lt;code&gt;wakeSessionWithCache&lt;/code&gt; are wrappers returning the session.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Session.Wake.findSessionForToken :: Maybe ContinuationStore -&amp;gt; SessionBackend -&amp;gt; ContinuationToken -&amp;gt; IO (Maybe SessionId)&lt;/code&gt;
asks &lt;code&gt;csFindSession&lt;/code&gt; first and scans the backend’s sessions only for tokens
the store does not know.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;csComplete&lt;/code&gt; uses &lt;code&gt;UPDATE … RETURNING&lt;/code&gt; instead of &lt;code&gt;SELECT changes()&lt;/code&gt;, which
another user of the same connection could change in between.
&lt;/li&gt;
&lt;li&gt;The continuation table’s schema goes through &lt;code&gt;runMigrations&lt;/code&gt; (component
&lt;code&gt;continuations&lt;/code&gt;); migration 2 adds the &lt;code&gt;(session_id, completed_at)&lt;/code&gt; index.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The CLI &lt;code&gt;complete&lt;/code&gt; command keeps its scan over the file store: CLI agents
have no continuation store. The runner (§4.3) uses &lt;code&gt;findSessionForToken&lt;/code&gt; and
&lt;code&gt;wakeSessionWith&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Agents store their session before each step, so the session a run stops in
is not stored by the agent: callers store it (the session commands and
one-shot &lt;code&gt;run&lt;/code&gt; do; the runner stores after every step, §4.2).&lt;/p&gt;
&lt;h4 id="4-systemagentshostrunner-session-lifecycle-implemented-phase-5"&gt;4. &lt;code&gt;System.Agents.Host.Runner&lt;/code&gt;: session lifecycle (implemented, Phase 5)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt;  &lt;span class="co"&gt;-- opaque&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;newSessionRunner      ::&lt;/span&gt; &lt;span class="dt"&gt;Host&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;shutdownSessionRunner ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()   &lt;span class="co"&gt;-- cancels active runs, stores their sessions&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withSessionRunner     ::&lt;/span&gt; &lt;span class="dt"&gt;Host&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; a&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;runnerStats           ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;RunnerStats&lt;/span&gt;   &lt;span class="co"&gt;-- live sessions, active runs&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;RunMode&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;StepOnce&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;UntilBlocked&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;createSession ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;NewMessage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;RunMode&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;postMessage   ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;NewMessage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;RunMode&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;)&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;resume        ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;RunMode&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;)&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;completeCall  ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ContinuationToken&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="co"&gt;{- auto-resume -}&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;)&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;cancelRun     ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;)&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getSession    ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;Session&lt;/span&gt;, &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;))&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;awaitRun      ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;NominalDiffTime&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt; (&lt;span class="dt"&gt;SessionMeta&lt;/span&gt;, &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="co"&gt;{- run still active -}&lt;/span&gt;))&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;deleteSession ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;DeleteMode&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt; &lt;span class="dt"&gt;DeletionPlan&lt;/span&gt;)&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;subscribe     ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;SessionEvent&lt;/span&gt;)   &lt;span class="co"&gt;-- blocking &amp;quot;next event&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;recoverOnStartup ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [&lt;span class="dt"&gt;SessionId&lt;/span&gt;]&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;NewMessage&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;NewMessage&lt;/span&gt; {&lt;span class="ot"&gt; nmText ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;,&lt;span class="ot"&gt; nmMedia ::&lt;/span&gt; [&lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;] }&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;DeleteMode&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;DryRun&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeleteForReal&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;DeletionPlan&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;DeletionPlan&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; dpSessions      ::&lt;/span&gt; [&lt;span class="dt"&gt;SessionId&lt;/span&gt;]   &lt;span class="co"&gt;-- ^ the session and all descendants, deepest first&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; dpContinuations ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;           &lt;span class="co"&gt;-- ^ continuation rows removed (or that would be)&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; dpDryRun        ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UnknownAgent&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;UnknownSession&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;UnknownToken&lt;/span&gt; &lt;span class="dt"&gt;ContinuationToken&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TokenAlreadyCompleted&lt;/span&gt; &lt;span class="dt"&gt;ContinuationToken&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;RunInProgress&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;          &lt;span class="co"&gt;-- ^ a run owns the session (on delete: one of the tree, or an ancestor)&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;NoActiveRun&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;            &lt;span class="co"&gt;-- ^ cancel without a run (HTTP 409 no_active_run)&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;NotAcceptingMessages&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;SessionStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Conflict&lt;/span&gt; &lt;span class="dt"&gt;VersionConflict&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Agents built by the runner always run asynchronously
(&lt;code&gt;withExecutionMode Asynchronous&lt;/code&gt;), like the CLI &lt;code&gt;session&lt;/code&gt; commands, so that
runs can stop and resume.&lt;/p&gt;
&lt;h5 id="41-per-session-state"&gt;4.1 Per-session state&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;LiveSession&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;LiveSession&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; lsLock        ::&lt;/span&gt; &lt;span class="dt"&gt;MVar&lt;/span&gt; ()                          &lt;span class="co"&gt;-- serialises every change&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; lsRun         ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;Async&lt;/span&gt; ()))          &lt;span class="co"&gt;-- the active run, if any&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; lsAgent       ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;Agent&lt;/span&gt; …))           &lt;span class="co"&gt;-- kept between runs (G8)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; lsLatest      ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;Session&lt;/span&gt;, &lt;span class="dt"&gt;SessionMeta&lt;/span&gt;))  &lt;span class="co"&gt;-- last version stored or loaded&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; lsInbox       ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; [(&lt;span class="dt"&gt;ContinuationToken&lt;/span&gt;, &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;)]  &lt;span class="co"&gt;-- see 4.3&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; lsLastTouched ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; lsEvicted     ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- held in: TVar (Map SessionId LiveSession)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The runner creates a &lt;code&gt;LiveSession&lt;/code&gt; on first access. A reaper thread (every
half TTL, between 50 ms and 60 s) evicts sessions idle for longer than
&lt;code&gt;hostLiveSessionTtl&lt;/code&gt; that have no active run and no &lt;code&gt;Running&lt;/code&gt; call, and
shuts their engine down. An operation that took a &lt;code&gt;LiveSession&lt;/code&gt; just before
it was evicted notices &lt;code&gt;lsEvicted&lt;/code&gt; once it holds the lock, and retries with
a fresh one.
&lt;/li&gt;
&lt;li&gt;The first run of a session builds its agent with &lt;code&gt;buildAgent&lt;/code&gt; and keeps it
in &lt;code&gt;lsAgent&lt;/code&gt;. &lt;code&gt;runStepM&lt;/code&gt; installs a World and an engine on demand and
returns the agent holding them; the runner keeps that agent, so the engine
survives between runs. The runner has its own loop over &lt;code&gt;runStepM&lt;/code&gt;, with
the stop conditions of &lt;code&gt;runUntilBlocked&lt;/code&gt;, and shuts the engine down only on
cancel, eviction, deletion, or runner shutdown.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Running&lt;/code&gt; calls whose engine was lost (restart or eviction) are resolved as
orphaned by &lt;code&gt;pollRunningCall&lt;/code&gt; on the next step. No new code is needed.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="42-mutation-protocol"&gt;4.2 Mutation protocol&lt;/h5&gt;
&lt;p&gt;Every operation that changes a session:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Takes &lt;code&gt;lsLock&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;If a run is active and the operation is not &lt;code&gt;cancelRun&lt;/code&gt;, returns
&lt;code&gt;RunInProgress&lt;/code&gt;. &lt;code&gt;completeCall&lt;/code&gt; is the exception: see 4.3.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sbLoadMeta&lt;/code&gt;, then applies the change (&lt;code&gt;wakeSessionWith&lt;/code&gt;, or pushes a
&lt;code&gt;UserTurn&lt;/code&gt;), then &lt;code&gt;sbCompareAndStore&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Emits a &lt;code&gt;SessionEvent&lt;/code&gt;, then releases the lock.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A run takes the lock for each step’s store, not for the whole run. Inside the
run loop each step: &lt;code&gt;runStepM&lt;/code&gt;, then &lt;code&gt;sbCompareAndStore&lt;/code&gt; under &lt;code&gt;lsLock&lt;/code&gt;, then
emit &lt;code&gt;session.updated&lt;/code&gt;. A &lt;code&gt;VersionConflict&lt;/code&gt; inside a run stops it with
&lt;code&gt;StatusFailed&lt;/code&gt; with detail “concurrent modification”. That cannot happen with a single
server process; it guards against a second process or the CLI writing to the
same database.&lt;/p&gt;
&lt;p&gt;The runner sets &lt;code&gt;status = running&lt;/code&gt; when a run starts and &lt;code&gt;sessionStatusOf s&lt;/code&gt;
when it ends. On an exception it sets &lt;code&gt;StatusFailed&lt;/code&gt; with &lt;code&gt;displayException e&lt;/code&gt; as detail.
Progress storage installed by &lt;code&gt;buildAgent&lt;/code&gt; (§2.5) is &lt;strong&gt;disabled&lt;/strong&gt; for
runner-built agents (&lt;code&gt;SinkNone&lt;/code&gt;),
because the runner does the versioned stores itself.&lt;/p&gt;
&lt;h5 id="43-completing-a-deferred-call-during-a-run"&gt;4.3 Completing a deferred call during a run&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;runUntilBlocked&lt;/code&gt; only stops once nothing can progress in-process, so an
active run and a pending deferred call can coexist. For example, a deferred
call waits while a background call is still running.&lt;/p&gt;
&lt;p&gt;Writing the woken session while the run is in a step would make the run’s
next versioned store conflict. So &lt;code&gt;completeCall&lt;/code&gt; on a session with an active
run, under the lock:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;checks the token against the run’s latest version (and the queue), and
answers &lt;code&gt;UnknownToken&lt;/code&gt; or &lt;code&gt;TokenAlreadyCompleted&lt;/code&gt; right away;
&lt;/li&gt;
&lt;li&gt;otherwise appends the result to &lt;code&gt;lsInbox&lt;/code&gt; and returns.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before each step and before deciding to stop, the run, under the lock,
applies the queued results with &lt;code&gt;wakeSessionWith&lt;/code&gt; (which also marks the
continuations completed) and stores the result. A run that was about to
stop on deferred calls therefore carries on when their results are queued.
&lt;code&gt;cancelRun&lt;/code&gt; applies the queue too.&lt;/p&gt;
&lt;p&gt;Without an active run, &lt;code&gt;completeCall&lt;/code&gt; applies the result and stores it at
once, and with auto-resume starts an &lt;code&gt;UntilBlocked&lt;/code&gt; run when the session is
&lt;code&gt;ready&lt;/code&gt;. Two concurrent completions of one turn are serialised by the lock:
the first stores, the second sees the first’s version (tested).&lt;/p&gt;
&lt;h5 id="44-follow-up-messages"&gt;4.4 Follow-up messages&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;postMessage&lt;/code&gt; is valid only when the status is &lt;code&gt;StatusIdle&lt;/code&gt; (head is a final
&lt;code&gt;LlmTurn&lt;/code&gt;). It pushes&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;UserTurn&lt;/span&gt; (&lt;span class="dt"&gt;UserTurnContent&lt;/span&gt; sysPrompt sysTools (&lt;span class="dt"&gt;Just&lt;/span&gt; (&lt;span class="dt"&gt;UserQuery&lt;/span&gt; text media)) []) &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;onto &lt;code&gt;turns&lt;/code&gt; (newest first, as &lt;code&gt;handleStart&lt;/code&gt; does), taking &lt;code&gt;sysPrompt&lt;/code&gt; and
&lt;code&gt;sysTools&lt;/code&gt; from the live agent. &lt;code&gt;naiveTilNoToolCallStep&lt;/code&gt; then sends it to the
LLM on the next step (&lt;code&gt;Step.hs:1081&lt;/code&gt;). Agents built by the runner keep
&lt;code&gt;usrQuery = pure Nothing&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The code that builds the first turn from a prompt moves out of
&lt;code&gt;CLI/SessionDurable.handleStart&lt;/code&gt; into
&lt;code&gt;Session.Types.newSessionFromPrompt :: SystemPrompt -&amp;gt; [SystemTool] -&amp;gt; NewMessage -&amp;gt; IO Session&lt;/code&gt;
(fixes G10). &lt;code&gt;createSession&lt;/code&gt; and &lt;code&gt;handleStart&lt;/code&gt; both use it.&lt;/p&gt;
&lt;h5 id="45-events"&gt;4.5 Events&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionEvent&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunStarted&lt;/span&gt;   &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;RunMode&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionUpdated&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt; &lt;span class="dt"&gt;Turn&lt;/span&gt;   &lt;span class="co"&gt;-- ^ the new head turn&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;CallsDeferred&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; [&lt;span class="dt"&gt;DeferredCallView&lt;/span&gt;]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;RunStopped&lt;/span&gt;   &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;SessionStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionFailed&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;DeferredCallView&lt;/code&gt; is the same data &lt;code&gt;agents-exe session pending&lt;/code&gt; prints: tool
name, call id, token, disposition, and the call with its arguments. It lives
in &lt;code&gt;Session.Types&lt;/code&gt; with &lt;code&gt;pendingDeferredCalls :: Session -&amp;gt; [DeferredCallView]&lt;/code&gt;;
the CLI’s &lt;code&gt;extractDeferredCalls&lt;/code&gt; wraps it.&lt;/p&gt;
&lt;p&gt;Every stored version emits &lt;code&gt;SessionUpdated&lt;/code&gt; (with the head turn), including
the stores at the start and end of a run. Events go through one runner-wide
broadcast channel: &lt;code&gt;subscribe&lt;/code&gt; returns an action yielding the next event of
one session, so a subscriber keeps its stream when the session is evicted
and loaded again. &lt;code&gt;subscribeSTM&lt;/code&gt; gives the same stream as a transaction that
consumes one event of any session and yields &lt;code&gt;Nothing&lt;/code&gt; for another session’s,
to combine with timers or flags (the HTTP events stream uses it). Filtering
must consume other sessions’ events one transaction at a time: a &lt;code&gt;retry&lt;/code&gt;
after &lt;code&gt;readTChan&lt;/code&gt; rolls the read back, which in the first version of
&lt;code&gt;subscribe&lt;/code&gt; blocked a subscriber for good on another session’s event. Each
event is also traced as &lt;code&gt;HostRunnerTrace kind sid&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id="46-startup-recovery"&gt;4.6 Startup recovery&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;recoverOnStartup&lt;/code&gt; queries &lt;code&gt;status = running&lt;/code&gt;. For each session found that
this runner is not running itself:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Load it.
&lt;/li&gt;
&lt;li&gt;Set its status to &lt;code&gt;sessionStatusOf s&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Emit nothing, since no subscribers exist yet.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; resume automatically. Rows left &lt;code&gt;running&lt;/code&gt; mean the process
died mid-step. The partially started step is lost, and any &lt;code&gt;Running&lt;/code&gt; calls
become orphaned on the next resume. The server logs how many sessions it
recovered. Automatic resume can be added later as &lt;code&gt;--resume-interrupted&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id="47-cancellation"&gt;4.7 Cancellation&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;cancelRun&lt;/code&gt; cancels the run’s &lt;code&gt;Async&lt;/code&gt; without holding the lock (the run takes
it to store its steps), then, under the lock and only if that run still
owns the session:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;shuts the engine down, which marks background calls cancelled in the
World, and keeps the agent (and World) with no engine, so the next run
gets a fresh engine on the same World;
&lt;/li&gt;
&lt;li&gt;applies queued external results;
&lt;/li&gt;
&lt;li&gt;refreshes the head partial turn from the World, so its cancelled calls
become &lt;code&gt;Failed &amp;quot;async tool call was cancelled&amp;quot;&lt;/code&gt;;
&lt;/li&gt;
&lt;li&gt;stores the session with the status its turns imply, and emits
&lt;code&gt;RunStopped&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Background calls below the head (the LLM already got a placeholder for them)
stay &lt;code&gt;Running&lt;/code&gt; in the stored session. The next run’s late-result collection
finds them cancelled in the kept World and tells the LLM, in a user message,
as for any late result (tested). If the session is evicted first, they are
reported as orphaned instead. Sub-agent runs execute inside the parent’s
tool call, so cancelling the parent cancels them.&lt;/p&gt;
&lt;h5 id="48-waiting-for-a-run"&gt;4.8 Waiting for a run&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;awaitRun&lt;/code&gt; blocks until the session’s active run stops or the timeout
expires, whichever comes first. It returns the current meta and whether a run
is still active. With no active run it returns at once. It watches
&lt;code&gt;lsRun&lt;/code&gt; (STM &lt;code&gt;waitCatch&lt;/code&gt; on the &lt;code&gt;Async&lt;/code&gt;, raced against a timer), so waiting
never holds &lt;code&gt;lsLock&lt;/code&gt;. A waiter going away (for example an HTTP client
disconnecting) never cancels the run.&lt;/p&gt;
&lt;h5 id="49-deleting-sessions"&gt;4.9 Deleting sessions&lt;/h5&gt;
&lt;p&gt;Deletion always cascades: a session goes together with every descendant
(sub-agent sessions, found recursively through &lt;code&gt;sbQuery&lt;/code&gt; on &lt;code&gt;parent&lt;/code&gt;) and
their continuation rows. &lt;code&gt;deleteSession&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Collects the tree and builds a &lt;code&gt;DeletionPlan&lt;/code&gt;, deepest sessions first.
&lt;/li&gt;
&lt;li&gt;Returns &lt;code&gt;RunInProgress&lt;/code&gt; if any session in the tree has an active run. This
applies in both modes, so a dry run shows whether the real delete would
succeed.
&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;DryRun&lt;/code&gt;, returns the plan and changes nothing.
&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;DeleteForReal&lt;/code&gt;, walks the plan in order. For each session it takes
that session’s &lt;code&gt;lsLock&lt;/code&gt;, deletes its continuation rows, calls &lt;code&gt;sbDelete&lt;/code&gt;,
drops its &lt;code&gt;LiveSession&lt;/code&gt; (shutting down its engine), and releases the lock.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Deleting leaves first means a crash part-way through never leaves a
sub-session whose parent is gone; running the delete again finishes the job.
This needs two new &lt;code&gt;ContinuationStore&lt;/code&gt; fields:
&lt;code&gt;csCountSession :: SessionId -&amp;gt; IO Int&lt;/code&gt; for dry runs, and
&lt;code&gt;csDeleteSession :: SessionId -&amp;gt; IO Int&lt;/code&gt;, which deletes every row of a session
(pending or completed) and returns the count. Deletion is also refused while
an &lt;em&gt;ancestor&lt;/em&gt; of the session has an active run: its sub-agent calls write
into the tree, and would recreate what was deleted. The runner does the cascade,
not SQL foreign keys, so the file backend behaves the same.&lt;/p&gt;
&lt;h4 id="5-http-api-agents-server-implemented-phase-6"&gt;5. HTTP API (&lt;code&gt;agents-server&lt;/code&gt;) (implemented, Phase 6)&lt;/h4&gt;
&lt;p&gt;The server lives in &lt;code&gt;examples/agents-server/&lt;/code&gt;, on &lt;code&gt;wai&lt;/code&gt; and &lt;code&gt;warp&lt;/code&gt;. The
application code is a private sub-library, &lt;code&gt;agents-server-internal&lt;/code&gt;
(&lt;code&gt;AgentsServer.Api&lt;/code&gt;, &lt;code&gt;AgentsServer.Log&lt;/code&gt;, &lt;code&gt;AgentsServer.Server&lt;/code&gt;), shared by the
&lt;code&gt;agents-server&lt;/code&gt; executable and its &lt;code&gt;agents-server-tests&lt;/code&gt; suite; &lt;code&gt;agents-lib&lt;/code&gt;
does not depend on wai or warp. SSE is written by hand with &lt;code&gt;responseStream&lt;/code&gt;
(no &lt;code&gt;wai-extra&lt;/code&gt;). All bodies are JSON. Session objects embed the raw
&lt;code&gt;Session&lt;/code&gt; JSON that is already stored, so clients can reuse &lt;code&gt;session-print&lt;/code&gt;
logic. The user guide is &lt;code&gt;documentation/agents-server.md&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;agents-server --agent-file a.json [--agent-file b.json …] --api-keys keys.json \
              [--db ./agents-server.db] [--port 8080] [--bind 127.0.0.1] \
              [--live-session-ttl 900] [--shutdown-grace 10]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The server binds to &lt;code&gt;127.0.0.1&lt;/code&gt; by default. There is no authentication in
milestone 1 (see non-goals); the &lt;code&gt;server.started&lt;/code&gt; log line says so.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Method &amp;amp; path&lt;/th&gt;&lt;th&gt;Body&lt;/th&gt;&lt;th&gt;Success&lt;/th&gt;&lt;th&gt;Errors&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/agents&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 [{slug, description, tools:[name]}]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions?wait=&amp;amp;timeout=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{agent, prompt, media?:[{mime, base64, filename?}], run?: "none"\|"step"\|"until_blocked"}&lt;/code&gt; (default &lt;code&gt;until_blocked&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;code&gt;201 SessionView&lt;/code&gt;, &lt;code&gt;Location&lt;/code&gt; header&lt;/td&gt;&lt;td&gt;404 &lt;code&gt;unknown_agent&lt;/code&gt;, 400 &lt;code&gt;bad_request&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions?agent=&amp;amp;status=&amp;amp;parent=&amp;amp;limit=&amp;amp;before=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {sessions:[SessionMetaView], next_before}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;400&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions/:id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 SessionView&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404 &lt;code&gt;unknown_session&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/messages?wait=&amp;amp;timeout=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{prompt, media?, run?}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;202&lt;/code&gt;/&lt;code&gt;200 SessionView&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404, 409 &lt;code&gt;run_in_progress&lt;/code&gt;, 409 &lt;code&gt;not_accepting_messages&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/resume?wait=&amp;amp;timeout=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{mode?: "step"\|"until_blocked"}&lt;/code&gt; or no body&lt;/td&gt;&lt;td&gt;&lt;code&gt;202&lt;/code&gt;/&lt;code&gt;200 SessionView&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404, 409 &lt;code&gt;run_in_progress&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/cancel&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 SessionMetaView&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404, 409 &lt;code&gt;no_active_run&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions/:id/pending&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {calls:[DeferredCallView]}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/continuations/:token?wait=&amp;amp;timeout=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{result: UserToolResponse \| string, resume?: bool}&lt;/code&gt; (default &lt;code&gt;true&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;code&gt;202&lt;/code&gt;/&lt;code&gt;200 SessionView&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404 &lt;code&gt;unknown_token&lt;/code&gt;, 409 &lt;code&gt;token_already_completed&lt;/code&gt;, 409 &lt;code&gt;conflict&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions/:id/events&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 text/event-stream&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;DELETE /v1/sessions/:id?dry_run=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {sessions:[id], continuations, dry_run}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404, 409 &lt;code&gt;run_in_progress&lt;/code&gt; (also for a dry run, when the real delete would fail)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /healthz&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {ok:true, live_sessions, active_runs}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Other errors: 404 &lt;code&gt;not_found&lt;/code&gt; (unknown path), 405 &lt;code&gt;method_not_allowed&lt;/code&gt;, 413
&lt;code&gt;payload_too_large&lt;/code&gt; (bodies over 32 MiB), 500 &lt;code&gt;internal_error&lt;/code&gt;. A malformed
session id answers 404 &lt;code&gt;unknown_session&lt;/code&gt;, a malformed token 404
&lt;code&gt;unknown_token&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SessionMetaView&lt;/code&gt; is the &lt;code&gt;SessionMeta&lt;/code&gt; JSON: &lt;code&gt;{session_id, agent, parent_session_id, owner, status, status_detail, version, created_at, updated_at}&lt;/code&gt; (&lt;code&gt;owner&lt;/code&gt; is always null in milestone 1).
&lt;code&gt;SessionView&lt;/code&gt; = &lt;code&gt;SessionMetaView&lt;/code&gt; + &lt;code&gt;{session: &amp;lt;Session JSON&amp;gt;, pending: [DeferredCallView]}&lt;/code&gt;.
Errors are &lt;code&gt;{error: &amp;quot;&amp;lt;code&amp;gt;&amp;quot;, message: &amp;quot;&amp;lt;text&amp;gt;&amp;quot;}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Listing.&lt;/strong&gt; Newest first by &lt;code&gt;updated_at&lt;/code&gt;. &lt;code&gt;status&lt;/code&gt; takes a comma-separated
list; &lt;code&gt;limit&lt;/code&gt; is 1–500, default 50. When a page is full, &lt;code&gt;next_before&lt;/code&gt; is the
&lt;code&gt;updated_at&lt;/code&gt; of its last session, used as &lt;code&gt;before=&lt;/code&gt; (strictly older) for the
next page. A session with exactly the boundary’s &lt;code&gt;updated_at&lt;/code&gt; would be
skipped; timestamps have nanosecond precision, so that takes two writes in
the same instant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Waiting.&lt;/strong&gt; Every endpoint that can start a run (create, messages, resume,
continuations) takes the same two query parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wait=true|false&lt;/code&gt;, default &lt;code&gt;false&lt;/code&gt; (&lt;code&gt;?wait&lt;/code&gt; alone means true). With
&lt;code&gt;false&lt;/code&gt;, the server answers as soon as the run has started. With &lt;code&gt;true&lt;/code&gt;, it
answers when the run stops (idle, blocked on deferred calls, or failed),
using &lt;code&gt;awaitRun&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timeout=&amp;lt;seconds&amp;gt;&lt;/code&gt;, only used with &lt;code&gt;wait=true&lt;/code&gt;. Default 120, maximum 600;
larger values are clamped. If it expires, the server answers with the
current state (&lt;code&gt;status: &amp;quot;running&amp;quot;&lt;/code&gt;) and the run carries on. Clients then
follow it through the events stream or by polling.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The response body is always the &lt;code&gt;SessionView&lt;/code&gt; at the time of answering, so a
waiting client gets the final turn and any pending deferred calls in one
round trip. A client disconnecting while waiting does not cancel the run.
Creation always answers &lt;code&gt;201&lt;/code&gt;. The other endpoints answer &lt;code&gt;202&lt;/code&gt; when the
stored status is &lt;code&gt;running&lt;/code&gt; at the time of answering (a run is still going,
including a continuation queued into an active run) and &lt;code&gt;200&lt;/code&gt; otherwise.
On shutdown, waiting requests answer at once with the current state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deleting.&lt;/strong&gt; &lt;code&gt;dry_run=true&lt;/code&gt; returns the same body as a real delete,
listing every session and the number of continuation rows that would be
removed, and changes nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SSE stream.&lt;/strong&gt; Each &lt;code&gt;SessionEvent&lt;/code&gt; becomes &lt;code&gt;event: &amp;lt;kind&amp;gt;&lt;/code&gt; plus one
&lt;code&gt;data: &amp;lt;json&amp;gt;&lt;/code&gt; line, where kind is &lt;code&gt;run.started&lt;/code&gt; (&lt;code&gt;{session_id, mode}&lt;/code&gt;),
&lt;code&gt;session.updated&lt;/code&gt; (&lt;code&gt;SessionMetaView&lt;/code&gt; + &lt;code&gt;head_turn&lt;/code&gt;), &lt;code&gt;calls.deferred&lt;/code&gt;
(&lt;code&gt;{session_id, calls}&lt;/code&gt;), &lt;code&gt;run.stopped&lt;/code&gt; (&lt;code&gt;{session_id, status}&lt;/code&gt;), or
&lt;code&gt;session.failed&lt;/code&gt; (&lt;code&gt;{session_id, message}&lt;/code&gt;). On connect the server first sends
&lt;code&gt;event: snapshot&lt;/code&gt; with the &lt;code&gt;SessionMetaView&lt;/code&gt;, so clients never need a
separate GET to sync; it subscribes before loading the snapshot, so no event
falls in between. A run’s &lt;code&gt;session.updated&lt;/code&gt; for the running version comes
just before its &lt;code&gt;run.started&lt;/code&gt;. The server sends a &lt;code&gt;: keepalive&lt;/code&gt; comment
after 15 s without events (warp pauses its idle timeout while the handler
runs, so quiet streams and long waits are not cut). Streams end on shutdown.
Events are not replayed on reconnect. The stream reads events with
&lt;code&gt;subscribeSTM&lt;/code&gt;, combined with the keepalive timer and the shutdown flag in
one transaction, so a timer firing never drops an event.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shutdown.&lt;/strong&gt; On SIGTERM or SIGINT: stop accepting connections, end event
streams and release waiting requests, give open requests
&lt;code&gt;--shutdown-grace&lt;/code&gt; seconds, then &lt;code&gt;shutdownSessionRunner&lt;/code&gt; (cancels active runs,
storing their sessions) and close the database.&lt;/p&gt;
&lt;h4 id="6-tracing-and-logs-implemented-phase-6"&gt;6. Tracing and logs (implemented, Phase 6)&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;HostTrace&lt;/code&gt; wraps the existing traces (&lt;code&gt;OneShot.Trace&lt;/code&gt;, tool registration,
OpenAI) plus runner events. The server prints them as JSON lines on stderr,
one object per line with &lt;code&gt;ts&lt;/code&gt;, &lt;code&gt;kind&lt;/code&gt;, and &lt;code&gt;session_id&lt;/code&gt; when known.
&lt;code&gt;AgentsServer.Log&lt;/code&gt; summarises each trace field by field instead of &lt;code&gt;show&lt;/code&gt;ing
it: LLM traces give byte and token counts, the HTTP client trace gives
method, host, path, and status only (its request carries the API key in a
header), and tool and agent-tree traces give their constructor name. Prompts,
payloads, headers, and API keys are never printed; a smoke test with a fake
key checked the log. Each HTTP request logs method, path, status, and time
to first byte.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="phases"&gt;Phases&lt;/h3&gt;
&lt;p&gt;Each phase leaves &lt;code&gt;cabal build all&lt;/code&gt; and &lt;code&gt;cabal test agents-tests&lt;/code&gt; passing with
&lt;code&gt;-Wall -Werror&lt;/code&gt;, and gets its own entry in a &lt;code&gt;todos/web-server-embedding.progress.md&lt;/code&gt;
tracker.&lt;/p&gt;
&lt;h4 id="phase-1-storage-wiring-fix-g1-g5-white_check_mark"&gt;Phase 1: storage wiring fix (G1, G5) ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SessionSink&lt;/code&gt; and &lt;code&gt;agentPersistSession&lt;/code&gt;; keep &lt;code&gt;agentStoreSession&lt;/code&gt; as a
wrapper.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session start&lt;/code&gt; derives its conversation ID from the session ID.
&lt;/li&gt;
&lt;li&gt;Tests: an agent built with a SQLite backend and a mock LLM runs to
completion and writes &lt;strong&gt;no&lt;/strong&gt; files under a temp session directory; the row
is keyed by the session’s &lt;code&gt;SessionId&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-2-single-agent-factory-g2-g3-g10-white_check_mark"&gt;Phase 2: single agent factory (G2, G3, G10) ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.AgentFactory&lt;/code&gt; with &lt;code&gt;AgentDeps&lt;/code&gt;, &lt;code&gt;buildAgent&lt;/code&gt;, and
&lt;code&gt;AgentRole&lt;/code&gt;; the three copies moved onto it; sub-agents get their parent
and call stack from &lt;code&gt;SubAgent&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;newSessionFromPrompt&lt;/code&gt; in the library.
&lt;/li&gt;
&lt;li&gt;Tests: the existing suite unchanged; new &lt;code&gt;AgentFactoryTests&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-3-metadata-versions-migrations-catalog-g4-g9-white_check_mark"&gt;Phase 3: metadata, versions, migrations, catalog (G4, G9) ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Extended &lt;code&gt;SessionBackend&lt;/code&gt;, &lt;code&gt;SessionLabels&lt;/code&gt;, &lt;code&gt;SessionMeta&lt;/code&gt;,
&lt;code&gt;sessionStatusOf&lt;/code&gt;, SQLite migrations, and the file sidecar.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionCatalog&lt;/code&gt;; the session tools and &lt;code&gt;Props&lt;/code&gt; switched to it.
&lt;/li&gt;
&lt;li&gt;Sub-agents store their agent slug and &lt;code&gt;parent_session_id&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Tests (&lt;code&gt;SessionMetadataTests&lt;/code&gt;): status derivation; version increments;
labels kept; CAS success and conflicts (stale, and version 0 twice);
running status kept by unconditional stores; &lt;code&gt;sbQuery&lt;/code&gt; filters and limit;
composite fallback; migrating a database from before metadata; migrations
run once; file sidecar and legacy files; file and backend catalogs;
list-sessions over a backend catalog; a parent agent calling a sub-agent
tool (mock LLM) leaves a sub-session row naming the parent.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-4-continuation-consistency-g7-white_check_mark"&gt;Phase 4: continuation consistency (G7) ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;csFindSession&lt;/code&gt;, &lt;code&gt;wakeSessionWith&lt;/code&gt; / &lt;code&gt;WakeOutcome&lt;/code&gt;, &lt;code&gt;findSessionForToken&lt;/code&gt;,
continuation migrations, &lt;code&gt;RETURNING&lt;/code&gt; in &lt;code&gt;csComplete&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Tests (&lt;code&gt;ContinuationConsistencyTests&lt;/code&gt;, on a real paused run: async agent,
defer policy, mock LLM, one SQLite database): a wake marks the continuation
completed; a second wake reports the token as already completed and leaves
the session unchanged; an unknown token is reported; the woken session
resumes to a final answer; a token lookup through the index loads no
session; without an index the sessions are searched; migrations run once.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-5-sessionrunner-g6-g8-white_check_mark"&gt;Phase 5: &lt;code&gt;SessionRunner&lt;/code&gt; (G6, G8) ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Host&lt;/code&gt; (&lt;code&gt;withHost&lt;/code&gt;) and &lt;code&gt;System.Agents.Host.Runner&lt;/code&gt; (§4).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DeferredCallView&lt;/code&gt; / &lt;code&gt;pendingDeferredCalls&lt;/code&gt;; &lt;code&gt;csCountSession&lt;/code&gt; and
&lt;code&gt;csDeleteSession&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Tests (&lt;code&gt;RunnerTests&lt;/code&gt;, mock LLM through the host’s completion override):
deferred call completed with auto-resume, with the event sequence; two
concurrent completions of one turn both land; messages refused during a
run and accepted after, giving a second LLM turn; a background call
started in one run picked up by the next; cancel during a background call,
then the cancellation reported on the next run; recovery of a session left
running, its call orphaned on resume; &lt;code&gt;awaitRun&lt;/code&gt; with timeout and
completion; delete cascade (refused during the parent’s run, also for the
sub-session; dry run changes nothing; real delete removes sessions and
continuation rows); idle eviction and reload; &lt;code&gt;withHost&lt;/code&gt; over agent and
database files.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-6-agents-server-executable-white_check_mark"&gt;Phase 6: &lt;code&gt;agents-server&lt;/code&gt; executable ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;wai/warp app, routes, SSE, CLI flags, graceful shutdown on SIGTERM (stop
accepting, &lt;code&gt;shutdownSessionRunner&lt;/code&gt;, close the database).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/agents-server.md&lt;/code&gt; user guide, plus links from
&lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Tests (&lt;code&gt;agents-server-tests&lt;/code&gt;, threaded, the application on a random port
with a mock LLM): the demo flow over SSE (snapshot, then per run
&lt;code&gt;run.started&lt;/code&gt; … &lt;code&gt;calls.deferred&lt;/code&gt;, &lt;code&gt;run.stopped&lt;/code&gt;, then the continuation’s
run ending &lt;code&gt;idle&lt;/code&gt;); the same flow with &lt;code&gt;wait=true&lt;/code&gt; and no events stream
(the create call returns the blocked session with its pending call, the
continuation call the final answer); keepalives; listing pages and filters;
delete with dry run; agents and health; error codes; shutdown releasing
waiting requests and ending streams.
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="milestone-2-the-later-work"&gt;Milestone 2: the later work&lt;/h3&gt;
&lt;p&gt;Recorded 2026-09-19, when the user asked to continue with the later work.
Each item becomes a phase, in this order: each phase is useful on its own,
and the riskier ones come after the ones they build on. Choices marked
&lt;em&gt;default&lt;/em&gt; were made without asking; they are listed again under Decisions.&lt;/p&gt;
&lt;h4 id="phase-7-authentication-and-owners-white_check_mark"&gt;Phase 7: authentication and owners ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agents-server --auth-tokens tokens.json&lt;/code&gt;: &lt;code&gt;{&amp;quot;tokens&amp;quot;: [{&amp;quot;owner&amp;quot;: &amp;quot;alice&amp;quot;, &amp;quot;sha256&amp;quot;: &amp;quot;&amp;lt;hex&amp;gt;&amp;quot;}, {&amp;quot;owner&amp;quot;: &amp;quot;bob&amp;quot;, &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;plain&amp;gt;&amp;quot;}]}&lt;/code&gt;. With it, every
endpoint but &lt;code&gt;/healthz&lt;/code&gt; needs &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; (401
&lt;code&gt;unauthorized&lt;/code&gt; otherwise, with &lt;code&gt;WWW-Authenticate: Bearer&lt;/code&gt;). Without it,
nothing changes. Tokens are compared by SHA-256 digest (&lt;em&gt;default&lt;/em&gt;: a
static file, like the API keys file; no token issuing or expiry).
&lt;/li&gt;
&lt;li&gt;Sessions created by a caller record its owner (&lt;code&gt;createSessionAs&lt;/code&gt;).
Sub-sessions record none: a session belongs to the owner of its &lt;strong&gt;root&lt;/strong&gt;
session (&lt;code&gt;sessionOwner&lt;/code&gt; walks up &lt;code&gt;parent_session_id&lt;/code&gt;). This needs no
change to how sub-agents store themselves.
&lt;/li&gt;
&lt;li&gt;Another owner’s session answers 404, as if it did not exist, for every
endpoint including continuations (404 &lt;code&gt;unknown_token&lt;/code&gt;). Listing filters by
owner (&lt;code&gt;SessionQuery.sqOwner&lt;/code&gt;, index &lt;code&gt;(owner, updated_at)&lt;/code&gt;, migration 3);
&lt;code&gt;?parent=&lt;/code&gt; lists the sub-sessions of an owned session.
&lt;/li&gt;
&lt;li&gt;Sessions stored before authentication was turned on have no owner and are
invisible to every caller (&lt;em&gt;default&lt;/em&gt;).
&lt;/li&gt;
&lt;li&gt;Not in this phase: per-owner API keys and a default &lt;code&gt;runIsolated&lt;/code&gt; policy
for bash and MCP tools. Both need agents built per owner, including
sub-agent tools, which the host builds once at load time today. They stay
in &lt;a href="#remaining-later-work"&gt;Remaining later work&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-8-mcp-over-http-white_check_mark"&gt;Phase 8: MCP over HTTP ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /mcp&lt;/code&gt; on &lt;code&gt;agents-server&lt;/code&gt; (&lt;code&gt;AgentsServer.Mcp&lt;/code&gt;) speaks MCP’s Streamable
HTTP transport. It handles JSON-RPC with aeson directly and reuses the
&lt;code&gt;MCP/Base.hs&lt;/code&gt; types for tools, tool lists, and the initialize result;
tool results are written by hand, because &lt;code&gt;TextContentImpl&lt;/code&gt; always
writes &lt;code&gt;&amp;quot;annotations&amp;quot;: null&lt;/code&gt;. Each request, or batch, gets a plain JSON
response. Messages that need no answer (notifications, client responses)
get 202. &lt;code&gt;GET /mcp&lt;/code&gt; answers 405: there are no server-initiated messages.
Protocol versions 2025-06-18, 2025-03-26, and 2024-11-05: the client’s is
echoed when supported, else the latest.
&lt;/li&gt;
&lt;li&gt;Methods: &lt;code&gt;initialize&lt;/code&gt;, &lt;code&gt;ping&lt;/code&gt;, &lt;code&gt;tools/list&lt;/code&gt;, &lt;code&gt;tools/call&lt;/code&gt;, and empty
&lt;code&gt;resources/list&lt;/code&gt; and &lt;code&gt;prompts/list&lt;/code&gt;. Anything else is -32601; a bad
or unknown tool is -32602; malformed JSON answers 400 with -32700.
&lt;/li&gt;
&lt;li&gt;Tools: one &lt;code&gt;ask_&amp;lt;slug&amp;gt;&lt;/code&gt; per root agent, input &lt;code&gt;{prompt}&lt;/code&gt;. A call creates a
session through the runner, owned by the caller, and waits up to 120 s.
The result carries &lt;code&gt;_meta.session_id&lt;/code&gt;. An idle session gives the final
answer; &lt;code&gt;waiting_external&lt;/code&gt; gives a sentence plus the pending calls as JSON
(not an error); a run still going gives the session id; &lt;code&gt;failed&lt;/code&gt; gives
&lt;code&gt;isError: true&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The same bearer tokens and owners apply. &lt;code&gt;Mcp-Session-Id&lt;/code&gt; is not used.
&lt;/li&gt;
&lt;li&gt;The Streamable HTTP transport requires validating &lt;code&gt;Origin&lt;/code&gt; against DNS
rebinding. Without authentication, every endpoint (not only &lt;code&gt;/mcp&lt;/code&gt;) refuses
an &lt;code&gt;Origin&lt;/code&gt; other than localhost, 127.0.0.1, or [::1] with 403
&lt;code&gt;forbidden_origin&lt;/code&gt;. With authentication, origins are not checked.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-9-tui-out-of-the-core-library-white_check_mark"&gt;Phase 9: TUI out of the core library ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;New public sub-library &lt;code&gt;agents-tui&lt;/code&gt; (source directory &lt;code&gt;tui/&lt;/code&gt;) with the 25
modules that need brick or vty, or import them: &lt;code&gt;System.Agents.TUI.*&lt;/code&gt;
(except &lt;code&gt;TUI.ToolCallActivity&lt;/code&gt;, which is pure and used by the tests),
&lt;code&gt;System.Agents.CLI.TUI&lt;/code&gt;, &lt;code&gt;System.Agents.CLI.Config&lt;/code&gt;, and &lt;code&gt;System.Agents.CLI&lt;/code&gt;.
Module names do not change. Only &lt;code&gt;agents-exe&lt;/code&gt; imports them.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-lib&lt;/code&gt; drops &lt;code&gt;brick&lt;/code&gt;, &lt;code&gt;vty&lt;/code&gt;, &lt;code&gt;text-zipper&lt;/code&gt;, and the unused
&lt;code&gt;data-clist&lt;/code&gt;; nothing in its dependency closure pulls brick or vty any
more. &lt;code&gt;agents-exe&lt;/code&gt; depends on both libraries.
&lt;/li&gt;
&lt;li&gt;The moved files live in their own source directory: with a shared &lt;code&gt;src/&lt;/code&gt;,
GHC would compile core modules again inside &lt;code&gt;agents-tui&lt;/code&gt; instead of using
&lt;code&gt;agents-lib&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Default&lt;/em&gt;: &lt;code&gt;agents-lib&lt;/code&gt; itself is the core instead of a new &lt;code&gt;agents-core&lt;/code&gt;
name, so nothing that depends on &lt;code&gt;agents-lib&lt;/code&gt; breaks.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-10-postgres-backend-white_check_mark"&gt;Phase 10: Postgres backend ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Public sub-library &lt;code&gt;agents-postgres&lt;/code&gt; (&lt;code&gt;postgres/System/Agents/Postgres.hs&lt;/code&gt;,
on &lt;code&gt;postgresql-simple&lt;/code&gt; and the &lt;code&gt;resource-pool&lt;/code&gt; already used by
&lt;code&gt;agents-lib&lt;/code&gt;): &lt;code&gt;withPostgresStores&lt;/code&gt;, &lt;code&gt;openPostgresPool&lt;/code&gt; (10 connections),
&lt;code&gt;mkPostgresSessionStore&lt;/code&gt;, &lt;code&gt;mkPostgresContinuationStore&lt;/code&gt;, &lt;code&gt;isPostgresUrl&lt;/code&gt;,
&lt;code&gt;runPostgresMigrations&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Same schema and semantics as SQLite. Postgres starts at migration 1 with the
full current schema: &lt;code&gt;TIMESTAMPTZ&lt;/code&gt;, and session JSON as &lt;code&gt;TEXT&lt;/code&gt;, not &lt;code&gt;JSONB&lt;/code&gt;,
which rejects &lt;code&gt;\u0000&lt;/code&gt;. CAS is &lt;code&gt;INSERT … ON CONFLICT DO UPDATE … WHERE version = 0 RETURNING&lt;/code&gt; or &lt;code&gt;UPDATE … WHERE version = ? RETURNING&lt;/code&gt;.
Timestamps are truncated to microseconds, as Postgres stores them, so the
metadata handed out matches what a query returns.
&lt;/li&gt;
&lt;li&gt;Migrations run in one transaction per component, under a
&lt;code&gt;pg_advisory_xact_lock&lt;/code&gt;, with &lt;code&gt;client_min_messages = warning&lt;/code&gt; so that
Postgres notices do not reach stderr.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Host.withHostStores&lt;/code&gt; takes &lt;code&gt;HostStores&lt;/code&gt; from the caller;
&lt;code&gt;withHost&lt;/code&gt; is the SQLite case. &lt;code&gt;agents-server --db&lt;/code&gt; takes a
&lt;code&gt;postgres://&lt;/code&gt;/&lt;code&gt;postgresql://&lt;/code&gt; URL; the startup log drops its user and
password.
&lt;/li&gt;
&lt;li&gt;Tests (&lt;code&gt;agents-postgres-tests&lt;/code&gt;, threaded): a throwaway cluster
(&lt;code&gt;initdb&lt;/code&gt; + &lt;code&gt;pg_ctl&lt;/code&gt; from &lt;code&gt;pg_config --bindir&lt;/code&gt;, a free port on
127.0.0.1), one fresh database per test; &lt;code&gt;AGENTS_TEST_POSTGRES_URL&lt;/code&gt; uses an
existing server instead, and without either the suite skips. They cover
migrations running once; CAS with conflicts, labels, and the kept
running status; queries (agent, owner, parent, status, limit, before); 16
concurrent CAS with exactly one winner; and a runner flow (deferred call,
completion, token already completed, cascade delete).
&lt;/li&gt;
&lt;li&gt;Coordinating runs between servers came later: see “Several server
processes on one Postgres database” under Remaining later work.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-11-token-streaming-white_check_mark"&gt;Phase 11: token streaming ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.LLMs.OpenAIStream&lt;/code&gt;: reads a streamed chat completion
(server-sent events, &lt;code&gt;data: [DONE]&lt;/code&gt;) and folds the chunks back into the
JSON of a non-streamed completion. It handles content, reasoning, tool calls
assembled by &lt;code&gt;index&lt;/code&gt; from name and argument pieces, &lt;code&gt;finish_reason&lt;/code&gt;, the
final &lt;code&gt;usage&lt;/code&gt; chunk, and an &lt;code&gt;error&lt;/code&gt; object sent mid-stream. Parsing, tool
calls, and storage do not change. Each non-empty text delta goes to a
callback.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HttpClient.Runtime.postStream&lt;/code&gt;: POST with a body reader for successful
answers (others are read whole, so the overloaded-retry check still
works). &lt;code&gt;OpenAI.callLLMPayloadStreaming&lt;/code&gt; shares the retry logic
(&lt;code&gt;withOverloadedRetry&lt;/code&gt;) with &lt;code&gt;callLLMPayload&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OpenAICompletionConfig.cfgOnTextDelta&lt;/code&gt; switches a completion to streaming
and adds &lt;code&gt;&amp;quot;stream&amp;quot;: true&lt;/code&gt; (plus &lt;code&gt;stream_options.include_usage&lt;/code&gt; for the
&lt;code&gt;OpenAIv1&lt;/code&gt; flavor only, as other providers may refuse it).
&lt;code&gt;AgentDeps.adOnTextDelta&lt;/code&gt; passes it through &lt;code&gt;buildAgent&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HostConfig.hcStreamTokens&lt;/code&gt; / &lt;code&gt;hostStreamTokens&lt;/code&gt;; the runner gives each
session’s agent a callback emitting &lt;code&gt;TextDelta sid text&lt;/code&gt;, which is not
traced (one per token, and it is content). &lt;code&gt;agents-server --stream-tokens&lt;/code&gt;;
&lt;code&gt;event: text.delta&lt;/code&gt; with &lt;code&gt;{session_id, text}&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Tests: five unit tests of the fold (text, tool call pieces, null content,
a body read in 7-byte pieces with CRLF, comments and &lt;code&gt;[DONE]&lt;/code&gt;, a stream
error), and an end-to-end server test against a fake streaming endpoint
(warp) that checks the deltas, the stored answer, and the request’s
&lt;code&gt;stream&lt;/code&gt; fields.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-12-agents-from-the-database-white_check_mark"&gt;Phase 12: agents from the database ✅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.AgentStore&lt;/code&gt;: &lt;code&gt;StoredAgent&lt;/code&gt; (config, &lt;code&gt;updated_at&lt;/code&gt;,
&lt;code&gt;updated_by&lt;/code&gt;), &lt;code&gt;AgentStore&lt;/code&gt; (&lt;code&gt;asList&lt;/code&gt;, &lt;code&gt;asPut&lt;/code&gt;, &lt;code&gt;asDelete&lt;/code&gt;),
&lt;code&gt;mkSqliteAgentStore&lt;/code&gt; (table &lt;code&gt;agents&lt;/code&gt;, component &lt;code&gt;agents&lt;/code&gt;),
&lt;code&gt;fileBasedFields&lt;/code&gt;. &lt;code&gt;agents-postgres&lt;/code&gt; has &lt;code&gt;mkPostgresAgentStore&lt;/code&gt;.
&lt;code&gt;HostStores.hsAgents :: Maybe AgentStore&lt;/code&gt;; &lt;code&gt;withHost&lt;/code&gt; and
&lt;code&gt;withPostgresStores&lt;/code&gt; provide one.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AgentTree.loadAgentTreeFromConfig&lt;/code&gt;: a tree of one agent from an in-memory
&lt;code&gt;Agent&lt;/code&gt;, reusing the loader’s later phases (create, wire tools, build) on a
one-node graph, with no file discovery.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Host&lt;/code&gt;: &lt;code&gt;hostStoredAgents&lt;/code&gt; (loaded stored agents in a &lt;code&gt;TVar&lt;/code&gt;, the store, a
loader, and a lock serialising edits); &lt;code&gt;hostAllAgents&lt;/code&gt;, &lt;code&gt;lookupAgent&lt;/code&gt;,
&lt;code&gt;putStoredAgent&lt;/code&gt;, &lt;code&gt;deleteStoredAgent&lt;/code&gt;, &lt;code&gt;AgentEditError&lt;/code&gt;. The runner looks
agents up through &lt;code&gt;lookupAgent&lt;/code&gt;, so new sessions see changes at once.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-server&lt;/code&gt;: &lt;code&gt;GET/PUT/DELETE /v1/agents/:slug&lt;/code&gt;, &lt;code&gt;source&lt;/code&gt; in listings,
MCP &lt;code&gt;tools/list&lt;/code&gt; includes stored agents, and &lt;code&gt;--admin-owners&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Differences from the plan:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;extraAgents&lt;/code&gt; is refused&lt;/strong&gt;, like the other file-based fields: stored
agents have no sub-agents yet.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Editing needs &lt;code&gt;--admin-owners&lt;/code&gt;, which needs &lt;code&gt;--auth-tokens&lt;/code&gt;&lt;/strong&gt;. The
plan let anyone edit agents without authentication. An agent definition
can start MCP servers, which are commands on the server’s machine, so
edits are off by default.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A file agent hides a stored agent with its slug&lt;/strong&gt;: the stored one is
skipped at startup, and the skip is logged. Refusing to start instead
would leave no way to fix the database through the API.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Known limitation: replacing or deleting a stored agent does not stop MCP
servers it started (the tree loader has no cleanup); they end with the
server.
&lt;/li&gt;
&lt;li&gt;Tests:
&lt;ul&gt;
&lt;li&gt;runner level: store, replace, and refuse (file-based fields, a file
agent’s slug); run a session on a stored agent; reload after a restart;
a file agent hiding a stored one, with the skip traced; delete persists;
&lt;/li&gt;
&lt;li&gt;server: admin and non-admin, 201 and then 200, listing with sources,
refusals, sessions and MCP on a stored agent, delete, and edits disabled
by default;
&lt;/li&gt;
&lt;li&gt;Postgres: put, replace, list, and delete.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="phase-13-self-description-and-a-chat-page-white_check_mark"&gt;Phase 13: self-description and a chat page ✅&lt;/h4&gt;
&lt;p&gt;The server answered &lt;code&gt;404&lt;/code&gt; at &lt;code&gt;/&lt;/code&gt; and published nothing a client could read:
the only reference was &lt;code&gt;documentation/agents-server.md&lt;/code&gt;, which a caller holding just a
URL does not have.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Routes as a servant type&lt;/strong&gt; (&lt;code&gt;AgentsServer.Routes&lt;/code&gt;). Every endpoint whose
shape OpenAPI can express is now described by &lt;code&gt;DocumentedAPI&lt;/code&gt;, and
&lt;code&gt;GET /openapi.json&lt;/code&gt; is generated from it, so the published document cannot
drift from the routes. The event stream and &lt;code&gt;POST /mcp&lt;/code&gt; stay hand-written
(&lt;code&gt;AgentsServer.OpenApi&lt;/code&gt;): neither server-sent events nor JSON-RPC is
expressible, and a wrong schema would be worse than a described one.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bodies as types&lt;/strong&gt; (&lt;code&gt;AgentsServer.Types&lt;/code&gt;), carrying both the JSON encoding
the API already used and an OpenAPI schema, with per-field descriptions and
enums added by hand because openapi3 does not read Haddock. The turn tree
stays an opaque object: it belongs to the library, not to the protocol.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A chat page&lt;/strong&gt; at &lt;code&gt;/&lt;/code&gt; (&lt;code&gt;AgentsServer.UI&lt;/code&gt;): one self-contained HTML
document, no build step, no assets. It is served on a loopback bind, or
when &lt;code&gt;--auth-tokens&lt;/code&gt; is on; &lt;code&gt;--no-ui&lt;/code&gt; turns it off.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;access_token&lt;/code&gt; on the event stream only&lt;/strong&gt;, because &lt;code&gt;EventSource&lt;/code&gt; cannot
set headers. The request log records no query strings, so the token does
not reach the logs.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Deviations from the plan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The rewrite is staged. The servant types describe and generate the
document; the wai router still dispatches. Moving dispatch onto servant
needs &lt;code&gt;UVerb&lt;/code&gt; for the 200/201/202 answers and &lt;code&gt;Raw&lt;/code&gt; for the stream, and
would rewrite 646 tested lines for no change a client can see. A test
asserts the document’s paths are exactly the router’s, so the two cannot
drift in the meantime.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openapi3&lt;/code&gt; needed the freeze’s &lt;code&gt;index-state&lt;/code&gt; bumped: 3.2.4 caps QuickCheck
below the pinned 2.16, and 3.2.5 (which allows it) was published after the
pinned index date. Every previously pinned version is unchanged.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="database-agents-with-tools-and-helpers-white_check_mark"&gt;Database agents with tools and helpers ✅&lt;/h4&gt;
&lt;p&gt;Lifts the two refusals of Phase 12 that decision 10 recorded.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tool files are stored with the agent.&lt;/strong&gt; &lt;code&gt;StoredAgent.saFiles&lt;/code&gt; (contents
by relative path; column &lt;code&gt;files&lt;/code&gt;, SQLite and Postgres migration 2);
&lt;code&gt;asPut&lt;/code&gt; takes them. &lt;code&gt;PUT /v1/agents/:slug&lt;/code&gt; reads them from a &lt;code&gt;files&lt;/code&gt; object
in the body, and &lt;code&gt;config.files&lt;/code&gt; shows them.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loading writes them to disk.&lt;/strong&gt; Each load of a stored agent gets its own
directory under a temporary directory of the host
(&lt;code&gt;materializeToolFiles&lt;/code&gt;); the loaded configuration’s &lt;code&gt;toolDirectory&lt;/code&gt; and
&lt;code&gt;bashToolboxes&lt;/code&gt; paths point there. The directory is removed when the node
is released, and with the host.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;extraAgents&lt;/code&gt; name stored agents by slug&lt;/strong&gt; (&lt;code&gt;path&lt;/code&gt; is now optional in
the JSON, and refused for a stored agent). &lt;code&gt;resolveHelpers&lt;/code&gt; computes what
an agent reaches; &lt;code&gt;AgentTree.loadAgentTreeFromConfigs&lt;/code&gt; loads the root and
those helpers as one tree, so each root has its own copy of its helpers,
like roots from files.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;putStoredAgentWithFiles&lt;/code&gt;; &lt;code&gt;AgentEditError&lt;/code&gt; gains &lt;code&gt;AgentInvalidPaths&lt;/code&gt;,
&lt;code&gt;AgentHelperError&lt;/code&gt; (&lt;code&gt;UnknownHelper&lt;/code&gt;, &lt;code&gt;HelperCycle&lt;/code&gt;), and &lt;code&gt;AgentInUse&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Choices made here (&lt;em&gt;default&lt;/em&gt;, none was planned in detail):
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cycles are refused&lt;/strong&gt;, self-reference included, although agent files
allow them: an edit is checked against the agents stored at that time,
and a helper must exist first, so a cycle can only be an error.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replacing a helper reloads its dependents&lt;/strong&gt;; a dependent that fails to
load again keeps its previous version, and the failure is traced.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A helper in use cannot be deleted&lt;/strong&gt; (&lt;code&gt;409 agent_in_use&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only stored agents can be named&lt;/strong&gt;, not agents from files.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openApiToolboxes&lt;/code&gt;, &lt;code&gt;postgrestToolboxes&lt;/code&gt;, &lt;code&gt;skillSources&lt;/code&gt;, and
&lt;code&gt;autoEnableSkills&lt;/code&gt; are still refused.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Tests: runner level (a stored agent with a tool directory and a stored
helper with a single tool, run end to end, across a restart, and after
replacing the helper; unknown helper, cycles, paths); server (&lt;code&gt;files&lt;/code&gt; in
and out, &lt;code&gt;unknown_helper&lt;/code&gt;, &lt;code&gt;helper_cycle&lt;/code&gt;, &lt;code&gt;agent_invalid_paths&lt;/code&gt;,
&lt;code&gt;agent_in_use&lt;/code&gt;, a session that runs the tool); Postgres (files round-trip).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="remaining-later-work"&gt;Remaining later work&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Per-owner API keys and isolation&lt;/strong&gt;: build agents per owner, including
sub-agent tools; default policy &lt;code&gt;runIsolated&lt;/code&gt; for bash and MCP tools, backed
by &lt;code&gt;dockerRunner&lt;/code&gt;. Partly done:
&lt;ul&gt;
&lt;li&gt;Keys: &lt;code&gt;HostConfig.hcOwnerApiKeysFiles&lt;/code&gt; (&lt;code&gt;--owner-api-keys OWNER=FILE&lt;/code&gt;),
loaded into &lt;code&gt;Host.hostOwnerApiKeys&lt;/code&gt;. The runner already builds one agent
per session, so it picks the keys there (&lt;code&gt;Runner.newAgent&lt;/code&gt;), from the
owner of the session’s root. Sub-agents needed one fix to be covered:
&lt;code&gt;createSessionForNodeWith&lt;/code&gt; now always builds the agent from the node it
was given. Before, a helper that was not also a root agent failed
&lt;code&gt;lookupAgent&lt;/code&gt; and silently fell back to the in-tool path, which is built
at load time and knows no owner. That fallback remains for real
failures, and gets no key at all when per-owner keys are in use.
&lt;/li&gt;
&lt;li&gt;Isolation: &lt;code&gt;System.Agents.Tools.Isolated&lt;/code&gt;, &lt;code&gt;AgentDeps.adToolIsolation&lt;/code&gt;,
&lt;code&gt;HostConfig.hcToolIsolation&lt;/code&gt; (&lt;code&gt;--isolate-tools docker:IMAGE|process:PATH&lt;/code&gt;).
Enforced in &lt;code&gt;buildAgent&lt;/code&gt;, around the tool execution rather than through
&lt;code&gt;ToolCallPolicy&lt;/code&gt;: a policy is the agent’s own (it would let an agent
file opt out, and replacing it would drop &lt;code&gt;defer&lt;/code&gt; rules), and a
&lt;code&gt;RunIsolated&lt;/code&gt; disposition without a runner runs in-process.
&lt;/li&gt;
&lt;li&gt;Still open (owner decisions): isolation is opt-in, not the default, as
there is no worker image to default to; it covers bash and MCP tool
calls only; MCP servers still start on the host; no worker ships with
the repository; unlisted owners use the shared keys.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;~~&lt;strong&gt;Several server processes on one Postgres database&lt;/strong&gt;: live-run ownership
through a lease column (&lt;code&gt;run_owner&lt;/code&gt;, &lt;code&gt;run_lease_until&lt;/code&gt;).~~ Done:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Host.Coordination&lt;/code&gt;: what a host needs from a shared
database (acquire, renew, release a run lease; who holds it; which
running sessions lost their owner; signals from the other processes).
&lt;code&gt;noCoordination&lt;/code&gt; is the single-process case (SQLite, the TUI) and
changes nothing there. &lt;code&gt;HostStores.hsCoordination&lt;/code&gt;,
&lt;code&gt;Host.hostCoordination&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-postgres&lt;/code&gt;: migration 4 adds &lt;code&gt;run_owner&lt;/code&gt; and &lt;code&gt;run_lease_until&lt;/code&gt;
to &lt;code&gt;sessions&lt;/code&gt;; lease times are the database’s &lt;code&gt;now()&lt;/code&gt;. Each process
gets a random instance name. Session writes and accepted mail are
announced with &lt;code&gt;pg_notify&lt;/code&gt; on &lt;code&gt;agents_sessions&lt;/code&gt;; one connection outside
the pool listens and reconnects.
&lt;/li&gt;
&lt;li&gt;The runner takes the lease in &lt;code&gt;startRun&lt;/code&gt; and releases it wherever a run
ends. A heartbeat (every third of &lt;code&gt;rcLeaseTtl&lt;/code&gt;, default 30 s) renews,
stops runs whose lease was taken (&lt;code&gt;abandonRun&lt;/code&gt;, nothing stored), syncs
the mail of running sessions, and takes over expired sessions
(&lt;code&gt;takeOverExpired&lt;/code&gt;, same recovery as &lt;code&gt;recoverOnStartup&lt;/code&gt;, nothing
resumed). &lt;code&gt;recoverOnStartup&lt;/code&gt; only recovers sessions without a live
lease. A run held elsewhere is busy: &lt;code&gt;postMessage&lt;/code&gt; and &lt;code&gt;completeCall&lt;/code&gt;
go to mail, &lt;code&gt;resume&lt;/code&gt; and &lt;code&gt;deleteSession&lt;/code&gt; are refused, &lt;code&gt;cancelRun&lt;/code&gt; posts
&lt;code&gt;StopRun&lt;/code&gt;, &lt;code&gt;awaitRun&lt;/code&gt; waits on forwarded events.
&lt;/li&gt;
&lt;li&gt;Writes are fenced by the versioned compare-and-store, not by the lease:
a takeover stores a version, so the previous owner’s next write
conflicts, and &lt;code&gt;failRun&lt;/code&gt; stores nothing once the lease is gone.
&lt;/li&gt;
&lt;li&gt;Mail: &lt;code&gt;msAppend&lt;/code&gt; answers with the envelope as stored. Postgres settles
&lt;code&gt;seq&lt;/code&gt; under an advisory lock per session, since two processes each
number from what they last loaded; &lt;code&gt;mbSync&lt;/code&gt; merges what others
appended.
&lt;/li&gt;
&lt;li&gt;Events: only &lt;code&gt;session.updated&lt;/code&gt;, &lt;code&gt;run.stopped&lt;/code&gt; and &lt;code&gt;session.deleted&lt;/code&gt; are
forwarded to the other servers. Text deltas and tool events stay on the
owner. A watch skips the forwarded copies (&lt;code&gt;srRemoteEvents&lt;/code&gt;), so a
registration known to two servers yields one mail per event.
&lt;/li&gt;
&lt;li&gt;Not done: resuming a taken-over run by itself; sharing stored-agent
edits and &lt;code&gt;watch-session&lt;/code&gt; registrations between servers; an
&lt;code&gt;agents-server&lt;/code&gt; flag for the lease duration.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;~~&lt;strong&gt;Database agents with files or sub-agents&lt;/strong&gt;~~: done, see
&lt;a href="#database-agents-with-tools-and-helpers"&gt;Database agents with tools and helpers&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stopping a stored agent’s MCP servers&lt;/strong&gt; when it is replaced or deleted.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dispatching through servant&lt;/strong&gt;, replacing the wai router (see Phase 13).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="decisions"&gt;Decisions&lt;/h3&gt;
&lt;p&gt;Recorded 2026-09-18.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Waiting for a run is chosen per request&lt;/strong&gt; with the &lt;code&gt;wait&lt;/code&gt; and &lt;code&gt;timeout&lt;/code&gt;
query parameters (§5), on every endpoint that can start a run. The default
is not to wait. The body’s &lt;code&gt;run&lt;/code&gt; field still controls how far the run goes.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deleting cascades&lt;/strong&gt; to sub-sessions and continuation rows, and supports
a dry run (&lt;code&gt;?dry_run=true&lt;/code&gt;) that reports what would be deleted (§4.9).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Idle live sessions keep their engine for 15 minutes&lt;/strong&gt;
(&lt;code&gt;hcLiveSessionTtl&lt;/code&gt;, configurable). A background call still running when
its session is evicted ends up orphaned.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The MCP server over HTTP is wanted, but later&lt;/strong&gt; (see
&lt;a href="#phase-8-mcp-over-http"&gt;Phase 8&lt;/a&gt;).
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Recorded 2026-09-19 (defaults taken when the user asked to continue with the
later work; see &lt;a href="#milestone-2-the-later-work"&gt;Milestone 2&lt;/a&gt;):&lt;/p&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;Authentication is a static bearer-tokens file&lt;/strong&gt; mapping tokens (or their
SHA-256) to owners. A session belongs to the owner of its root session;
other owners get 404. Sessions without an owner are invisible once
authentication is on.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP over HTTP answers each request with plain JSON&lt;/strong&gt; and does not use
MCP sessions.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;agents-lib&lt;/code&gt; becomes the core&lt;/strong&gt; by moving the TUI into a new
&lt;code&gt;agents-tui&lt;/code&gt; library, rather than creating an &lt;code&gt;agents-core&lt;/code&gt; library.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Postgres lives in its own &lt;code&gt;agents-postgres&lt;/code&gt; library&lt;/strong&gt;; the host takes
its stores from the caller.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token streaming is opt-in&lt;/strong&gt; (&lt;code&gt;--stream-tokens&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database agents cannot use file-based tools&lt;/strong&gt; in their first version,
nor &lt;code&gt;extraAgents&lt;/code&gt;. Storing agents needs &lt;code&gt;--admin-owners&lt;/code&gt; (and so
authentication). A file agent hides a stored agent with the same slug.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Recorded 2026-09-20:&lt;/p&gt;
&lt;ol start="11"&gt;
&lt;li&gt;&lt;strong&gt;The OpenAPI document is generated from servant types&lt;/strong&gt;, rather than
hand-written or derived from a full servant rewrite of the dispatcher.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The chat page is loopback-only by default&lt;/strong&gt; and off with &lt;code&gt;--no-ui&lt;/code&gt;.
It is plain HTML and JavaScript in one document, with no build step.
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="related-docs"&gt;Related docs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;todos/durable-workflows.md&lt;/code&gt;, &lt;code&gt;todos/durable-workflows.progress.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;todos/async-tool-calls.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt;, &lt;code&gt;documentation/async-tool-calls.md&lt;/code&gt;, &lt;code&gt;documentation/sessions.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-web-server-embedding.html" rel="alternate"/><summary type="text">Status: proposed (2026-09-18)</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-internal-tool-mapping.html</id><title type="text">Internal Tool Mapping Documentation</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/internal-tool-mapping.md"&gt;&lt;code&gt;documentation/internal-tool-mapping.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="internal-tool-mapping-documentation"&gt;Internal Tool Mapping Documentation&lt;/h2&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;p&gt;This document describes how tools from various sources (OpenAPI, MCP, Bash, IO) are mapped to LLM-compatible tool names. This mapping is critical because different systems have different naming constraints.&lt;/p&gt;
&lt;h3 id="the-problem"&gt;The Problem&lt;/h3&gt;
&lt;p&gt;LLM APIs (like OpenAI) have strict requirements for function names:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Must start with a letter (a-z, A-Z)
&lt;/li&gt;
&lt;li&gt;Can only contain alphanumeric characters and underscores: &lt;code&gt;[a-zA-Z0-9_]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Some providers have additional length constraints
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: Dashes (&lt;code&gt;-&lt;/code&gt;) and colons (&lt;code&gt;:&lt;/code&gt;) are &lt;strong&gt;not&lt;/strong&gt; allowed, even though some documentation may suggest otherwise.&lt;/p&gt;
&lt;p&gt;However, tool identifiers from external sources may contain invalid characters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenAPI operation IDs can contain dots (e.g., &lt;code&gt;pet.findByStatus&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;OpenAPI operation IDs can contain slashes (e.g., &lt;code&gt;users/pets/get&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;URLs may contain dots, colons, slashes, and other special characters (e.g., &lt;code&gt;localhost:8001&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;MCP tool names may contain dashes, colons, or other special characters
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="current-naming-schemes"&gt;Current Naming Schemes&lt;/h3&gt;
&lt;h4 id="1-io-tools"&gt;1. IO Tools&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;io2LLMName ::&lt;/span&gt; &lt;span class="dt"&gt;IOScript&lt;/span&gt; a b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;io2LLMName io &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;io_&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; io&lt;span class="op"&gt;.&lt;/span&gt;description&lt;span class="op"&gt;.&lt;/span&gt;ioSlug)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Prefix: &lt;code&gt;io_&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Source: User-defined slug
&lt;/li&gt;
&lt;li&gt;Constraints: Assumed valid (user-controlled)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-bash-tools"&gt;2. Bash Tools&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;bash2LLMName ::&lt;/span&gt; &lt;span class="dt"&gt;ScriptDescription&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;bash2LLMName bash &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;bash_&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; bash&lt;span class="op"&gt;.&lt;/span&gt;scriptInfo&lt;span class="op"&gt;.&lt;/span&gt;scriptSlug)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Prefix: &lt;code&gt;bash_&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Source: User-defined slug
&lt;/li&gt;
&lt;li&gt;Constraints: Assumed valid (user-controlled)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-mcp-tools"&gt;3. MCP Tools&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mcp2LLMName ::&lt;/span&gt; &lt;span class="dt"&gt;Toolbox&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolDescription&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;mcp2LLMName box mcp &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;mcp_&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; box&lt;span class="op"&gt;.&lt;/span&gt;name &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;_&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; mcp&lt;span class="op"&gt;.&lt;/span&gt;getToolDescription&lt;span class="op"&gt;.&lt;/span&gt;name)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Prefix: &lt;code&gt;mcp_&amp;lt;toolboxName&amp;gt;_&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Source: MCP tool name from server
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Issue&lt;/strong&gt;: MCP tool names may contain invalid characters (dashes, colons, etc.)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-openapi-tools"&gt;4. OpenAPI Tools&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;openapi2LLMName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;openapi2LLMName tboxName operationId &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;openapi_&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; tboxName &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;_&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; operationId)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Prefix: &lt;code&gt;openapi_&amp;lt;toolboxName&amp;gt;_&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Source: OpenAPI operationId
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Issue&lt;/strong&gt;: operationId often contains dots (e.g., &lt;code&gt;pet.findByStatus&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Issue&lt;/strong&gt;: Toolbox names derived from URLs may contain colons (e.g., &lt;code&gt;localhost:8001&lt;/code&gt;)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="error-manifestation"&gt;Error Manifestation&lt;/h3&gt;
&lt;p&gt;When an invalid tool name is sent to an LLM API, you may see errors like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;quot;Invalid request: function name is invalid, must start with a letter 
 and can contain only alphanumerics and underscores&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This commonly occurs with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenAPI specs that use dot-notation for operation IDs:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pet.findByStatus&lt;/code&gt; → Invalid (contains dot)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;users/pets/get&lt;/code&gt; → Invalid (contains slash)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Toolbox names derived from URLs:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;localhost:8001&lt;/code&gt; → Invalid (contains colon)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;api.example.com&lt;/code&gt; → Invalid (contains dots)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MCP tool names with dashes or special characters:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get-pet&lt;/code&gt; → Invalid (contains dash)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="proposed-solution-normalization-with-bi-directional-mapping"&gt;Proposed Solution: Normalization with Bi-directional Mapping&lt;/h3&gt;
&lt;h4 id="core-principles"&gt;Core Principles&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Normalization&lt;/strong&gt;: Convert all tool names to LLM-valid format (alphanumeric + underscore only)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bi-directional Mapping&lt;/strong&gt;: Maintain ability to map back to original names
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistency&lt;/strong&gt;: Same normalization logic for registration and lookup
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collision Avoidance&lt;/strong&gt;: Ensure unique normalized names
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="normalization-function"&gt;Normalization Function&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Normalize a tool name to be LLM-compatible.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Rules:&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 1. Must start with a letter (prefix with &amp;#39;t&amp;#39; if needed)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 2. Replace all non-alphanumeric characters with underscores&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 3. Collapse multiple consecutive underscores&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 4. Preserve case (some providers are case-sensitive)&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Examples:&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;gt;&amp;gt;&amp;gt; normalizeToolName &amp;quot;pet.findByStatus&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;quot;pet_findByStatus&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;gt;&amp;gt;&amp;gt; normalizeToolName &amp;quot;users/pets/get&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;quot;users_pets_get&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;gt;&amp;gt;&amp;gt; normalizeToolName &amp;quot;2.0_getPet&amp;quot;  -- starts with number&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;quot;t2_0_getPet&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;gt;&amp;gt;&amp;gt; normalizeToolName &amp;quot;localhost:8001&amp;quot;  -- contains colon&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;quot;localhost_8001&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;gt;&amp;gt;&amp;gt; normalizeToolName &amp;quot;get-pet&amp;quot;  -- contains dash&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;quot;get_pet&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;normalizeToolName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="character-replacement-rules"&gt;Character Replacement Rules&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Character&lt;/th&gt;&lt;th&gt;Replacement&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;.&lt;/code&gt; (dot)&lt;/td&gt;&lt;td&gt;&lt;code&gt;_&lt;/code&gt; (underscore)&lt;/td&gt;&lt;td&gt;&lt;code&gt;pet.find&lt;/code&gt; → &lt;code&gt;pet_find&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;/&lt;/code&gt; (slash)&lt;/td&gt;&lt;td&gt;&lt;code&gt;_&lt;/code&gt; (underscore)&lt;/td&gt;&lt;td&gt;&lt;code&gt;users/pets&lt;/code&gt; → &lt;code&gt;users_pets&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;:&lt;/code&gt; (colon)&lt;/td&gt;&lt;td&gt;&lt;code&gt;_&lt;/code&gt; (underscore)&lt;/td&gt;&lt;td&gt;&lt;code&gt;localhost:8001&lt;/code&gt; → &lt;code&gt;localhost_8001&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-&lt;/code&gt; (dash)&lt;/td&gt;&lt;td&gt;&lt;code&gt;_&lt;/code&gt; (underscore)&lt;/td&gt;&lt;td&gt;&lt;code&gt;get-pet&lt;/code&gt; → &lt;code&gt;get_pet&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Other special chars&lt;/td&gt;&lt;td&gt;&lt;code&gt;_&lt;/code&gt; (underscore)&lt;/td&gt;&lt;td&gt;&lt;code&gt;pet@home&lt;/code&gt; → &lt;code&gt;pet_home&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Leading digit&lt;/td&gt;&lt;td&gt;Prefix with &lt;code&gt;t&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;2.0_api&lt;/code&gt; → &lt;code&gt;t2_0_api&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="bi-directional-mapping-strategy"&gt;Bi-directional Mapping Strategy&lt;/h4&gt;
&lt;p&gt;For OpenAPI tools, we need to maintain a mapping from normalized LLM names back to original operation IDs:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolNameMapping&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolNameMapping&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; originalName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;        &lt;span class="co"&gt;-- ^ Original operationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; normalizedName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;      &lt;span class="co"&gt;-- ^ LLM-safe name&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; fullLLMName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;         &lt;span class="co"&gt;-- ^ With prefix (e.g., &amp;quot;openapi_pets_pet_findByStatus&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Build mapping during tool registration&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;buildNameMapping ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;OpenAPITool&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;ToolNameMapping&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;buildNameMapping toolboxName tools &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Lookup during tool execution&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;findToolByLLMName ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;ToolNameMapping&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;OpenAPITool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="implementation-in-openapi-toolbox"&gt;Implementation in OpenAPI Toolbox&lt;/h4&gt;
&lt;p&gt;The OpenAPI toolbox should:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;During Initialization&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Normalize the toolbox name itself (may contain colons from URLs)
&lt;/li&gt;
&lt;li&gt;Convert all operation IDs to normalized form
&lt;/li&gt;
&lt;li&gt;Store mapping from normalized → original
&lt;/li&gt;
&lt;li&gt;Generate LLM tool names with normalized IDs
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;During Tool Execution&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Receive LLM tool call with normalized name
&lt;/li&gt;
&lt;li&gt;Look up original operation ID from mapping
&lt;/li&gt;
&lt;li&gt;Execute using original ID
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="updated-naming-flow"&gt;Updated Naming Flow&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;OpenAPI Spec
    │
    ▼
Parse Operations
    │
    ▼
Extract operationId (e.g., &amp;quot;pet.findByStatus&amp;quot;)
    │
    ▼
Normalize ──────────────────┐
    │                        │
    ▼                        │
&amp;quot;pet_findByStatus&amp;quot;          │
    │                        │
    ▼                        ▼
Add prefix:              Store mapping:
&amp;quot;openapi_pets_pet_findByStatus&amp;quot;  &amp;quot;pet_findByStatus&amp;quot; → &amp;quot;pet.findByStatus&amp;quot;
    │
    ▼
Register with LLM
    │
    ▼
LLM calls tool with name &amp;quot;openapi_pets_pet_findByStatus&amp;quot;
    │
    ▼
Lookup mapping → &amp;quot;pet.findByStatus&amp;quot;
    │
    ▼
Execute HTTP request
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="implementation-plan"&gt;Implementation Plan&lt;/h3&gt;
&lt;h4 id="phase-1-normalization-function"&gt;Phase 1: Normalization Function&lt;/h4&gt;
&lt;p&gt;Add to &lt;code&gt;System.Agents.Tools.OpenAPI.Converter&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Normalize a tool name for LLM compatibility.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Only allows alphanumeric characters and underscores.&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;normalizeForLLM ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;normalizeForLLM &lt;span class="ot"&gt;=&lt;/span&gt; collapseUnderscores &lt;span class="op"&gt;.&lt;/span&gt; ensureLetterStart &lt;span class="op"&gt;.&lt;/span&gt; replaceInvalid&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    replaceInvalid &lt;span class="ot"&gt;=&lt;/span&gt; Text.map replaceChar&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    replaceChar c&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;|&lt;/span&gt; isValidChar c &lt;span class="ot"&gt;=&lt;/span&gt; c&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Only alphanumeric and underscore allowed (NO dashes, NO colons)&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    isValidChar c &lt;span class="ot"&gt;=&lt;/span&gt; isLetter c &lt;span class="op"&gt;||&lt;/span&gt; &lt;span class="fu"&gt;isDigit&lt;/span&gt; c &lt;span class="op"&gt;||&lt;/span&gt; c &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ensureLetterStart t&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;|&lt;/span&gt; Text.null t &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;|&lt;/span&gt; isLetter (Text.head t) &lt;span class="ot"&gt;=&lt;/span&gt; t&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;t&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; t&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    collapseUnderscores &lt;span class="ot"&gt;=&lt;/span&gt; Text.intercalate &lt;span class="st"&gt;&amp;quot;_&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;filter&lt;/span&gt; (&lt;span class="fu"&gt;not&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; Text.null) &lt;span class="op"&gt;.&lt;/span&gt; Text.splitOn &lt;span class="st"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="phase-2-bi-directional-mapping"&gt;Phase 2: Bi-directional Mapping&lt;/h4&gt;
&lt;p&gt;Add to &lt;code&gt;System.Agents.Tools.OpenAPI.Converter&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;NameMapping&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;NameMapping&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; nmOriginal ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; nmNormalized ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;buildToolNameMapping ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;OpenAPITool&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;NameMapping&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;buildToolNameMapping toolboxName tools &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    Map.fromList [(nmNormalized m, m) &lt;span class="op"&gt;|&lt;/span&gt; m &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; mappings]&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    mappings &lt;span class="ot"&gt;=&lt;/span&gt; [ &lt;span class="dt"&gt;NameMapping&lt;/span&gt; orig (normalizeForLLM orig)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;               &lt;span class="op"&gt;|&lt;/span&gt; tool &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; tools&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;               , &lt;span class="kw"&gt;let&lt;/span&gt; orig &lt;span class="ot"&gt;=&lt;/span&gt; getOperationIdOrFallback tool&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;               ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="phase-3-update-openapi-toolbox"&gt;Phase 3: Update OpenAPI Toolbox&lt;/h4&gt;
&lt;p&gt;Modify &lt;code&gt;Toolbox&lt;/code&gt; to store name mapping:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Toolbox&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Toolbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; toolboxName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolboxBaseUrl ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolboxTools ::&lt;/span&gt; [&lt;span class="dt"&gt;OpenAPITool&lt;/span&gt;]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolboxNameMapping ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;NameMapping&lt;/span&gt;  &lt;span class="co"&gt;-- ^ normalized → original&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; httpRuntime ::&lt;/span&gt; &lt;span class="dt"&gt;HttpClient.Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; headerFunc ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;))&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; staticHeaders ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="phase-4-update-registration-functions"&gt;Phase 4: Update Registration Functions&lt;/h4&gt;
&lt;p&gt;Update &lt;code&gt;openapi2LLMName&lt;/code&gt; to use normalized names for both toolbox and operation:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;openapi2LLMName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;openapi2LLMName tboxName operationId &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; normalizedBox &lt;span class="ot"&gt;=&lt;/span&gt; normalizeForLLM tboxName&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        normalizedOp &lt;span class="ot"&gt;=&lt;/span&gt; normalizeForLLM operationId&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolName&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;openapi_&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; normalizedBox &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;_&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; normalizedOp)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Note: Both &lt;code&gt;tboxName&lt;/code&gt; and &lt;code&gt;operationId&lt;/code&gt; must be normalized because toolbox names may come from URLs containing colons.&lt;/p&gt;
&lt;h3 id="testing-strategy"&gt;Testing Strategy&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Unit Tests&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test normalization of various edge cases (dots, slashes, colons, dashes)
&lt;/li&gt;
&lt;li&gt;Test bi-directional mapping
&lt;/li&gt;
&lt;li&gt;Test collision handling
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Integration Tests&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test with real OpenAPI specs containing dots in operationIds
&lt;/li&gt;
&lt;li&gt;Test with toolbox names from URLs containing colons
&lt;/li&gt;
&lt;li&gt;Test end-to-end tool registration and execution
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Property Tests&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Round-trip property: normalize → denormalize should preserve original
&lt;/li&gt;
&lt;li&gt;Validity property: normalized names always match &lt;code&gt;[a-zA-Z][a-zA-Z0-9_]*&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="edge-cases"&gt;Edge Cases&lt;/h3&gt;
&lt;h4 id="1-name-collisions"&gt;1. Name Collisions&lt;/h4&gt;
&lt;p&gt;When two different operation IDs normalize to the same name:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Original names&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;pet.find&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;and&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;pet_find&amp;quot;&lt;/span&gt; both normalize to &lt;span class="st"&gt;&amp;quot;pet_find&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Solution: Append number suffix&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;pet_find&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;and&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;pet_find_2&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="2-empty-operation-ids"&gt;2. Empty Operation IDs&lt;/h4&gt;
&lt;p&gt;When operationId is missing, we fall back to path/method:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- From path &amp;quot;/pets/{id}&amp;quot; and method &amp;quot;GET&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Generated name: &amp;quot;get_pets__id_&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="3-very-long-names"&gt;3. Very Long Names&lt;/h4&gt;
&lt;p&gt;Some providers have length limits. Strategy:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Truncate with hash suffix to maintain uniqueness&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;openapi_very_long_toolbox_name_very_long_operation_id_...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  → &lt;span class="st"&gt;&amp;quot;openapi_very_long_toolbox_name_very_long_operat_a1b2c3&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="4-unicode-characters"&gt;4. Unicode Characters&lt;/h4&gt;
&lt;p&gt;Non-ASCII characters in operation IDs:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Replace with underscores&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;获取宠物&amp;quot;&lt;/span&gt; → &lt;span class="st"&gt;&amp;quot;____&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Then ensure letter start: &amp;quot;t____&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="5-toolbox-names-from-urls"&gt;5. Toolbox Names from URLs&lt;/h4&gt;
&lt;p&gt;When toolbox names are derived from URLs, they may contain colons and dots:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Original URL-based name&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;localhost:8001&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Normalized&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;localhost_8001&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Original URL-based name&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;api.example.com:8080&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Normalized&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;api_example_com_8080&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="related-files"&gt;Related Files&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/System/Agents/Tools/OpenAPI/Converter.hs&lt;/code&gt; - Tool conversion logic
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/System/Agents/Tools/OpenAPI/Types.hs&lt;/code&gt; - Type definitions
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/System/Agents/Tools/OpenAPIToolbox.hs&lt;/code&gt; - Toolbox implementation
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/System/Agents/ToolRegistration.hs&lt;/code&gt; - LLM registration
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/System/Agents/LLMs/OpenAI.hs&lt;/code&gt; - LLM ToolName type
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="future-considerations"&gt;Future Considerations&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Caching&lt;/strong&gt;: Cache normalized names to avoid recomputation
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration&lt;/strong&gt;: Allow users to provide custom normalization rules
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation&lt;/strong&gt;: Pre-validate specs during initialization
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reporting&lt;/strong&gt;: Log warnings when names are normalized
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-internal-tool-mapping.html" rel="alternate"/><summary type="text">## Overview This document describes how tools from various sources (OpenAPI, MCP, Bash, IO) are mapped to LLM-compatible tool names. This mapping is critical because different systems have different naming constraints. ## The Problem LLM AP</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-cli-commands.html</id><title type="text">CLI Reference</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/cli-commands.md"&gt;&lt;code&gt;documentation/cli-commands.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="cli-reference"&gt;CLI Reference&lt;/h2&gt;
&lt;p&gt;Complete reference for the Agents CLI commands and options.&lt;/p&gt;
&lt;h3 id="global-options"&gt;Global Options&lt;/h3&gt;
&lt;p&gt;These options apply to all commands:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;GLOBAL_OPTS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt; COMMAND &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;COMMAND_OPTS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--api-keys FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/.config/agents-exe/secret-keys&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path to API keys JSON file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--agent-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(from config)&lt;/td&gt;&lt;td&gt;Agent configuration file(s)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--agent SLUG&lt;/code&gt;&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;Select agent by slug instead of file path&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--log-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;agents-logfile&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Raw log output file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--log-http URL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;HTTP endpoint for JSON logs&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--log-json-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;Local JSON log file&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="commands"&gt;Commands&lt;/h3&gt;
&lt;h4 id="check"&gt;check&lt;/h4&gt;
&lt;p&gt;Validate agent configuration and display loaded tools.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check [--tools MODE] &lt;span class="pp"&gt;[--&lt;/span&gt;&lt;span class="ss"&gt;show&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;config&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--tools MODE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Tool display mode: &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;agents-exe&lt;/code&gt;, &lt;code&gt;openai&lt;/code&gt; (default: &lt;code&gt;none&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--show-config&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Print each agent file's JSON before its check line; for a &lt;code&gt;.tramaj&lt;/code&gt; [template](/docs-agent-templates.html), the JSON it evaluates to&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;my-agent: A helpful file assistant (12 tools)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Exit codes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; - All agents loaded successfully
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt; - Configuration errors found
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Check default agents&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Check specific agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./custom-agent.json&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# List tools in agents-exe format&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check &lt;span class="at"&gt;--tools&lt;/span&gt; agents-exe&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="run"&gt;run&lt;/h4&gt;
&lt;p&gt;Execute a one-shot agent conversation.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--session-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Resume from existing session&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--thinking TARGET&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output thinking: &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;stdout&lt;/code&gt;, &lt;code&gt;stderr&lt;/code&gt; (default: &lt;code&gt;none&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-m, --media MEDIA&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Attach media file (can be specified multiple times)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--prompt TEXT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Initial prompt text&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Read prompt from file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--shell COMMAND&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Use shell command output as prompt&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--alias NAME&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Use predefined prompt alias&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--sep4 TEXT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Short separator (4 chars)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--sep40 TEXT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Long separator (40 chars)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--session-xs FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Inject session at minimal verbosity&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--session-s FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Inject session at low verbosity&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--session-m FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Inject session at medium verbosity&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--session-l FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Inject session at high verbosity&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--session-xl FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Inject session at maximum verbosity&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Asynchronous tool calls:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If the agent file enables asynchronous execution (see
&lt;a href="/agents-exe/docs-async-tool-calls.html"&gt;async-tool-calls.md&lt;/a&gt;), tool calls run concurrently and
the model can be answered while they run. &lt;code&gt;run&lt;/code&gt; still waits for them, since
they cannot outlive the process.&lt;/p&gt;
&lt;p&gt;It stops early only when a turn waits on &lt;em&gt;deferred&lt;/em&gt; calls, which an external
worker completes. It then prints a JSON report and stores the session:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;paused&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;waiting for deferred tool calls&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;session_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;deferred_calls&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;approve_deploy&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;call_9&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;continuation_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Continue it with &lt;code&gt;session complete&lt;/code&gt; and &lt;code&gt;session resume&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Media Attachment Format:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-m, --media&lt;/code&gt; option accepts file paths with optional MIME type:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Auto-detect MIME type from extension&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;-m&lt;/span&gt; /path/to/image.png &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Describe this image&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Explicit MIME type (semicolon separator)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;-m&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/jpeg;/path/to/photo.jpg&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Analyze this photo&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Supported Media Types:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Category&lt;/th&gt;&lt;th&gt;Extensions&lt;/th&gt;&lt;th&gt;MIME Types&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Images&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.png&lt;/code&gt;, &lt;code&gt;.jpg&lt;/code&gt;, &lt;code&gt;.jpeg&lt;/code&gt;, &lt;code&gt;.gif&lt;/code&gt;, &lt;code&gt;.webp&lt;/code&gt;, &lt;code&gt;.svg&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;image/png&lt;/code&gt;, &lt;code&gt;image/jpeg&lt;/code&gt;, &lt;code&gt;image/gif&lt;/code&gt;, &lt;code&gt;image/webp&lt;/code&gt;, &lt;code&gt;image/svg+xml&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Documents&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.pdf&lt;/code&gt;, &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.md&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;, &lt;code&gt;.xml&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;application/pdf&lt;/code&gt;, &lt;code&gt;text/plain&lt;/code&gt;, &lt;code&gt;text/markdown&lt;/code&gt;, &lt;code&gt;application/json&lt;/code&gt;, &lt;code&gt;application/xml&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Audio&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.mp3&lt;/code&gt;, &lt;code&gt;.wav&lt;/code&gt;, &lt;code&gt;.ogg&lt;/code&gt;, &lt;code&gt;.aac&lt;/code&gt;, &lt;code&gt;.flac&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;audio/mp3&lt;/code&gt;, &lt;code&gt;audio/wav&lt;/code&gt;, &lt;code&gt;audio/ogg&lt;/code&gt;, &lt;code&gt;audio/aac&lt;/code&gt;, &lt;code&gt;audio/flac&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Video&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.mp4&lt;/code&gt;, &lt;code&gt;.webm&lt;/code&gt;, &lt;code&gt;.mov&lt;/code&gt;, &lt;code&gt;.avi&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;video/mp4&lt;/code&gt;, &lt;code&gt;video/webm&lt;/code&gt;, &lt;code&gt;video/quicktime&lt;/code&gt;, &lt;code&gt;video/avi&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Size Limit:&lt;/strong&gt; 50MB per file&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Simple prompt&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Hello!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Read from file&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="at"&gt;--file&lt;/span&gt; prompt.txt&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Shell command output as prompt&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="at"&gt;--shell&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;git diff&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Resume session&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="at"&gt;--session-file&lt;/span&gt; session.json&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Use alias&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="at"&gt;--alias&lt;/span&gt; code-review &lt;span class="at"&gt;--file&lt;/span&gt; changes.patch&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Multi-part prompt with separators&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Review this code:&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--sep4&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;----&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--file&lt;/span&gt; code.py &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--sep40&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;========================================&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;What improvements can be made?&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Inject previous session at medium verbosity&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--session-m&lt;/span&gt; previous-session.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Continue from where we left off&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Attach single image&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; vision-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;-m&lt;/span&gt; ./screenshot.png &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;What do you see in this image?&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Attach multiple images&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; vision-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;-m&lt;/span&gt; ./image1.png &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;-m&lt;/span&gt; ./image2.jpg &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;-m&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/gif;./animation.gif&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Compare these images&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Attach document for analysis&lt;/span&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; document-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;-m&lt;/span&gt; ./report.pdf &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Summarize the key findings&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Combine media with text from file&lt;/span&gt;&lt;/span&gt;
&lt;span id="51"&gt;&lt;a href="#51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="52"&gt;&lt;a href="#52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; multimodal-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="53"&gt;&lt;a href="#53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Analyze this diagram and code:&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="54"&gt;&lt;a href="#54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;-m&lt;/span&gt; ./diagram.png &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="55"&gt;&lt;a href="#55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--sep4&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;----&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="56"&gt;&lt;a href="#56" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--file&lt;/span&gt; ./source-code.py&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tui"&gt;tui&lt;/h4&gt;
&lt;p&gt;Start the interactive Terminal UI.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui [--agent-file FILE...] [--keymap FILE] [--db PATH]&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="at"&gt;--attach&lt;/span&gt; URL&lt;span class="kw"&gt;|&lt;/span&gt;&lt;span class="ex"&gt;PATH&lt;/span&gt; [--token TOKEN &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;--token-file&lt;/span&gt; FILE] [--keymap FILE]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The TUI is a client of an in-process &lt;code&gt;SessionRunner&lt;/code&gt; it starts over the
same &lt;code&gt;Host&lt;/code&gt; config &lt;code&gt;agents-exe serve&lt;/code&gt; uses, or, with &lt;code&gt;--attach&lt;/code&gt;, of a
running &lt;code&gt;agents-exe serve&lt;/code&gt;/&lt;code&gt;agents-server&lt;/code&gt; (see
&lt;a href="/agents-exe/docs-tui.html#architecture"&gt;tui.md&lt;/a&gt; and
&lt;a href="/agents-exe/docs-agents-server.html#attaching-the-tui"&gt;agents-server.md&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--keymap FILE&lt;/code&gt;, &lt;code&gt;-k FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;td&gt;Path to a keymap configuration JSON file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--db PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;next to the resolved sessions directory&lt;/td&gt;&lt;td&gt;SQLite database for the TUI's embedded session runner. Old &lt;code&gt;conv.&amp;lt;uuid&amp;gt;.json&lt;/code&gt; history under the resolved sessions directories stays readable as a read-only fallback. Not with &lt;code&gt;--attach&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--attach URL\|PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;td&gt;Drive a running server instead of an embedded runner. &lt;code&gt;http://HOST:PORT&lt;/code&gt; (or &lt;code&gt;https://&lt;/code&gt;, optionally with a path prefix), &lt;code&gt;unix:///path/to.sock&lt;/code&gt; for &lt;code&gt;serve --socket&lt;/code&gt;, or a bare socket path (anything containing a &lt;code&gt;/&lt;/code&gt; or ending in &lt;code&gt;.sock&lt;/code&gt;). Nothing is loaded locally: agents, API keys and sessions are the server's.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--token TOKEN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;td&gt;Bearer token for &lt;code&gt;--attach&lt;/code&gt;, when the server runs with &lt;code&gt;--auth-tokens&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--token-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;td&gt;The same, read from a file (surrounding whitespace ignored); keeps the token out of the process list.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Real-time streaming responses
&lt;/li&gt;
&lt;li&gt;Multiple agent support (Tab to switch)
&lt;/li&gt;
&lt;li&gt;Tool call visualization
&lt;/li&gt;
&lt;li&gt;Session persistence
&lt;/li&gt;
&lt;li&gt;Turn navigation and forking
&lt;/li&gt;
&lt;li&gt;Message queue management
&lt;/li&gt;
&lt;li&gt;File attachments (Ctrl+F)
&lt;/li&gt;
&lt;li&gt;Clipboard paste support (Ctrl+V)
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Keyboard Shortcuts:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Tab&lt;/code&gt; / &lt;code&gt;Shift+Tab&lt;/code&gt; - Switch between agents
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Enter&lt;/code&gt; - Send message
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+C&lt;/code&gt; - Quit
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Up/Down&lt;/code&gt; - Scroll history
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+[&lt;/code&gt; / &lt;code&gt;Ctrl+]&lt;/code&gt; - Previous/Next tab
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+E&lt;/code&gt; - Pause/unpause conversation
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+D&lt;/code&gt; (when paused) - Clear queued messages
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+F&lt;/code&gt; - Attach file
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+Shift+F&lt;/code&gt; - Clear all attachments
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+V&lt;/code&gt; - Paste from clipboard
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Single agent TUI&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Multi-agent TUI&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; coder.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; reviewer.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; tester.json&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Attach to a server started elsewhere with `agents-exe serve`&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="at"&gt;--attach&lt;/span&gt; http://127.0.0.1:8080&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="at"&gt;--attach&lt;/span&gt; unix:///run/agents/agents.sock&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="at"&gt;--attach&lt;/span&gt; https://agents.example &lt;span class="at"&gt;--token-file&lt;/span&gt; ~/.agents-token&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="spectate"&gt;spectate&lt;/h4&gt;
&lt;p&gt;Watch a running server: a read-only, live dashboard.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; spectate &lt;span class="at"&gt;--attach&lt;/span&gt; URL&lt;span class="kw"&gt;|&lt;/span&gt;&lt;span class="ex"&gt;PATH&lt;/span&gt; [--token TOKEN &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;--token-file&lt;/span&gt; FILE]&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="ex"&gt;[--panels&lt;/span&gt; SPEC] [--refresh SECONDS] [--layout-file FILE]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;spectate&lt;/code&gt; is one more client of a running &lt;code&gt;agents-exe serve&lt;/code&gt;/&lt;code&gt;agents-server&lt;/code&gt;,
like &lt;code&gt;tui --attach&lt;/code&gt;, except that it only reads: it follows the server’s
event feed and changes nothing. It is made for watching one long run, in
three panels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;agents&lt;/strong&gt; (&lt;code&gt;tree&lt;/code&gt;; top left by default): the tree of sessions and of the
sub-agent calls they make, indented by depth, each with its state and for
how long.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tool calls&lt;/strong&gt; (&lt;code&gt;tools&lt;/code&gt;; bottom left): the calls running now, with elapsed
time and the latest progress a background call reported, then the ones
that finished recently.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;text&lt;/strong&gt; (&lt;code&gt;text&lt;/code&gt;; right): what the model writes in one session, with the
user queries it answers. By default the panel follows the session that
wrote last; selecting a row of the tree pins it to that session.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which panels show, where, how large, and how often the screen refreshes can
be chosen on the command line and changed while running, as in &lt;code&gt;top&lt;/code&gt;: see
&lt;a href="#spectate-layout"&gt;Layout&lt;/a&gt; below.&lt;/p&gt;
&lt;p&gt;The events carry no timestamp, so every duration is measured by
&lt;code&gt;spectate&lt;/code&gt; from the moment it received the event; a run that started
before &lt;code&gt;spectate&lt;/code&gt; attached counts from the attach. Text arrives as the
model writes it when the server runs with &lt;code&gt;--stream-tokens&lt;/code&gt;, and turn by
turn otherwise. A sub-agent call that runs inside its caller’s tool call
(rather than as a session of its own) is in the tree, but has no event
stream and so no text; and a session already running when &lt;code&gt;spectate&lt;/code&gt;
attaches shows its text from its next turn on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--attach URL\|PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;required&lt;/td&gt;&lt;td&gt;The server to watch. Same forms as &lt;code&gt;tui --attach&lt;/code&gt;: &lt;code&gt;http://HOST:PORT&lt;/code&gt;, &lt;code&gt;https://...&lt;/code&gt;, &lt;code&gt;unix:///path/to.sock&lt;/code&gt;, or a bare socket path.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--token TOKEN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;td&gt;Bearer token, when the server runs with &lt;code&gt;--auth-tokens&lt;/code&gt;. &lt;code&gt;spectate&lt;/code&gt; then sees that owner's sessions only.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--token-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;td&gt;The same, read from a file.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--panels SPEC&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;tree:60+tools:40/45,text/55&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The panels shown, their places and sizes (see below).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--refresh SECONDS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Time between two refreshes of the screen, from &lt;code&gt;0.1&lt;/code&gt; to &lt;code&gt;60&lt;/code&gt;; decimals are accepted (&lt;code&gt;0.5&lt;/code&gt;).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--layout-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/.config/agents-exe/spectate-layout&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The saved layout: read at start when the file exists, written by the &lt;code&gt;W&lt;/code&gt; key.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a id="spectate-layout"&gt;&lt;/a&gt;
&lt;strong&gt;Layout:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The screen is columns, left to right, each a stack of panels, top to
bottom. &lt;code&gt;--panels&lt;/code&gt; describes it in one string:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;,&lt;/code&gt; separates columns, and &lt;code&gt;+&lt;/code&gt; the panels stacked in one column;
&lt;/li&gt;
&lt;li&gt;a panel is &lt;code&gt;tree&lt;/code&gt; (or &lt;code&gt;agents&lt;/code&gt;), &lt;code&gt;tools&lt;/code&gt; or &lt;code&gt;text&lt;/code&gt;; one that is not named
is hidden, and none can be named twice;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:N&lt;/code&gt; after a panel is its share of its column’s height, and &lt;code&gt;/N&lt;/code&gt; after a
column its share of the screen’s width. Shares go from 1 to 100, count
relative to their neighbours, and are 50 when left out.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;--panels&lt;/span&gt; tree,tools,text               &lt;span class="co"&gt;# three equal columns&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;--panels&lt;/span&gt; text                          &lt;span class="co"&gt;# only the text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;--panels&lt;/span&gt; tree+tools+text               &lt;span class="co"&gt;# one stack&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;--panels&lt;/span&gt; text/70,tree:30+tools:70/30   &lt;span class="co"&gt;# text on the left, wide&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Between two refreshes the events received wait, and the durations stand
still: a longer interval makes a busy run calmer to read, a shorter one
more live. Durations are still counted from when each event was received.&lt;/p&gt;
&lt;p&gt;The layout is remembered only when asked, as &lt;code&gt;top&lt;/code&gt; does with &lt;code&gt;W&lt;/code&gt;: the &lt;code&gt;W&lt;/code&gt;
key writes it to the layout file, and the next &lt;code&gt;spectate&lt;/code&gt; starts from that
file. &lt;code&gt;--panels&lt;/code&gt; and &lt;code&gt;--refresh&lt;/code&gt; each go over what the file says, so a
scripted layout (for a screenshot, say) is the same whatever was saved. A
layout file that cannot be read is an error, not a layout silently dropped.
The file holds what the flags take:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;panels tree:60+tools:40/45,text/55
refresh 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Keyboard Shortcuts:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Up&lt;/code&gt; / &lt;code&gt;Down&lt;/code&gt; (or &lt;code&gt;k&lt;/code&gt; / &lt;code&gt;j&lt;/code&gt;) - Select a session in the tree; the text panel shows it
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f&lt;/code&gt; - Follow the session that writes, again
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PgUp&lt;/code&gt; / &lt;code&gt;PgDn&lt;/code&gt; - Scroll the text
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt; / &lt;code&gt;2&lt;/code&gt; / &lt;code&gt;3&lt;/code&gt; - Show or hide the agents, tool calls, text panel (the last one shown stays); a panel that comes back is a new last column
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Tab&lt;/code&gt; / &lt;code&gt;Shift+Tab&lt;/code&gt; - Choose the panel the next keys act on; its title is in brackets
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&lt;/code&gt; / &lt;code&gt;&amp;gt;&lt;/code&gt; - Exchange it with the panel before or after
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&lt;/code&gt; / &lt;code&gt;]&lt;/code&gt; - Narrow or widen its column
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt; / &lt;code&gt;+&lt;/code&gt; - Shorten or heighten it in its column
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt; - Stack it under the column before, or give it a column of its own
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; - Back to the layout at start
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt; / &lt;code&gt;D&lt;/code&gt; - Longer or shorter refresh interval (0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60 seconds)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;W&lt;/code&gt; - Save the layout to the layout file
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?&lt;/code&gt; or &lt;code&gt;h&lt;/code&gt; - Show the keys, and the &lt;code&gt;--panels&lt;/code&gt;/&lt;code&gt;--refresh&lt;/code&gt; flags that reproduce the layout on screen
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;q&lt;/code&gt;, &lt;code&gt;Esc&lt;/code&gt; or &lt;code&gt;Ctrl+C&lt;/code&gt; - Quit (the runs go on)
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No key sends anything to the server or to the agents.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# In one terminal: a server, and a TUI or any other client driving it&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; serve &lt;span class="at"&gt;--socket&lt;/span&gt; /run/agents/agents.sock &lt;span class="at"&gt;--stream-tokens&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="at"&gt;--attach&lt;/span&gt; /run/agents/agents.sock&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# In another: watch&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; spectate &lt;span class="at"&gt;--attach&lt;/span&gt; /run/agents/agents.sock&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# The same, as three columns refreshed twice a second&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; spectate &lt;span class="at"&gt;--attach&lt;/span&gt; /run/agents/agents.sock &lt;span class="at"&gt;--panels&lt;/span&gt; tree,tools,text &lt;span class="at"&gt;--refresh&lt;/span&gt; 0.5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;A TUI started without &lt;code&gt;--attach&lt;/code&gt; runs its agents in its own process and
exposes no endpoint, so there is nothing for &lt;code&gt;spectate&lt;/code&gt; to attach to: run
&lt;code&gt;agents-exe serve&lt;/code&gt; and attach both.&lt;/p&gt;
&lt;h4 id="mcp-server"&gt;mcp-server&lt;/h4&gt;
&lt;p&gt;Start an MCP (Model Context Protocol) server.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; mcp-server [--agent-file FILE...]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
Exposes loaded agents as MCP tools for integration with MCP clients like Claude Desktop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Single agent MCP server&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; mcp-server &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Multi-agent MCP server&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; mcp-server &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; research-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; writing-agent.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="echo-prompt"&gt;echo-prompt&lt;/h4&gt;
&lt;p&gt;Process and echo the prompt without calling the LLM.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; echo-prompt &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt; Same as &lt;code&gt;run&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; Verify prompt construction before sending to LLM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; echo-prompt &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Context:&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--file&lt;/span&gt; context.txt &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Question:&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--file&lt;/span&gt; question.txt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="session-print"&gt;session-print&lt;/h4&gt;
&lt;p&gt;Display a session file in markdown format.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt; SESSIONFILE&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--show-tool-call-results MODE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Display mode: &lt;code&gt;hidden&lt;/code&gt;, &lt;code&gt;shown&lt;/code&gt;, &lt;code&gt;elided&lt;/code&gt; (default: &lt;code&gt;hidden&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--show-tool-call-arguments MODE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Display mode: &lt;code&gt;hidden&lt;/code&gt;, &lt;code&gt;shown&lt;/code&gt;, &lt;code&gt;elided&lt;/code&gt; (default: &lt;code&gt;hidden&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--n-turns N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Limit to last N turns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--repeat-system-prompt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Show system prompt each turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--repeat-tools&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Show available tools each turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--antichronological&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Newest first (default: oldest first)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--no-funny-stamp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Skip the ASCII art logo&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Print full session&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print session.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Print with tool results visible&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--show-tool-call-results&lt;/span&gt; shown session.json&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Elide long outputs (show first/last 10 lines)&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--show-tool-call-results&lt;/span&gt; elided session.json&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Last 5 turns only&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--n-turns&lt;/span&gt; 5 session.json&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Reverse order&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print &lt;span class="at"&gt;--antichronological&lt;/span&gt; session.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="session-edit"&gt;session-edit&lt;/h4&gt;
&lt;p&gt;Edit a session file (reads JSON from STDIN, writes JSON to STDOUT).&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; input.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; output.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--take&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Take first N turns (use with &lt;code&gt;--count&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--take-tail&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Take last N turns (use with &lt;code&gt;--count&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--drop&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Drop first N turns (use with &lt;code&gt;--count&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--drop-tail&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Drop last N turns (use with &lt;code&gt;--count&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--count N&lt;/code&gt;, &lt;code&gt;-n N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Number of turns for take/drop operations&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--censor-tool-calls&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Remove all tool calls&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--censor-thinking&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Remove all thinking content&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Keep only first 10 turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--take&lt;/span&gt; &lt;span class="at"&gt;--count&lt;/span&gt; 10 &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; session.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; trimmed.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Keep only last 5 turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--take-tail&lt;/span&gt; &lt;span class="at"&gt;--count&lt;/span&gt; 5 &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; session.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; recent.json&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Remove first 2 turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--drop&lt;/span&gt; &lt;span class="at"&gt;--count&lt;/span&gt; 2 &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; session.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; dropped.json&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Remove all tool calls&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--censor-tool-calls&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; session.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; no-tools.json&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Remove thinking content&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--censor-thinking&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; session.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; no-thinking.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="session-index"&gt;session-index&lt;/h4&gt;
&lt;p&gt;Manage the SQLite FTS5 search index for session files.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--build&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Build the search index from scratch&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--update&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Incrementally update the search index&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Show index status (default)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--clean&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Remove the search index&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--db-path PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path to search index database (default: &lt;code&gt;.agents-search.db&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--include-tool-outputs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Include tool outputs in the index&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
The &lt;code&gt;session-index&lt;/code&gt; command manages a SQLite FTS5-based search index for fast fuzzy text search across session files. The index uses trigram tokenization to enable fuzzy matching (e.g., “error” matches “errors”, “erroring”).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Index Schema:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;session_index&lt;/code&gt; - Session metadata cache (path, mtime, agent, turn count)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;search_content&lt;/code&gt; - FTS5 virtual table with trigram tokenizer
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tool_index&lt;/code&gt; - Tool call index for filtering by tool name
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Build the search index&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--build&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Check index status&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--status&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Update index incrementally&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--update&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Remove the index&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--clean&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Build with tool outputs included&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--build&lt;/span&gt; &lt;span class="at"&gt;--include-tool-outputs&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Custom database location&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--build&lt;/span&gt; &lt;span class="at"&gt;--db-path&lt;/span&gt; ~/.config/agents-exe/search.db&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="session-search"&gt;session-search&lt;/h4&gt;
&lt;p&gt;Search session files with fuzzy text matching and filtering.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;QUERY&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Arguments:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;QUERY&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Search query text (supports fuzzy matching)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--db-path PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path to search index database&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--after DATE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Filter sessions after date (YYYY-MM-DD)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--before DATE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Filter sessions before date (YYYY-MM-DD)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--tool TOOLNAME&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Filter by tool name (can specify multiple)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--agent SLUG&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Filter by agent slug&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--include-tool-outputs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Include tool outputs in search&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output results as JSON&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--preview N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Show N lines of context around matches&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--limit N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Limit to N results&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--auto&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Auto-update index if stale before searching&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
Performs fast fuzzy text search across session files using an SQLite FTS5 index. The search supports trigram-based fuzzy matching, allowing queries like “error” to match “errors”, “erroring”, “terror”, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Search Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fuzzy matching&lt;/strong&gt;: Trigram tokenizer handles typos and variations
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metadata filtering&lt;/strong&gt;: Filter by date, tool usage, or agent
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Incremental indexing&lt;/strong&gt;: Only re-indexes changed sessions
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSON output&lt;/strong&gt;: Machine-readable format for scripting
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Basic fuzzy search&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;database error&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Search with auto-update&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;migration&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--auto&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Include tool outputs in search&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;config.yaml&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--include-tool-outputs&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Filter by date and tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;auth&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--after&lt;/span&gt; 2024-01-01 &lt;span class="at"&gt;--tool&lt;/span&gt; write-file&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Filter by agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;refactor&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--agent&lt;/span&gt; my-coder&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# JSON output for scripting&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;TODO&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--json&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Show context lines&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;deploy&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--preview&lt;/span&gt; 5&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Combined filters&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;fix&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--after&lt;/span&gt; 2024-01-01 &lt;span class="at"&gt;--before&lt;/span&gt; 2024-12-31 &lt;span class="at"&gt;--tool&lt;/span&gt; bash_write-file &lt;span class="at"&gt;--json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;JSON Output Format:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;resultItems&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;resultMetadata&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;resultSessionId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;550e8400-e29b-41d4-a716-446655440000&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;resultFilePath&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/session.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;resultAgentSlug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;resultTurnCount&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;15&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;resultRank&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fl"&gt;0.5&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;resultPreview&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...context around match...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;resultMatchedTerms&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;database&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;resultTotalMatches&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;42&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;resultQueryTimeMs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fl"&gt;15.3&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;resultIndexWasUpdated&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="list-tool-calls"&gt;list-tool-calls&lt;/h4&gt;
&lt;p&gt;Extract and list all tool calls from a session file.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; list-tool-calls &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt; SESSIONFILE&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f, --format FORMAT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output format: &lt;code&gt;human&lt;/code&gt;, &lt;code&gt;json&lt;/code&gt;, &lt;code&gt;brief&lt;/code&gt; (default: &lt;code&gt;human&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
Parses a session file and extracts all tool calls made during the conversation.
Useful for debugging, auditing, and replaying specific tool calls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output formats:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;human&lt;/code&gt; - Detailed human-readable format with indices, turn numbers, and arguments
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;json&lt;/code&gt; - JSON array for machine processing
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brief&lt;/code&gt; - Compact tabular format (index, name, arguments preview)
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# List tool calls in human-readable format&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; list-tool-calls session.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Output as JSON&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; list-tool-calls session.json &lt;span class="at"&gt;--format&lt;/span&gt; json&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Brief format for quick overview&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; list-tool-calls session.json &lt;span class="at"&gt;--format&lt;/span&gt; brief&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example output (human format):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Found 3 tool call(s):

[0] bash_read-file
  Turn: 1
  Arguments: 
    {&amp;quot;filepath&amp;quot;:&amp;quot;./src/Main.hs&amp;quot;}

[1] bash_grep-files
  Turn: 2
  Arguments: 
    {&amp;quot;pattern&amp;quot;:&amp;quot;TODO&amp;quot;,&amp;quot;filepath&amp;quot;:&amp;quot;./src&amp;quot;}

[2] bash_write-file
  Turn: 2
  Arguments: 
    {&amp;quot;filepath&amp;quot;:&amp;quot;./src/Main.hs&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;...&amp;quot;}

To replay a tool call:
  agents-exe replay-tool-call --session &amp;lt;file&amp;gt; --tool-call &amp;lt;index&amp;gt; --tool &amp;lt;tool-path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="replay-tool-call"&gt;replay-tool-call&lt;/h4&gt;
&lt;p&gt;Replay a specific tool call from a session file, with validation.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; replay-tool-call &lt;span class="at"&gt;--session&lt;/span&gt; FILE &lt;span class="at"&gt;--tool-call&lt;/span&gt; INDEX &lt;span class="at"&gt;--tool&lt;/span&gt; TOOLPATH &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-s, --session FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path to the session file containing the tool call&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-i, --tool-call INDEX&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Index of the tool call to replay (0-based)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-t, --tool TOOLPATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path to the tool script to execute&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--validate-only&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Only validate arguments, don't execute&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--raw&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Show raw output instead of formatted&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
Extracts a tool call from a session file, validates its arguments against the tool’s schema,
and optionally executes the tool with the same arguments. This is useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debugging failed tool calls
&lt;/li&gt;
&lt;li&gt;Reproducing tool execution for testing
&lt;/li&gt;
&lt;li&gt;Validating historical tool calls against updated schemas
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Exit codes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; - Validation passed (and tool executed if not –validate-only)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt; - Validation failed or tool execution failed
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# First, list tool calls to find the index&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; list-tool-calls session.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Validate and execute a tool call&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; replay-tool-call &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--session&lt;/span&gt; session.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool-call&lt;/span&gt; 0 &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/read-file.sh&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Only validate without executing&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; replay-tool-call &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--session&lt;/span&gt; session.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool-call&lt;/span&gt; 1 &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/grep-files.sh &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--validate-only&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Execute and show raw output&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; replay-tool-call &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--session&lt;/span&gt; session.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool-call&lt;/span&gt; 2 &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/write-file.sh &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--raw&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;✓ Tool call validation passed
Tool: read-file
Arguments: {&amp;quot;filepath&amp;quot;:&amp;quot;./src/Main.hs&amp;quot;}

Executing tool...

=== Tool Output ===
module Main where

main :: IO ()
main = putStrLn &amp;quot;Hello, World!&amp;quot;
===================
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="tool-call"&gt;tool-call&lt;/h4&gt;
&lt;p&gt;Call a tool from the first loaded agent with JSON payload from stdin.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{}&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;agents-exe&lt;/span&gt; tool-call TOOLNAME &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Arguments:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;TOOLNAME&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Name of the tool to call&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-l, --log-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Optional log file for tracing tool execution&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
Executes a single tool directly without involving the LLM. Useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Testing tool implementations
&lt;/li&gt;
&lt;li&gt;Scripting tool usage
&lt;/li&gt;
&lt;li&gt;Debugging tool behavior
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Call a tool with arguments&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;filepath&amp;quot;: &amp;quot;./README.md&amp;quot;}&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ex"&gt;agents-exe&lt;/span&gt; tool-call read-file &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./agent.json&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Call with logging&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;command&amp;quot;: &amp;quot;ls -la&amp;quot;}&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ex"&gt;agents-exe&lt;/span&gt; tool-call bash &lt;span class="at"&gt;--log-file&lt;/span&gt; ./tool-debug.log&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="serve"&gt;serve&lt;/h4&gt;
&lt;p&gt;Run agents over HTTP, like &lt;code&gt;agents-server&lt;/code&gt;, loading agents-exe.cfg.json like the TUI does.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; serve [--agent-file FILE...] [--agent SLUG] &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;agents-exe serve&lt;/code&gt; is &lt;code&gt;agents-server&lt;/code&gt;’s code (sessions in SQLite or Postgres,
the HTTP API and SSE stream, MCP over HTTP, the chat page) run behind
agents-exe’s own config loading, so it resolves agent files the same way
every other &lt;code&gt;agents-exe&lt;/code&gt; command does: &lt;code&gt;--agent-file&lt;/code&gt; (repeatable), else
&lt;code&gt;agents-exe.cfg.json&lt;/code&gt;’s &lt;code&gt;agentsFiles&lt;/code&gt; plus every &lt;code&gt;.json&lt;/code&gt; and &lt;code&gt;.tramaj&lt;/code&gt; file under
&lt;code&gt;agentsDirectories&lt;/code&gt;, else &lt;code&gt;~/.config/agents-exe/default&lt;/code&gt;; &lt;code&gt;--agent SLUG&lt;/code&gt;
narrows to one agent by slug, failing with the list of available slugs if it
does not match. It shares agents-exe’s global &lt;code&gt;--api-keys&lt;/code&gt;,
&lt;code&gt;--set&lt;/code&gt;/&lt;code&gt;--set-json&lt;/code&gt;/&lt;code&gt;--pin&lt;/code&gt;/&lt;code&gt;--pin-json&lt;/code&gt; and &lt;code&gt;--params-file&lt;/code&gt;, so those are
not repeated below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--db FILE\|URL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;next to the resolved sessions directory&lt;/td&gt;&lt;td&gt;SQLite file, or &lt;code&gt;postgresql://&lt;/code&gt; URL, for sessions and continuations&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--bind HOST&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Address to listen on&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--port PORT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;8080&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Port to listen on&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--live-session-ttl SECONDS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;900&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Idle time before a session's in-memory state is dropped&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--shutdown-grace SECONDS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Time open requests get to finish on shutdown&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--auth-tokens FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Bearer tokens and their owners; without, no authentication&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--stream-tokens&lt;/code&gt;&lt;/td&gt;&lt;td&gt;off&lt;/td&gt;&lt;td&gt;Stream LLM answers as &lt;code&gt;text.delta&lt;/code&gt; events&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--admin-owners OWNER,…&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Owners allowed to store and delete agents over the API (needs &lt;code&gt;--auth-tokens&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--no-ui&lt;/code&gt;&lt;/td&gt;&lt;td&gt;off&lt;/td&gt;&lt;td&gt;Do not serve the chat page at &lt;code&gt;/&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--cors-origin ORIGIN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Allow this origin to call the server cross-origin; repeatable, or &lt;code&gt;*&lt;/code&gt; for any (needs no &lt;code&gt;--auth-tokens&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--socket PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Also listen on this Unix domain socket, in addition to &lt;code&gt;--bind&lt;/code&gt;/&lt;code&gt;--port&lt;/code&gt;; created &lt;code&gt;0600&lt;/code&gt;, a stale file removed at start, closed and unlinked on shutdown. The socket is the local trust boundary: no &lt;code&gt;Origin&lt;/code&gt;, no bearer token beyond &lt;code&gt;--auth-tokens&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--owner-api-keys OWNER=FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;This owner's sessions call the LLM with the keys in &lt;code&gt;FILE&lt;/code&gt; instead of the shared ones; repeatable (needs &lt;code&gt;--auth-tokens&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--isolate-tools docker:IMAGE\|process:PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Run bash and MCP tool calls outside the server, in a worker you provide&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;See &lt;a href="/agents-exe/docs-agents-server.html"&gt;agents-server.md&lt;/a&gt; for everything the running server
does (the HTTP API, sessions, deferred calls, CORS, authentication, running
it as a service).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Explicit agent files, like agents-server&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; serve &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./weather.json &lt;span class="at"&gt;--api-keys&lt;/span&gt; ./keys.json &lt;span class="at"&gt;--port&lt;/span&gt; 8080&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# From a directory with an agents-exe.cfg.json&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; serve &lt;span class="at"&gt;--port&lt;/span&gt; 8080&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# One agent from a multi-agent config, over a local socket only auth-tokens gate&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; serve &lt;span class="at"&gt;--agent&lt;/span&gt; architect &lt;span class="at"&gt;--socket&lt;/span&gt; /run/agents-exe/agents.sock &lt;span class="at"&gt;--auth-tokens&lt;/span&gt; ./tokens.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="check-tool-call"&gt;check-tool-call&lt;/h4&gt;
&lt;p&gt;Validate a tool call payload against a tool schema (reads JSON from stdin).&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;cat&lt;/span&gt; payload.json &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;agents-exe&lt;/span&gt; check-tool-call &lt;span class="at"&gt;--tool&lt;/span&gt; TOOLPATH&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-t, --tool TOOLPATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path to the tool script to validate against&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
Validates that a JSON payload from stdin matches the tool’s declared schema.
Returns exit code 0 if valid, 1 if invalid with detailed error messages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create a test payload&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;filepath&amp;quot;: &amp;quot;/path/to/file&amp;quot;}&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;agents-exe&lt;/span&gt; check-tool-call &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/read-file.sh&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Validate from file&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;cat&lt;/span&gt; payload.json &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;agents-exe&lt;/span&gt; check-tool-call &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/my-tool.sh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example output (valid):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;✓ Tool call payload is valid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Example output (invalid):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Tool call validation failed for './tools/my-tool.sh (my-tool)' with 2 errors:

1. filepath: Required property missing

2. content: Required property missing

Please correct these issues and try again.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="init"&gt;init&lt;/h4&gt;
&lt;p&gt;Initialize a new agent configuration.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; init [--agent-file FILE]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Creates:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agent.json&lt;/code&gt; - Agent configuration
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tools/&lt;/code&gt; - Tool directory
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;secret-keys&lt;/code&gt; - API keys file (if doesn’t exist)
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; init &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="new"&gt;new&lt;/h4&gt;
&lt;p&gt;Create scaffolding for new agents or tools.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new &lt;span class="er"&gt;(&lt;/span&gt;&lt;span class="ex"&gt;agent&lt;/span&gt;&lt;span class="kw"&gt;|&lt;/span&gt;&lt;span class="ex"&gt;tool&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt; &lt;span class="ex"&gt;[OPTIONS]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="new-agent"&gt;new agent&lt;/h5&gt;
&lt;p&gt;Create a new agent configuration file from a template.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new agent SLUG FILE &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;MODEL&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt; &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Arguments:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SLUG&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Unique identifier for the agent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output file path&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;MODEL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Model name (e.g., gpt-4o, mistral-large). The provider preset is inferred from the model catalog.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--add-to-config&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Add the agent to the &lt;code&gt;agentsFiles&lt;/code&gt; of &lt;code&gt;agents-exe.cfg.json&lt;/code&gt; when it is not listed there, without asking&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--no-add-to-config&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Never modify &lt;code&gt;agents-exe.cfg.json&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f, --force&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Overwrite existing file (given before the subcommand: &lt;code&gt;agents-exe new --force agent ...&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Provider presets (URL, default model, API key ID) are selected automatically
based on the model name. Use &lt;code&gt;agents-exe new models list&lt;/code&gt; to see the built-in
model patterns and &lt;code&gt;agents-exe new models init&lt;/code&gt; to customize them locally.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create agent with the default OpenAI preset&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new agent my-assistant ./my-assistant.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create agent with custom model (preset inferred from the catalog)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new agent coder ./coder.json gpt-4o&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create agent in a subdirectory and list it in agents-exe.cfg.json&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new agent my-assistant ./agents/assistant.json &lt;span class="at"&gt;--add-to-config&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Overwrite existing&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new &lt;span class="at"&gt;--force&lt;/span&gt; agent my-assistant ./my-assistant.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;What a new agent can do:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A new agent works on the directory it is started from:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Toolbox&lt;/th&gt;&lt;th&gt;Gives the agent&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;developer&lt;/code&gt; (DeveloperToolbox)&lt;/td&gt;&lt;td&gt;Reading and editing files (&lt;code&gt;read-file-range&lt;/code&gt;, &lt;code&gt;write-file-range&lt;/code&gt;, &lt;code&gt;patch-file&lt;/code&gt;), and the agent/tool scaffolding helpers&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;system&lt;/code&gt; (SystemToolbox)&lt;/td&gt;&lt;td&gt;The working directory and directory listings (&lt;code&gt;working-directory&lt;/code&gt;, &lt;code&gt;list-directory&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;memory&lt;/code&gt; (SqliteToolbox)&lt;/td&gt;&lt;td&gt;A read-write SQLite database, &lt;code&gt;./{slug}-memory.sqlite&lt;/code&gt;, created on first use&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;File access is limited by one file sandbox, &lt;code&gt;workspace&lt;/code&gt;, declared in the
agent’s &lt;code&gt;fileSandboxes&lt;/code&gt; and shared by the &lt;code&gt;developer&lt;/code&gt; and &lt;code&gt;system&lt;/code&gt; toolboxes.
It allows reading and writing &lt;code&gt;./&lt;/code&gt; and everything below it, where &lt;code&gt;./&lt;/code&gt; is the
directory the agent runs in (not the directory of the agent file). Edit its
&lt;code&gt;fsbPredicate&lt;/code&gt; to narrow or widen what the agent may touch; see
&lt;a href="/agents-exe/docs-tools.html"&gt;Tools&lt;/a&gt; for the predicates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generated agent file:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-assistant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;main-key&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIv1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4-turbo-preview&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;a helpful assistant powered by gpt-4-turbo-preview&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You are my-assistant, a helpful AI assistant.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You provide clear, accurate, and concise responses.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;When using tools, you explain your actions to the user.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;mcpServers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;fileSandboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;workspace&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;fsbMaxFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;52428800&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;fsbName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;builtinToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DeveloperToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;developer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Tools for developing agents and tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;show-spec&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;validate-agent&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;create-agent&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;create-tool&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-file-range&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;write-file-range&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;patch-file&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;ref&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;workspace&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SystemToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;system&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Working directory and directory listings&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;working-directory&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;list-directory&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;ref&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;workspace&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SqliteToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;memory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Notes and facts to remember across conversations&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Versioning&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SqliteReadWrite&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./my-assistant-memory.sqlite&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="51"&gt;&lt;a href="#51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="52"&gt;&lt;a href="#52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="53"&gt;&lt;a href="#53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Listing the agent in &lt;code&gt;agents-exe.cfg.json&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After writing the file, &lt;code&gt;new agent&lt;/code&gt; looks for an &lt;code&gt;agents-exe.cfg.json&lt;/code&gt; (in the
current directory, then upward) and reports whether the new agent is loaded by
it, that is, named in &lt;code&gt;agentsFiles&lt;/code&gt; or sitting directly in one of the
&lt;code&gt;agentsDirectories&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;listed: nothing else to do;
&lt;/li&gt;
&lt;li&gt;not listed, on an interactive terminal: it asks whether to add the file to
&lt;code&gt;agentsFiles&lt;/code&gt; (default: no);
&lt;/li&gt;
&lt;li&gt;not listed, not interactive: it prints the entry to add. Pass
&lt;code&gt;--add-to-config&lt;/code&gt; to add it without being asked, &lt;code&gt;--no-add-to-config&lt;/code&gt; to
never be asked.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adding the entry rewrites the config file as formatted JSON; every other field
is kept. Without any &lt;code&gt;agents-exe.cfg.json&lt;/code&gt;, pass the file with &lt;code&gt;--agent-file&lt;/code&gt;
or create a config with &lt;code&gt;agents-exe config local init&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id="new-tool"&gt;new tool&lt;/h5&gt;
&lt;p&gt;Create a new tool script from a template.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new tool SLUG LANGUAGE FILE &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Arguments:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SLUG&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Unique identifier for the tool&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;LANGUAGE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Programming language: &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;python&lt;/code&gt;, &lt;code&gt;haskell&lt;/code&gt;, &lt;code&gt;node&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output file path (without extension)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f, --force&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Overwrite existing file&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create bash tool (default)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new tool my-tool bash ./tools/my-tool&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create Python tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new tool my-tool python ./scripts/my-tool&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create Haskell tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new tool my-tool haskell ./tools/my-tool&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create Node.js tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new tool my-tool node ./scripts/my-tool&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Generated bash tool:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# my-tool - A bash tool for agents-exe&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;set&lt;/span&gt; &lt;span class="at"&gt;-euo&lt;/span&gt; pipefail&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Agents-exe tool protocol: describe|run&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Environment variables available during &amp;#39;run&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#   AGENT_SESSION_ID      - UUID of the current session&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#   AGENT_CONVERSATION_ID - UUID of the conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#   AGENT_TURN_ID         - UUID of the current turn&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#   AGENT_AGENT_ID        - UUID of the executing agent (if available)&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${1&lt;/span&gt;&lt;span class="op"&gt;:-&lt;/span&gt;&lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ss"&gt;describe&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;cat&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;lt;&amp;#39;DESCRIBE_EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;slug&amp;quot;: &amp;quot;my-tool&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;description&amp;quot;: &amp;quot;Tool my-tool - describe what this tool does&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;args&amp;quot;: [],&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;empty-result&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    &amp;quot;tag&amp;quot;: &amp;quot;AddMessage&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    &amp;quot;contents&amp;quot;: &amp;quot;--no output--&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;DESCRIBE_EOF&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ss"&gt;run&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;# &lt;/span&gt;&lt;span class="al"&gt;TODO&lt;/span&gt;&lt;span class="co"&gt;: Implement tool logic&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;# Access arguments via environment or command line&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Tool my-tool executed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;*&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Usage: my-tool &amp;lt;describe|run&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;esac&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Next steps after creating a tool:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Edit the &lt;code&gt;args&lt;/code&gt; array in the describe function
&lt;/li&gt;
&lt;li&gt;Implement the &lt;code&gt;run&lt;/code&gt; function logic
&lt;/li&gt;
&lt;li&gt;Test with: &lt;code&gt;agents-exe describe-tool ./tools/my-tool&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="config"&gt;config&lt;/h4&gt;
&lt;p&gt;Configure agents-exe itself: the project config file, the TUI keymap and the
API keys file, without writing their JSON by hand.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; config [-f&lt;span class="kw"&gt;|&lt;/span&gt;&lt;span class="ex"&gt;--force]&lt;/span&gt; &lt;span class="er"&gt;(&lt;/span&gt;&lt;span class="bu"&gt;local&lt;/span&gt;&lt;span class="kw"&gt;|&lt;/span&gt;&lt;span class="ex"&gt;keymap&lt;/span&gt;&lt;span class="kw"&gt;|&lt;/span&gt;&lt;span class="ex"&gt;api-key&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt; &lt;span class="ex"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f, --force&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Overwrite an existing file or API key entry. It belongs to &lt;code&gt;config&lt;/code&gt;, so it goes last: &lt;code&gt;agents-exe config local init --force&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h5 id="config-local-init"&gt;config local init&lt;/h5&gt;
&lt;p&gt;Create an &lt;code&gt;agents-exe.cfg.json&lt;/code&gt; in the current directory.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; config local init&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The file is minimal: &lt;code&gt;agentsConfigDir&lt;/code&gt; pointing at &lt;code&gt;~/.config/agents-exe&lt;/code&gt; and
an empty &lt;code&gt;agentsFiles&lt;/code&gt;. Add agents to &lt;code&gt;agentsFiles&lt;/code&gt; or &lt;code&gt;agentsDirectories&lt;/code&gt;
(see &lt;a href="#configuration-file"&gt;Configuration File&lt;/a&gt;); &lt;code&gt;agents-exe new agent&lt;/code&gt; offers
to do it for the agents it creates. Only the current directory is checked for
an existing file, not its parents; an existing file is kept unless &lt;code&gt;--force&lt;/code&gt;
is given.&lt;/p&gt;
&lt;h5 id="config-keymap-init"&gt;config keymap init&lt;/h5&gt;
&lt;p&gt;Write a keymap file holding the default TUI key bindings and input settings,
as a starting point for customization.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; config keymap init FILE&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path where the keymap file is created (parent directories are created as needed)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Point the &lt;code&gt;keymap&lt;/code&gt; field of &lt;code&gt;agents-exe.cfg.json&lt;/code&gt; at the file to use it. An
existing file is kept unless &lt;code&gt;--force&lt;/code&gt; is given.&lt;/p&gt;
&lt;h5 id="config-api-key-list"&gt;config api-key list&lt;/h5&gt;
&lt;p&gt;List the names of the configured API keys (never their values).&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; config api-key list&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="config-api-key-create"&gt;config api-key create&lt;/h5&gt;
&lt;p&gt;Add an entry to the API keys file with a placeholder value, to be replaced by
the real key in an editor.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; config api-key create NAME&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;NAME&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Name of the key, as referenced by an agent's &lt;code&gt;apiKeyId&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;An existing entry of that name is kept unless &lt;code&gt;--force&lt;/code&gt; is given, in which
case it is reset to the placeholder.&lt;/p&gt;
&lt;p&gt;Both &lt;code&gt;api-key&lt;/code&gt; subcommands work on the &lt;code&gt;secret-keys&lt;/code&gt; file of the config
directory (&lt;code&gt;~/.config/agents-exe/secret-keys&lt;/code&gt; by default), and create it empty
if it does not exist. The global &lt;code&gt;--api-keys&lt;/code&gt; option does not redirect them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Start a project: config file, then an agent listed in it&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; config local init&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new agent helper ./helper.json &lt;span class="at"&gt;--add-to-config&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Declare the key the agent&amp;#39;s preset refers to, then fill in its value&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; config api-key create main-key&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; config api-key list&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Customize the TUI key bindings&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; config keymap init ./keymap.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="spec"&gt;spec&lt;/h4&gt;
&lt;p&gt;Display embedded specification documentation.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; spec TOPIC&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Topics:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Topic&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bash-tools&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Binary tool protocol specification&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Display bash-tools specification&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; spec bash-tools&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; Learn the protocol for writing bash tools without leaving the CLI.&lt;/p&gt;
&lt;h4 id="describe-tool"&gt;describe-tool&lt;/h4&gt;
&lt;p&gt;Display information about a tool script.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; describe-tool TOOL_PATH &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f, --format FORMAT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output format: &lt;code&gt;json&lt;/code&gt; or &lt;code&gt;pretty&lt;/code&gt; (default: &lt;code&gt;json&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--check-only&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Only check validity, don't output full description&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
Loads and displays the tool’s description (the output of &lt;code&gt;tool describe&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; describe-tool ./tools/my-tool.sh&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Pretty format&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; describe-tool ./tools/my-tool.sh &lt;span class="at"&gt;--format&lt;/span&gt; pretty&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Only check validity&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; describe-tool ./tools/my-tool.sh &lt;span class="at"&gt;--check-only&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;What this tool does&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="er"&gt;...&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;empty-result&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="er"&gt;...&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="paths"&gt;paths&lt;/h4&gt;
&lt;p&gt;Show important configuration paths.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; paths &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output in JSON format&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
Displays configuration paths including config directory, agent files,
API keys file, and session storage configuration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Session Storage:&lt;/strong&gt;
The session storage configuration supports multiple read locations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Write location&lt;/strong&gt;: Where new sessions are saved
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read locations&lt;/strong&gt;: Directories searched for existing sessions (includes write location by default)
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Human-readable output&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; paths&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# JSON output&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; paths &lt;span class="at"&gt;--json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Configuration:
  File: /home/user/project/agents-exe.cfg.json
  Directory: /home/user/project
  Default: /home/user/.config/agents-exe

Agent Files:
  - ./main-agent.json
  - ./secondary-agent.json

API Keys:
  /home/user/.config/agents-exe/secret-keys

Session Storage:
  Write location: ./sessions/
  Read locations:
    1. ./sessions/
    2. ./.agents-sessions/
    3. ~/.config/agents-exe/sessions/
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="export"&gt;export&lt;/h4&gt;
&lt;p&gt;Export agent/tool configurations to archive or git.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; export &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Source Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--all&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Export all loaded agents&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--agent-slug SLUG&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Export specific agent by slug&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--tools-only&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Export only tools, not agent config&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--tool TOOLNAME&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Export specific tool&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Destination Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-o, --output FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output file path&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--git-url URL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Git remote URL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--git-branch BRANCH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Git branch&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--git-message MESSAGE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Commit message&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--git-push&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Push after commit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--git-tag TAG&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Create git tag&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Format Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--format FORMAT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Archive format: tar, tar.gz, zip&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--namespace NAMESPACE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Namespace for export (e.g., "team.project")&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--no-tools&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Exclude tools from export&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--no-mcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Exclude MCP servers from export&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Export to tar.gz&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; export &lt;span class="at"&gt;--output&lt;/span&gt; ./my-agent.tar.gz&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Export to git&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; export &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--git-url&lt;/span&gt; https://github.com/user/agents-repo &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--git-branch&lt;/span&gt; main &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--git-message&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Update agent&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--git-push&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Export tools only&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; export &lt;span class="at"&gt;--tools-only&lt;/span&gt; &lt;span class="at"&gt;--output&lt;/span&gt; ./tools.tar.gz&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Export specific agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; export &lt;span class="at"&gt;--agent-slug&lt;/span&gt; my-agent &lt;span class="at"&gt;--output&lt;/span&gt; ./agent.tar.gz&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# With namespace&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; export &lt;span class="at"&gt;--namespace&lt;/span&gt; team-a.project-1 &lt;span class="at"&gt;--output&lt;/span&gt; ./export.tar.gz&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="import"&gt;import&lt;/h4&gt;
&lt;p&gt;Import agent/tool configurations from archive or git.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; import &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Source Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-f, --from-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Import from archive file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--git-url URL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Import from git URL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--git-ref REF&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Git ref (branch, tag, commit)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--namespace NAMESPACE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Namespace to import from&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Destination Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--to-current&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Import to current directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--to PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Import to specific path&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--to-config-dir&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Import to config directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--install-to-agent FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Install tools to agent's tool directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--install-to-tooldir DIR&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Install tools to specific directory&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Mode Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--overwrite&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Overwrite existing files&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--merge&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Merge with existing files&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(default)&lt;/td&gt;&lt;td&gt;Fail on conflict&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;List Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--list-namespaces&lt;/code&gt;&lt;/td&gt;&lt;td&gt;List available namespaces (git only)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--list-tools&lt;/code&gt;&lt;/td&gt;&lt;td&gt;List available tools (git only)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Import from archive&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; import &lt;span class="at"&gt;--from-file&lt;/span&gt; ./agent.tar.gz&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Import from git&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; import &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--git-url&lt;/span&gt; https://github.com/user/agents-repo &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--git-ref&lt;/span&gt; main&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Import tools to agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; import &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--from-file&lt;/span&gt; ./tools.tar.gz &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--install-to-agent&lt;/span&gt; ./my-agent.json&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Import with overwrite&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; import &lt;span class="at"&gt;--from-file&lt;/span&gt; ./agent.tar.gz &lt;span class="at"&gt;--overwrite&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# List namespaces&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; import &lt;span class="at"&gt;--git-url&lt;/span&gt; https://github.com/user/repo &lt;span class="at"&gt;--list-namespaces&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Import specific namespace&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; import &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--git-url&lt;/span&gt; https://github.com/user/repo &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--namespace&lt;/span&gt; team-a.tools &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--to&lt;/span&gt; ./tools/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="cowsay"&gt;cowsay&lt;/h4&gt;
&lt;p&gt;Display a fun message with the agents-exe mascot.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; cowsay &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;MESSAGE&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt; &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-W, --width WIDTH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Maximum width of speech bubble (default: 40)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;
If no message is provided, reads from stdin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; cowsay &lt;span class="st"&gt;&amp;quot;Hello, agents!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# With custom width&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; cowsay &lt;span class="st"&gt;&amp;quot;A much longer message that needs more space&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--width&lt;/span&gt; 60&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Pipe from another command&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;System ready&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;agents-exe&lt;/span&gt; cowsay&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="describe"&gt;describe&lt;/h4&gt;
&lt;p&gt;Output self-describing schema for the agent.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; describe &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;OPTIONS&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--self-describe-slug NAME&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Override the slug field&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--self-describe-description DESC&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Override the description&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt; JSON schema for tool calling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; Integration with external systems that need to understand the agent’s interface.&lt;/p&gt;
&lt;h4 id="self-describe"&gt;self-describe&lt;/h4&gt;
&lt;p&gt;Output information about the agents-exe binary itself.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; self-describe&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt; Version, build info, and available commands.&lt;/p&gt;
&lt;h3 id="configuration-file"&gt;Configuration File&lt;/h3&gt;
&lt;p&gt;Project-level configuration in &lt;code&gt;agents-exe.cfg.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsConfigDir&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/custom/config/path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsDirectories&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;./agents&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;./more-agents&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsFiles&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;./main-agent.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;promptAliases&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;translate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;You are a translator...&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;userPromptPrefix&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Translate to English:&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;selfDescribeSlug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;selfDescribeDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;A custom agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsLogs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;logJsonHttpEndpoint&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;http://localhost:8080/log&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;logJsonPath&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./logs/agents.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;logRawPath&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./logs/agents.log&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;writeLocation&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;readLocations&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./sessions/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;./.agents-sessions/&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;~/.config/agents-exe/sessions/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Search order:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Current directory
&lt;/li&gt;
&lt;li&gt;Parent directories (upward search)
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="sessions-configuration"&gt;Sessions Configuration&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;sessions&lt;/code&gt; section configures multi-location session storage:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;writeLocation&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;FilePath&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Directory where new sessions are written&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;readLocations&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[FilePath]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Directories to search for existing sessions&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Key behaviors:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deduplication&lt;/strong&gt;: First location in &lt;code&gt;readLocations&lt;/code&gt; has highest priority for duplicate session IDs
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-prepending&lt;/strong&gt;: If &lt;code&gt;writeLocation&lt;/code&gt; is not in &lt;code&gt;readLocations&lt;/code&gt;, it’s automatically prepended
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tilde expansion&lt;/strong&gt;: Paths like &lt;code&gt;~/.config/agents-exe/sessions/&lt;/code&gt; are resolved to the user’s home directory
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backwards compatibility&lt;/strong&gt;: If &lt;code&gt;sessions&lt;/code&gt; is not present, falls back to &lt;code&gt;agentsLogs.logSessionsJsonPrefix&lt;/code&gt; (deprecated)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="environment-variables"&gt;Environment Variables&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Variable&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENTS_API_KEY&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Default API key (overrides file)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENTS_CONFIG_DIR&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Config directory path&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENTS_LOG_LEVEL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Logging verbosity&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_MD_VIEWER&lt;/code&gt;&lt;/td&gt;&lt;td&gt;External markdown viewer for TUI session viewing&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="exit-codes"&gt;Exit Codes&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Code&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Success&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;General error&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Invalid arguments&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Configuration error&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Agent loading error&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;5&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Tool execution error&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Export error&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;11&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Import error&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="examples"&gt;Examples&lt;/h3&gt;
&lt;h4 id="complete-workflow"&gt;Complete Workflow&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 1. Initialize new agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new agent my-assistant&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 2. Create a custom tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new tool file-reader python ./tools/file-reader&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 3. Edit tool and agent configurations&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# (edit files as needed)&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 4. Check configuration&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-assistant.json&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 5. Test with one-shot&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-assistant.json &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Test&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 6. Start interactive session&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-assistant.json&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 7. Export for sharing&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; export &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-assistant.json &lt;span class="at"&gt;--output&lt;/span&gt; ./my-assistant.tar.gz&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 8. Import elsewhere&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; import &lt;span class="at"&gt;--from-file&lt;/span&gt; ./my-assistant.tar.gz &lt;span class="at"&gt;--to&lt;/span&gt; ./new-location/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="multi-agent-setup"&gt;Multi-Agent Setup&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Start multi-agent TUI&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./router.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./coder.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./reviewer.json&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Start multi-agent MCP server&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; mcp-server &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./router.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./coder.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="session-management-workflow"&gt;Session Management Workflow&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Run an agent session&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--session-file&lt;/span&gt; ./session.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Let&amp;#39;s work on a project&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Later, inspect the session&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print ./session.json&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# List all tool calls from the session&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; list-tool-calls ~/.config/agents-exe/sessions/session-&lt;span class="pp"&gt;*&lt;/span&gt;.json&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Replay a specific tool call for debugging&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; replay-tool-call &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--session&lt;/span&gt; ./session.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool-call&lt;/span&gt; 0 &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/read-file.sh &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--validate-only&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Trim to last 20 turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-edit &lt;span class="at"&gt;--take-tail&lt;/span&gt; &lt;span class="at"&gt;--count&lt;/span&gt; 20 &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; ./session.json &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; ./trimmed.json&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;mv&lt;/span&gt; ./trimmed.json ./session.json&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Continue the session&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--session-file&lt;/span&gt; ./session.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Where were we?&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="session-search-workflow"&gt;Session Search Workflow&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Build the search index&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-index &lt;span class="at"&gt;--build&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Search for error-related sessions&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;error&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--json&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Find sessions using specific tool after a date&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;config&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--after&lt;/span&gt; 2024-01-01 &lt;span class="at"&gt;--tool&lt;/span&gt; write-file&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Search with context preview&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;TODO&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--preview&lt;/span&gt; 3&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Auto-update index before searching&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-search &lt;span class="st"&gt;&amp;quot;refactor&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;--auto&lt;/span&gt; &lt;span class="at"&gt;--limit&lt;/span&gt; 10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="multi-modal-workflow"&gt;Multi-Modal Workflow&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Analyze a screenshot with a vision-capable agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./vision-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;-m&lt;/span&gt; ./screenshot.png &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;What UI issues do you see in this screenshot?&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Analyze multiple images&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./design-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;-m&lt;/span&gt; ./mockup-v1.png &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;-m&lt;/span&gt; ./mockup-v2.png &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Compare these two design mockups and recommend which to use&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Analyze a PDF document&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./document-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;-m&lt;/span&gt; ./report.pdf &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Summarize the key findings and recommendations&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Combine image with code for debugging&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./debug-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;This error appears in the UI:&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;-m&lt;/span&gt; ./error-screenshot.png &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--sep4&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;----&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Here&amp;#39;s the relevant code:&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--file&lt;/span&gt; ./src/Main.hs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="automation"&gt;Automation&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Process all files in directory&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;for&lt;/span&gt; file &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span class="pp"&gt;*&lt;/span&gt;.txt&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./processor.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Process this file:&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="at"&gt;--file&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$file&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;End of file.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Git pre-commit hook&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./reviewer.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--shell&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;git diff --cached&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Review these changes.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Daily summary from logs&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./summarizer.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--shell&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;cat /var/log/app.log | tail -100&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Summarize any errors or warnings&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Automated image analysis with timestamp&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./monitor-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;-m&lt;/span&gt; ./screenshots/&lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="fu"&gt;date&lt;/span&gt; +%Y%m%d-%H%M%S&lt;span class="va"&gt;)&lt;/span&gt;.png &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Check for any alerts or errors in this status dashboard&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="developer-workflow"&gt;Developer Workflow&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Learn the tool protocol&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; spec bash-tools&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create and validate a tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new tool my-validator bash ./tools/my-validator&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# (edit the tool)&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; describe-tool ./tools/my-validator &lt;span class="at"&gt;--format&lt;/span&gt; pretty&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Validate a payload&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;input&amp;quot;: &amp;quot;test&amp;quot;}&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;agents-exe&lt;/span&gt; check-tool-call &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/my-validator&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Test the tool directly&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;input&amp;quot;: &amp;quot;test&amp;quot;}&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;agents-exe&lt;/span&gt; tool-call my-validator&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create agent with dev tools&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new agent dev-assistant&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# (add DeveloperToolbox to builtinToolboxes)&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Now the agent can use developer file-editing tools and show specs!&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create a tool that outputs media&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; new tool chart-generator bash ./tools/chart-gen&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Add to describe output:&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#   &amp;quot;output-media-type&amp;quot;: &amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Now the tool&amp;#39;s output is treated as a PNG image&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="debugging-tool-calls"&gt;Debugging Tool Calls&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Run an agent session&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Read the README&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Find the session file&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; paths&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# List all tool calls&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; list-tool-calls ~/.config/agents-exe/sessions/session-&lt;span class="pp"&gt;*&lt;/span&gt;.json&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Replay with validation only&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; replay-tool-call &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--session&lt;/span&gt; ~/.config/agents-exe/sessions/session-xxx.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool-call&lt;/span&gt; 0 &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/read-file.sh &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--validate-only&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Actually replay the tool call&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; replay-tool-call &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--session&lt;/span&gt; ~/.config/agents-exe/sessions/session-xxx.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool-call&lt;/span&gt; 0 &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/read-file.sh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="related-documentation"&gt;Related Documentation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-tools.html"&gt;tools.md&lt;/a&gt; - Tool system details
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-tui.html"&gt;tui.md&lt;/a&gt; - Terminal UI documentation
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-sessions.html"&gt;sessions.md&lt;/a&gt; - Session management
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-architecture.html"&gt;architecture.md&lt;/a&gt; - System architecture
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-cli-commands.html" rel="alternate"/><summary type="text">Complete reference for the Agents CLI commands and options. ## Global Options These options apply to all commands: ```bash agents-exe [GLOBAL_OPTS] COMMAND [COMMAND_OPTS] ``` | Option | Default | Description | |--------|---------|----------</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-mcp.html</id><title type="text">MCP Protocol</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/mcp.md"&gt;&lt;code&gt;documentation/mcp.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="mcp-protocol"&gt;MCP Protocol&lt;/h2&gt;
&lt;p&gt;The Model Context Protocol (MCP) integration allows agents to connect to external servers that provide dynamic tool listings and execution capabilities.&lt;/p&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;p&gt;MCP is a protocol for model context exchange that enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dynamic tool discovery&lt;/strong&gt;: Servers advertise available tools at runtime
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Structured tool calls&lt;/strong&gt;: JSON-RPC based communication
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Process isolation&lt;/strong&gt;: MCP servers run in separate processes
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standardized interface&lt;/strong&gt;: Common protocol across different tool providers
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────┐      JSON-RPC       ┌─────────────┐
│   Agent     │&amp;lt;-------------------&amp;gt;│ MCP Server  │
│  Runtime    │   (stdio/stdin)     │  Process    │
└─────────────┘                     └─────────────┘
       │                                   │
       │ Tool descriptions                 │ Tool execution
       │                                   │
       ▼                                   ▼
┌─────────────┐                     ┌─────────────┐
│     LLM     │                     │  External   │
│  (tool use) │                     │   Systems   │
└─────────────┘                     └─────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="architecture"&gt;Architecture&lt;/h3&gt;
&lt;h4 id="client-architecture-systemagentsmcpclient"&gt;Client Architecture (&lt;code&gt;System.Agents.MCP.Client&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Client runtime managing MCP server process&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; procHandle ::&lt;/span&gt; &lt;span class="dt"&gt;ProcessHandle&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; stdinHandle ::&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; stdoutHandle ::&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolsList ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; [&lt;span class="dt"&gt;ToolDescription&lt;/span&gt;]&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; callResults ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;CallId&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; serverName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="server-architecture-systemagentsmcpserver"&gt;Server Architecture (&lt;code&gt;System.Agents.MCP.Server&lt;/code&gt;)&lt;/h4&gt;
&lt;p&gt;The framework can also act as an MCP server, exposing agents as tools to other MCP clients:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;multiAgentsServer ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;McpServerConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [&lt;span class="dt"&gt;AgentTree.Props&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="mcp-server-configuration"&gt;MCP Server Configuration&lt;/h3&gt;
&lt;h4 id="simple-binary-configuration"&gt;Simple Binary Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;mcpServers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;McpSimpleBinary&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;filesystem&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;executable&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/usr/bin/mcp-server-filesystem&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;--root&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/home/user/projects&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="environment-variables-env"&gt;Environment variables (&lt;code&gt;env&lt;/code&gt;)&lt;/h4&gt;
&lt;p&gt;An MCP server can receive configuration, including secrets, through
environment variables. &lt;code&gt;env&lt;/code&gt; maps a variable name to a binding value: a
literal, or a reference to an agent parameter (see
&lt;a href="/agents-exe/docs-parameters-and-bindings.html"&gt;parameters-and-bindings.md&lt;/a&gt;). The variables are
added to the inherited environment (and win on a clash).&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;McpSimpleBinary&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;github&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;executable&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/usr/bin/mcp-server-github&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;env&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;GITHUB_TOKEN&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Param&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;github_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;GITHUB_HOST&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Literal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;github.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The server starts once per agent tree, so a &lt;code&gt;Param&lt;/code&gt; must have a value at load
time (process scope: &lt;code&gt;--set&lt;/code&gt;, &lt;code&gt;--params-file&lt;/code&gt;, or a default). A parameter with
no such value, such as a session-scope one, is a load error. The values are not
put on the command line, and the traced process description shows variable
names only, so a secret parameter does not leak through &lt;code&gt;ps&lt;/code&gt; or traces.&lt;/p&gt;
&lt;h4 id="haskell-configuration-type"&gt;Haskell Configuration Type&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;McpServerDescription&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;McpSimpleBinary&lt;/span&gt; &lt;span class="dt"&gt;McpSimpleBinaryConfiguration&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;McpSimpleBinaryConfiguration&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;McpSimpleBinaryConfiguration&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; name ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;           &lt;span class="co"&gt;-- Display name&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; executable ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="co"&gt;-- Path to server binary&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; args ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]         &lt;span class="co"&gt;-- Command line arguments&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; env ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;BindingValue&lt;/span&gt;) &lt;span class="co"&gt;-- Extra environment variables&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="protocol-flow"&gt;Protocol Flow&lt;/h3&gt;
&lt;h4 id="1-server-initialization"&gt;1. Server Initialization&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Agent Runtime                    MCP Server
     │                                │
     │── Spawn process ──────────────&amp;gt;│
     │   (executable with args)       │
     │                                │
     │&amp;lt;─ Initialize request ──────────│
     │   (protocol version, etc.)     │
     │                                │
     │── Initialize response ────────&amp;gt;│
     │   (server capabilities)        │
     │                                │
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="2-tool-discovery"&gt;2. Tool Discovery&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Request tools list&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sendRequest ::&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Method&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;CallId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Receive tool descriptions&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;receiveTools ::&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [&lt;span class="dt"&gt;ToolDescription&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="3-tool-execution-loop"&gt;3. Tool Execution Loop&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Agent Runtime                    MCP Server        LLM
     │                                │             │
     │&amp;lt;───────────────────────────────│&amp;lt;── Tool call│
     │   (Tool call from server)      │   request   │
     │                                │             │
     │── Execute tool locally ────────│             │
     │   (if agent-as-tool)           │             │
     │                                │             │
     │── Tool result ────────────────&amp;gt;│             │
     │                                │             │
     │&amp;lt;───────────────────────────────│─── Forward ─&amp;gt;│
     │                                │    result   │
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="json-rpc-protocol"&gt;JSON-RPC Protocol&lt;/h3&gt;
&lt;h4 id="message-format"&gt;Message Format&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;JsonRpcMessage&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;JsonRpcRequest&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        {&lt;span class="ot"&gt; jsonrpc ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; method ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; params ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; id ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;CallId&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;JsonRpcResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        {&lt;span class="ot"&gt; jsonrpc ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; result ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; error ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;JsonRpcError&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; id ::&lt;/span&gt; &lt;span class="dt"&gt;CallId&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;JsonRpcNotification&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        {&lt;span class="ot"&gt; jsonrpc ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; method ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; params ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tool-list-method"&gt;Tool List Method&lt;/h4&gt;
&lt;p&gt;Request:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;jsonrpc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;method&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools/list&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Response:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;jsonrpc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read_file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Read contents of a file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;inputSchema&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;object&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Path to the file&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tool-call-method"&gt;Tool Call Method&lt;/h4&gt;
&lt;p&gt;Request:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;jsonrpc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;method&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools/call&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;params&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read_file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;arguments&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/home/user/README.md&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Response:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;jsonrpc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;# Project README&lt;/span&gt;&lt;span class="ch"&gt;\n\n&lt;/span&gt;&lt;span class="st"&gt;This is the content...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;isError&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="client-runtime"&gt;Client Runtime&lt;/h3&gt;
&lt;h4 id="starting-a-client"&gt;Starting a Client&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;startMcpClient ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;McpSimpleBinaryConfiguration&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;McpError&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;startMcpClient tracer config &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Spawn process&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; procConfig &lt;span class="ot"&gt;=&lt;/span&gt; (proc (unpack config&lt;span class="op"&gt;.&lt;/span&gt;executable) &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            (&lt;span class="fu"&gt;map&lt;/span&gt; unpack config&lt;span class="op"&gt;.&lt;/span&gt;args))&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;           { std_in &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;CreatePipe&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;           , std_out &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;CreatePipe&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;           , std_err &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Inherit&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;           }&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (stdinH, stdoutH, _, procH) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createProcess_ config&lt;span class="op"&gt;.&lt;/span&gt;name procConfig&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Initialize communication&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    runtime &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt; procH stdinH stdoutH &lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; newTVarIO []&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; newTVarIO Map.empty&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; config&lt;span class="op"&gt;.&lt;/span&gt;name&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Query tools&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; queryTools runtime&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    atomically &lt;span class="op"&gt;$&lt;/span&gt; writeTVar (toolsList runtime) tools&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;return&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Right&lt;/span&gt; runtime&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tool-execution"&gt;Tool Execution&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;callTool ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Runtime&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;       &lt;span class="co"&gt;-- Tool name&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Value&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;      &lt;span class="co"&gt;-- Arguments&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;McpError&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;callTool rt toolName args &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    callId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; nextCallId&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Send call request&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    sendRequest rt &lt;span class="st"&gt;&amp;quot;tools/call&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; object&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ &lt;span class="st"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; toolName&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="st"&gt;&amp;quot;arguments&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; args&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Wait for response&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    waitForResponse rt callId&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="server-mode"&gt;Server Mode&lt;/h3&gt;
&lt;p&gt;The framework can expose agents as MCP servers:&lt;/p&gt;
&lt;h4 id="starting-mcp-server-mode"&gt;Starting MCP Server Mode&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; mcp-server &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="server-capabilities"&gt;Server Capabilities&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;McpServerConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;McpServerConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; serverName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; serverVersion ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; supportedProtocols ::&lt;/span&gt; [&lt;span class="dt"&gt;ProtocolVersion&lt;/span&gt;]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;defaultMcpServerConfig ::&lt;/span&gt; &lt;span class="dt"&gt;McpServerConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;defaultMcpServerConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;McpServerConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { serverName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;agents-mcp-server&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , serverVersion &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , supportedProtocols &lt;span class="ot"&gt;=&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;2024-11-05&amp;quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="agent-as-tool-mapping"&gt;Agent-as-Tool Mapping&lt;/h4&gt;
&lt;p&gt;Each loaded agent is exposed as an MCP tool:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;agentToMcpTool ::&lt;/span&gt; &lt;span class="dt"&gt;AgentTree.AgentTree&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolDescription&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;agentToMcpTool tree &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolDescription&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { toolName &lt;span class="ot"&gt;=&lt;/span&gt; agentSlug tree&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , toolDescription &lt;span class="ot"&gt;=&lt;/span&gt; agentAnnounce tree&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , toolInputSchema &lt;span class="ot"&gt;=&lt;/span&gt; object&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;object&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="st"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; object&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            [ &lt;span class="st"&gt;&amp;quot;prompt&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; object&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                [ &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;)&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                , &lt;span class="st"&gt;&amp;quot;description&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;Prompt to send to the agent&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                ]&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            ]&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="st"&gt;&amp;quot;required&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; ([&lt;span class="st"&gt;&amp;quot;prompt&amp;quot;&lt;/span&gt;]&lt;span class="ot"&gt; ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;])&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="error-handling"&gt;Error Handling&lt;/h3&gt;
&lt;h4 id="mcp-errors"&gt;MCP Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;McpError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ProcessStartError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ProtocolError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolNotFound&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ParseError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TimeoutError&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="error-response-format"&gt;Error Response Format&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;jsonrpc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;-32600&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Invalid Request&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Additional error details&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="tracing"&gt;Tracing&lt;/h3&gt;
&lt;p&gt;MCP operations are traced for debugging:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;McpClientClientTrace&lt;/span&gt; &lt;span class="dt"&gt;ClientTrace&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;McpClientRunTrace&lt;/span&gt; &lt;span class="dt"&gt;RunTrace&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;McpClientLoopTrace&lt;/span&gt; &lt;span class="dt"&gt;LoopTrace&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ClientTrace&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SendingRequest&lt;/span&gt; &lt;span class="dt"&gt;CallId&lt;/span&gt; &lt;span class="dt"&gt;Method&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ReceivedResponse&lt;/span&gt; &lt;span class="dt"&gt;CallId&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ReceivedError&lt;/span&gt; &lt;span class="dt"&gt;CallId&lt;/span&gt; &lt;span class="dt"&gt;JsonRpcError&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;RunTrace&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunCommandStart&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;RunCommandStopped&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;ExitCode&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;RunBufferMoved&lt;/span&gt; &lt;span class="dt"&gt;ByteString&lt;/span&gt; &lt;span class="dt"&gt;ByteString&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;LoopTrace&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolsRefreshed&lt;/span&gt; [&lt;span class="dt"&gt;ToolDescription&lt;/span&gt;]&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StartToolCall&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EndToolCall&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ExitingToolCallLoop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="best-practices"&gt;Best Practices&lt;/h3&gt;
&lt;h4 id="server-implementation"&gt;Server Implementation&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Idempotency&lt;/strong&gt;: Tools should be safe to call multiple times
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeouts&lt;/strong&gt;: Set reasonable timeouts for operations
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation&lt;/strong&gt;: Validate all inputs before execution
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error messages&lt;/strong&gt;: Return clear, actionable error messages
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource cleanup&lt;/strong&gt;: Properly cleanup on process exit
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="client-usage"&gt;Client Usage&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reconnect logic&lt;/strong&gt;: Handle server crashes gracefully
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool caching&lt;/strong&gt;: Cache tool lists but refresh periodically
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrent calls&lt;/strong&gt;: Be aware of server concurrency limits
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input validation&lt;/strong&gt;: Validate arguments before sending
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="example-filesystem-mcp-server"&gt;Example: Filesystem MCP Server&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;McpSimpleBinary&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;filesystem&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;executable&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;npx&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;-y&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;@modelcontextprotocol/server-filesystem&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/home/user/docs&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="example-custom-mcp-server"&gt;Example: Custom MCP Server&lt;/h3&gt;
&lt;p&gt;A minimal MCP server in Python:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#!/usr/bin/env python3&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; sys&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; send_message(msg):&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;print&lt;/span&gt;(json.dumps(msg))&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    sys.stdout.flush()&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; handle_request(request):&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    method &lt;span class="op"&gt;=&lt;/span&gt; request.get(&lt;span class="st"&gt;&amp;quot;method&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;if&lt;/span&gt; method &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;initialize&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;return&lt;/span&gt; {&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;protocolVersion&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;2024-11-05&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;capabilities&amp;quot;&lt;/span&gt;: {},&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;serverInfo&amp;quot;&lt;/span&gt;: {&lt;span class="st"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;example&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;}&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;elif&lt;/span&gt; method &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools/list&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;return&lt;/span&gt; {&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;: [&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                {&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="st"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;echo&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="st"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;Echo back the input&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="st"&gt;&amp;quot;inputSchema&amp;quot;&lt;/span&gt;: {&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                        &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;object&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                        &lt;span class="st"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;: {&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            &lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;: {&lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;}&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                        },&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                        &lt;span class="st"&gt;&amp;quot;required&amp;quot;&lt;/span&gt;: [&lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    }&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                }&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            ]&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;elif&lt;/span&gt; method &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools/call&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        params &lt;span class="op"&gt;=&lt;/span&gt; request.get(&lt;span class="st"&gt;&amp;quot;params&amp;quot;&lt;/span&gt;, {})&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        name &lt;span class="op"&gt;=&lt;/span&gt; params.get(&lt;span class="st"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        args &lt;span class="op"&gt;=&lt;/span&gt; params.get(&lt;span class="st"&gt;&amp;quot;arguments&amp;quot;&lt;/span&gt;, {})&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;if&lt;/span&gt; name &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;echo&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="cf"&gt;return&lt;/span&gt; {&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="st"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;: [{&lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;: args.get(&lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)}],&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="st"&gt;&amp;quot;isError&amp;quot;&lt;/span&gt;: &lt;span class="va"&gt;False&lt;/span&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="va"&gt;None&lt;/span&gt;&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; main():&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;while&lt;/span&gt; &lt;span class="va"&gt;True&lt;/span&gt;:&lt;/span&gt;
&lt;span id="51"&gt;&lt;a href="#51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        line &lt;span class="op"&gt;=&lt;/span&gt; sys.stdin.readline()&lt;/span&gt;
&lt;span id="52"&gt;&lt;a href="#52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="kw"&gt;not&lt;/span&gt; line:&lt;/span&gt;
&lt;span id="53"&gt;&lt;a href="#53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="cf"&gt;break&lt;/span&gt;&lt;/span&gt;
&lt;span id="54"&gt;&lt;a href="#54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="55"&gt;&lt;a href="#55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        request &lt;span class="op"&gt;=&lt;/span&gt; json.loads(line)&lt;/span&gt;
&lt;span id="56"&gt;&lt;a href="#56" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        result &lt;span class="op"&gt;=&lt;/span&gt; handle_request(request)&lt;/span&gt;
&lt;span id="57"&gt;&lt;a href="#57" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="58"&gt;&lt;a href="#58" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;in&lt;/span&gt; request:&lt;/span&gt;
&lt;span id="59"&gt;&lt;a href="#59" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            send_message({&lt;/span&gt;
&lt;span id="60"&gt;&lt;a href="#60" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="st"&gt;&amp;quot;jsonrpc&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="61"&gt;&lt;a href="#61" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="st"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;: result,&lt;/span&gt;
&lt;span id="62"&gt;&lt;a href="#62" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;: request[&lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span id="63"&gt;&lt;a href="#63" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            })&lt;/span&gt;
&lt;span id="64"&gt;&lt;a href="#64" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="65"&gt;&lt;a href="#65" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="va"&gt;__name__&lt;/span&gt; &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="66"&gt;&lt;a href="#66" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    main()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="debugging"&gt;Debugging&lt;/h3&gt;
&lt;p&gt;Enable MCP tracing with verbose logging:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="at"&gt;--log-http&lt;/span&gt; http://localhost:8080/log&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;View MCP communications in the trace output:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;e&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;server&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;filesystem&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;val&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tool-call-start&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read_file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-mcp.html" rel="alternate"/><summary type="text">The Model Context Protocol (MCP) integration allows agents to connect to external servers that provide dynamic tool listings and execution capabilities. ## Overview MCP is a protocol for model context exchange that enables: - **Dynamic tool</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-export-import.html</id><title type="text">Export/Import</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/export-import.md"&gt;&lt;code&gt;documentation/export-import.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="exportimport"&gt;Export/Import&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Status: Removed&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The export and import commands have been removed from agents-exe. They were wonky and hard to use, so we’re taking another approach (see issue #339).&lt;/p&gt;
&lt;h3 id="alternatives"&gt;Alternatives&lt;/h3&gt;
&lt;p&gt;For sharing agents and tools, consider these alternatives:&lt;/p&gt;
&lt;h4 id="1-direct-file-copy"&gt;1. Direct File Copy&lt;/h4&gt;
&lt;p&gt;Tools and agent configurations are just files. You can copy them directly:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Copy tools to another agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;cp&lt;/span&gt; ./source-agent/tools/&lt;span class="pp"&gt;*&lt;/span&gt; ./target-agent/tools/&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Copy entire agent configuration&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;cp&lt;/span&gt; &lt;span class="at"&gt;-r&lt;/span&gt; ./my-agent ./shared-agents/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="2-git-submodules"&gt;2. Git Submodules&lt;/h4&gt;
&lt;p&gt;For team sharing, use git submodules:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Add shared tools as submodule&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; submodule add https://github.com/company/shared-tools.git tools/shared&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Update when needed&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; submodule update &lt;span class="at"&gt;--remote&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="3-package-managers"&gt;3. Package Managers&lt;/h4&gt;
&lt;p&gt;Use standard package managers for your platform:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nix&lt;/strong&gt;: Package tools as nix derivations
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Homebrew&lt;/strong&gt;: Tap for macOS/Linux
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apt/Yum&lt;/strong&gt;: System packages for tools
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-container-distribution"&gt;4. Container Distribution&lt;/h4&gt;
&lt;p&gt;Package agents with their tools in containers:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; agents-exe:latest&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;COPY&lt;/span&gt; ./tools /app/tools/&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;COPY&lt;/span&gt; ./agent.json /app/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="historical-context"&gt;Historical Context&lt;/h3&gt;
&lt;p&gt;The original export/import system supported:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Exporting agents, tools, and MCP servers to archives (tar.gz, zip)
&lt;/li&gt;
&lt;li&gt;Git-based distribution with namespacing
&lt;/li&gt;
&lt;li&gt;Tool installation with conflict resolution
&lt;/li&gt;
&lt;li&gt;Namespace-based organization
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This functionality was removed because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Complexity&lt;/strong&gt;: The namespace and packaging system added significant complexity
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overlap&lt;/strong&gt;: Functionality overlapped with standard tools (tar, git, cp)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Usage patterns&lt;/strong&gt;: Users preferred direct file management
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintenance burden&lt;/strong&gt;: High effort to maintain relative to usage
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="migration"&gt;Migration&lt;/h3&gt;
&lt;p&gt;If you were using export/import, migrate to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Simple archives&lt;/strong&gt;: Use &lt;code&gt;tar&lt;/code&gt; directly&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Instead of: agents-exe export --output pkg.tar.gz&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;tar&lt;/span&gt; czf pkg.tar.gz ./my-agent/&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Instead of: agents-exe import --from-file pkg.tar.gz&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;tar&lt;/span&gt; xzf pkg.tar.gz &lt;span class="at"&gt;-C&lt;/span&gt; ./destination/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Git workflows&lt;/strong&gt;: Use standard git workflows&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Clone and copy what you need&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; clone https://github.com/company/agents /tmp/agents&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;cp&lt;/span&gt; /tmp/agents/tools/&lt;span class="pp"&gt;*&lt;/span&gt; ./my-tools/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configuration management&lt;/strong&gt;: Use tools like Ansible, Chef, or simple shell scripts&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-export-import.html" rel="alternate"/><summary type="text">**Status: Removed** The export and import commands have been removed from agents-exe. They were wonky and hard to use, so we're taking another approach (see issue &amp;#35;339). ## Alternatives For sharing agents and tools, consider these alternati</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-web-server-embedding.progress.html</id><title type="text">Web server embedding — Implementation Progress</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/web-server-embedding.progress.md"&gt;&lt;code&gt;todos/web-server-embedding.progress.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="web-server-embedding--implementation-progress"&gt;Web server embedding — Implementation Progress&lt;/h2&gt;
&lt;p&gt;Progress tracker for &lt;code&gt;todos/web-server-embedding.md&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="phase-1--storage-wiring-fix-white_check_mark-complete"&gt;Phase 1 — Storage wiring fix ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Combinators.StoreSessionProgress&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SessionSink&lt;/code&gt; (&lt;code&gt;SinkBackend&lt;/code&gt; / &lt;code&gt;SinkFiles&lt;/code&gt; / &lt;code&gt;SinkNone&lt;/code&gt;), chosen when the
agent is built.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agentPersistSession&lt;/code&gt; and &lt;code&gt;sinkStoreCallback&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agentStoreSession&lt;/code&gt; and &lt;code&gt;agentStoreSessionWithCallback&lt;/code&gt; keep their
behaviour (backend read from the wrapped agent, else files) on top of
&lt;code&gt;sinkStoreCallback&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLI/SessionDurable.handleStart&lt;/code&gt; derives the conversation ID from the
session ID, so &lt;code&gt;session start --step&lt;/code&gt; no longer writes a second
&lt;code&gt;conv.&amp;lt;random&amp;gt;.json&lt;/code&gt; next to &lt;code&gt;conv.&amp;lt;session-id&amp;gt;.json&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-2--single-agent-factory-white_check_mark-complete"&gt;Phase 2 — Single agent factory ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;New &lt;code&gt;System.Agents.AgentFactory&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;buildAgent :: Tracer IO Trace -&amp;gt; AgentDeps -&amp;gt; AgentRole -&amp;gt; ConversationId -&amp;gt; OSAgentNode -&amp;gt; IO Agent&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AgentDeps&lt;/code&gt; (API keys, session sink, continuation store, tool cache,
completion override), &lt;code&gt;defaultAgentDeps&lt;/code&gt;, &lt;code&gt;fileAgentDeps&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AgentRole&lt;/code&gt; = &lt;code&gt;RootAgent | SubAgent parentConv callStack&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Trace&lt;/code&gt; (moved from &lt;code&gt;OneShot&lt;/code&gt;, which re-exports it) and
&lt;code&gt;mapProgressiveDisclosureTrace&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Callers moved onto it, and their copies of the agent record, the OpenAI
completion setup, API key lookup, and &lt;code&gt;toolRegistrationToSystemTool&lt;/code&gt; removed:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OneShot.nodeToAgent&lt;/code&gt; / &lt;code&gt;nodeToAgentWithThinking&lt;/code&gt; (also used by the TUI):
thinking output, media injection, and the &lt;code&gt;--session-file&lt;/code&gt; copy are now
decorators on the factory’s agent.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AgentTree.OneShotTool.turnAgentRuntimeIntoIOTool&lt;/code&gt; takes &lt;code&gt;AgentDeps&lt;/code&gt;
instead of a &lt;code&gt;SessionStore&lt;/code&gt; and API keys. &lt;code&gt;OneShotTool.Trace&lt;/code&gt; is now a
single &lt;code&gt;OneShotTrace&lt;/code&gt; constructor.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MCP.Server.runAgentWithQuery&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLI.SessionDurable.buildAgentForFile&lt;/code&gt; (drops its own JSON re-parse).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toolRegistrationToSystemTool&lt;/code&gt; has one definition, exported from
&lt;code&gt;Combinators.ProgressiveDisclosure&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Session.Types.newSessionFromPrompt&lt;/code&gt;, used by &lt;code&gt;session start&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="behaviour-changes"&gt;Behaviour changes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Progressive disclosure now applies to the MCP server and the durable
&lt;code&gt;session&lt;/code&gt; commands too; before, only &lt;code&gt;run&lt;/code&gt;, the TUI, and sub-agents had it.
&lt;/li&gt;
&lt;li&gt;The MCP server applies the agent’s &lt;code&gt;executionMode&lt;/code&gt; / &lt;code&gt;toolCallPolicyConfig&lt;/code&gt;
and runs with &lt;code&gt;runUntilBlocked&lt;/code&gt;. A turn waiting on deferred calls returns an
error rather than looping forever.
&lt;/li&gt;
&lt;li&gt;A sub-agent’s session file is named after the conversation ID used for its
call-stack entry and OS World entity, not an unrelated random ID.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cabal build all --enable-tests&lt;/code&gt; succeeded. (It did not check warnings: the
library was not built with &lt;code&gt;-Wall&lt;/code&gt; then, see the Phase 4 section.)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-tests&lt;/code&gt;: 902 tests pass, including 8 new &lt;code&gt;AgentFactoryTests&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Smoke test of &lt;code&gt;session start&lt;/code&gt;, &lt;code&gt;session start --step&lt;/code&gt;, and &lt;code&gt;session step&lt;/code&gt;
with an isolated &lt;code&gt;HOME&lt;/code&gt;: exactly one &lt;code&gt;conv.&amp;lt;session-id&amp;gt;.json&lt;/code&gt; per session.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-3--metadata-versions-migrations-catalog-white_check_mark-complete"&gt;Phase 3 — Metadata, versions, migrations, catalog ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Session.Types&lt;/code&gt;: &lt;code&gt;SessionStatus&lt;/code&gt; (idle / ready / running /
waiting_external / failed) with text and JSON forms, and &lt;code&gt;sessionStatusOf&lt;/code&gt;.
&lt;code&gt;isBlockedOnDeferredCalls&lt;/code&gt; (from &lt;code&gt;Session.Loop&lt;/code&gt;) and &lt;code&gt;hasBackgroundCalls&lt;/code&gt; /
&lt;code&gt;backgroundCalls&lt;/code&gt; (from &lt;code&gt;Session.Step&lt;/code&gt;) moved here; &lt;code&gt;Session.Loop&lt;/code&gt; still
re-exports &lt;code&gt;isBlockedOnDeferredCalls&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionStore&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SessionLabels&lt;/code&gt;, &lt;code&gt;SessionMeta&lt;/code&gt;, &lt;code&gt;SessionQuery&lt;/code&gt;, &lt;code&gt;VersionConflict&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionBackend&lt;/code&gt; gains &lt;code&gt;sbStoreLabelled&lt;/code&gt;, &lt;code&gt;sbLoadMeta&lt;/code&gt;,
&lt;code&gt;sbCompareAndStore&lt;/code&gt;, and &lt;code&gt;sbQuery&lt;/code&gt;. Every write increments the version;
unconditional stores derive the status, except that a running status is
kept.
&lt;/li&gt;
&lt;li&gt;SQLite: &lt;code&gt;runMigrations&lt;/code&gt; with a component-scoped &lt;code&gt;schema_migrations&lt;/code&gt;
table; migration 2 adds the metadata columns and indexes and derives the
status of existing rows. Compare-and-store is a single conditional
statement with &lt;code&gt;RETURNING&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;File backend: &lt;code&gt;meta.&amp;lt;uuid&amp;gt;.json&lt;/code&gt; sidecars.
&lt;/li&gt;
&lt;li&gt;Composite: writes and queries on the primary, loads with fallback.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionCatalog&lt;/code&gt; / &lt;code&gt;CatalogEntry&lt;/code&gt;, &lt;code&gt;fileCatalog&lt;/code&gt;, &lt;code&gt;backendCatalog&lt;/code&gt;,
&lt;code&gt;isFileBusy&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StoreSessionProgress&lt;/code&gt;: &lt;code&gt;sinkStoreCallback&lt;/code&gt; and &lt;code&gt;agentPersistSession&lt;/code&gt; take
&lt;code&gt;SessionLabels&lt;/code&gt;; &lt;code&gt;backendStoreCallbackWith&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AgentFactory&lt;/code&gt; labels sessions with the agent slug and, for sub-agents, the
parent session. &lt;code&gt;OneShotTool&lt;/code&gt; gives a sub-agent’s session the ID of its
conversation.
&lt;/li&gt;
&lt;li&gt;Session tools (&lt;code&gt;SystemToolbox/Session&lt;/code&gt;) read through
&lt;code&gt;introspectionCatalog&lt;/code&gt;; &lt;code&gt;getSessionModTime&lt;/code&gt; removed. &lt;code&gt;AgentTree.Props&lt;/code&gt;
takes &lt;code&gt;sessionCatalog&lt;/code&gt;; the CLI and TUI pass &lt;code&gt;fileCatalog&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents.cabal&lt;/code&gt;: the library’s &lt;code&gt;import: warnings&lt;/code&gt; moved above &lt;code&gt;visibility&lt;/code&gt;.
Cabal ignored it in its old position, so the library was built without
&lt;code&gt;-Wall -Werror&lt;/code&gt; since the library was made public.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="not-done-here"&gt;Not done here&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The search index (&lt;code&gt;Session/Search&lt;/code&gt;) stays on the file store (CLI-only).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PRAGMA&lt;/code&gt; settings are left to &lt;code&gt;withHost&lt;/code&gt; (Phase 5).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-1"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agents-tests&lt;/code&gt;: 923 tests pass, including 21 new &lt;code&gt;SessionMetadataTests&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The “forced full rebuild shows no warnings” claim made here (and in the
Phase 3 commit message) was wrong: that rebuild did not recompile with
&lt;code&gt;-Wall -Werror&lt;/code&gt;. See the Phase 4 section for the real check and the fixes.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="warning-fixes-after-re-enabling--wall--werror"&gt;Warning fixes after re-enabling &lt;code&gt;-Wall -Werror&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A rebuild of the library from an empty build directory under &lt;code&gt;-Wall -Werror&lt;/code&gt;
reported warnings, now fixed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From Phases 2 and 3 (this branch): unused imports in
&lt;code&gt;Tools/SystemToolbox/Session.hs&lt;/code&gt;, &lt;code&gt;TUI/Event/Conversation.hs&lt;/code&gt;,
&lt;code&gt;CLI/SessionDurable.hs&lt;/code&gt;, and &lt;code&gt;MCP/Server.hs&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Already present before this branch: a &lt;code&gt;name&lt;/code&gt; binding shadowing a record
field in &lt;code&gt;Session/Step.hs&lt;/code&gt; (&lt;code&gt;lateResultsQuery&lt;/code&gt;), and a missing signature on
&lt;code&gt;resetQuitConfirmation&lt;/code&gt; in &lt;code&gt;TUI/Event.hs&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-4--continuation-consistency-white_check_mark-complete"&gt;Phase 4 — Continuation consistency ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Session.Async&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ContinuationStore.csFindSession&lt;/code&gt;: the session of a pending or completed
token.
&lt;/li&gt;
&lt;li&gt;The continuation schema goes through &lt;code&gt;runMigrations&lt;/code&gt; (component
&lt;code&gt;continuations&lt;/code&gt;); migration 2 adds a &lt;code&gt;(session_id, completed_at)&lt;/code&gt; index.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;csComplete&lt;/code&gt; detects the update with &lt;code&gt;RETURNING&lt;/code&gt; instead of
&lt;code&gt;SELECT changes()&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Session.Wake&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wakeSessionWith&lt;/code&gt; returns a &lt;code&gt;WakeOutcome&lt;/code&gt; (applied / already completed /
unknown tokens) and marks applied tokens completed in the store.
&lt;code&gt;wakeSession&lt;/code&gt; and &lt;code&gt;wakeSessionWithCache&lt;/code&gt; wrap it.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;findSessionForToken&lt;/code&gt; (index first, then a scan of the backend) and
&lt;code&gt;sessionHasToken&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="not-done-here-1"&gt;Not done here&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The CLI &lt;code&gt;complete&lt;/code&gt; command keeps scanning the file store: CLI agents have
no continuation store.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-2"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library rebuilt from an empty build directory under &lt;code&gt;-Wall -Werror&lt;/code&gt;:
clean.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cabal build all --enable-tests&lt;/code&gt; succeeded.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-tests&lt;/code&gt;: 930 tests pass, including 7 new
&lt;code&gt;ContinuationConsistencyTests&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-5--session-runner-white_check_mark-complete"&gt;Phase 5 — Session runner ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Host&lt;/code&gt;: &lt;code&gt;Host&lt;/code&gt;, &lt;code&gt;HostConfig&lt;/code&gt; / &lt;code&gt;defaultHostConfig&lt;/code&gt;,
&lt;code&gt;HostTrace&lt;/code&gt;, &lt;code&gt;HostError&lt;/code&gt;, &lt;code&gt;withHost&lt;/code&gt; (WAL, busy timeout, migrations, agent
files, sub-agent tools storing into the database).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Host.Runner&lt;/code&gt;: &lt;code&gt;SessionRunner&lt;/code&gt; with &lt;code&gt;createSession&lt;/code&gt;,
&lt;code&gt;postMessage&lt;/code&gt;, &lt;code&gt;resume&lt;/code&gt;, &lt;code&gt;completeCall&lt;/code&gt;, &lt;code&gt;cancelRun&lt;/code&gt;, &lt;code&gt;getSession&lt;/code&gt;,
&lt;code&gt;awaitRun&lt;/code&gt;, &lt;code&gt;deleteSession&lt;/code&gt; (dry run and cascade), &lt;code&gt;subscribe&lt;/code&gt;,
&lt;code&gt;recoverOnStartup&lt;/code&gt;, &lt;code&gt;runnerStats&lt;/code&gt;, and an idle-session reaper.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Session.Types&lt;/code&gt;: &lt;code&gt;DeferredCallView&lt;/code&gt; and &lt;code&gt;pendingDeferredCalls&lt;/code&gt;; the CLI’s
&lt;code&gt;extractDeferredCalls&lt;/code&gt; wraps them.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Session.Async&lt;/code&gt;: &lt;code&gt;csCountSession&lt;/code&gt; and &lt;code&gt;csDeleteSession&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="differences-from-the-first-version-of-the-spec-spec-updated"&gt;Differences from the first version of the spec (spec updated)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Results completed during a run are queued and applied by the run, instead
of being written by &lt;code&gt;completeCall&lt;/code&gt;, which would make the run’s next
versioned store conflict.
&lt;/li&gt;
&lt;li&gt;Events use one runner-wide broadcast channel; &lt;code&gt;subscribe&lt;/code&gt; returns a
blocking “next event” action for one session, which survives eviction.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NoActiveRun&lt;/code&gt; error; &lt;code&gt;csCountSession&lt;/code&gt; for dry runs; deletion also refused
while an ancestor runs; runner agents always run asynchronously.
&lt;/li&gt;
&lt;li&gt;After a cancel, background calls below the head turn are reported as
cancelled by the next run (late results), not by &lt;code&gt;cancelRun&lt;/code&gt; itself.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-3"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Library under &lt;code&gt;-Wall -Werror&lt;/code&gt;: clean. &lt;code&gt;cabal build all --enable-tests&lt;/code&gt;
succeeded.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-tests&lt;/code&gt;: 940 tests pass, including 10 new &lt;code&gt;RunnerTests&lt;/code&gt;. The runner
tests passed 15 repeated runs. The test suite is not built with
&lt;code&gt;-threaded&lt;/code&gt;; the bundled SQLite is &lt;code&gt;THREADSAFE=1&lt;/code&gt; (serialized), which the
threaded server in Phase 6 relies on.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-6--agents-server-executable-white_check_mark-complete"&gt;Phase 6 — &lt;code&gt;agents-server&lt;/code&gt; executable ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;examples/agents-server/&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/AgentsServer/Api.hs&lt;/code&gt;: the wai application (routing, JSON views,
&lt;code&gt;wait&lt;/code&gt;/&lt;code&gt;timeout&lt;/code&gt;, SSE with keepalives and a shutdown flag).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/AgentsServer/Log.hs&lt;/code&gt;: JSON-line logs on stderr, traces summarised
field by field.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/AgentsServer/Server.hs&lt;/code&gt;: CLI options, startup (host, runner,
startup recovery), warp settings, SIGTERM/SIGINT handling.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app/Main.hs&lt;/code&gt;, &lt;code&gt;test/Main.hs&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents.cabal&lt;/code&gt;: private library &lt;code&gt;agents-server-internal&lt;/code&gt;, executable
&lt;code&gt;agents-server&lt;/code&gt;, test suite &lt;code&gt;agents-server-tests&lt;/code&gt; (all threaded where it
matters). wai 3.2.4 and warp 3.4.12 were already in the build plan, so
nothing new is downloaded.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Host.Runner&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Fixed &lt;code&gt;subscribe&lt;/code&gt;: it filtered with &lt;code&gt;retry&lt;/code&gt; after &lt;code&gt;readTChan&lt;/code&gt;, which rolls
the read back, so a subscriber blocked forever on the first event of
another session. The Phase 5 tests only ever had one session emitting.
New regression test &lt;code&gt;a subscriber skips other sessions' events&lt;/code&gt; (fails on
the old code: no events after 5 s).
&lt;/li&gt;
&lt;li&gt;New &lt;code&gt;subscribeSTM&lt;/code&gt;, used by the events stream.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/agents-server.md&lt;/code&gt;; links from &lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt; and
&lt;code&gt;README.md&lt;/code&gt;; added to &lt;code&gt;extra-doc-files&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="differences-from-the-first-version-of-the-spec-spec-updated-1"&gt;Differences from the first version of the spec (spec updated)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The app code is a private sub-library so the test suite can run it.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionMetaView&lt;/code&gt; is the &lt;code&gt;SessionMeta&lt;/code&gt; JSON, so it includes &lt;code&gt;owner&lt;/code&gt;
(always null for now).
&lt;/li&gt;
&lt;li&gt;Status codes: &lt;code&gt;202&lt;/code&gt; exactly when the stored status is &lt;code&gt;running&lt;/code&gt; at the
time of answering, &lt;code&gt;200&lt;/code&gt; otherwise; creation always &lt;code&gt;201&lt;/code&gt;, with a
&lt;code&gt;Location&lt;/code&gt; header.
&lt;/li&gt;
&lt;li&gt;In the events stream, a run’s &lt;code&gt;session.updated&lt;/code&gt; (running version) comes
just before its &lt;code&gt;run.started&lt;/code&gt;: the runner stores, then announces.
&lt;/li&gt;
&lt;li&gt;Additions: &lt;code&gt;--live-session-ttl&lt;/code&gt;, &lt;code&gt;--shutdown-grace&lt;/code&gt;, &lt;code&gt;filename&lt;/code&gt; on media,
&lt;code&gt;mode&lt;/code&gt; on resume, 404 &lt;code&gt;not_found&lt;/code&gt;, 405, 413 (32 MiB bodies), list
&lt;code&gt;limit&lt;/code&gt; 1–500 (default 50), comma-separated &lt;code&gt;status&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;On shutdown, waiting requests answer at once and event streams end, so the
grace period is only for other requests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-4"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cabal build all --enable-tests&lt;/code&gt; under &lt;code&gt;-Wall -Werror&lt;/code&gt;: clean.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-tests&lt;/code&gt;: 941 tests pass (one new runner test).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-server-tests&lt;/code&gt;: 7 tests pass; 30 repeated runs plus 10 with
&lt;code&gt;+RTS -N4&lt;/code&gt;, no failures.
&lt;/li&gt;
&lt;li&gt;Smoke tests of the binary against a fake OpenAI endpoint:
&lt;ul&gt;
&lt;li&gt;health, agents, and a created session answered by the LLM;
&lt;/li&gt;
&lt;li&gt;a deferred call completed over HTTP, with the events stream;
&lt;/li&gt;
&lt;li&gt;a restart on the same database, with the session still there;
&lt;/li&gt;
&lt;li&gt;SIGTERM with an open events stream: exit 0 in 0.01 s;
&lt;/li&gt;
&lt;li&gt;the API key reached the LLM but not the log.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The guide’s Haskell snippet typechecks.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-7--authentication-and-owners-white_check_mark-complete"&gt;Phase 7 — Authentication and owners ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Spec: new “Milestone 2” section planning Phases 7–12, with the defaults
taken recorded as decisions 5–10.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionStore&lt;/code&gt;: &lt;code&gt;SessionQuery.sqOwner&lt;/code&gt; (SQLite, file, composite), and
migration 3 adding an &lt;code&gt;(owner, updated_at)&lt;/code&gt; index.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Host.Runner&lt;/code&gt;: &lt;code&gt;createSessionAs&lt;/code&gt; (with an owner) and &lt;code&gt;sessionOwner&lt;/code&gt;, which
returns the owner of the root session.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-server&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AgentsServer.Auth&lt;/code&gt;: loads the tokens file (&lt;code&gt;sha256&lt;/code&gt; or plain &lt;code&gt;token&lt;/code&gt;
entries), compares tokens by SHA-256 digest, parses &lt;code&gt;Bearer&lt;/code&gt; headers.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--auth-tokens&lt;/code&gt;: 401 &lt;code&gt;unauthorized&lt;/code&gt; without a valid token (&lt;code&gt;/healthz&lt;/code&gt;
stays open). Every session endpoint checks the owner, answering 404 for
another owner’s session. Continuations check the owner of the token’s
session, answering 404 &lt;code&gt;unknown_token&lt;/code&gt;. Listing filters by owner, or by
an owned &lt;code&gt;parent&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;server.started&lt;/code&gt; logs &lt;code&gt;authentication: bearer|none&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/agents-server.md&lt;/code&gt;: an Authentication section.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="not-done-here-2"&gt;Not done here&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Per-owner API keys and a default isolation policy (see “Remaining later
work” in the spec).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-5"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cabal build all --enable-tests&lt;/code&gt; under &lt;code&gt;-Wall -Werror&lt;/code&gt;: clean.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-tests&lt;/code&gt;: 941 pass. The delete test now also checks that a
sub-session has its root’s owner. The migrations test expects
migrations 1–3.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-server-tests&lt;/code&gt;: 9 pass, including the two-owner flow and loading a
tokens file.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-8--mcp-over-http-white_check_mark-complete"&gt;Phase 8 — MCP over HTTP ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AgentsServer.Mcp&lt;/code&gt;: the Streamable HTTP transport, answering with JSON,
one &lt;code&gt;ask_&amp;lt;slug&amp;gt;&lt;/code&gt; tool per root agent, runs through the session runner.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AgentsServer.Api&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;routes &lt;code&gt;POST /mcp&lt;/code&gt; (405 for other methods);
&lt;/li&gt;
&lt;li&gt;refuses non-loopback &lt;code&gt;Origin&lt;/code&gt;s when authentication is off (403
&lt;code&gt;forbidden_origin&lt;/code&gt;), as the MCP transport requires against DNS rebinding;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;waitForRun&lt;/code&gt; is shared by the REST and MCP handlers.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/agents-server.md&lt;/code&gt;: an MCP over HTTP section, and the origin rule.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-6"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agents-server-tests&lt;/code&gt;: 12 pass. New tests: an MCP flow
(initialize with version negotiation, the notification’s 202, tools/list,
tools/call with &lt;code&gt;_meta.session_id&lt;/code&gt;, unknown tool, unknown method, batch,
GET 405), a deferred call reported through MCP then completed over REST,
and origin checks with and without authentication.
&lt;/li&gt;
&lt;li&gt;The official Python MCP SDK (2.2.0, &lt;code&gt;streamable_http_client&lt;/code&gt;) against the
binary and a fake OpenAI endpoint: initialize (2025-06-18), list tools,
call &lt;code&gt;ask_weather&lt;/code&gt;, which reported the deferred call and its token.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-9--tui-out-of-the-core-library-white_check_mark-complete"&gt;Phase 9 — TUI out of the core library ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git mv&lt;/code&gt; of 25 modules from &lt;code&gt;src/&lt;/code&gt; to &lt;code&gt;tui/&lt;/code&gt;: &lt;code&gt;TUI.*&lt;/code&gt; except
&lt;code&gt;ToolCallActivity&lt;/code&gt;, plus &lt;code&gt;CLI.TUI&lt;/code&gt;, &lt;code&gt;CLI.Config&lt;/code&gt;, and &lt;code&gt;CLI&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents.cabal&lt;/code&gt;: new public library &lt;code&gt;agents-tui&lt;/code&gt;. &lt;code&gt;agents-lib&lt;/code&gt; loses
those modules and &lt;code&gt;brick&lt;/code&gt;, &lt;code&gt;vty&lt;/code&gt;, &lt;code&gt;text-zipper&lt;/code&gt;, &lt;code&gt;data-clist&lt;/code&gt;.
&lt;code&gt;agents-exe&lt;/code&gt; adds &lt;code&gt;agents-tui&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/architecture.md&lt;/code&gt;: a “Libraries and executables” table.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-7"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cabal build all --enable-tests&lt;/code&gt;: clean. The build plan shows brick, vty,
and text-zipper only under &lt;code&gt;agents-tui&lt;/code&gt;, and nowhere in &lt;code&gt;agents-lib&lt;/code&gt;’s
transitive closure.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cabal test all&lt;/code&gt;: 941 + 12 pass. &lt;code&gt;agents-exe --help&lt;/code&gt; runs.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-10--postgres-backend-white_check_mark-complete"&gt;Phase 10 — Postgres backend ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agents-postgres&lt;/code&gt; library and &lt;code&gt;agents-postgres-tests&lt;/code&gt; suite (see the spec).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Host.withHostStores&lt;/code&gt; / &lt;code&gt;HostStores&lt;/code&gt;; &lt;code&gt;withHost&lt;/code&gt; uses it.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-server --db postgresql://…&lt;/code&gt;; &lt;code&gt;redactDatabase&lt;/code&gt; for the log.
&lt;/li&gt;
&lt;li&gt;Docs: a Postgres section in &lt;code&gt;documentation/agents-server.md&lt;/code&gt;, and the library in
the table in &lt;code&gt;documentation/architecture.md&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-8"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agents-postgres-tests&lt;/code&gt;: 5 pass against a throwaway Postgres 16 cluster.
&lt;/li&gt;
&lt;li&gt;Smoke test of the binary on a Postgres 16 cluster:
&lt;ul&gt;
&lt;li&gt;created a session blocked on a deferred call, restarted the server, and
completed the call: the session reached &lt;code&gt;idle&lt;/code&gt;, with consistent rows;
&lt;/li&gt;
&lt;li&gt;the URL’s password is absent from the log, which holds only JSON lines.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-11--token-streaming-white_check_mark-complete"&gt;Phase 11 — Token streaming ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LLMs/OpenAIStream.hs&lt;/code&gt; (new), &lt;code&gt;HttpClient.postStream&lt;/code&gt;,
&lt;code&gt;OpenAI.callLLMPayloadStreaming&lt;/code&gt; and &lt;code&gt;withOverloadedRetry&lt;/code&gt;,
&lt;code&gt;OpenAICompletionConfig.cfgOnTextDelta&lt;/code&gt;, &lt;code&gt;AgentDeps.adOnTextDelta&lt;/code&gt;,
&lt;code&gt;HostConfig.hcStreamTokens&lt;/code&gt;, &lt;code&gt;SessionEvent.TextDelta&lt;/code&gt;,
&lt;code&gt;agents-server --stream-tokens&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Docs: a “Streaming answers” section and the &lt;code&gt;text.delta&lt;/code&gt; event in
&lt;code&gt;documentation/agents-server.md&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-9"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agents-tests&lt;/code&gt;: 5 new &lt;code&gt;OpenAIStreamTests&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-server-tests&lt;/code&gt;: 13 pass, including streaming against a fake
streaming endpoint.
&lt;/li&gt;
&lt;li&gt;The non-streaming path through the binary still works (fake endpoint,
deferred call reported).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-12--agents-from-the-database-white_check_mark-complete"&gt;Phase 12 — Agents from the database ✅ COMPLETE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AgentStore&lt;/code&gt; (new), &lt;code&gt;AgentTree.loadAgentTreeFromConfig&lt;/code&gt;, stored agents in
&lt;code&gt;Host&lt;/code&gt;, &lt;code&gt;mkPostgresAgentStore&lt;/code&gt;, &lt;code&gt;/v1/agents/:slug&lt;/code&gt; endpoints,
&lt;code&gt;--admin-owners&lt;/code&gt;. See the spec for the differences from the plan.
&lt;/li&gt;
&lt;li&gt;Docs: a “Storing agents” section in &lt;code&gt;documentation/agents-server.md&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="verification-10"&gt;Verification&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agents-tests&lt;/code&gt;: 947 pass (a new runner test for stored agents).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-server-tests&lt;/code&gt;: 15 pass.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-postgres-tests&lt;/code&gt;: 6 pass.
&lt;/li&gt;
&lt;li&gt;Smoke test of the binary with authentication:
&lt;ul&gt;
&lt;li&gt;a non-admin PUT is refused (403); an admin PUT stores an agent whose MCP
server is &lt;code&gt;agents-exe mcp-server&lt;/code&gt;, and its tool
(&lt;code&gt;mcp_weather_ask_weather_000&lt;/code&gt;) is listed;
&lt;/li&gt;
&lt;li&gt;after a restart the agent is reloaded from SQLite with its tool;
&lt;/li&gt;
&lt;li&gt;no tokens in the logs, and no MCP server process left after shutdown.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-web-server-embedding.progress.html" rel="alternate"/><summary type="text">Status: no status line yet</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-async-tool-calls-progress.html</id><title type="text">Async Tool Calls Implementation Progress</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/async-tool-calls-progress.md"&gt;&lt;code&gt;todos/async-tool-calls-progress.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="async-tool-calls-implementation-progress"&gt;Async Tool Calls Implementation Progress&lt;/h2&gt;
&lt;h3 id="plan"&gt;Plan&lt;/h3&gt;
&lt;p&gt;See &lt;code&gt;todos/async-tool-calls.md&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="phase-status"&gt;Phase Status&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[x] Phase 1: ECS Tool-Call Entities
&lt;/li&gt;
&lt;li&gt;[x] Phase 2: Async Engine
&lt;/li&gt;
&lt;li&gt;[x] Phase 3: System Capability (building blocks only — see review below)
&lt;/li&gt;
&lt;li&gt;[x] Phase 3.5: End-to-End Correctness (added after review; blocks Phase 4)
&lt;/li&gt;
&lt;li&gt;[x] Phase 4: TUI / OneShot UX (TUI rendering not yet checked by hand)
&lt;/li&gt;
&lt;li&gt;[x] Phase 5: Cleanup &amp;amp; Hardening (tracing not done — see notes)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="success-criteria-status"&gt;Success Criteria Status&lt;/h3&gt;
&lt;p&gt;Revised after the 2026-09-16 review, then after Phase 3.5 and Phase 4. The
criteria are met in the library and tests, and async execution is now enabled
from the agent JSON in the TUI, OneShot, sub-agents, and &lt;code&gt;session&lt;/code&gt; commands.
The TUI rendering has not been checked by hand.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Criterion&lt;/th&gt;&lt;th&gt;Status&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Two long-running tool calls issued in one LLM turn execute concurrently&lt;/td&gt;&lt;td&gt;Met&lt;/td&gt;&lt;td&gt;&lt;code&gt;asyncEngineTests&lt;/code&gt;; async calls now start before inline calls so they overlap.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LLM receives a partial user turn as soon as the first call finishes (&lt;code&gt;YieldOnAnyProgress&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;Met (stepper)&lt;/td&gt;&lt;td&gt;Running calls get a placeholder tool message; late results are delivered in the next user turn. &lt;code&gt;AsyncToolCallsTests&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LLM can call &lt;code&gt;get_tool_call_status&lt;/code&gt; and see structured progress or final result&lt;/td&gt;&lt;td&gt;Met&lt;/td&gt;&lt;td&gt;Accepts the provider id. Bash tools report output lines; sub-agent tools report their steps.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LLM can call &lt;code&gt;cancel_tool_call&lt;/code&gt; to stop a running call&lt;/td&gt;&lt;td&gt;Met&lt;/td&gt;&lt;td&gt;Interrupts the engine thread via &lt;code&gt;ctxCancelToolCall&lt;/code&gt;; a running subprocess is terminated (&lt;code&gt;processKilledOnCancel&lt;/code&gt;).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Tool calls appear as ECS entities in the OS &lt;code&gt;World&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Met&lt;/td&gt;&lt;td&gt;Covered by &lt;code&gt;sessionStepEntityTests&lt;/code&gt; and &lt;code&gt;toolCallEntityTests&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Existing synchronous behavior unchanged when &lt;code&gt;ExecutionMode = Synchronous&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Met&lt;/td&gt;&lt;td&gt;Same turns as before. Sync steps only differ when a session already holds background calls from an async run.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;get_tool_call_status&lt;/code&gt; returns &lt;code&gt;orphaned&lt;/code&gt; for calls referenced in history that no longer exist&lt;/td&gt;&lt;td&gt;Met&lt;/td&gt;&lt;td&gt;Capability returns &lt;code&gt;orphaned&lt;/code&gt; with &lt;code&gt;is_final: true&lt;/code&gt;; the stepper fails such calls. Verified across a save/reload round-trip in a fresh world (&lt;code&gt;orphanedAcrossRestart&lt;/code&gt;).&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="phase-1-completion-notes"&gt;Phase 1 Completion Notes&lt;/h3&gt;
&lt;p&gt;Phase 1 is complete. The following was done:&lt;/p&gt;
&lt;h4 id="ecs-tool-call-components"&gt;ECS Tool-Call Components&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.OS.Conversation.Types&lt;/code&gt; already had &lt;code&gt;ToolCallConfig&lt;/code&gt;/&lt;code&gt;ToolCallState&lt;/code&gt; extended with:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tcSessionId&lt;/code&gt;, &lt;code&gt;tcConversationId&lt;/code&gt; on &lt;code&gt;ToolCallConfig&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tcProgress :: [ToolCallProgress]&lt;/code&gt;, &lt;code&gt;TcCancelled&lt;/code&gt; on &lt;code&gt;ToolCallState&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolCallProgress&lt;/code&gt; / &lt;code&gt;ProgressKind&lt;/code&gt; for structured progress.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tracked-tool-calls"&gt;Tracked Tool Calls&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Session.Types&lt;/code&gt; already had &lt;code&gt;tcEntityId :: Maybe EntityId&lt;/code&gt; added to &lt;code&gt;TrackedToolCall&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tool-call-entity-helpers"&gt;Tool-Call Entity Helpers&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Extended &lt;code&gt;System.Agents.OS.Conversation.ToolCalls&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;ensureToolCallComponents&lt;/code&gt; / &lt;code&gt;ensureToolCallComponentsIO&lt;/code&gt; for idempotent component-store registration (safe to call on every step).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;createToolCallEntity&lt;/code&gt;, &lt;code&gt;startToolCall&lt;/code&gt;, &lt;code&gt;completeToolCall&lt;/code&gt;, &lt;code&gt;failToolCall&lt;/code&gt;, &lt;code&gt;cancelToolCall&lt;/code&gt;, &lt;code&gt;addToolCallProgress&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Query helpers &lt;code&gt;findToolCallEntityBySessionId&lt;/code&gt; and &lt;code&gt;listToolCallsBySessionAndConversation&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="session-step-integration"&gt;Session Step Integration&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Updated &lt;code&gt;System.Agents.Session.Step&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;prepareAgentWorld&lt;/code&gt; ensures tool-call component stores are registered idempotently and threads the registered world through the agent/context.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ensureTrackedCallEntities&lt;/code&gt; promotes every &lt;code&gt;TrackedToolCall&lt;/code&gt; to an OS entity when a &lt;code&gt;World&lt;/code&gt; is available.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;executeTrackedCallWithEntity&lt;/code&gt; updates the OS entity state to &lt;code&gt;TcExecuting&lt;/code&gt; before running a call and &lt;code&gt;TcCompleted&lt;/code&gt; (with the JSON result) after.
&lt;/li&gt;
&lt;li&gt;Both &lt;code&gt;runStepMSync&lt;/code&gt; and &lt;code&gt;runStepMAsync&lt;/code&gt; now create/update OS entities for every tool call.
&lt;/li&gt;
&lt;li&gt;Existing behavior is unchanged when no &lt;code&gt;World&lt;/code&gt; is configured.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tests"&gt;Tests&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;sessionStepEntityTests&lt;/code&gt; to &lt;code&gt;test/OS/ConversationTests.hs&lt;/code&gt; covering:
&lt;ul&gt;
&lt;li&gt;Sync step creates completed tool-call entities.
&lt;/li&gt;
&lt;li&gt;Async step creates entities for both sync-completed and deferred calls.
&lt;/li&gt;
&lt;li&gt;Async step with all-sync policy completes all calls and creates entities.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="baseline"&gt;Baseline&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Full test suite passes.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-2-completion-notes"&gt;Phase 2 Completion Notes&lt;/h3&gt;
&lt;p&gt;Phase 2 is complete. The async engine now runs &lt;code&gt;RunAsync&lt;/code&gt; tool calls concurrently, keeps OS entity state in sync, and supports structured progress callbacks.&lt;/p&gt;
&lt;h4 id="async-engine-systemagentssessionasyncengine"&gt;Async Engine (&lt;code&gt;System.Agents.Session.Async.Engine&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AsyncEngine&lt;/code&gt; manages a shared semaphore for max concurrency and a registry of active batches keyed by &lt;code&gt;ToolCallId&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;startAsyncBatch&lt;/code&gt; spawns each call in a background &lt;code&gt;Async&lt;/code&gt; thread, injects a per-call progress callback into &lt;code&gt;ToolExecutionContext&lt;/code&gt;, and records the call in the registry.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;waitForProgress&lt;/code&gt; / &lt;code&gt;waitForProgressTimeout&lt;/code&gt; block until at least one call reaches a final state.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;finalizeCompleted&lt;/code&gt; collects finished calls and removes them from the running set and engine registry.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancelToolCall&lt;/code&gt; / &lt;code&gt;cancelAsyncBatch&lt;/code&gt; send async exceptions to background threads and mark OS entities as &lt;code&gt;TcCancelled&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="yield-strategy"&gt;Yield Strategy&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AsyncYieldStrategy&lt;/code&gt; (&lt;code&gt;YieldOnAnyProgress&lt;/code&gt;, &lt;code&gt;YieldWhenAllDone&lt;/code&gt;, &lt;code&gt;YieldOnTimeout&lt;/code&gt;) is defined in &lt;code&gt;System.Agents.Session.Types&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;waitAccordingToStrategy&lt;/code&gt; in &lt;code&gt;System.Agents.Session.Step&lt;/code&gt; implements the three strategies.
&lt;/li&gt;
&lt;li&gt;The default strategy is &lt;code&gt;YieldWhenAllDone&lt;/code&gt; (set by &lt;code&gt;withAsyncConfig&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="progress--lifecycle"&gt;Progress &amp;amp; Lifecycle&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;When a background call starts, the engine emits a &lt;code&gt;ToolCallProgress&lt;/code&gt; entry with &lt;code&gt;ProgressStarted&lt;/code&gt; (payload &lt;code&gt;{&amp;quot;started&amp;quot;:true}&lt;/code&gt;) alongside setting the entity status to &lt;code&gt;TcExecuting&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The progress callback writes &lt;code&gt;ProgressPartial&lt;/code&gt; entries with arbitrary JSON payloads to the entity.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;completeToolCall&lt;/code&gt; and &lt;code&gt;failToolCall&lt;/code&gt; in &lt;code&gt;System.Agents.OS.Conversation.ToolCalls&lt;/code&gt; now leave the state unchanged if it is already &lt;code&gt;TcCancelled&lt;/code&gt;, preventing late engine completions from overwriting a cancellation.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="helpers"&gt;Helpers&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;isToolCallCompletedIO&lt;/code&gt; and &lt;code&gt;findToolCallEntityByToolCallId&lt;/code&gt; to &lt;code&gt;System.Agents.OS.Conversation.ToolCalls&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tests-1"&gt;Tests&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;asyncEngineTests&lt;/code&gt; to &lt;code&gt;test/OS/ConversationTests.hs&lt;/code&gt; covering:
&lt;ul&gt;
&lt;li&gt;Two &lt;code&gt;RunAsync&lt;/code&gt; calls execute concurrently (total time &amp;lt; 300 ms for two 200 ms sleeps).
&lt;/li&gt;
&lt;li&gt;Progress callback emits &lt;code&gt;ToolCallProgress&lt;/code&gt; entries, including &lt;code&gt;ProgressStarted&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancelToolCall&lt;/code&gt; marks an entity as &lt;code&gt;TcCancelled&lt;/code&gt; and a later engine completion does not overwrite it; a second cancellation attempt returns &lt;code&gt;False&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="baseline-1"&gt;Baseline&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Full test suite passes.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-3-completion-notes"&gt;Phase 3 Completion Notes&lt;/h3&gt;
&lt;p&gt;Phase 3 is complete. Agents can now inspect and cancel async tool calls through the system toolbox.&lt;/p&gt;
&lt;h4 id="capability-constructors"&gt;Capability Constructors&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added to &lt;code&gt;SystemToolCapability&lt;/code&gt; in &lt;code&gt;System.Agents.Base&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SystemToolGetToolCallStatus&lt;/code&gt; serialized as &lt;code&gt;get-tool-call-status&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SystemToolListRunningToolCalls&lt;/code&gt; serialized as &lt;code&gt;list-running-tool-calls&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SystemToolCancelToolCall&lt;/code&gt; serialized as &lt;code&gt;cancel-tool-call&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="types-systemagentstoolssystemtoolboxtypes"&gt;Types (&lt;code&gt;System.Agents.Tools.SystemToolbox.Types&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GetToolCallStatusParams&lt;/code&gt; — &lt;code&gt;tool_call_id&lt;/code&gt;, &lt;code&gt;include_progress&lt;/code&gt;, &lt;code&gt;wait_for_completion&lt;/code&gt;, &lt;code&gt;timeout_seconds&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolCallStatusResult&lt;/code&gt; — status, tool name, timing, result, progress, &lt;code&gt;is_final&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ListRunningToolCallsResult&lt;/code&gt; / &lt;code&gt;RunningToolCallInfo&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CancelToolCallParams&lt;/code&gt; / &lt;code&gt;CancelToolCallResult&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="implementation-systemagentstoolssystemtoolboxtoolcallstatus"&gt;Implementation (&lt;code&gt;System.Agents.Tools.SystemToolbox.ToolCallStatus&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;getToolCallStatus&lt;/code&gt; looks up the OS entity by &lt;code&gt;ToolCallId&lt;/code&gt; and translates &lt;code&gt;ToolCallStatus&lt;/code&gt; to LLM-facing strings (&lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;running&lt;/code&gt;, &lt;code&gt;completed&lt;/code&gt;, &lt;code&gt;failed&lt;/code&gt;, &lt;code&gt;cancelled&lt;/code&gt;).
&lt;ul&gt;
&lt;li&gt;Supports &lt;code&gt;wait_for_completion&lt;/code&gt; with a configurable timeout (polls every 50 ms).
&lt;/li&gt;
&lt;li&gt;If the entity is missing, searches the session’s &lt;code&gt;PartialUserTurn&lt;/code&gt; history and returns &lt;code&gt;orphaned&lt;/code&gt; when the call is referenced but no longer exists.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;listRunningToolCalls&lt;/code&gt; returns all non-final tool-call entities for the current session/conversation.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancelToolCallById&lt;/code&gt; marks a non-final entity as &lt;code&gt;TcCancelled&lt;/code&gt; and reports the previous status; returns &lt;code&gt;cancelled: false&lt;/code&gt; if already final.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="registration-systemagentstoolregistration"&gt;Registration (&lt;code&gt;System.Agents.ToolRegistration&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Updated &lt;code&gt;capabilityToText&lt;/code&gt; and &lt;code&gt;buildSystemToolParams&lt;/code&gt; to expose the new capabilities and their parameters (&lt;code&gt;tool_call_id&lt;/code&gt;, &lt;code&gt;include_progress&lt;/code&gt;, &lt;code&gt;wait_for_completion&lt;/code&gt;, &lt;code&gt;timeout_seconds&lt;/code&gt;, &lt;code&gt;reason&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Routed &lt;code&gt;get-tool-call-status&lt;/code&gt;, &lt;code&gt;list-running-tool-calls&lt;/code&gt;, and &lt;code&gt;cancel-tool-call&lt;/code&gt; in the &lt;code&gt;system_info&lt;/code&gt; tool handler.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="exports"&gt;Exports&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Tools.SystemToolbox&lt;/code&gt; re-exports the new types and functions.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents.cabal&lt;/code&gt; exposes &lt;code&gt;System.Agents.Tools.SystemToolbox.ToolCallStatus&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tests-2"&gt;Tests&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;toolCallStatusTests&lt;/code&gt; to &lt;code&gt;test/OS/ConversationTests.hs&lt;/code&gt; covering:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt; returns &lt;code&gt;pending&lt;/code&gt; then &lt;code&gt;running&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt; returns &lt;code&gt;completed&lt;/code&gt; after completion.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt; returns &lt;code&gt;orphaned&lt;/code&gt; for a tracked call missing an OS entity.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list-running-tool-calls&lt;/code&gt; returns only non-final calls.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancel-tool-call&lt;/code&gt; marks a running entity as cancelled and a second attempt reports already final.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="baseline-2"&gt;Baseline&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Full test suite passes (870 tests).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="review-2026-09-16"&gt;Review (2026-09-16)&lt;/h3&gt;
&lt;p&gt;State at review time: branch &lt;code&gt;asynctools&lt;/code&gt;, build green, 870 tests pass.
Phases 1–3 delivered the building blocks (entities, concurrent engine,
status/list/cancel capabilities), but the feature does not work end-to-end
in a real session. Findings:&lt;/p&gt;
&lt;h4 id="r1-the-llm-cannot-address-its-own-tool-calls"&gt;R1. The LLM cannot address its own tool calls&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt; / &lt;code&gt;cancel-tool-call&lt;/code&gt; take the internal &lt;code&gt;ToolCallId&lt;/code&gt;
UUID generated in &lt;code&gt;mkReadyTrackedCall&lt;/code&gt; (&lt;code&gt;Session/Step.hs&lt;/code&gt;, &lt;code&gt;newToolCallId&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;The model only ever sees the provider’s id (e.g. &lt;code&gt;call_abc123&lt;/code&gt;). There is no
mapping between the two and the UUID is never surfaced to the model.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="r2-partial-answers-never-reach-the-llm-correctly"&gt;R2. Partial answers never reach the LLM correctly&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;turnToMessages (PartialUserTurn …)&lt;/code&gt; in &lt;code&gt;Session/OpenAI.hs&lt;/code&gt; emits tool
messages for completed calls only. A running call has no tool message, which
OpenAI-compatible APIs reject.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;naiveTilNoToolCallStep&lt;/code&gt; (&lt;code&gt;Session/Step.hs&lt;/code&gt;) only treats &lt;code&gt;Ready&lt;/code&gt; / &lt;code&gt;Deferred&lt;/code&gt;
as outstanding. With only &lt;code&gt;Running&lt;/code&gt; calls left, it asks for an LLM completion
with a partial set of responses, then pushes an &lt;code&gt;LlmTurn&lt;/code&gt; on top. The running
calls’ results are buried and never delivered.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;continuePartialTurn&lt;/code&gt; → &lt;code&gt;executeTrackedCalls&lt;/code&gt; prepends a new
&lt;code&gt;PartialUserTurn&lt;/code&gt; instead of replacing the head (unlike &lt;code&gt;Session/Wake.hs&lt;/code&gt;,
which does &lt;code&gt;newTurn : drop 1 turns&lt;/code&gt;). Every resume duplicates the turn in
history. Pre-existing bug, but running calls now trigger it on every resume.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="r3-cancel-tool-call-does-not-stop-anything"&gt;R3. &lt;code&gt;cancel-tool-call&lt;/code&gt; does not stop anything&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cancelToolCallById&lt;/code&gt; (&lt;code&gt;Tools/SystemToolbox/ToolCallStatus.hs&lt;/code&gt;) only calls
&lt;code&gt;TCT.cancelToolCall&lt;/code&gt;, i.e. flips the entity to &lt;code&gt;TcCancelled&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The background thread keeps running. &lt;code&gt;Engine.cancelToolCall&lt;/code&gt; does kill the
thread, but the capability cannot reach the engine from
&lt;code&gt;ToolExecutionContext&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The capability test only asserts the status flag.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="r4-the-engine-does-not-survive-between-steps"&gt;R4. The engine does not survive between steps&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;runAsyncWithProgress&lt;/code&gt; (&lt;code&gt;Session/Loop.hs&lt;/code&gt;) returns only the &lt;code&gt;Session&lt;/code&gt;; the
agent carrying &lt;code&gt;ctxAsyncEngine&lt;/code&gt; is dropped. The caller resumes with an agent
that has no engine.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ensureAsyncEngine&lt;/code&gt; then creates a fresh engine on each step, so
&lt;code&gt;defaultMaxConcurrency = 4&lt;/code&gt; is per step rather than global, and the
cancellation registry is lost.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="r5-the-stepper-does-not-handle-orphaned-calls"&gt;R5. The stepper does not handle orphaned calls&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pollRunningCall&lt;/code&gt; leaves a call &lt;code&gt;Running&lt;/code&gt; forever when its entity is missing
(e.g. after a restart), so the partial turn never resolves.
&lt;/li&gt;
&lt;li&gt;Only the capability reports &lt;code&gt;orphaned&lt;/code&gt;, and it returns &lt;code&gt;is_final: false&lt;/code&gt; for
a call that can never finish.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="r6-smaller-issues"&gt;R6. Smaller issues&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Crash on malformed calls:&lt;/strong&gt; &lt;code&gt;requireEntityId&lt;/code&gt; in
&lt;code&gt;Session/Async/Engine.hs&lt;/code&gt; calls &lt;code&gt;error&lt;/code&gt; when a call has no entity id. That
happens whenever &lt;code&gt;parseToolCallFromLlmToolCall&lt;/code&gt; fails, so a malformed call
under an async policy crashes the step instead of degrading to inline.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No real overlap:&lt;/strong&gt; in &lt;code&gt;executeTrackedCalls&lt;/code&gt;, inline calls run sequentially
before the async batch is started.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No progress emitters:&lt;/strong&gt; nothing calls &lt;code&gt;ctxProgressCallback&lt;/code&gt;. Also,
&lt;code&gt;mkSubcallContext&lt;/code&gt; propagates the callback into sub-agent contexts, which
would write their progress into the parent call’s entity.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard to enable:&lt;/strong&gt; the agent JSON has &lt;code&gt;executionMode&lt;/code&gt; and
&lt;code&gt;toolCallPolicyConfig&lt;/code&gt;, but only the durable &lt;code&gt;session&lt;/code&gt; CLI applies them
(&lt;code&gt;applyAgentDurableConfig&lt;/code&gt; in &lt;code&gt;CLI/SessionDurable.hs&lt;/code&gt;). The TUI and OneShot
ignore them, and there is no config for yield strategy or concurrency.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-35-completion-notes"&gt;Phase 3.5 Completion Notes&lt;/h3&gt;
&lt;p&gt;Done 2026-09-16. Build green, 875 tests pass (5 new end-to-end tests).&lt;/p&gt;
&lt;h4 id="semantics"&gt;Semantics&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Placeholders.&lt;/strong&gt; &lt;code&gt;partialToolMessages&lt;/code&gt; (&lt;code&gt;Session/Types.hs&lt;/code&gt;) emits one tool
message per call. Final calls carry their result. Non-final calls, and calls
whose result was delivered late, get a JSON placeholder
(&lt;code&gt;status&lt;/code&gt;, &lt;code&gt;tool_call_id&lt;/code&gt;, a hint to use &lt;code&gt;get-tool-call-status&lt;/code&gt; /
&lt;code&gt;cancel-tool-call&lt;/code&gt;). Used by &lt;code&gt;OpenAI.hs&lt;/code&gt;, both naive step functions, and
&lt;code&gt;Wake.hs&lt;/code&gt;. &lt;code&gt;Failed&lt;/code&gt; calls now also get their tool message (previously
dropped).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Late delivery.&lt;/strong&gt; &lt;code&gt;collectLateResults&lt;/code&gt; (&lt;code&gt;Session/Step.hs&lt;/code&gt;) finds &lt;code&gt;Running&lt;/code&gt;
calls in partial turns below the head, polls them, marks finished ones
&lt;code&gt;tcDeliveredLate = True&lt;/code&gt; (new field on &lt;code&gt;TrackedToolCall&lt;/code&gt;, optional in JSON),
and &lt;code&gt;lateResultsQuery&lt;/code&gt; renders them into the next user turn’s &lt;code&gt;userQuery&lt;/code&gt;
(media is attached). The partial turn keeps showing the placeholder, so
history matches what the model saw. Runs in both sync and async steps.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stopping.&lt;/strong&gt; &lt;code&gt;naiveTilNoToolCallStep&lt;/code&gt; no longer stops on an LLM turn without
tool calls while &lt;code&gt;hasBackgroundCalls&lt;/code&gt;. It asks for a user turn, and the
stepper blocks until the results arrive (all under &lt;code&gt;YieldWhenAllDone&lt;/code&gt;,
otherwise at least one).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refresh.&lt;/strong&gt; &lt;code&gt;runStepMAsync&lt;/code&gt; refreshes the head partial turn before each
step (&lt;code&gt;refreshHeadPartialTurn&lt;/code&gt;). Background completions are picked up, and
the head becomes a full &lt;code&gt;UserTurn&lt;/code&gt; once every call is final.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resume.&lt;/strong&gt; &lt;code&gt;executeTrackedCalls&lt;/code&gt; takes &lt;code&gt;replaceHead&lt;/code&gt;; &lt;code&gt;continuePartialTurn&lt;/code&gt;
replaces the head instead of stacking. It also waits, per yield strategy, on
calls carried over from earlier steps together with newly started ones.
Finalization accepts &lt;code&gt;Completed&lt;/code&gt; or &lt;code&gt;Failed&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message order.&lt;/strong&gt; &lt;code&gt;OpenAI.hs&lt;/code&gt; now emits tool messages before the user
message in a turn (required once a user turn carries both).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="engine--ids--cancellation"&gt;Engine / ids / cancellation&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ToolCallConfig.tcProviderCallId&lt;/code&gt; stores the provider’s id
(&lt;code&gt;createToolCallEntityWithProviderId&lt;/code&gt;); &lt;code&gt;findToolCallEntityByProviderCallId&lt;/code&gt;
resolves it within a session and conversation, preferring in-flight then
most recently started calls (Kimi-style ids repeat).
&lt;/li&gt;
&lt;li&gt;Capabilities accept the provider id or the internal UUID;
&lt;code&gt;list-running-tool-calls&lt;/code&gt; returns the provider id. Session fallback reports
final calls from history, &lt;code&gt;Running&lt;/code&gt; as &lt;code&gt;orphaned&lt;/code&gt; (&lt;code&gt;is_final: true&lt;/code&gt;), and
deferred as &lt;code&gt;pending&lt;/code&gt;. &lt;code&gt;waitForFinal&lt;/code&gt; blocks on STM instead of polling.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;runStepMAsync&lt;/code&gt; installs one engine on the agent (&lt;code&gt;prepareAsyncEngine&lt;/code&gt;) and
keeps it on &lt;code&gt;Evolve&lt;/code&gt;. &lt;code&gt;buildContext&lt;/code&gt; exposes &lt;code&gt;Engine.cancelToolCall&lt;/code&gt; as
&lt;code&gt;ctxCancelToolCall&lt;/code&gt;. &lt;code&gt;cancel-tool-call&lt;/code&gt; uses it, falling back to marking the
entity.
&lt;/li&gt;
&lt;li&gt;Engine: asynchronous exceptions are no longer swallowed (cancel really
interrupts the tool), each call unregisters itself when it finishes,
&lt;code&gt;cancelToolCall&lt;/code&gt; reports whether the entity actually ended up cancelled,
and &lt;code&gt;TCT.cancelToolCall&lt;/code&gt; never overwrites a final state. &lt;code&gt;startAsyncBatch&lt;/code&gt;
ignores calls without an entity; the stepper runs those inline.
&lt;/li&gt;
&lt;li&gt;Orphans: &lt;code&gt;pollRunningCall&lt;/code&gt; fails a &lt;code&gt;Running&lt;/code&gt; call whose entity (or world) is
missing.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withAsyncEngine&lt;/code&gt; registers tool-call stores first and stores the resulting
world on the agent, so engine and agent share the same world value.
&lt;/li&gt;
&lt;li&gt;Waits use &lt;code&gt;System.Timeout&lt;/code&gt; rather than &lt;code&gt;registerDelay&lt;/code&gt;, which needs the
threaded RTS (the test suite is not threaded).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tests-testasynctoolcallstestshs"&gt;Tests (&lt;code&gt;test/AsyncToolCallsTests.hs&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Fast and gated slow call with &lt;code&gt;YieldOnAnyProgress&lt;/code&gt;: partial turn, placeholder
seen by the LLM, stepper blocks and delivers the late result exactly once, no
duplicated partial turn, every completion pairs each tool call with exactly
one tool message, session stops afterwards.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancel-tool-call&lt;/code&gt; by provider id interrupts a sleeping tool (its
&lt;code&gt;onException&lt;/code&gt; handler runs, it never finishes), entity is &lt;code&gt;cancelled&lt;/code&gt;, next
step finalizes the turn.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Running&lt;/code&gt; call with a missing entity resolves as orphaned.
&lt;/li&gt;
&lt;li&gt;Partial turn with a deferred and a running call resumed twice stays a single
head turn.
&lt;/li&gt;
&lt;li&gt;Malformed &lt;code&gt;RunAsync&lt;/code&gt; call runs inline instead of crashing.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OS.ConversationTests&lt;/code&gt; orphan capability test now uses a &lt;code&gt;Running&lt;/code&gt; call and
expects &lt;code&gt;is_final: true&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="known-gaps-carried-forward"&gt;Known gaps carried forward&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;runAsync&lt;/code&gt; / &lt;code&gt;runAsyncWithProgress&lt;/code&gt; still return only the session. Resuming
in-process with a fresh agent loses the engine registry unless
&lt;code&gt;withAsyncEngine&lt;/code&gt; was installed up front (documented on both).
&lt;/li&gt;
&lt;li&gt;Placeholders do not include progress (history is pure; the model can call
&lt;code&gt;get-tool-call-status&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;If the LLM fetches a result via &lt;code&gt;get-tool-call-status&lt;/code&gt;, the late-delivery
notice still repeats it once.
&lt;/li&gt;
&lt;li&gt;A head partial turn with only &lt;code&gt;Deferred&lt;/code&gt; calls still spins under &lt;code&gt;run&lt;/code&gt;
(pre-existing; &lt;code&gt;runAsync&lt;/code&gt; pauses correctly).
&lt;/li&gt;
&lt;li&gt;Cancel against a call whose engine is gone only marks the entity; the thread
(if any) keeps running.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-4-completion-notes"&gt;Phase 4 Completion Notes&lt;/h3&gt;
&lt;h4 id="enablement"&gt;Enablement&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Base.Agent&lt;/code&gt; gains &lt;code&gt;asyncYieldStrategy&lt;/code&gt; and &lt;code&gt;maxConcurrency&lt;/code&gt;; the runtime
&lt;code&gt;Agent&lt;/code&gt; gains &lt;code&gt;ctxMaxConcurrency&lt;/code&gt; (used when the engine is created).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;applyAgentDurableConfig&lt;/code&gt; / &lt;code&gt;buildToolCallPolicy&lt;/code&gt; moved to
&lt;code&gt;System.Agents.Session.AgentConfig&lt;/code&gt; (re-exported by &lt;code&gt;CLI.SessionDurable&lt;/code&gt;) and
are applied in &lt;code&gt;OneShot.nodeToAgentWithThinking&lt;/code&gt; (OneShot, TUI, &lt;code&gt;session&lt;/code&gt;
commands) and &lt;code&gt;AgentTree.OneShotTool.nodeToAgent&lt;/code&gt; (sub-agents).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prepareAgentWorld&lt;/code&gt; gives an asynchronous agent without a &lt;code&gt;World&lt;/code&gt; a private
one; otherwise &lt;code&gt;RunAsync&lt;/code&gt; calls silently ran inline.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;llmToolCallName&lt;/code&gt; now lives in &lt;code&gt;Session.Types&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example agent JSON:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;executionMode&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;asynchronous&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;asyncYieldStrategy&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;yieldOnAnyProgress&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;maxConcurrency&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;&lt;span class="er"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;toolCallPolicyConfig&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runAsync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="progress-events"&gt;Progress events&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OSEvent_ToolCallActivity ToolCallActivity&lt;/code&gt; (&lt;code&gt;OS.Events&lt;/code&gt;) with phases
started / progressed / completed / failed / cancelled, keyed by session id,
conversation id, tool-call id and provider id.
&lt;/li&gt;
&lt;li&gt;The engine publishes them on the context’s &lt;code&gt;ctxEventQueue&lt;/code&gt;. The TUI already
bridges its OS event queue to the Brick channel (&lt;code&gt;TUI.Core.startOSEventBridge&lt;/code&gt;),
so &lt;code&gt;convertOSEvent&lt;/code&gt; maps them to &lt;code&gt;AppEvent_ToolCallActivity&lt;/code&gt;; no
&lt;code&gt;RuntimeBridge&lt;/code&gt; change was needed.
&lt;/li&gt;
&lt;li&gt;Tool-call progress entries on the entity are capped at 50 (newest first).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tui"&gt;TUI&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TUI.ToolCallActivity&lt;/code&gt; keeps a &lt;code&gt;ToolCallViews&lt;/code&gt; map (per session, per call)
in &lt;code&gt;UIState._toolCallViews&lt;/code&gt;: latest phase, start time, last progress. Views
are pruned when a session update shows the call is no longer running.
&lt;/li&gt;
&lt;li&gt;Rendering: a “Background tool calls running: …” line above the turns, and
one line per tracked call in partial turns (pending / deferred / running with
latest progress / completed / delivered later / failed). No spinner.
&lt;/li&gt;
&lt;li&gt;While background calls run and the LLM has nothing to do, the TUI asks for
user input instead of blocking: the stepper’s new &lt;code&gt;askUserQuery&lt;/code&gt; races
&lt;code&gt;usrQuery&lt;/code&gt; against the background calls (per the yield strategy) and
cancels &lt;code&gt;usrQuery&lt;/code&gt; if the calls finish first. &lt;code&gt;usrQuery&lt;/code&gt; must tolerate
cancellation (the TUI reads a &lt;code&gt;BChan&lt;/code&gt;, which is STM).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="oneshot--loops"&gt;OneShot / loops&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--wait-for-async&lt;/code&gt; was not added. &lt;code&gt;run&lt;/code&gt; already waits for in-process
background calls (they cannot outlive the process). Stopping early would
only orphan them.
&lt;/li&gt;
&lt;li&gt;New &lt;code&gt;Loop.runUntilBlocked&lt;/code&gt; / &lt;code&gt;isBlockedOnDeferredCalls&lt;/code&gt;: returns the session
when the head partial turn only waits on deferred calls instead of spinning.
OneShot uses it, stores the session under its session id too, and prints a
JSON report (&lt;code&gt;status: paused&lt;/code&gt;, &lt;code&gt;session_id&lt;/code&gt;, deferred calls with continuation
tokens) for &lt;code&gt;session complete&lt;/code&gt; / &lt;code&gt;session resume&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Markdown export (&lt;code&gt;SessionPrint&lt;/code&gt;) lists each call’s status in partial turns
and shows finished results. The search index includes failed results and
names of all calls in partial turns.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="progress-emitters"&gt;Progress emitters&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Bash tools: when &lt;code&gt;ctxProgressCallback&lt;/code&gt; is set (async calls), the script runs
through &lt;code&gt;Bash.runProcessReportingOutput&lt;/code&gt;, which reports
&lt;code&gt;{stream, line, lines, bytes}&lt;/code&gt; at most every 0.5s per stream. The process is
terminated if the call is cancelled. Synchronous calls keep the old path.
&lt;/li&gt;
&lt;li&gt;Sub-agent tools (&lt;code&gt;OneShotTool&lt;/code&gt;) report &lt;code&gt;{message, turns}&lt;/code&gt; after each
sub-agent step, and now rethrow async exceptions so cancelling them works
(they were caught and turned into failures).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mkSubcallContext&lt;/code&gt; no longer copies the parent’s progress callback or cancel
hook.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tests-testasynctoolcallstestshs-now-17"&gt;Tests (&lt;code&gt;test/AsyncToolCallsTests.hs&lt;/code&gt;, now 17)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Async agent without a World; &lt;code&gt;ctxMaxConcurrency&lt;/code&gt; bound; engine activity
events; background results vs user query race (both ways); TUI view
apply/prune/summaries; markdown partial turn; &lt;code&gt;runUntilBlocked&lt;/code&gt;; subprocess
output reports; subprocess terminated on cancel.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionDurableTests&lt;/code&gt;: yield strategy / max concurrency application and JSON
parsing. Full suite: 890 tests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="known-gaps-carried-forward-1"&gt;Known gaps carried forward&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;TUI rendering and the input race were not exercised by hand.
&lt;/li&gt;
&lt;li&gt;Bash progress is tested on &lt;code&gt;runProcessReportingOutput&lt;/code&gt; directly, not through
a registered bash toolbox end to end.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;terminateProcess&lt;/code&gt; sends SIGTERM to the script only; its children may
survive (Phase 5: process groups).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run&lt;/code&gt; itself still spins on deferred-only partial turns; only
&lt;code&gt;runUntilBlocked&lt;/code&gt; users (OneShot) avoid it. The TUI still uses &lt;code&gt;run&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Earlier gaps (engine not returned by &lt;code&gt;runAsync&lt;/code&gt;, repeated result after
&lt;code&gt;get-tool-call-status&lt;/code&gt;) remain.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-5-completion-notes"&gt;Phase 5 Completion Notes&lt;/h3&gt;
&lt;h4 id="shutdown-and-cancellation"&gt;Shutdown and cancellation&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Engine.shutdownAsyncEngine&lt;/code&gt; cancels every batch the engine still owns.
&lt;code&gt;Loop.run&lt;/code&gt; / &lt;code&gt;runWithProgress&lt;/code&gt; / &lt;code&gt;runUntilBlocked&lt;/code&gt; shut the engine down when
the run ends or throws (tracking the evolving agent in an &lt;code&gt;IORef&lt;/code&gt;);
&lt;code&gt;runAsync*&lt;/code&gt; only on failure, since pausing with calls running is the point.
&lt;/li&gt;
&lt;li&gt;Bash scripts run in their own process group and are killed with
&lt;code&gt;SIGTERM&lt;/code&gt;, then &lt;code&gt;SIGKILL&lt;/code&gt; after 100ms, so cancelling kills what the script
started. Verified: the test fails without the group kill.
&lt;/li&gt;
&lt;li&gt;The TUI kills conversation threads when quitting (bounded to 2s), which runs
the same cleanup.
&lt;/li&gt;
&lt;li&gt;The TUI uses &lt;code&gt;runUntilBlocked&lt;/code&gt;, so a conversation waiting only on deferred
calls stops with a status message instead of spinning.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="stale-calls"&gt;Stale calls&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;asyncCallTimeoutSeconds&lt;/code&gt; (agent JSON) → &lt;code&gt;ctxAsyncCallTimeout&lt;/code&gt; →
&lt;code&gt;aeCallTimeout&lt;/code&gt;. A call that outlives it is interrupted (killing its
subprocess) and reported as failed: “async tool call timed out after Ns”.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="orphans-across-a-restart"&gt;Orphans across a restart&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt; used to need &lt;code&gt;includeFullSession&lt;/code&gt;, which is off by
default (it also pushes the whole session into every bash tool’s
environment). Contexts now carry &lt;code&gt;ctxSessionToolCalls&lt;/code&gt;: the tracked calls of
the session’s partial turns only. Without it, a reloaded session answered
“tool call not found” instead of “orphaned”.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;orphanedAcrossRestart&lt;/code&gt; writes a session with a running call to disk, reloads
it in a fresh &lt;code&gt;World&lt;/code&gt;, and checks both the capability and the stepper.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="concurrency"&gt;Concurrency&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;maxConcurrency&lt;/code&gt; stays per agent. &lt;code&gt;newAsyncConcurrencyLimit&lt;/code&gt; +
&lt;code&gt;mkAsyncEngineSharing&lt;/code&gt; let a host share one limit across agents (each agent
needs its own engine, since the executor is tied to its tools). No rate
limiting (calls per minute) was added.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="docs"&gt;Docs&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;New &lt;code&gt;documentation/async-tool-calls.md&lt;/code&gt; covers configuration, placeholders and late
delivery, the capabilities, progress, cancellation, the TUI, one-shot runs,
session files and the limits. Linked from &lt;code&gt;documentation/README.md&lt;/code&gt;,
&lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/tools.md&lt;/code&gt; lists the three capabilities; &lt;code&gt;documentation/tui.md&lt;/code&gt; documents
background call display and input while calls run; &lt;code&gt;documentation/cli-commands.md&lt;/code&gt;
documents the paused JSON report of &lt;code&gt;run&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The agent JSON in the new doc was checked by parsing it with &lt;code&gt;Base.Agent&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="mcp--openapi-streaming-question-from-the-plan"&gt;MCP / OpenAPI streaming (question from the plan)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;OpenAPI tools wait for one complete HTTP response: nothing to stream.
&lt;/li&gt;
&lt;li&gt;Done: &lt;code&gt;MCP.Client&lt;/code&gt; advertises a &lt;code&gt;_meta.progressToken&lt;/code&gt; on &lt;code&gt;tools/call&lt;/code&gt; when
the call has a progress callback, and forwards the server’s
&lt;code&gt;notifications/progress&lt;/code&gt; for that token to &lt;code&gt;ctxProgressCallback&lt;/code&gt; (payload
&lt;code&gt;{progress, total?, message?}&lt;/code&gt;), so MCP tools report progress like bash
tools (&lt;code&gt;tool.progressed&lt;/code&gt; events, &lt;code&gt;get_tool_call_status&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="not-done"&gt;Not done&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tracing.&lt;/strong&gt; &lt;code&gt;Agent&lt;/code&gt; carries no tracer (tracers live in the builders’
closures), so &lt;code&gt;Prod.Tracer&lt;/code&gt; support would mean threading one through the
agent and the engine. The activity events (&lt;code&gt;OSEvent_ToolCallActivity&lt;/code&gt;) and
the progress entries on the entity are the observability path for now.
&lt;/li&gt;
&lt;li&gt;Rate limiting beyond a concurrency cap.
&lt;/li&gt;
&lt;li&gt;A pre-existing docs bug found on the way, now fixed: JSON examples used key
spellings the parsers reject. Every builtin toolbox (&lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;Description&lt;/code&gt;,
&lt;code&gt;Capabilities&lt;/code&gt;, &lt;code&gt;FileSandbox&lt;/code&gt;, …), file sandboxes (&lt;code&gt;fsbPredicate&lt;/code&gt;,
&lt;code&gt;fsbMaxFileSize&lt;/code&gt;, &lt;code&gt;fsbName&lt;/code&gt;), bash toolboxes (&lt;code&gt;Path&lt;/code&gt;, &lt;code&gt;BasenameFilter&lt;/code&gt;),
OpenAPI/PostgREST servers (&lt;code&gt;SpecUrl&lt;/code&gt;, &lt;code&gt;BaseUrl&lt;/code&gt;, &lt;code&gt;Token&lt;/code&gt;), the removed Lua
&lt;code&gt;allowedPaths&lt;/code&gt; field, the old SQLite &lt;code&gt;path&lt;/code&gt;/&lt;code&gt;access&lt;/code&gt; fields (now
&lt;code&gt;Versioning&lt;/code&gt;), and the kebab-case agent keys in
&lt;code&gt;documentation/advanced-configuration.md&lt;/code&gt; (&lt;code&gt;api-key-id&lt;/code&gt; → &lt;code&gt;apiKeyId&lt;/code&gt;, …). Fixed in
&lt;code&gt;documentation/tools.md&lt;/code&gt;, &lt;code&gt;documentation/file-loader.md&lt;/code&gt;, &lt;code&gt;documentation/advanced-configuration.md&lt;/code&gt; and
the &lt;code&gt;Agent&lt;/code&gt;/&lt;code&gt;bashToolboxes&lt;/code&gt; Haddock in &lt;code&gt;System.Agents.Base&lt;/code&gt;. Every JSON block
in &lt;code&gt;documentation/&lt;/code&gt; now decodes into the real types; the throwaway checker used for
this is in the session scratchpad.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tests-testasynctoolcallstestshs-now-21"&gt;Tests (&lt;code&gt;test/AsyncToolCallsTests.hs&lt;/code&gt;, now 21)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Failing run cancels background calls; call timeout; orphan across a
save/reload; subprocess killed on cancel; process group killed on cancel.
&lt;/li&gt;
&lt;li&gt;Full suite: 894 tests, async group stable over repeated runs.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="completion-plan"&gt;Completion Plan&lt;/h3&gt;
&lt;h4 id="phase-35-end-to-end-correctness-done--see-completion-notes-above"&gt;Phase 3.5: End-to-End Correctness (done — see completion notes above)&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Call ids (R1).&lt;/strong&gt; Accept the provider’s tool-call id in
&lt;code&gt;get-tool-call-status&lt;/code&gt; / &lt;code&gt;cancel-tool-call&lt;/code&gt; / &lt;code&gt;list-running-tool-calls&lt;/code&gt;,
either by storing it on &lt;code&gt;ToolCallConfig&lt;/code&gt; or by resolving it through the
tracked calls. Keep the internal UUID as a fallback. &lt;code&gt;list-running-tool-calls&lt;/code&gt;
should return the id the model knows.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Placeholder responses (R2).&lt;/strong&gt; For calls still &lt;code&gt;Running&lt;/code&gt; (or &lt;code&gt;Deferred&lt;/code&gt;)
when the LLM is asked for a completion, emit a tool message such as
&lt;code&gt;{&amp;quot;status&amp;quot;:&amp;quot;running&amp;quot;,&amp;quot;tool_call_id&amp;quot;:…,&amp;quot;progress&amp;quot;:[…]}&lt;/code&gt; so the request is
valid and the model knows the call is pending.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delivering late results (R2).&lt;/strong&gt; A finished result cannot be attached to a
tool message the model already answered. Inject it into the next user turn
as a notice (e.g. “tool call X completed: …”). Update
&lt;code&gt;naiveTilNoToolCallStep&lt;/code&gt; so &lt;code&gt;Running&lt;/code&gt; calls count as outstanding and so
completed-late calls are surfaced.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partial turns (R2).&lt;/strong&gt; Replace the head &lt;code&gt;PartialUserTurn&lt;/code&gt; on resume instead
of prepending a new one (match &lt;code&gt;Session/Wake.hs&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One engine (R3, R4).&lt;/strong&gt; Either return the agent from
&lt;code&gt;runAsync&lt;/code&gt; / &lt;code&gt;runAsyncWithProgress&lt;/code&gt;, or keep the engine alongside the OS
&lt;code&gt;World&lt;/code&gt; so every step shares it. Add a cancel hook to
&lt;code&gt;ToolExecutionContext&lt;/code&gt; so &lt;code&gt;cancel-tool-call&lt;/code&gt; actually kills the thread via
&lt;code&gt;Engine.cancelToolCall&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orphaned calls (R5).&lt;/strong&gt; In &lt;code&gt;pollRunningCall&lt;/code&gt;, mark a &lt;code&gt;Running&lt;/code&gt; call whose
entity is missing as &lt;code&gt;Failed&lt;/code&gt; with an “orphaned” response. Return
&lt;code&gt;is_final: true&lt;/code&gt; for orphaned calls in the capability.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Malformed calls (R6).&lt;/strong&gt; Replace the &lt;code&gt;error&lt;/code&gt; in &lt;code&gt;requireEntityId&lt;/code&gt; with a
fallback that executes the call inline.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;End-to-end tests.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Two slow calls with &lt;code&gt;YieldOnAnyProgress&lt;/code&gt; → &lt;code&gt;PartialUserTurn&lt;/code&gt; → resume →
full &lt;code&gt;UserTurn&lt;/code&gt;, with a valid OpenAI message list at every step (every
tool call has exactly one tool message, no duplicated turns).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancel-tool-call&lt;/code&gt; stops a real running tool (e.g. a sleeping bash
command) and the thread is gone.
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Running&lt;/code&gt; call whose entity is missing is resolved as orphaned.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="phase-4-tui--oneshot-ux-done--see-completion-notes-above"&gt;Phase 4: TUI / OneShot UX (done — see completion notes above)&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enablement.&lt;/strong&gt; &lt;code&gt;executionMode&lt;/code&gt; and &lt;code&gt;toolCallPolicyConfig&lt;/code&gt; already exist in
the agent JSON; apply them in the TUI and OneShot agent builders (reuse
&lt;code&gt;applyAgentDurableConfig&lt;/code&gt;), and add &lt;code&gt;asyncYieldStrategy&lt;/code&gt; and
&lt;code&gt;maxConcurrency&lt;/code&gt;. Without this nothing in the UI can be exercised.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Progress events.&lt;/strong&gt; Add &lt;code&gt;AppEvent_ToolCallProgress&lt;/code&gt; to
&lt;code&gt;System.Agents.TUI.Types&lt;/code&gt;. The engine emits through &lt;code&gt;ctxEventQueue&lt;/code&gt; when
present. Decide how the event reaches the TUI &lt;code&gt;BChan&lt;/code&gt; given the TUI still
goes through the legacy &lt;code&gt;RuntimeBridge&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rendering.&lt;/strong&gt; Show running calls with a spinner and latest progress in
&lt;code&gt;TUI/Render/Conversation.hs&lt;/code&gt;; handle partial turns in &lt;code&gt;SessionPrint&lt;/code&gt; /
&lt;code&gt;formatSessionAsMarkdown&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OneShot.&lt;/strong&gt; Add &lt;code&gt;--wait-for-async&lt;/code&gt;. Without it, exit with JSON listing the
pending calls and the session to resume.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A real progress emitter.&lt;/strong&gt; Make one tool call &lt;code&gt;ctxProgressCallback&lt;/code&gt;
(bash output lines are the obvious candidate). Stop propagating the
callback into sub-agent contexts, or give sub-calls their own.
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="phase-5-cleanup--hardening-done-except-tracing--see-completion-notes-above"&gt;Phase 5: Cleanup &amp;amp; Hardening (done except tracing — see completion notes above)&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Cancel running batches on session abort, TUI quit, or exception; shut the
engine down with the agent. Kill whole process groups on cancel.
Stop &lt;code&gt;run&lt;/code&gt; (and the TUI) from spinning on deferred-only partial turns.
&lt;/li&gt;
&lt;li&gt;Expire stale calls (timeout plus a check that the thread is still alive).
&lt;/li&gt;
&lt;li&gt;Global max concurrency / rate limiting, configurable (builds on Phase 3.5
step 5).
&lt;/li&gt;
&lt;li&gt;Tracing for async calls and progress in &lt;code&gt;Prod.Tracer&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Verify orphan handling across a real process restart + session reload.
&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;documentation/tools.md&lt;/code&gt;, &lt;code&gt;documentation/tui.md&lt;/code&gt;, &lt;code&gt;documentation/cli-commands.md&lt;/code&gt;, and document
the agent JSON schema for async.
&lt;/li&gt;
&lt;li&gt;Clarify whether MCP / OpenAPI tools can stream into the progress callback.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-async-tool-calls-progress.html" rel="alternate"/><summary type="text">Status: no status line yet</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-README.html</id><title type="text">Agents - AI Agent Framework</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/README.md"&gt;&lt;code&gt;documentation/README.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="agents---ai-agent-framework"&gt;Agents - AI Agent Framework&lt;/h2&gt;
&lt;p&gt;A Haskell-based framework for building and orchestrating AI agents with support for multi-agent hierarchies, tool systems, and LLM integrations.&lt;/p&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;p&gt;The Agents framework provides a complete infrastructure for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Agent Definition&lt;/strong&gt;: JSON-based agent configurations with system prompts, tool directories, and LLM settings
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-Agent Orchestration&lt;/strong&gt;: Hierarchical agent trees with parent-child relationships and cross-agent references
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool System&lt;/strong&gt;: Extensible tool registration with support for bash scripts, MCP servers, and OpenAPI integrations
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session Management&lt;/strong&gt;: Persistent conversation sessions with turn-based interactions
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Durable Workflows&lt;/strong&gt;: Asynchronous, resumable execution with deferred tool calls and isolated deployments
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiple Interfaces&lt;/strong&gt;: CLI, TUI (Terminal UI), MCP server, and an HTTP server
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="quick-start"&gt;Quick Start&lt;/h3&gt;
&lt;h4 id="installation"&gt;Installation&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Build the project&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cabal&lt;/span&gt; build&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Run the durable-workflow demonstrator (no API key needed)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cabal&lt;/span&gt; run durable-workflow-demo&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Run tests&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cabal&lt;/span&gt; test&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="creating-an-agent"&gt;Creating an Agent&lt;/h4&gt;
&lt;p&gt;Create an &lt;code&gt;agent.json&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;A helpful assistant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;You are a helpful assistant.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;mcpServers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="running-the-agent"&gt;Running the Agent&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Check agent configuration&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Run in one-shot mode&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Hello!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Start interactive TUI&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Start MCP server&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; mcp-server &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="configuration"&gt;Configuration&lt;/h3&gt;
&lt;h4 id="api-keys"&gt;API Keys&lt;/h4&gt;
&lt;p&gt;Store API keys in &lt;code&gt;~/.config/agents-exe/secret-keys&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sk-...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;openrouter&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sk-...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="project-configuration"&gt;Project Configuration&lt;/h4&gt;
&lt;p&gt;Create &lt;code&gt;agents-exe.cfg.json&lt;/code&gt; in your project root:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsDirectories&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./agents&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsFiles&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./main-agent.json&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agentsLogs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;logJsonHttpEndpoint&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;http://localhost:8080/log&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;logJsonPath&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./logs/agents.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;logRawPath&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./logs/agents.log&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="project-structure"&gt;Project Structure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;agents/
├── app/                      # Application entry point
│   └── Main.hs              # CLI argument parsing and command routing
├── examples/                # Runnable example programs
│   └── durable-workflow-demo/
│       └── Main.hs          # Self-contained durable workflow demonstrator
├── src/
│   └── System/Agents/
│       ├── Base.hs          # Core types (Agent, AgentId, ConversationId)
│       ├── Runtime.hs       # Agent runtime and execution
│       ├── AgentTree.hs     # Multi-agent hierarchy management
│       ├── Session/         # Session management
│       ├── Tools/           # Tool system
│       ├── MCP/             # Model Context Protocol
│       ├── TUI/             # Terminal UI
│       ├── CLI/             # Command implementations
│       ├── ExportImport/    # Tool sharing
│       └── FileLoader/      # File loading utilities
├── documentation/                    # Documentation
└── test/                    # Test suite
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="key-features"&gt;Key Features&lt;/h3&gt;
&lt;h4 id="multi-agent-hierarchies"&gt;Multi-Agent Hierarchies&lt;/h4&gt;
&lt;p&gt;Agents can reference other agents via:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tool Directory&lt;/strong&gt;: Child agents in a subdirectory
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extra Agents&lt;/strong&gt;: Explicit references via &lt;code&gt;extraAgents&lt;/code&gt; field
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tool-types"&gt;Tool Types&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Bash Tools&lt;/strong&gt;: Executable scripts in the tool directory
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP Tools&lt;/strong&gt;: Model Context Protocol servers
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenAPI Tools&lt;/strong&gt;: REST API endpoints via OpenAPI specs
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IO Tools&lt;/strong&gt;: Haskell-based tool implementations
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="session-persistence"&gt;Session Persistence&lt;/h4&gt;
&lt;p&gt;Sessions are automatically saved and can be resumed:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Resume a session&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json &lt;span class="at"&gt;--session-file&lt;/span&gt; session.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Print session history&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session-print session.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="durable-workflows"&gt;Durable Workflows&lt;/h4&gt;
&lt;p&gt;Turns can pause mid-execution, persist, and resume when external results
arrive:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Pause after one async step&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents&lt;/span&gt; session pause &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; --agent-file agent.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# List deferred calls&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents&lt;/span&gt; session pending &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Inject an external result&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents&lt;/span&gt; session complete &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;token&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; result.json&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Resume until completion or next yield&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents&lt;/span&gt; session resume &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; --agent-file agent.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;See &lt;a href="/agents-exe/docs-durable-workflows-howto.html"&gt;Durable Workflows How-To&lt;/a&gt; for a full walkthrough,
including a runnable mock-LLM demonstrator.&lt;/p&gt;
&lt;h3 id="documentation"&gt;Documentation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-architecture.html"&gt;Architecture&lt;/a&gt; - Runtime and core architecture
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-tools.html"&gt;Tool System&lt;/a&gt; - Tool registration and execution
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-mcp.html"&gt;MCP Protocol&lt;/a&gt; - Model Context Protocol integration
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-sessions.html"&gt;Session Management&lt;/a&gt; - Session lifecycle and persistence
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-agent-templates.html"&gt;Agent Templates&lt;/a&gt; - Write an agent file as a tramaj program: shared sandboxes and toolboxes, values picked by the operator
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-parameters-and-bindings.html"&gt;Parameters, Bindings &amp;amp; Narrowing Sub-Agents&lt;/a&gt; - Bind tool arguments to declared parameters, keep secrets out of the model, and narrow sub-agents at call time
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-durable-workflows-howto.html"&gt;Durable Workflows How-To&lt;/a&gt; - Resumable async execution
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-agents-server.html"&gt;agents-server&lt;/a&gt; - Agents over HTTP: sessions, events, OpenAPI, and a chat page
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-async-tool-calls.html"&gt;Asynchronous Tool Calls&lt;/a&gt; - Background tool calls, progress and cancellation
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-tui.html"&gt;Terminal UI&lt;/a&gt; - TUI interface
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-cli-commands.html"&gt;CLI Reference&lt;/a&gt; - Command reference
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-export-import.html"&gt;Export/Import&lt;/a&gt; - Tool sharing and distribution
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-file-loader.html"&gt;File Loader&lt;/a&gt; - File loading utilities
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="architecture-overview"&gt;Architecture Overview&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                        CLI / TUI / MCP                       │
└──────────────────────┬──────────────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────────────┐
│                      AgentTree                               │
│         (multi-agent hierarchy management)                   │
└──────────────────────┬──────────────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────────────┐
│                     Runtime                                  │
│    (agent execution, tool registration, LLM calls)           │
└──────────────────────┬──────────────────────────────────────┘
                       │
        ┌──────────────┼──────────────┐
        ▼              ▼              ▼
┌──────────────┐ ┌──────────┐ ┌──────────────┐
│   Session    │ │  Tools   │ │     LLM      │
│  Management  │ │  System  │ │  Integration │
└──────────────┘ └──────────┘ └──────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="contributing"&gt;Contributing&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Fork the repository
&lt;/li&gt;
&lt;li&gt;Create a feature branch
&lt;/li&gt;
&lt;li&gt;Make your changes
&lt;/li&gt;
&lt;li&gt;Run tests: &lt;code&gt;cabal test&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Submit a pull request
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="license"&gt;License&lt;/h3&gt;
&lt;p&gt;See the project LICENSE file for details.&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-README.html" rel="alternate"/><summary type="text">A Haskell-based framework for building and orchestrating AI agents with support for multi-agent hierarchies, tool systems, and LLM integrations. ## Overview The Agents framework provides a complete infrastructure for: - **Agent Definition**</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-binary-tool.html</id><title type="text">Adding New Executable-Program Tools</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/binary-tool.md"&gt;&lt;code&gt;documentation/binary-tool.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="adding-new-executable-program-tools"&gt;Adding New Executable-Program Tools&lt;/h2&gt;
&lt;p&gt;Executable-program tools (also called “bash tools”) are external programs that &lt;code&gt;agents-exe&lt;/code&gt; can invoke as part of agent execution. These tools extend agent capabilities by performing side effects like reading files, installing packages, probing the network, or interacting with external APIs.&lt;/p&gt;
&lt;h3 id="tool-protocol-overview"&gt;Tool Protocol Overview&lt;/h3&gt;
&lt;p&gt;Bash tools must adhere to a simple protocol with two commands:&lt;/p&gt;
&lt;h4 id="1-the-describe-command"&gt;1. The &lt;code&gt;describe&lt;/code&gt; Command&lt;/h4&gt;
&lt;p&gt;When called with a single &lt;code&gt;describe&lt;/code&gt; argument (no other parameters), the tool must return a JSON description of its interface:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; ./my-tool describe&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="st"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my_tool&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="st"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;What this tool does&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="st"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; [&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;arg_name&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Argument description&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;backing_type&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;arity&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;single&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;mode&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;dashdashspace&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ex"&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="st"&gt;&amp;quot;empty-result&amp;quot;&lt;/span&gt;&lt;span class="ex"&gt;:&lt;/span&gt; { &lt;span class="st"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;AddMessage&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;No results found&amp;quot;&lt;/span&gt; }&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="2-the-run-command"&gt;2. The &lt;code&gt;run&lt;/code&gt; Command&lt;/h4&gt;
&lt;p&gt;When called with &lt;code&gt;run&lt;/code&gt; followed by arguments, the tool executes its function and &lt;strong&gt;must&lt;/strong&gt; write output to stdout:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; ./my-tool run &lt;span class="at"&gt;--arg-name&lt;/span&gt; value&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;Tool&lt;/span&gt; output here&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="json-description-format"&gt;JSON Description Format&lt;/h3&gt;
&lt;h4 id="top-level-fields"&gt;Top-Level Fields&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Required&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;slug&lt;/code&gt;&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Unique identifier for the tool (no spaces)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Human-readable description for the LLM&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;args&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Array&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;List of argument definitions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;empty-result&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Object&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Behavior when tool returns empty output&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="argument-definition"&gt;Argument Definition&lt;/h4&gt;
&lt;p&gt;Each argument in the &lt;code&gt;args&lt;/code&gt; array has the following fields:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Required&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Argument name (used in JSON input)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Description for the LLM&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;type&lt;/code&gt;&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Semantic type (e.g., "string", "number")&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;backing_type&lt;/code&gt;&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Implementation type (e.g., "string")&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;arity&lt;/code&gt;&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;"single" or "optional"&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;mode&lt;/code&gt;&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;How to pass the argument (see below)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="argument-modes"&gt;Argument Modes&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;mode&lt;/code&gt; field determines how arguments are passed to the script:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Mode&lt;/th&gt;&lt;th&gt;Behavior&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;positional&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Added as consecutive arguments&lt;/td&gt;&lt;td&gt;&lt;code&gt;script run value&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dashdashspace&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Added as &lt;code&gt;--name value&lt;/code&gt; (two args)&lt;/td&gt;&lt;td&gt;&lt;code&gt;script run --name value&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dashdashequal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Added as &lt;code&gt;--name=value&lt;/code&gt; (one arg)&lt;/td&gt;&lt;td&gt;&lt;code&gt;script run --name=value&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;stdin&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Concatenated to stdin with blank separators&lt;/td&gt;&lt;td&gt;&lt;code&gt;echo "value" \| script run&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="empty-result-behavior"&gt;Empty Result Behavior&lt;/h3&gt;
&lt;p&gt;The optional &lt;code&gt;empty-result&lt;/code&gt; field controls what happens when the tool produces no output:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Do&lt;/span&gt; &lt;span class="er"&gt;nothing&lt;/span&gt; &lt;span class="er"&gt;(default&lt;/span&gt; &lt;span class="er"&gt;behavior)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DoNothing&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Add&lt;/span&gt; &lt;span class="er"&gt;a&lt;/span&gt; &lt;span class="er"&gt;message&lt;/span&gt; &lt;span class="er"&gt;when&lt;/span&gt; &lt;span class="er"&gt;output&lt;/span&gt; &lt;span class="er"&gt;is&lt;/span&gt; &lt;span class="er"&gt;empty&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;AddMessage&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;No results found&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="session-context-via-environment-variables"&gt;Session Context via Environment Variables&lt;/h3&gt;
&lt;p&gt;When a tool is executed within a session, &lt;code&gt;agents-exe&lt;/code&gt; passes session context via environment variables. This allows tools to access session metadata without requiring the LLM to provide it as explicit arguments.&lt;/p&gt;
&lt;h4 id="available-environment-variables"&gt;Available Environment Variables&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Variable&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Example Value&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_SESSION_ID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;UUID of the current session&lt;/td&gt;&lt;td&gt;&lt;code&gt;550e8400-e29b-41d4-a716-446655440000&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_CONVERSATION_ID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;UUID of the conversation&lt;/td&gt;&lt;td&gt;&lt;code&gt;6ba7b810-9dad-11d1-80b4-00c04fd430c8&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_TURN_ID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;UUID of the current turn&lt;/td&gt;&lt;td&gt;&lt;code&gt;7c8b9d20-beef-22e2-91c5-11d15fe541d9&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_AGENT_ID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;UUID of the executing agent (if available)&lt;/td&gt;&lt;td&gt;&lt;code&gt;a1b2c3d4-e5f6-7890-abcd-ef1234567890&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_SESSION_JSON&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Full session serialized as JSON (when requested)&lt;/td&gt;&lt;td&gt;&lt;code&gt;{...}&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="use-cases-for-context"&gt;Use Cases for Context&lt;/h4&gt;
&lt;p&gt;Tools can use session context for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Audit logging&lt;/strong&gt;: Include session IDs in external API calls for traceability
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context-aware processing&lt;/strong&gt;: Access conversation history to make smarter decisions
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Correlation&lt;/strong&gt;: Tag external telemetry with session identifiers
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent-specific behavior&lt;/strong&gt;: Adjust behavior based on which agent is executing the tool
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="example-tool-with-session-context"&gt;Example: Tool with Session Context&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="bu"&gt;[&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;describe&amp;quot;&lt;/span&gt; &lt;span class="bu"&gt;]&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;cat&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;slug&amp;quot;: &amp;quot;session-aware-logger&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;description&amp;quot;: &amp;quot;Logs operations with session context for audit trails&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;args&amp;quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;name&amp;quot;: &amp;quot;operation&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;description&amp;quot;: &amp;quot;The operation being logged&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;backing_type&amp;quot;: &amp;quot;string&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;arity&amp;quot;: &amp;quot;single&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;mode&amp;quot;: &amp;quot;dashdashspace&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;exit&lt;/span&gt; 0&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Access session context from environment (with defaults)&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;SESSION_ID&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${AGENT_SESSION_ID&lt;/span&gt;&lt;span class="op"&gt;:-&lt;/span&gt;unknown&lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;CONVERSATION_ID&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${AGENT_CONVERSATION_ID&lt;/span&gt;&lt;span class="op"&gt;:-&lt;/span&gt;unknown&lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;TURN_ID&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${AGENT_TURN_ID&lt;/span&gt;&lt;span class="op"&gt;:-&lt;/span&gt;unknown&lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;AGENT_ID&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${AGENT_AGENT_ID&lt;/span&gt;&lt;span class="op"&gt;:-&lt;/span&gt;unknown&lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Parse the operation argument (skipping &amp;#39;run&amp;#39;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;OPERATION&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;while&lt;/span&gt; &lt;span class="kw"&gt;[[&lt;/span&gt; &lt;span class="va"&gt;$#&lt;/span&gt; &lt;span class="ot"&gt;-gt&lt;/span&gt; 0 &lt;span class="kw"&gt;]];&lt;/span&gt; &lt;span class="cf"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="va"&gt;$1&lt;/span&gt; &lt;span class="kw"&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="ss"&gt;--operation&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="va"&gt;OPERATION&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$2&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="bu"&gt;shift&lt;/span&gt; 2&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="pp"&gt;*&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="bu"&gt;shift&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;esac&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Log with context&lt;/span&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;[session=&lt;/span&gt;&lt;span class="va"&gt;$SESSION_ID&lt;/span&gt;&lt;span class="st"&gt; turn=&lt;/span&gt;&lt;span class="va"&gt;$TURN_ID&lt;/span&gt;&lt;span class="st"&gt;] Executing: &lt;/span&gt;&lt;span class="va"&gt;$OPERATION&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Optionally access full session JSON for complex operations&lt;/span&gt;&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="bu"&gt;[&lt;/span&gt; &lt;span class="ot"&gt;-n&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$AGENT_SESSION_JSON&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="bu"&gt;]&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;# Parse session JSON for additional context&lt;/span&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="va"&gt;TURN_COUNT&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$AGENT_SESSION_JSON&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;jq&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;.turns | length&amp;#39;&lt;/span&gt;&lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;[session=&lt;/span&gt;&lt;span class="va"&gt;$SESSION_ID&lt;/span&gt;&lt;span class="st"&gt;] Turn &lt;/span&gt;&lt;span class="va"&gt;$TURN_COUNT&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="51"&gt;&lt;a href="#51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="note-on-session-json"&gt;Note on Session JSON&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;AGENT_SESSION_JSON&lt;/code&gt; variable is only set when the full session context is available and requested. It contains the complete serialized session, which can be large. Tools should:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check if the variable is set before using it
&lt;/li&gt;
&lt;li&gt;Handle potentially large JSON payloads efficiently
&lt;/li&gt;
&lt;li&gt;Consider using &lt;code&gt;jq&lt;/code&gt; or similar for parsing
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="complete-example-tool"&gt;Complete Example Tool&lt;/h3&gt;
&lt;p&gt;Here’s a complete example of a file-reading tool:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# File: tools/read-file.sh&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="bu"&gt;[&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;describe&amp;quot;&lt;/span&gt; &lt;span class="bu"&gt;]&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;cat&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;slug&amp;quot;: &amp;quot;read_file&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;description&amp;quot;: &amp;quot;Reads the contents of a file at the specified path&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;args&amp;quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;name&amp;quot;: &amp;quot;path&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;description&amp;quot;: &amp;quot;Absolute or relative path to the file to read&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;backing_type&amp;quot;: &amp;quot;string&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;arity&amp;quot;: &amp;quot;single&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;      &amp;quot;mode&amp;quot;: &amp;quot;dashdashspace&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;empty-result&amp;quot;: { &amp;quot;tag&amp;quot;: &amp;quot;AddMessage&amp;quot;, &amp;quot;contents&amp;quot;: &amp;quot;File is empty or could not be read&amp;quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;exit&lt;/span&gt; 0&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Extract the path argument&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;FILE_PATH&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;while&lt;/span&gt; &lt;span class="kw"&gt;[[&lt;/span&gt; &lt;span class="va"&gt;$#&lt;/span&gt; &lt;span class="ot"&gt;-gt&lt;/span&gt; 0 &lt;span class="kw"&gt;]];&lt;/span&gt; &lt;span class="cf"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="va"&gt;$1&lt;/span&gt; &lt;span class="kw"&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="ss"&gt;--path&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="va"&gt;FILE_PATH&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$2&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="bu"&gt;shift&lt;/span&gt; 2&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="pp"&gt;*&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="bu"&gt;shift&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;esac&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="bu"&gt;[&lt;/span&gt; &lt;span class="ot"&gt;-z&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$FILE_PATH&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="bu"&gt;]&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Error: No path specified&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="bu"&gt;[&lt;/span&gt; &lt;span class="ot"&gt;!&lt;/span&gt; &lt;span class="ot"&gt;-f&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$FILE_PATH&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="bu"&gt;]&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Error: File not found: &lt;/span&gt;&lt;span class="va"&gt;$FILE_PATH&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;cat&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$FILE_PATH&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="tool-discovery"&gt;Tool Discovery&lt;/h3&gt;
&lt;p&gt;Tools are discovered from the &lt;code&gt;tools&lt;/code&gt; directory relative to your &lt;code&gt;agent.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;project/
├── agent.json          # Agent definition
└── tools/              # Tool directory
    ├── read-file.sh    # Executable tool script
    ├── git-helper      # Another tool
    └── ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;agents-exe&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lists all executable files in the tools directory
&lt;/li&gt;
&lt;li&gt;Calls each with &lt;code&gt;describe&lt;/code&gt; to load its interface
&lt;/li&gt;
&lt;li&gt;Makes successfully loaded tools available to the agent
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="using-agents-exe-as-a-tool"&gt;Using &lt;code&gt;agents-exe&lt;/code&gt; as a Tool&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;agents-exe&lt;/code&gt; itself adheres to the same protocol, allowing you to nest agents:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# This allows agents-exe to be used as a tool by another agents-exe instance&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; describe&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; run &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This is useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating hierarchies of agents with different access rights
&lt;/li&gt;
&lt;li&gt;Running agents across container boundaries
&lt;/li&gt;
&lt;li&gt;Delegating to specialized sub-agents
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="best-practices"&gt;Best Practices&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Always validate arguments&lt;/strong&gt; - Check for missing or invalid arguments before processing
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write to stdout&lt;/strong&gt; - The LLM receives stdout; use stderr for errors
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Return non-zero on errors&lt;/strong&gt; - Use appropriate exit codes
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep descriptions concise&lt;/strong&gt; - LLMs work better with clear, brief descriptions
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use appropriate modes&lt;/strong&gt; - Choose argument modes that make sense for your tool’s interface
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handle empty results gracefully&lt;/strong&gt; - Consider using &lt;code&gt;empty-result&lt;/code&gt; to provide helpful messages
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Document context usage&lt;/strong&gt; - If your tool uses environment variables, document it for users
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provide sensible defaults&lt;/strong&gt; - Use bash parameter expansion for optional context variables: &lt;code&gt;${AGENT_SESSION_ID:-unknown}&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="debugging-tools"&gt;Debugging Tools&lt;/h3&gt;
&lt;p&gt;Test your tool independently before using it with &lt;code&gt;agents-exe&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Test the describe command&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;./my-tool&lt;/span&gt; describe &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;jq&lt;/span&gt; .&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Test the run command&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;./my-tool&lt;/span&gt; run &lt;span class="at"&gt;--arg-name&lt;/span&gt; value&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Verify exit codes&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="va"&gt;$?&lt;/span&gt;  &lt;span class="co"&gt;# Should be 0 on success, non-zero on error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Use &lt;code&gt;agents-exe check&lt;/code&gt; to validate all tools in your agent configuration.&lt;/p&gt;
&lt;h3 id="inspecting-tool-schemas"&gt;Inspecting Tool Schemas&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;check&lt;/code&gt; command supports an optional &lt;code&gt;--tools&lt;/code&gt; flag that allows you to inspect how tools are serialized for LLM calls. This is useful for debugging tool definition issues:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Default behavior - just validate and show tool counts&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# List tools with their names and descriptions&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check &lt;span class="at"&gt;--tools&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;list&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Show the internal agents-exe tool representation as JSON (wrapped in markdown details tags)&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check &lt;span class="at"&gt;--tools&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;agents-exe&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Show the OpenAI LLM tool representation as JSON (wrapped in markdown details tags)&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; check &lt;span class="at"&gt;--tools&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;openai&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--tools&lt;/code&gt; option accepts the following modes:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Mode&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;none&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Default. Only show agent names and tool counts.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;list&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Print a markdown list of tool names and descriptions.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents-exe&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output the internal tool representation as JSON within &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; tags.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;openai&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Output the OpenAI LLM tool schema (as sent to the API) within &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; tags.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;This feature is particularly useful when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debugging why a tool isn’t being called by the LLM
&lt;/li&gt;
&lt;li&gt;Verifying that tool schemas are correctly formed
&lt;/li&gt;
&lt;li&gt;Documenting available tools for users
&lt;/li&gt;
&lt;li&gt;Comparing internal vs. LLM-facing representations
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-binary-tool.html" rel="alternate"/><summary type="text">Executable-program tools (also called \"bash tools\") are external programs that `agents-exe` can invoke as part of agent execution. These tools extend agent capabilities by performing side effects like reading files, installing packages, pro</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-sqq-flow.html</id><title type="text">SQQ Agent Flow Documentation</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/sqq-flow.md"&gt;&lt;code&gt;documentation/sqq-flow.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="sqq-agent-flow-documentation"&gt;SQQ Agent Flow Documentation&lt;/h2&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;sqq-agent.sh&lt;/code&gt; is a task queue automation system that manages AI agent execution on Git repositories. It integrates with GitHub issues, uses git worktrees for isolated task execution, and automatically creates pull requests with the results.&lt;/p&gt;
&lt;h3 id="architecture-components"&gt;Architecture Components&lt;/h3&gt;
&lt;h4 id="core-configuration"&gt;Core Configuration&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Variable&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SQQ_BIN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path to the &lt;code&gt;sqq&lt;/code&gt; queue management binary&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;QUEUE_DB&lt;/code&gt;&lt;/td&gt;&lt;td&gt;SQLite database path for task queue storage (&lt;code&gt;tasks/queue.sql&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;TASK_DIR&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Directory for instruction files (&lt;code&gt;tasks/&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SESSIONS_DIR&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Directory for agent session outputs (&lt;code&gt;tasks-sessions/&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;BASE_BRANCH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Base git branch for new worktrees (&lt;code&gt;main&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GITHUB_USERNAME&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GitHub username to filter issues by author (security filter)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;PROJECT_MAP&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Maps labels to relative paths in worktree&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_MAP&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Maps labels to agent configuration files&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="data-flow"&gt;Data Flow&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  GitHub Issues  │────▶│  Task Files     │────▶│  Queue (sqq)    │
│  (with labels)  │     │  (.md files)    │     │  (SQLite)       │
└─────────────────┘     └─────────────────┘     └─────────────────┘
         │                                               │
         │                                               ▼
         │                                      ┌─────────────────┐
         │                                      │  Process Loop   │
         │                                      └─────────────────┘
         │                                               │
         ▼                                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                        WORKTREE EXECUTION                         │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐  │
│  │ Setup        │─▶│ Prepare      │─▶│ Run Agent            │  │
│  │ Worktree     │  │ Environment  │  │ (agents-exe)         │  │
│  └──────────────┘  └──────────────┘  └──────────────────────┘  │
│                                              │                  │
│  ┌──────────────┐  ┌──────────────┐         │                  │
│  │ Create PR    │◀─│ Push Branch  │◀────────┘                  │
│  └──────────────┘  └──────────────┘                            │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="command-flows"&gt;Command Flows&lt;/h3&gt;
&lt;h4 id="1-initialization-init"&gt;1. Initialization (&lt;code&gt;init&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;sqq-agent.sh&lt;/span&gt; init&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Creates &lt;code&gt;TASK_DIR&lt;/code&gt; and &lt;code&gt;SESSIONS_DIR&lt;/code&gt; directories
&lt;/li&gt;
&lt;li&gt;Initializes SQLite queue database via &lt;code&gt;sqq init --queue&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="2-manual-task-addition-add"&gt;2. Manual Task Addition (&lt;code&gt;add&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;sqq-agent.sh&lt;/span&gt; add &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;label&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;branch&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Validates the project label exists in &lt;code&gt;PROJECT_MAP&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Finds or creates a numbered task file (format: &lt;code&gt;NNNN-&amp;lt;branch&amp;gt;.md&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;Opens &lt;code&gt;$EDITOR&lt;/code&gt; for user to write instructions
&lt;/li&gt;
&lt;li&gt;Enqueues job: &lt;code&gt;sqq-agent.sh worktree_exec &amp;quot;&amp;lt;label&amp;gt;&amp;quot; &amp;quot;&amp;lt;branch&amp;gt;&amp;quot; &amp;quot;&amp;lt;taskfile&amp;gt;&amp;quot;&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="3-github-issue-import-from_github"&gt;3. GitHub Issue Import (&lt;code&gt;from_github&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;sqq-agent.sh&lt;/span&gt; from_github&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Queries GitHub for issues labeled &lt;code&gt;agents/to-be-taken&lt;/code&gt; &lt;strong&gt;from the configured author only&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;For each issue:
&lt;ul&gt;
&lt;li&gt;Matches project label from issue labels
&lt;/li&gt;
&lt;li&gt;Creates task file with issue content (title, body, comments)
&lt;/li&gt;
&lt;li&gt;Adds note to mention issue number in commit
&lt;/li&gt;
&lt;li&gt;Enqueues worktree_exec job
&lt;/li&gt;
&lt;li&gt;Updates issue labels: removes &lt;code&gt;agents/to-be-taken&lt;/code&gt;, adds &lt;code&gt;agents/taken&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Security Note:&lt;/strong&gt; The &lt;code&gt;GITHUB_USERNAME&lt;/code&gt; filter ensures that only issues created by the trusted author are processed. This prevents arbitrary code execution from malicious issues filed by third parties on public repositories.&lt;/p&gt;
&lt;h4 id="4-queue-processing-process"&gt;4. Queue Processing (&lt;code&gt;process&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;sqq-agent.sh&lt;/span&gt; process&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Runs &lt;code&gt;sqq process --action Exec&lt;/code&gt; in a loop
&lt;/li&gt;
&lt;li&gt;On failure: waits 60 seconds and retries
&lt;/li&gt;
&lt;li&gt;Continues until queue is empty or manually stopped
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="5-worktree-execution-worktree_exec---core-engine"&gt;5. Worktree Execution (&lt;code&gt;worktree_exec&lt;/code&gt;) - Core Engine&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;sqq-agent.sh&lt;/span&gt; worktree_exec &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;label&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;name&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;instruction_file&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="phase-1-worktree-setup"&gt;Phase 1: Worktree Setup&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Fetch latest &lt;code&gt;origin/BASE_BRANCH&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Remove existing worktree (if any) and prune
&lt;/li&gt;
&lt;li&gt;Create new git worktree at directory &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id="phase-2-navigation"&gt;Phase 2: Navigation&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Change to project directory based on &lt;code&gt;PROJECT_MAP[&amp;lt;label&amp;gt;]&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id="phase-3-environment-preparation"&gt;Phase 3: Environment Preparation&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Execute &lt;code&gt;./git-agent-task.sh prepare&lt;/code&gt; if present
&lt;/li&gt;
&lt;li&gt;This allows per-project dependency installation or setup
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id="phase-4-agent-execution"&gt;Phase 4: Agent Execution&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Check agent configuration with &lt;code&gt;agents-exe --agent-file check&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run agent with instruction file:
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;config&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; run &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--session-file&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;-f&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;instruction_file&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Capture agent output as commit message
&lt;/li&gt;
&lt;li&gt;Export session to markdown: &lt;code&gt;agents-exe session-print&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id="phase-5-commit-and-pr"&gt;Phase 5: Commit and PR&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Create and checkout new branch &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If changes detected:
&lt;ul&gt;
&lt;li&gt;Stage all changes: &lt;code&gt;git add -A&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Commit with agent output as message (no verify)
&lt;/li&gt;
&lt;li&gt;Push to origin
&lt;/li&gt;
&lt;li&gt;Create Pull Request via &lt;code&gt;gh pr create&lt;/code&gt; with label &lt;code&gt;agents/agent-pr&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;For non-GitHub tasks: optionally run &lt;code&gt;./git-agent-task.sh preview&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="6-automatic-merging-merge-pr"&gt;6. Automatic Merging (&lt;code&gt;merge-pr&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;sqq-agent.sh&lt;/span&gt; merge-pr&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Identifies the default branch of the repository.
&lt;/li&gt;
&lt;li&gt;Lists all Pull Requests with the label &lt;code&gt;agents/agent-pr&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;For each PR:
&lt;ul&gt;
&lt;li&gt;If the base branch is &lt;strong&gt;not&lt;/strong&gt; the default branch, it triggers an automatic merge (&lt;code&gt;gh pr merge --auto&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;If the base branch is the default branch, it skips the PR to ensure manual review for main branch changes.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="file-naming-conventions"&gt;File Naming Conventions&lt;/h3&gt;
&lt;h4 id="task-files"&gt;Task Files&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Format: &lt;code&gt;TASK_DIR/NNNN-&amp;lt;branch&amp;gt;.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Sequential numbering starting from 0001
&lt;/li&gt;
&lt;li&gt;Preserves existing files when re-queueing same branch
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="session-files"&gt;Session Files&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;JSON: &lt;code&gt;SESSIONS_DIR/&amp;lt;name&amp;gt;.session.json&lt;/code&gt; (agent state)
&lt;/li&gt;
&lt;li&gt;Markdown: &lt;code&gt;SESSIONS_DIR/&amp;lt;name&amp;gt;.session.md&lt;/code&gt; (human-readable)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="error-handling-and-retries"&gt;Error Handling and Retries&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Queue processing loops indefinitely with 60s delay on failure
&lt;/li&gt;
&lt;li&gt;Failed worktrees are force-removed before retry
&lt;/li&gt;
&lt;li&gt;Agent execution errors don’t prevent commit/push if changes exist
&lt;/li&gt;
&lt;li&gt;Missing &lt;code&gt;git-agent-task.sh&lt;/code&gt; generates warnings but continues
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="integration-points"&gt;Integration Points&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Tool&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sqq&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Task queue management (enqueue/dequeue/process)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;gh&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GitHub CLI for issue/PR management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents-exe&lt;/code&gt;&lt;/td&gt;&lt;td&gt;AI agent execution engine&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;git worktree&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Isolated working directories per task&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="security-considerations"&gt;Security Considerations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;--no-verify&lt;/code&gt; on git commits to bypass hooks in worktrees
&lt;/li&gt;
&lt;li&gt;Force-removes worktrees (potential data loss if in-progress)
&lt;/li&gt;
&lt;li&gt;Executes &lt;code&gt;./git-agent-task.sh&lt;/code&gt; without sandboxing
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Critical:&lt;/strong&gt; &lt;code&gt;GITHUB_USERNAME&lt;/code&gt; environment variable filters GitHub issues by author to prevent processing malicious issues from third parties on public repositories. Default is &lt;code&gt;lucasdicioccio&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-sqq-flow.html" rel="alternate"/><summary type="text">## Overview The `sqq-agent.sh` is a task queue automation system that manages AI agent execution on Git repositories. It integrates with GitHub issues, uses git worktrees for isolated task execution, and automatically creates pull requests</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-ai-assistant-guidelines.html</id><title type="text">AI Assistant Guidelines - Agents Framework</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/ai-assistant-guidelines.md"&gt;&lt;code&gt;documentation/ai-assistant-guidelines.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="ai-assistant-guidelines---agents-framework"&gt;AI Assistant Guidelines - Agents Framework&lt;/h2&gt;
&lt;p&gt;This document provides guidance for AI assistants (including future instances of myself) working on the Agents framework codebase.&lt;/p&gt;
&lt;h3 id="quick-start-for-ai-assistants"&gt;Quick Start for AI Assistants&lt;/h3&gt;
&lt;h4 id="first-steps"&gt;First Steps&lt;/h4&gt;
&lt;p&gt;When invoked on this codebase, always:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Check the knowledge base&lt;/strong&gt; - Query &lt;code&gt;sqlite_knowledge_store_query&lt;/code&gt; for existing state
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review recent commits&lt;/strong&gt; - Use &lt;code&gt;bash_get_git_log&lt;/code&gt; to see what’s changed
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check existing docs&lt;/strong&gt; - Review &lt;code&gt;docs_index&lt;/code&gt; table for current documentation
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identify the task&lt;/strong&gt; - Understand what changes or documentation are needed
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="essential-queries"&gt;Essential Queries&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Get project overview&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="kw"&gt;FROM&lt;/span&gt; project_overview;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- List all documented modules&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;span class="kw"&gt;WHERE&lt;/span&gt; documented_in &lt;span class="kw"&gt;IS&lt;/span&gt; &lt;span class="kw"&gt;NOT&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt;;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find undocumented modules&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; filepath, module_name &lt;span class="kw"&gt;FROM&lt;/span&gt; code_index &lt;span class="kw"&gt;WHERE&lt;/span&gt; documented_in &lt;span class="kw"&gt;IS&lt;/span&gt; &lt;span class="kw"&gt;NULL&lt;/span&gt;;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check existing documentation&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="kw"&gt;FROM&lt;/span&gt; docs_index;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="knowledge-base-structure"&gt;Knowledge Base Structure&lt;/h3&gt;
&lt;h4 id="tables"&gt;Tables&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Table&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;commits_seen&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Git commits already processed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;project_overview&lt;/code&gt;&lt;/td&gt;&lt;td&gt;High-level project information&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;code_index&lt;/code&gt;&lt;/td&gt;&lt;td&gt;All source modules with metadata&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;docs_index&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Documentation files index&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="code-index-schema"&gt;Code Index Schema&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Track which modules are documented where&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    filepath,&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    module_name,&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    purpose,&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    documented_in,&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    last_updated&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; code_index&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; filepath;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="documentation-index-schema"&gt;Documentation Index Schema&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check documentation coverage&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    doc_path,&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    title,&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    description,&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    related_modules&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;FROM&lt;/span&gt; docs_index&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;ORDER&lt;/span&gt; &lt;span class="kw"&gt;BY&lt;/span&gt; doc_path;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="documentation-standards"&gt;Documentation Standards&lt;/h3&gt;
&lt;h4 id="file-organization"&gt;File Organization&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;documentation/
├── README.md                 # Project overview (always up to date)
├── architecture.md           # System architecture
├── tools.md                  # Tool system
├── mcp.md                    # MCP protocol
├── sessions.md               # Session management
├── tui.md                    # Terminal UI
├── cli-commands.md           # CLI reference
├── export-import.md          # Tool sharing
├── file-loader.md            # File loading utilities
└── ai-assistant-guidelines.md # This file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="documentation-format"&gt;Documentation Format&lt;/h4&gt;
&lt;p&gt;All docs should:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;strong&gt;Markdown&lt;/strong&gt; format
&lt;/li&gt;
&lt;li&gt;Include &lt;strong&gt;ASCII diagrams&lt;/strong&gt; for architecture (Graphviz when complex)
&lt;/li&gt;
&lt;li&gt;Provide &lt;strong&gt;Haskell type definitions&lt;/strong&gt; for key types
&lt;/li&gt;
&lt;li&gt;Include &lt;strong&gt;code examples&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Have a &lt;strong&gt;Table of Contents&lt;/strong&gt; for longer docs
&lt;/li&gt;
&lt;li&gt;Reference related modules in &lt;code&gt;System.Agents.*&lt;/code&gt; namespace
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="graphviz-guidelines"&gt;Graphviz Guidelines&lt;/h4&gt;
&lt;p&gt;When creating diagrams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Save dot files to &lt;code&gt;documentation/*.dot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generate PNGs with matching names
&lt;/li&gt;
&lt;li&gt;Keep diagrams focused on one concept
&lt;/li&gt;
&lt;li&gt;Use consistent styling
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// documentation/example.dot&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;digraph&lt;/span&gt; &lt;span class="va"&gt;Architecture&lt;/span&gt; &lt;span class="ot"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;    &lt;/span&gt;&lt;span class="at"&gt;rankdir&lt;/span&gt;&lt;span class="ot"&gt;=&lt;/span&gt;&lt;span class="va"&gt;TB&lt;/span&gt;&lt;span class="ot"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;    &lt;/span&gt;&lt;span class="kw"&gt;node&lt;/span&gt;&lt;span class="co"&gt; &lt;/span&gt;&lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="at"&gt;shape&lt;/span&gt;&lt;span class="ot"&gt;=&lt;/span&gt;&lt;span class="va"&gt;box&lt;/span&gt;&lt;span class="co"&gt;, &lt;/span&gt;&lt;span class="at"&gt;style&lt;/span&gt;&lt;span class="ot"&gt;=&lt;/span&gt;&lt;span class="va"&gt;rounded&lt;/span&gt;&lt;span class="ot"&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;    &lt;/span&gt;&lt;span class="va"&gt;Main&lt;/span&gt;&lt;span class="co"&gt; &lt;/span&gt;&lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="co"&gt; &lt;/span&gt;&lt;span class="va"&gt;AgentTree&lt;/span&gt;&lt;span class="ot"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;    &lt;/span&gt;&lt;span class="va"&gt;AgentTree&lt;/span&gt;&lt;span class="co"&gt; &lt;/span&gt;&lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="co"&gt; &lt;/span&gt;&lt;span class="va"&gt;Runtime&lt;/span&gt;&lt;span class="ot"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;    &lt;/span&gt;&lt;span class="va"&gt;Runtime&lt;/span&gt;&lt;span class="co"&gt; &lt;/span&gt;&lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="co"&gt; &lt;/span&gt;&lt;span class="va"&gt;Session&lt;/span&gt;&lt;span class="ot"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;    &lt;/span&gt;&lt;span class="va"&gt;Runtime&lt;/span&gt;&lt;span class="co"&gt; &lt;/span&gt;&lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="co"&gt; &lt;/span&gt;&lt;span class="va"&gt;Tools&lt;/span&gt;&lt;span class="ot"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="working-with-the-codebase"&gt;Working with the Codebase&lt;/h3&gt;
&lt;h4 id="module-categories"&gt;Module Categories&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Category&lt;/th&gt;&lt;th&gt;Path Pattern&lt;/th&gt;&lt;th&gt;Doc Reference&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Core&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.Base&lt;/code&gt;, &lt;code&gt;System.Agents.Runtime*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;architecture.md&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;CLI&lt;/td&gt;&lt;td&gt;&lt;code&gt;app/Main.hs&lt;/code&gt;, &lt;code&gt;System.Agents.CLI.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;cli-commands.md&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Tools&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;tools.md&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;MCP&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.MCP.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;mcp.md&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Sessions&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;sessions.md&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TUI&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.TUI.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;tui.md&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Export/Import&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.ExportImport.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;export-import.md&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;File Loading&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.FileLoader*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;file-loader.md&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="key-types-to-document"&gt;Key Types to Document&lt;/h4&gt;
&lt;p&gt;When encountering new types, always document:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt; - What problem does this solve?
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fields&lt;/strong&gt; - What does each field represent?
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relationships&lt;/strong&gt; - How does it connect to other types?
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Usage examples&lt;/strong&gt; - How is it used in practice?
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="tracing-conventions"&gt;Tracing Conventions&lt;/h4&gt;
&lt;p&gt;The codebase uses &lt;code&gt;Prod.Tracer&lt;/code&gt; extensively:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- All significant operations should be traced&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;OperationStart&lt;/span&gt; &lt;span class="dt"&gt;Param&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OperationComplete&lt;/span&gt; &lt;span class="dt"&gt;Result&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OperationError&lt;/span&gt; &lt;span class="dt"&gt;Error&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Use contramap for sub-tracers&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;subTracer ::&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ParentTrace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ChildTrace&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;subTracer &lt;span class="ot"&gt;=&lt;/span&gt; contramap &lt;span class="dt"&gt;ParentConstructor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="maintenance-tasks"&gt;Maintenance Tasks&lt;/h3&gt;
&lt;h4 id="keeping-documentation-current"&gt;Keeping Documentation Current&lt;/h4&gt;
&lt;p&gt;When code changes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Identify affected docs&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SELECT&lt;/span&gt; doc_path &lt;span class="kw"&gt;FROM&lt;/span&gt; docs_index &lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; related_modules &lt;span class="kw"&gt;LIKE&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;%ModuleName%&amp;#39;&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Update code_index&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;UPDATE&lt;/span&gt; code_index &lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;SET&lt;/span&gt; documented_in &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;documentation/file.md&amp;#39;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    last_updated &lt;span class="op"&gt;=&lt;/span&gt; datetime(&lt;span class="st"&gt;&amp;#39;now&amp;#39;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;WHERE&lt;/span&gt; module_name &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;System.Agents.Module&amp;#39;&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Review and update&lt;/strong&gt; the relevant doc file&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="adding-new-modules"&gt;Adding New Modules&lt;/h4&gt;
&lt;p&gt;When new modules are added:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add to &lt;code&gt;code_index&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;INSERT&lt;/span&gt; &lt;span class="kw"&gt;INTO&lt;/span&gt; code_index (filepath, module_name, purpose, last_updated)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;VALUES&lt;/span&gt; (&lt;span class="st"&gt;&amp;#39;src/System/Agents/NewModule.hs&amp;#39;&lt;/span&gt;, &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;#39;System.Agents.NewModule&amp;#39;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;#39;Description of purpose&amp;#39;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        datetime(&lt;span class="st"&gt;&amp;#39;now&amp;#39;&lt;/span&gt;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Determine if new documentation needed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update existing docs with cross-references&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="handling-commits"&gt;Handling Commits&lt;/h4&gt;
&lt;p&gt;Track commits in &lt;code&gt;commits_seen&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- After processing a commit&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;INSERT&lt;/span&gt; &lt;span class="kw"&gt;INTO&lt;/span&gt; commits_seen (commit_hash, commit_date, commit_message)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;VALUES&lt;/span&gt; (&lt;span class="st"&gt;&amp;#39;abc123...&amp;#39;&lt;/span&gt;, &lt;span class="st"&gt;&amp;#39;2024-01-15&amp;#39;&lt;/span&gt;, &lt;span class="st"&gt;&amp;#39;message&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="common-patterns"&gt;Common Patterns&lt;/h3&gt;
&lt;h4 id="agent-configuration"&gt;Agent Configuration&lt;/h4&gt;
&lt;p&gt;Agents are configured via JSON:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;agent-name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;key-ref&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Instructions&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;mcpServers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="er"&gt;...&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="er"&gt;...&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tool-definition"&gt;Tool Definition&lt;/h4&gt;
&lt;p&gt;Tools follow this pattern:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; toolName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolDescription ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolParameters ::&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;  &lt;span class="co"&gt;-- JSON Schema&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolExecutor ::&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ToolResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="session-flow"&gt;Session Flow&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;User Input -&amp;gt; Session -&amp;gt; LLM Call -&amp;gt; Tool Execution -&amp;gt; Response -&amp;gt; Persist Session
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="documentation-gaps-to-watch-for"&gt;Documentation Gaps to Watch For&lt;/h3&gt;
&lt;p&gt;Watch for these common omissions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;New CLI commands&lt;/strong&gt; - Update &lt;code&gt;cli-commands.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New tool types&lt;/strong&gt; - Update &lt;code&gt;tools.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API changes&lt;/strong&gt; - Document breaking changes
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration options&lt;/strong&gt; - Keep examples current
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error types&lt;/strong&gt; - Document error conditions
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="questions-to-ask"&gt;Questions to Ask&lt;/h3&gt;
&lt;p&gt;When documentation is unclear:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What is the purpose of this module/component?
&lt;/li&gt;
&lt;li&gt;How does it relate to other parts of the system?
&lt;/li&gt;
&lt;li&gt;What are the key data types?
&lt;/li&gt;
&lt;li&gt;What is the typical usage flow?
&lt;/li&gt;
&lt;li&gt;Are there any gotchas or edge cases?
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="iterative-documentation-workflow"&gt;Iterative Documentation Workflow&lt;/h3&gt;
&lt;p&gt;For large documentation tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Plan&lt;/strong&gt; - List all modules/files to document
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chunk&lt;/strong&gt; - Work on one subsystem at a time
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query&lt;/strong&gt; - Check knowledge base for existing state
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write&lt;/strong&gt; - Create/update markdown files
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Index&lt;/strong&gt; - Update &lt;code&gt;docs_index&lt;/code&gt; and &lt;code&gt;code_index&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review&lt;/strong&gt; - Check for consistency and completeness
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Commit&lt;/strong&gt; - First line of response should be summary
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="summary-line-format"&gt;Summary Line Format&lt;/h3&gt;
&lt;p&gt;The first line of every response should be a concise summary:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Brief description of what was done or discovered
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Updated tool system documentation with OpenAPI toolbox details”
&lt;/li&gt;
&lt;li&gt;“Discovered undocumented MCP server configuration types”
&lt;/li&gt;
&lt;li&gt;“Created architecture diagram for agent tree system”
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="self-correction-checklist"&gt;Self-Correction Checklist&lt;/h3&gt;
&lt;p&gt;Before completing work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ ] Knowledge base tables are consistent
&lt;/li&gt;
&lt;li&gt;[ ] All new modules indexed in &lt;code&gt;code_index&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Documentation links are valid
&lt;/li&gt;
&lt;li&gt;[ ] Code examples compile (if applicable)
&lt;/li&gt;
&lt;li&gt;[ ] ASCII diagrams render correctly
&lt;/li&gt;
&lt;li&gt;[ ] Summary line is present
&lt;/li&gt;
&lt;li&gt;[ ] Related modules cross-referenced
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="emergency-recovery"&gt;Emergency Recovery&lt;/h3&gt;
&lt;p&gt;If knowledge base is corrupted:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Rebuild &lt;code&gt;code_index&lt;/code&gt; by scanning all &lt;code&gt;.hs&lt;/code&gt; files
&lt;/li&gt;
&lt;li&gt;Rebuild &lt;code&gt;docs_index&lt;/code&gt; by listing &lt;code&gt;documentation/*.md&lt;/code&gt; files
&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;project_overview&lt;/code&gt; with basic project info
&lt;/li&gt;
&lt;li&gt;Re-link modules to documentation manually
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="useful-one-liners"&gt;Useful One-Liners&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Count modules by subsystem&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;ghc&lt;/span&gt; &lt;span class="at"&gt;-i&lt;/span&gt; src &lt;span class="at"&gt;-e&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;:browse System.Agents.Tools&amp;quot;&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;/dev/null &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;wc&lt;/span&gt; &lt;span class="at"&gt;-l&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Find undocumented exports&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;find&lt;/span&gt; src &lt;span class="at"&gt;-name&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;*.hs&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;-exec&lt;/span&gt; grep &lt;span class="at"&gt;-l&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;^module &amp;quot;&lt;/span&gt; {} &lt;span class="dt"&gt;\;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="cf"&gt;while&lt;/span&gt; &lt;span class="bu"&gt;read&lt;/span&gt; &lt;span class="va"&gt;f&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="va"&gt;mod&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="fu"&gt;grep&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;^module &amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$f&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;head&lt;/span&gt; &lt;span class="at"&gt;-1&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;awk&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;# Check if in code_index...&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# List all types in a module&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;ghc&lt;/span&gt; &lt;span class="at"&gt;-i&lt;/span&gt; src &lt;span class="at"&gt;-e&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;:browse System.Agents.Base&amp;quot;&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;/dev/null &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;grep&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;data &amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="contact-points"&gt;Contact Points&lt;/h3&gt;
&lt;p&gt;Key files for understanding the system:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;File&lt;/th&gt;&lt;th&gt;Why It's Important&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;app/Main.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Entry point, CLI commands&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/Base.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Core types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/AgentTree.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Multi-agent orchestration&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;src/System/Agents/Runtime/Runtime.hs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Execution engine&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents.cabal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Dependencies and build config&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;p&gt;Remember: This documentation is for AI assistants. Keep it practical, specific to this codebase, and actionable.&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-ai-assistant-guidelines.html" rel="alternate"/><summary type="text">This document provides guidance for AI assistants (including future instances of myself) working on the Agents framework codebase. ## Quick Start for AI Assistants ### First Steps When invoked on this codebase, always: 1. **Check the knowle</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-async-tool-calls.html</id><title type="text">Asynchronous Tool Calls</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/async-tool-calls.md"&gt;&lt;code&gt;documentation/async-tool-calls.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="asynchronous-tool-calls"&gt;Asynchronous Tool Calls&lt;/h2&gt;
&lt;p&gt;&lt;img src="/agents-exe/gen/images/async-tool-call.dot.png" alt="One tool call in asynchronous mode: a placeholder while it runs, a notice when it finishes." /&gt;&lt;/p&gt;
&lt;p&gt;By default an agent runs every tool call of a turn one after another and only
answers the LLM once all of them are done. In asynchronous mode, calls run
concurrently in the background, the LLM can be handed a partial answer while
they run, and it can ask about, wait for, or cancel them.&lt;/p&gt;
&lt;p&gt;This is useful when a turn issues several slow calls (builds, test runs, HTTP
requests), and when you want the model (or the user) to keep working while a
long call finishes.&lt;/p&gt;
&lt;p&gt;For deferred calls completed by an &lt;em&gt;external&lt;/em&gt; worker (rather than in this
process), see &lt;a href="/agents-exe/docs-durable-workflows-howto.html"&gt;durable-workflows-howto.md&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="enabling-it"&gt;Enabling it&lt;/h3&gt;
&lt;p&gt;Async execution is configured per agent in the agent JSON:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;executionMode&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;asynchronous&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;asyncYieldStrategy&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;yieldOnAnyProgress&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;maxConcurrency&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;asyncCallTimeoutSeconds&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;900&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;toolCallPolicyConfig&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runSync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;build_project&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;disposition&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runAsync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;run_tests&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;disposition&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runAsync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;executionMode&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;synchronous&lt;/code&gt; or &lt;code&gt;asynchronous&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;synchronous&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;toolCallPolicyConfig&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Which tools run in the background (&lt;code&gt;runAsync&lt;/code&gt;), inline (&lt;code&gt;runSync&lt;/code&gt;), isolated (&lt;code&gt;runIsolated&lt;/code&gt;), or deferred to an external worker (&lt;code&gt;defer&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;everything &lt;code&gt;runSync&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;asyncYieldStrategy&lt;/code&gt;&lt;/td&gt;&lt;td&gt;When a step hands control back to the LLM while calls run&lt;/td&gt;&lt;td&gt;&lt;code&gt;yieldWhenAllDone&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;maxConcurrency&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Calls running at once for this agent&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;asyncCallTimeoutSeconds&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Give up on a call that runs this long&lt;/td&gt;&lt;td&gt;no limit&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Yield strategies:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Behaviour&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yieldWhenAllDone&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Wait for every call of the turn (like synchronous mode, but concurrent)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yieldOnAnyProgress&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Answer the LLM as soon as one call finishes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{"tag": "yieldOnTimeout", "milliseconds": 500}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Answer after the given delay, finished or not&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Both &lt;code&gt;executionMode&lt;/code&gt; and &lt;code&gt;toolCallPolicyConfig&lt;/code&gt; are needed: the mode enables
the machinery, the policy decides which calls actually go to the background.&lt;/p&gt;
&lt;p&gt;The settings apply everywhere an agent runs: &lt;code&gt;run&lt;/code&gt; (one-shot), the TUI, the
&lt;code&gt;session&lt;/code&gt; commands, and agents called as tools by other agents.&lt;/p&gt;
&lt;h3 id="what-the-llm-sees"&gt;What the LLM sees&lt;/h3&gt;
&lt;p&gt;A call that has not finished when the LLM is asked for its next completion
gets a placeholder tool message instead of a result:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;running&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;This tool call has not finished yet. Its result will be delivered in a later message. Use get-tool-call-status with this tool_call_id to inspect it, or cancel-tool-call to stop it.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;call_abc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Every tool call always gets exactly one tool message, as OpenAI-compatible
APIs require.&lt;/p&gt;
&lt;p&gt;When the call finishes, its result is delivered in the next user message,
once, as a notice:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Background tool calls finished since their placeholder responses:

tool_call_id call_abc (run_tests) completed:
42 tests passed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the LLM ends its turn while calls are still running, the session does not
stop: it waits for the results and sends them.&lt;/p&gt;
&lt;h3 id="tool-call-capabilities"&gt;Tool-call capabilities&lt;/h3&gt;
&lt;p&gt;Enable these in the System Toolbox so the model can manage its own background
calls:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;builtinToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SystemToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;   &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;system&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;System context and background tool calls&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;get-tool-call-status&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;list-running-tool-calls&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;cancel-tool-call&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;   &lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Capability&lt;/th&gt;&lt;th&gt;Use&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;list-running-tool-calls&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The calls still running in this session&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Status, progress and (once final) result of a call; can block until it finishes with &lt;code&gt;wait_for_completion&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;cancel-tool-call&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Interrupt a running call&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Calls are addressed by the &lt;code&gt;tool_call_id&lt;/code&gt; the model itself used (e.g.
&lt;code&gt;call_abc&lt;/code&gt;); the internal UUID also works.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt; reports &lt;code&gt;orphaned&lt;/code&gt; for a call that was running when its
process went away (e.g. the session was saved and reloaded elsewhere). Such a
call can never finish, so the stepper resolves it as failed rather than
waiting for it.&lt;/p&gt;
&lt;h3 id="progress"&gt;Progress&lt;/h3&gt;
&lt;p&gt;Tools that run in the background can report progress, which the model reads
through &lt;code&gt;get-tool-call-status&lt;/code&gt; and the TUI shows next to the running call.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bash tools&lt;/strong&gt; report their latest output line, at most twice a second:
&lt;code&gt;{&amp;quot;stream&amp;quot;: &amp;quot;stdout&amp;quot;, &amp;quot;line&amp;quot;: &amp;quot;compiling module 12/40&amp;quot;, &amp;quot;lines&amp;quot;: 12, &amp;quot;bytes&amp;quot;: 480}&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agents called as tools&lt;/strong&gt; report each step of the sub-agent:
&lt;code&gt;{&amp;quot;message&amp;quot;: &amp;quot;sub-agent calling read_file&amp;quot;, &amp;quot;turns&amp;quot;: 7}&lt;/code&gt;. This applies to a
&lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; call that still runs in-tool (narrowed with
&lt;code&gt;bindings&lt;/code&gt;/&lt;code&gt;with&lt;/code&gt;/&lt;code&gt;as&lt;/code&gt;, or outside the runner). Under the runner, a
sub-agent call with no narrowing runs as its own session instead
(&lt;code&gt;todos/os-as-standalone-server.md&lt;/code&gt;, Phase 5): its progress is that
session’s own &lt;code&gt;session.updated&lt;/code&gt;/&lt;code&gt;text.delta&lt;/code&gt;/&lt;code&gt;tool.*&lt;/code&gt; events, not this
per-step callback.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your own tools&lt;/strong&gt; can report anything JSON through &lt;code&gt;ctxProgressCallback&lt;/code&gt; in
the &lt;code&gt;ToolExecutionContext&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MCP and OpenAPI tools do not report progress yet. An OpenAPI call waits for
one complete HTTP response, so there is nothing to stream. MCP &lt;em&gt;does&lt;/em&gt; define
progress notifications (&lt;code&gt;ProgressNotification&lt;/code&gt; in &lt;code&gt;System.Agents.MCP.Base&lt;/code&gt;),
but the client currently ignores them; forwarding them to
&lt;code&gt;ctxProgressCallback&lt;/code&gt; would make MCP tools report progress like bash tools.&lt;/p&gt;
&lt;p&gt;The 50 most recent progress entries per call are kept.&lt;/p&gt;
&lt;h3 id="cancelling"&gt;Cancelling&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;cancel-tool-call&lt;/code&gt; interrupts the call’s thread. A bash tool runs its script
in its own process group, so cancelling kills the script &lt;em&gt;and&lt;/em&gt; whatever it
started. The same happens when a call exceeds &lt;code&gt;asyncCallTimeoutSeconds&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Background calls are cancelled when the agent that owns them finishes or
fails, so nothing keeps running (or keeps a subprocess alive) after a run.&lt;/p&gt;
&lt;h3 id="in-the-tui"&gt;In the TUI&lt;/h3&gt;
&lt;p&gt;Running calls appear under the turn that issued them, with their latest
progress:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Partial] &amp;gt; run the tests and the linter
  ✓ lint (call_1): completed
  ⏳ run_tests (call_2): running: 128 tests passed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A line above the conversation lists what is still running. While background
calls run and the LLM has nothing to do, the TUI accepts input, so you can
keep talking; whichever comes first — your message or the results — is sent
to the model.&lt;/p&gt;
&lt;h3 id="in-one-shot-runs"&gt;In one-shot runs&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;agents-exe run&lt;/code&gt; waits for background calls: they cannot outlive the process.&lt;/p&gt;
&lt;p&gt;It stops early only when a turn waits on &lt;em&gt;deferred&lt;/em&gt; calls, which an external
worker has to complete. It then prints a JSON report and stores the session so
it can be continued:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;paused&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;waiting for deferred tool calls&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;session_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;deferred_calls&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;approve_deploy&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;call_9&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;continuation_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Continue it with &lt;code&gt;agents-exe session complete&lt;/code&gt; and &lt;code&gt;agents-exe session resume&lt;/code&gt;
(see &lt;a href="/agents-exe/docs-durable-workflows-howto.html"&gt;durable-workflows-howto.md&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id="session-files"&gt;Session files&lt;/h3&gt;
&lt;p&gt;Partial turns are stored in the session, with each call’s state. &lt;code&gt;session-print&lt;/code&gt;
shows them:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## ⏸️ Step 4: Partial Turn (in progress)
_(Some tool calls had not finished when this turn was sent)_

### ⏳ Tool Call Status

- `lint` (`call_1`): completed
- `run_tests` (`call_2`): running (placeholder sent)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="limits"&gt;Limits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Background calls live in the process that started them. A session reloaded
elsewhere reports them as orphaned.
&lt;/li&gt;
&lt;li&gt;A pause/resume in the same process keeps the running calls only if the agent
was built with &lt;code&gt;withAsyncEngine&lt;/code&gt;; &lt;code&gt;runAsync&lt;/code&gt; does not hand the engine back.
&lt;/li&gt;
&lt;li&gt;If the model reads a result with &lt;code&gt;get-tool-call-status&lt;/code&gt;, the delivery notice
repeats it once.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxConcurrency&lt;/code&gt; is per agent. To cap several agents together, share one
limit built with &lt;code&gt;newAsyncConcurrencyLimit&lt;/code&gt; between their engines.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-async-tool-calls.html" rel="alternate"/><summary type="text">By default an agent runs every tool call of a turn one after another and only answers the LLM once all of them are done. In asynchronous mode, calls run concurrently in the background, the LLM can be handed a partial answer while they run,</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-durable-workflows.html</id><title type="text">Plan: Durable Workflows for agents-exe</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/durable-workflows.md"&gt;&lt;code&gt;todos/durable-workflows.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="plan-durable-workflows-for-agents-exe"&gt;Plan: Durable Workflows for agents-exe&lt;/h2&gt;
&lt;p&gt;See &lt;a href="/agents-exe/specs-durable-workflows.progress.html"&gt;&lt;code&gt;todos/durable-workflows.progress.md&lt;/code&gt;&lt;/a&gt; for implementation progress.&lt;/p&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;
&lt;h3 id="goal-1"&gt;Goal&lt;/h3&gt;
&lt;p&gt;Turn agents-exe into a system suitable for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Durable executions&lt;/strong&gt;: sessions can be stored in and resumed from databases.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolated deployments&lt;/strong&gt;: tool calls can run inside Docker or as local processes, transparently.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transparent synchronous/asynchronous tool calls&lt;/strong&gt;: the runtime can pause a turn after any subset of tool calls, yield to the outside world, and wake up later when results arrive.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Requested example flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;user-turn 1: some question
&lt;/li&gt;
&lt;li&gt;agent-turn 1: reply with 3 tool calls
&lt;/li&gt;
&lt;li&gt;user-turn: perform 1 tool call, mark 2 as deferred
&lt;/li&gt;
&lt;li&gt;system: yields (possibly even reboots)
&lt;/li&gt;
&lt;li&gt;system: wakes up, executes deferred tool calls and places results, then wakes up again
&lt;/li&gt;
&lt;li&gt;user-turn: provides 3 tool results to agent
&lt;/li&gt;
&lt;li&gt;agent: continues
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This document lists the primitives and architectural changes needed to support that flow.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="current-state"&gt;Current state&lt;/h3&gt;
&lt;p&gt;The codebase already has scaffolding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ExecutionMode&lt;/code&gt; (&lt;code&gt;Synchronous&lt;/code&gt; / &lt;code&gt;Asynchronous&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PartialUserTurn&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ContinuationToken&lt;/code&gt;, &lt;code&gt;AsyncToolResponse&lt;/code&gt; (&lt;code&gt;ToolComplete&lt;/code&gt; / &lt;code&gt;ToolYield&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ContinuationStore&lt;/code&gt; / &lt;code&gt;ToolContinuation&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolCache&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;OS persistence layer with SQLite/Postgres backends
&lt;/li&gt;
&lt;li&gt;File-based &lt;code&gt;SessionStore&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What is missing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The async scheduler does not actually use &lt;code&gt;ctxAsyncToolCall&lt;/code&gt; or &lt;code&gt;AsyncToolResponse&lt;/code&gt;; it just runs tools synchronously and pauses after each one.
&lt;/li&gt;
&lt;li&gt;There is no per-call decision primitive for sync vs. deferred vs. isolated execution.
&lt;/li&gt;
&lt;li&gt;There is no “wake up and inject external results” primitive.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ContinuationStore&lt;/code&gt; has stubbed load/list implementations.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolExecutionContext&lt;/code&gt; contains non-serializable fields (portal, world, event queue), making durable continuations fragile.
&lt;/li&gt;
&lt;li&gt;Session storage is file-only.
&lt;/li&gt;
&lt;li&gt;There is no abstraction for running a tool call outside the current process (Docker / subprocess).
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="phase-1--core-primitives-types--interfaces"&gt;Phase 1 — Core primitives (types &amp;amp; interfaces)&lt;/h3&gt;
&lt;h4 id="11-rich-tool-call-state-inside-a-turn"&gt;1.1 Rich tool-call state inside a turn&lt;/h4&gt;
&lt;p&gt;Introduce an explicit state machine for every LLM-issued tool call within a user turn:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-text"&gt;Ready      -&amp;gt; Running | Deferred | Completed
Running    -&amp;gt; Completed | Failed
Deferred   -&amp;gt; Ready | Completed   (via external wake)
Completed  -&amp;gt; terminal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add a &lt;code&gt;TrackedToolCall&lt;/code&gt; type wrapping &lt;code&gt;LlmToolCall&lt;/code&gt; with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tcId :: ToolCallId&lt;/code&gt; — stable ID for matching external results
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tcState :: ToolCallState&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tcResult :: Maybe UserToolResponse&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tcContinuation :: Maybe ContinuationToken&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tcPolicy :: AppliedPolicy&lt;/code&gt; — record of why it ran this way
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Refactor &lt;code&gt;PartialUserTurnContent&lt;/code&gt; to hold &lt;code&gt;[TrackedToolCall]&lt;/code&gt; instead of separate &lt;code&gt;pCompletedResponses&lt;/code&gt;, &lt;code&gt;pPendingCalls&lt;/code&gt;, and &lt;code&gt;pPendingContinuations&lt;/code&gt; lists.&lt;/p&gt;
&lt;h4 id="12-tool-call-policy--decorator"&gt;1.2 Tool-call policy / decorator&lt;/h4&gt;
&lt;p&gt;Add a pure decision primitive:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolCallDisposition&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunSync&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;RunAsync&lt;/span&gt;                  &lt;span class="co"&gt;-- yield a continuation token&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;RunIsolated&lt;/span&gt; &lt;span class="dt"&gt;IsolationSpec&lt;/span&gt; &lt;span class="co"&gt;-- run outside the current process&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Defer&lt;/span&gt; &lt;span class="dt"&gt;Reason&lt;/span&gt;              &lt;span class="co"&gt;-- intentionally pause (e.g., approval)&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Decorate&lt;/span&gt; [&lt;span class="dt"&gt;Decorator&lt;/span&gt;] &lt;span class="dt"&gt;ToolCallDisposition&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicy&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LlmToolCall&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolCallDisposition&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This is the requested decoration primitive. It lets the runtime decide, per call, whether to execute immediately, defer, or run in isolation.&lt;/p&gt;
&lt;p&gt;Provide &lt;code&gt;defaultToolCallPolicy = const $ const RunSync&lt;/code&gt; for backward compatibility.&lt;/p&gt;
&lt;h4 id="13-pluggable-executor-interface"&gt;1.3 Pluggable executor interface&lt;/h4&gt;
&lt;p&gt;Decouple &lt;em&gt;how&lt;/em&gt; a tool call runs from the session loop:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutor&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutor&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  {&lt;span class="ot"&gt; execSync  ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LlmToolCall&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  ,&lt;span class="ot"&gt; execAsync ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LlmToolCall&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;AsyncToolResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Concrete executors to provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;inProcessExecutor&lt;/code&gt; — current behavior
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yieldingExecutor&lt;/code&gt; — always returns &lt;code&gt;ToolYield&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cachingExecutor :: ToolCache -&amp;gt; ToolExecutor -&amp;gt; ToolExecutor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isolatedExecutor :: DeploymentRunner -&amp;gt; ToolExecutor&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Replace the single &lt;code&gt;Agent.ctxAsyncToolCall&lt;/code&gt; with an optional &lt;code&gt;ToolExecutor&lt;/code&gt; selected by the policy.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="phase-2--async-scheduler-in-the-session-loop"&gt;Phase 2 — Async scheduler in the session loop&lt;/h3&gt;
&lt;h4 id="21-replace-the-one-at-a-time-async-loop"&gt;2.1 Replace the one-at-a-time async loop&lt;/h4&gt;
&lt;p&gt;Current &lt;code&gt;runStepMAsync&lt;/code&gt; executes exactly one pending call per step and then pauses.&lt;/p&gt;
&lt;p&gt;New scheduler behavior, given a set of &lt;code&gt;TrackedToolCall&lt;/code&gt;s:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Classify each call via &lt;code&gt;ToolCallPolicy&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Run all &lt;code&gt;RunSync&lt;/code&gt; calls and collect results.
&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;RunAsync&lt;/code&gt; / &lt;code&gt;Defer&lt;/code&gt; calls, generate continuation tokens and move them to &lt;code&gt;Deferred&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Yield a &lt;code&gt;PartialUserTurn&lt;/code&gt; containing:
&lt;ul&gt;
&lt;li&gt;completed calls,
&lt;/li&gt;
&lt;li&gt;deferred calls with tokens,
&lt;/li&gt;
&lt;li&gt;any remaining ready calls.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This matches the requested flow:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;perform 1 tool call, mark 2 as deferred → system yields → wakes up, executes deferred calls, places results → user-turn provides 3 tool results.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="22-continuation-snapshot"&gt;2.2 Continuation snapshot&lt;/h4&gt;
&lt;p&gt;When a call is deferred, generate a &lt;code&gt;ContinuationToken&lt;/code&gt; and store a serializable &lt;code&gt;ToolContinuationSnapshot&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;token&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sessionId&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toolCallId&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;llmToolCall&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cacheKey&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;policy&lt;/code&gt; / &lt;code&gt;isolationSpec&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;serializable context fields: &lt;code&gt;ctxSessionId&lt;/code&gt;, &lt;code&gt;ctxConversationId&lt;/code&gt;, &lt;code&gt;ctxTurnId&lt;/code&gt;, &lt;code&gt;ctxCallStack&lt;/code&gt;, &lt;code&gt;ctxAllowedTools&lt;/code&gt;, &lt;code&gt;ctxParentConversation&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do &lt;strong&gt;not&lt;/strong&gt; store the non-serializable fields (&lt;code&gt;ctxToolPortal&lt;/code&gt;, &lt;code&gt;ctxWorld&lt;/code&gt;, &lt;code&gt;ctxEventQueue&lt;/code&gt;). Re-hydrate those on wake.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="phase-3--durable-session-storage"&gt;Phase 3 — Durable session storage&lt;/h3&gt;
&lt;h4 id="31-generalize-sessionstore"&gt;3.1 Generalize &lt;code&gt;SessionStore&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The current &lt;code&gt;SessionStore&lt;/code&gt; is file-only. Introduce a backend interface:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SessionBackend&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionBackend&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  {&lt;span class="ot"&gt; sbStore  ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  ,&lt;span class="ot"&gt; sbLoad   ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  ,&lt;span class="ot"&gt; sbList   ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [(&lt;span class="dt"&gt;SessionId&lt;/span&gt;, &lt;span class="dt"&gt;UTCTime&lt;/span&gt;)]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  ,&lt;span class="ot"&gt; sbDelete ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Backends:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FileSessionStore FilePath&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SqliteSessionStore Connection&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CompositeSessionStore [SessionBackend]&lt;/code&gt; for read fallback with a single write target
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="32-use-os-persistence-optional"&gt;3.2 Use OS persistence (optional)&lt;/h4&gt;
&lt;p&gt;The OS layer already has &lt;code&gt;SqliteBackend&lt;/code&gt;, component tables, and migrations. Consider adding a &lt;code&gt;SessionComponent&lt;/code&gt; persisted via &lt;code&gt;persistComponent&lt;/code&gt;/&lt;code&gt;loadComponent&lt;/code&gt;. This reuses ECS migrations and unifies backends.&lt;/p&gt;
&lt;p&gt;If session storage stays separate, at least align IDs: &lt;code&gt;SessionId&lt;/code&gt;/&lt;code&gt;TurnId&lt;/code&gt;/&lt;code&gt;ConversationId&lt;/code&gt; are UUID-based, and OS &lt;code&gt;EntityId&lt;/code&gt; is also UUID-based, so conversion is trivial.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="phase-4--wake--resume-api"&gt;Phase 4 — Wake / resume API&lt;/h3&gt;
&lt;h4 id="41-inject-external-results"&gt;4.1 Inject external results&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;wakeSession ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [(&lt;span class="dt"&gt;ContinuationToken&lt;/span&gt;, &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;)]&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Behavior:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find the &lt;code&gt;PartialUserTurn&lt;/code&gt; and matching deferred &lt;code&gt;TrackedToolCall&lt;/code&gt;s.
&lt;/li&gt;
&lt;li&gt;Move them to &lt;code&gt;Completed&lt;/code&gt; with the provided result.
&lt;/li&gt;
&lt;li&gt;Update the cache if configured.
&lt;/li&gt;
&lt;li&gt;If all calls are complete, convert the &lt;code&gt;PartialUserTurn&lt;/code&gt; to a full &lt;code&gt;UserTurn&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Otherwise leave remaining deferred/ready calls in place.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="42-resume-execution"&gt;4.2 Resume execution&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;resumeSession ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; r &lt;span class="dt"&gt;Session&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;If the latest turn is &lt;code&gt;PartialUserTurn&lt;/code&gt;, run the scheduler on remaining ready/deferred calls.
&lt;/li&gt;
&lt;li&gt;If the latest turn is &lt;code&gt;UserTurn&lt;/code&gt;, continue to the LLM step.
&lt;/li&gt;
&lt;li&gt;Returns &lt;code&gt;Left r&lt;/code&gt; on completion, &lt;code&gt;Right Session&lt;/code&gt; when it needs to yield again.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="43-complete-continuations-from-external-workers"&gt;4.3 Complete continuations from external workers&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;completeContinuation ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="dt"&gt;ContinuationStore&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolCache&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ContinuationToken&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This already exists as &lt;code&gt;resumeAsyncToolCall&lt;/code&gt; but the &lt;code&gt;ContinuationStore&lt;/code&gt; implementation is stubbed. Finish the load/list implementations and ensure proper JSON round-tripping.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="phase-5--isolated-deployment-primitives"&gt;Phase 5 — Isolated deployment primitives&lt;/h3&gt;
&lt;h4 id="51-deploymentrunner-abstraction"&gt;5.1 &lt;code&gt;DeploymentRunner&lt;/code&gt; abstraction&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;DeploymentRunner&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;DeploymentRunner&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  {&lt;span class="ot"&gt; drName    ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  ,&lt;span class="ot"&gt; drExecute ::&lt;/span&gt; &lt;span class="dt"&gt;IsolationSpec&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LlmToolCall&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;IsolationError&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Implementations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;localProcessRunner&lt;/code&gt; — fork a worker process
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dockerRunner&lt;/code&gt; — run inside a container
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;functionRunner&lt;/code&gt; — for serverless/FaaS (future)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="52-serialization-contract-for-isolated-calls"&gt;5.2 Serialization contract for isolated calls&lt;/h4&gt;
&lt;p&gt;Define a stable JSON envelope consumed by any external runner:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;toolCall&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="er"&gt;...&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contextSnapshot&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="er"&gt;...&lt;/span&gt; &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;policy&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;RunIsolated&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;spec&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;image&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;sandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Result envelope:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;success&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="er"&gt;...&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This makes Docker vs. local execution transparent to the agent.&lt;/p&gt;
&lt;h4 id="53-tool-call-decorator-for-isolation"&gt;5.3 Tool-call decorator for isolation&lt;/h4&gt;
&lt;p&gt;Example policy:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;isolateBash ::&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicy&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;isolateBash ctx call&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; toolName call &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_command&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunIsolated&lt;/span&gt; (&lt;span class="dt"&gt;Docker&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;agents-exe/bash-runner:latest&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt;                       &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunSync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="phase-6--integration--agent-combinators"&gt;Phase 6 — Integration &amp;amp; agent combinators&lt;/h3&gt;
&lt;h4 id="61-extend-agent-record"&gt;6.1 Extend &lt;code&gt;Agent&lt;/code&gt; record&lt;/h4&gt;
&lt;p&gt;Add to &lt;code&gt;Agent r&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ctxToolCallPolicy :: ToolCallPolicy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctxSessionBackend :: Maybe SessionBackend&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctxContinuationStore :: Maybe ContinuationStore&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctxDeploymentRunner :: Maybe DeploymentRunner&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keep defaults so existing agents compile unchanged.&lt;/p&gt;
&lt;h4 id="62-new-combinators"&gt;6.2 New combinators&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withToolCallPolicy    ::&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicy&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withSessionBackend    ::&lt;/span&gt; &lt;span class="dt"&gt;SessionBackend&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withContinuationStore ::&lt;/span&gt; &lt;span class="dt"&gt;ContinuationStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withDeploymentRunner  ::&lt;/span&gt; &lt;span class="dt"&gt;DeploymentRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; r&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="63-update-agentstoresession"&gt;6.3 Update &lt;code&gt;agentStoreSession&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;System.Agents.Combinators.StoreSessionProgress&lt;/code&gt; should store via the configured &lt;code&gt;SessionBackend&lt;/code&gt; rather than only files, while still supporting file fallback.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="phase-7--cli--operator-api"&gt;Phase 7 — CLI / operator API&lt;/h3&gt;
&lt;p&gt;New commands for real operation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agents session pause &amp;lt;session-id&amp;gt;&lt;/code&gt; — yield after current step
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents session resume &amp;lt;session-id&amp;gt;&lt;/code&gt; — continue execution
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents session pending &amp;lt;session-id&amp;gt;&lt;/code&gt; — list deferred calls / continuation tokens
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents session complete &amp;lt;token&amp;gt; &amp;lt;result-file&amp;gt;&lt;/code&gt; — inject an external result
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents session run-isolated &amp;lt;session-id&amp;gt;&lt;/code&gt; — poll and execute &lt;code&gt;RunIsolated&lt;/code&gt; calls
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="phase-8--testing-strategy"&gt;Phase 8 — Testing strategy&lt;/h3&gt;
&lt;p&gt;Add tests for:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Policy classification: a policy can mark some calls sync and some deferred.
&lt;/li&gt;
&lt;li&gt;Partial turn serialization: a session with deferred calls round-trips through SQLite/file backends.
&lt;/li&gt;
&lt;li&gt;Wake/resume: &lt;code&gt;wakeSession&lt;/code&gt; injects results and eventually produces a full &lt;code&gt;UserTurn&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Cache integration: deferred calls whose result is later cached are resolved on resume.
&lt;/li&gt;
&lt;li&gt;Isolation contract: a &lt;code&gt;DeploymentRunner&lt;/code&gt; can execute a tool call via a subprocess and return a result envelope.
&lt;/li&gt;
&lt;li&gt;Determinism: the same session state resumed twice produces the same outcome.
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3 id="open-questions"&gt;Open questions&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Should &lt;code&gt;PartialUserTurnContent&lt;/code&gt; keep its current shape or be rewritten around &lt;code&gt;TrackedToolCall&lt;/code&gt;?&lt;/strong&gt;&lt;br /&gt;
Rewriting is cleaner but touches JSON serialization and existing tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Should session storage move into the OS ECS persistence layer or stay separate?&lt;/strong&gt;&lt;br /&gt;
Moving into ECS unifies migrations/backends; keeping it separate is less invasive.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;How do we handle non-serializable &lt;code&gt;ToolExecutionContext&lt;/code&gt; fields on resume?&lt;/strong&gt;&lt;br /&gt;
Recommended: store a serializable snapshot and re-hydrate portal/world/event queue in the runtime.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Do we want true concurrency for sync calls or sequential execution?&lt;/strong&gt;&lt;br /&gt;
Sequential is simpler and matches current cache semantics; concurrency can be added later behind a policy flag.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Should &lt;code&gt;ToolCallId&lt;/code&gt; be a UUID or an index into the turn?&lt;/strong&gt;&lt;br /&gt;
A UUID is safer for external workers and database keys; an index is smaller and deterministic. Hybrid: &lt;code&gt;ToolCallId = TurnId + Int index&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3 id="suggested-first-milestone"&gt;Suggested first milestone&lt;/h3&gt;
&lt;p&gt;The smallest vertical slice that proves the design:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;TrackedToolCall&lt;/code&gt; and refactor &lt;code&gt;PartialUserTurnContent&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Implement &lt;code&gt;ToolCallPolicy&lt;/code&gt; with &lt;code&gt;RunSync&lt;/code&gt; / &lt;code&gt;Defer&lt;/code&gt; decisions.
&lt;/li&gt;
&lt;li&gt;Update the async scheduler to batch sync calls and yield deferred ones.
&lt;/li&gt;
&lt;li&gt;Implement &lt;code&gt;wakeSession&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Add a SQLite-backed &lt;code&gt;SessionBackend&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Write a test exercising the full requested flow:
&lt;ul&gt;
&lt;li&gt;3 tool calls issued,
&lt;/li&gt;
&lt;li&gt;policy executes 1 and defers 2,
&lt;/li&gt;
&lt;li&gt;session persists,
&lt;/li&gt;
&lt;li&gt;wake injects 2 results,
&lt;/li&gt;
&lt;li&gt;session resumes and produces a &lt;code&gt;UserTurn&lt;/code&gt; with all 3 results.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This milestone delivers the requested primitives without yet building Docker runners or Postgres backends.&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-durable-workflows.html" rel="alternate"/><summary type="text">Status: no status line yet</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-os-as-standalone-server.html</id><title type="text">Spec: the OS as a standalone server (TUI and web UI as clients)</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/os-as-standalone-server.md"&gt;&lt;code&gt;todos/os-as-standalone-server.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="spec-the-os-as-a-standalone-server-tui-and-web-ui-as-clients"&gt;Spec: the OS as a standalone server (TUI and web UI as clients)&lt;/h2&gt;
&lt;p&gt;Status: proposal, 2026-09-23, revised the same day after checking service
readiness. Phases 0 and 1 done on branch &lt;code&gt;feature/os-standalone-server&lt;/code&gt;
(commits 8de2a64..dc01dc8); All phases landed (8de2a64..771c988), with the open items listed
under “Remaining after Phase 5”. Builds on
&lt;code&gt;todos/web-server-embedding.md&lt;/code&gt; (done) and &lt;code&gt;todos/session-mailbox.md&lt;/code&gt; (done).&lt;/p&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;
&lt;p&gt;One long-running &lt;code&gt;agents-exe&lt;/code&gt; process hosts the agents and their sessions. It
loads agents files the way the TUI does today (&lt;code&gt;agents-exe.cfg.json&lt;/code&gt;,
&lt;code&gt;agentsFiles&lt;/code&gt;, &lt;code&gt;agentsDirectories&lt;/code&gt;, &lt;code&gt;--agent-file&lt;/code&gt;, &lt;code&gt;--agent&lt;/code&gt;). Clients attach
to it and drive it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the TUI, in the same process or over a socket, with no loss of features;
&lt;/li&gt;
&lt;li&gt;the web chat page, as today;
&lt;/li&gt;
&lt;li&gt;any program, through the HTTP API: create and message sessions, wake them
(continuations, mail), interrupt them, cancel them, follow their events.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The end state: &lt;code&gt;agents-exe serve&lt;/code&gt; runs standalone; &lt;code&gt;agents-exe tui&lt;/code&gt; either
embeds the runner (today’s single-process experience) or attaches to a
running server with &lt;code&gt;--attach URL&lt;/code&gt;; both TUI modes are the same code.&lt;/p&gt;
&lt;h3 id="the-os-picture"&gt;The OS picture&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;OS&lt;/th&gt;&lt;th&gt;here&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;kernel&lt;/td&gt;&lt;td&gt;&lt;code&gt;Host&lt;/code&gt; + &lt;code&gt;Host.Runner&lt;/code&gt; (&lt;code&gt;SessionRunner&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;process table&lt;/td&gt;&lt;td&gt;the &lt;code&gt;sessions&lt;/code&gt; table, &lt;code&gt;srLive&lt;/code&gt; for the resident ones&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;syscall interface&lt;/td&gt;&lt;td&gt;the runner's operations, serialized as &lt;code&gt;Command&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;kernel log / netlink&lt;/td&gt;&lt;td&gt;the &lt;code&gt;SessionEvent&lt;/code&gt; broadcast, serialized as &lt;code&gt;Event&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;terminal&lt;/td&gt;&lt;td&gt;the TUI: a client that only renders and issues commands&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;init&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;agents-exe serve&lt;/code&gt;: config loading, then the runner&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The ECS &lt;code&gt;System.Agents.OS.*&lt;/code&gt; layer (World, components, &lt;code&gt;OS.Persistence&lt;/code&gt;) is
&lt;strong&gt;not&lt;/strong&gt; the kernel in this picture. In production it only tracks async
tool-call entities and subcall visibility for the TUI. The kernel’s state
model is sessions, mail and continuations, and its source of truth is the
persisted session.&lt;/p&gt;
&lt;h3 id="current-state"&gt;Current state&lt;/h3&gt;
&lt;p&gt;Two runtimes exist and share only the agent tree loader and
&lt;code&gt;AgentFactory.buildAgent&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;TUI (&lt;code&gt;tui/&lt;/code&gt;)&lt;/th&gt;&lt;th&gt;agents-server (&lt;code&gt;examples/agents-server&lt;/code&gt;, &lt;code&gt;src/System/Agents/Host*&lt;/code&gt;)&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;loop&lt;/td&gt;&lt;td&gt;&lt;code&gt;Session.Loop.runUntilBlocked&lt;/code&gt;, one forked thread per conversation (&lt;code&gt;TUI/Event/Conversation.hs&lt;/code&gt;, &lt;code&gt;spawnConversationIO&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;code&gt;Host.Runner.runLoop&lt;/code&gt;, one run at a time per session, under a lock&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;agent build&lt;/td&gt;&lt;td&gt;&lt;code&gt;OneShot.nodeToAgent&lt;/code&gt;, then the TUI rewrites &lt;code&gt;step&lt;/code&gt; and &lt;code&gt;usrQuery&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Runner.newAgent&lt;/code&gt; (&lt;code&gt;buildAgent … RootAgent&lt;/code&gt;, durable mailbox, router, spawn and watch hooks)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;mail&lt;/td&gt;&lt;td&gt;&lt;code&gt;newInMemoryMailbox&lt;/code&gt; + one process-local &lt;code&gt;MailRouter&lt;/code&gt; in &lt;code&gt;Core&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;newDurableMailbox&lt;/code&gt;, &lt;code&gt;session_mail&lt;/code&gt; table, &lt;code&gt;serverMailRouter&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;user input&lt;/td&gt;&lt;td&gt;a &lt;code&gt;BChan&lt;/code&gt; per conversation plus a &lt;code&gt;TVar&lt;/code&gt; of buffered messages&lt;/td&gt;&lt;td&gt;&lt;code&gt;postMessage&lt;/code&gt;, which becomes &lt;code&gt;UserMessage&lt;/code&gt; mail when the session is busy&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;pause&lt;/td&gt;&lt;td&gt;&lt;code&gt;Control Pause&lt;/code&gt; mail since b62e2a6&lt;/td&gt;&lt;td&gt;&lt;code&gt;pauseSession&lt;/code&gt; → &lt;code&gt;Control Pause&lt;/code&gt;, &lt;code&gt;POST /v1/sessions/:id/pause&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;sessions&lt;/td&gt;&lt;td&gt;file store, &lt;code&gt;conv.&amp;lt;uuid&amp;gt;.json&lt;/code&gt;, &lt;code&gt;SessionStore.listSessions&lt;/code&gt; once at startup&lt;/td&gt;&lt;td&gt;&lt;code&gt;SessionBackend&lt;/code&gt; (SQLite or Postgres), versioned &lt;code&gt;sbCompareAndStore&lt;/code&gt;, &lt;code&gt;sbQuery&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;config&lt;/td&gt;&lt;td&gt;&lt;code&gt;agents-exe.cfg.json&lt;/code&gt;, &lt;code&gt;agentsDirectories&lt;/code&gt;, &lt;code&gt;--agent&lt;/code&gt;, &lt;code&gt;--params-file&lt;/code&gt; (all in &lt;code&gt;app/Main.hs&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;flags only: &lt;code&gt;--agent-file&lt;/code&gt; (repeatable), &lt;code&gt;--db&lt;/code&gt;, &lt;code&gt;--set&lt;/code&gt;/&lt;code&gt;--pin&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;events out&lt;/td&gt;&lt;td&gt;&lt;code&gt;TQueue OSEvent&lt;/code&gt; bridged to Brick; a whole-&lt;code&gt;Session&lt;/code&gt; progress callback; heartbeat polling of TVars&lt;/td&gt;&lt;td&gt;&lt;code&gt;SessionEvent&lt;/code&gt; broadcast &lt;code&gt;TChan&lt;/code&gt;, per-session &lt;code&gt;subscribe&lt;/code&gt;, SSE&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;identity&lt;/td&gt;&lt;td&gt;&lt;code&gt;ConversationId&lt;/code&gt; generated independently of &lt;code&gt;SessionId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;ConversationId&lt;/code&gt; derived from &lt;code&gt;SessionId&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="what-we-can-reuse-as-is"&gt;What we can reuse as-is&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Host.withHost&lt;/code&gt; / &lt;code&gt;withHostStores&lt;/code&gt;: multi-file loading keyed by slug, plus
agents stored in the database.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Host.Runner&lt;/code&gt;: &lt;code&gt;createSession[As[WithParent]]&lt;/code&gt;, &lt;code&gt;spawnSession&lt;/code&gt;,
&lt;code&gt;postMessage&lt;/code&gt; (with &lt;code&gt;nmInterrupt&lt;/code&gt;), &lt;code&gt;resume&lt;/code&gt;, &lt;code&gt;completeCall&lt;/code&gt;, &lt;code&gt;cancelRun&lt;/code&gt;,
&lt;code&gt;cancelAttachedCalls&lt;/code&gt;, &lt;code&gt;pauseSession&lt;/code&gt;, &lt;code&gt;getSession&lt;/code&gt;, &lt;code&gt;awaitRun&lt;/code&gt;,
&lt;code&gt;deleteSession&lt;/code&gt;, &lt;code&gt;recoverOnStartup&lt;/code&gt;, &lt;code&gt;subscribe&lt;/code&gt;/&lt;code&gt;subscribeSTM&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The HTTP API and SSE stream (&lt;code&gt;AgentsServer.Api&lt;/code&gt;), MCP over HTTP, auth,
&lt;code&gt;/openapi.json&lt;/code&gt;, the chat page.
&lt;/li&gt;
&lt;li&gt;Mail: &lt;code&gt;Envelope&lt;/code&gt;, &lt;code&gt;MailBody&lt;/code&gt;, &lt;code&gt;Sender&lt;/code&gt;, &lt;code&gt;Priority&lt;/code&gt;, &lt;code&gt;ControlMsg&lt;/code&gt; all have
JSON. Every client-facing thing is addressed by a UUID (&lt;code&gt;SessionId&lt;/code&gt;,
&lt;code&gt;ContinuationToken&lt;/code&gt;, &lt;code&gt;ToolCallId&lt;/code&gt;, &lt;code&gt;MessageId&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Session&lt;/code&gt; and &lt;code&gt;SessionMeta&lt;/code&gt; have JSON; the TUI’s usage, signals and
trajectory views are pure functions over a &lt;code&gt;Session&lt;/code&gt;, so they run on a
client unchanged.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="gaps"&gt;Gaps&lt;/h4&gt;
&lt;p&gt;G1. &lt;strong&gt;The TUI is the host, not a client.&lt;/strong&gt; &lt;code&gt;spawnConversationIO&lt;/code&gt; builds the
agent, overrides &lt;code&gt;step&lt;/code&gt; (pause polling, progress callback, &lt;code&gt;Stop&lt;/code&gt; →
&lt;code&gt;AskUserPrompt&lt;/code&gt; rewrite) and &lt;code&gt;usrQuery&lt;/code&gt; (blocks on the &lt;code&gt;BChan&lt;/code&gt;), forks
&lt;code&gt;Loop.runUntilBlocked&lt;/code&gt;, and owns the World, the OSEvent queue and the
&lt;code&gt;MailRouter&lt;/code&gt;. Quit is &lt;code&gt;killThread&lt;/code&gt; on every conversation. None of this goes
through the runner.&lt;/p&gt;
&lt;p&gt;G2. &lt;strong&gt;The runner needs a first message.&lt;/strong&gt; &lt;code&gt;createSession&lt;/code&gt; takes a
&lt;code&gt;NewMessage&lt;/code&gt;; the TUI creates an empty conversation and waits for input.&lt;/p&gt;
&lt;p&gt;G3. &lt;strong&gt;Event shape.&lt;/strong&gt; The TUI renders from full &lt;code&gt;Session&lt;/code&gt; snapshots (the
&lt;code&gt;OnSessionProgress&lt;/code&gt; callback) and from &lt;code&gt;OSEvent_Subcall*&lt;/code&gt; and
&lt;code&gt;OSEvent_ToolCallActivity&lt;/code&gt;. The runner emits &lt;code&gt;SessionEvent&lt;/code&gt; (meta plus head
turn, deferred calls, run start/stop, text deltas, tool start/stop) and
&lt;code&gt;AgentFactory&lt;/code&gt; sets &lt;code&gt;ctxEventQueue = Nothing&lt;/code&gt;, so subcall progress and
tool-call activity never reach the server or its clients. Nine of the fifteen
&lt;code&gt;OSEvent&lt;/code&gt; constructors are never emitted.&lt;/p&gt;
&lt;p&gt;G4. &lt;strong&gt;No JSON for commands and events.&lt;/strong&gt; &lt;code&gt;SessionEvent&lt;/code&gt;, &lt;code&gt;NewMessage&lt;/code&gt;,
&lt;code&gt;RunMode&lt;/code&gt;, &lt;code&gt;RunnerError&lt;/code&gt;, &lt;code&gt;OSEvent&lt;/code&gt;, &lt;code&gt;ToolCallActivity&lt;/code&gt;, &lt;code&gt;ToolCallPhase&lt;/code&gt;,
&lt;code&gt;SessionProgress&lt;/code&gt;, &lt;code&gt;Outgoing&lt;/code&gt;, &lt;code&gt;Receipt&lt;/code&gt;, &lt;code&gt;SendError&lt;/code&gt; have no codecs. The only
encoder is &lt;code&gt;eventFrame&lt;/code&gt; in the server’s &lt;code&gt;Api.hs&lt;/code&gt;; the only decoders are its
request parsers.&lt;/p&gt;
&lt;p&gt;G5. &lt;strong&gt;No replay, no global feed.&lt;/strong&gt; Events carry no sequence number and are
not persisted; a reconnecting client gets a fresh &lt;code&gt;snapshot&lt;/code&gt;. Subscriptions
are per &lt;code&gt;SessionId&lt;/code&gt;; there is no owner-wide or server-wide feed, so a live
session list cannot be kept up to date.&lt;/p&gt;
&lt;p&gt;G6. &lt;strong&gt;Runner and HTTP operations the TUI relies on are missing:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;TUI feature&lt;/th&gt;&lt;th&gt;today&lt;/th&gt;&lt;th&gt;runner / HTTP&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;fork at a turn (&lt;code&gt;handleForkAtTurn&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;local &lt;code&gt;Session&lt;/code&gt; copy with &lt;code&gt;forkedFromSessionId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;continue a stored session with the currently selected agent&lt;/td&gt;&lt;td&gt;&lt;code&gt;handleRestoredConversation&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;smAgent&lt;/code&gt; is fixed per session&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;edit / delete queued messages (&lt;code&gt;TUI/Event/Queue.hs&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;shared &lt;code&gt;TVar&lt;/code&gt; of discrete messages read by the runtime&lt;/td&gt;&lt;td&gt;not needed: becomes a TUI-local draft (§5)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;list sessions&lt;/td&gt;&lt;td&gt;&lt;code&gt;SessionStore.listSessions&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;sbQuery&lt;/code&gt; directly on the backend, not a runner call&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;generic mail (send &lt;code&gt;AgentMessage&lt;/code&gt;, &lt;code&gt;StopRun&lt;/code&gt;, &lt;code&gt;CancelCalls [ids]&lt;/code&gt;, &lt;code&gt;Resume&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;&lt;code&gt;sendControlMail&lt;/code&gt; is internal; no route&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;complete a deferred call&lt;/td&gt;&lt;td&gt;not supported in the TUI&lt;/td&gt;&lt;td&gt;&lt;code&gt;completeCall&lt;/code&gt;, &lt;code&gt;POST /v1/continuations/:token&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;agent details (model, prompt, activation flags) for the Agents tab&lt;/td&gt;&lt;td&gt;live &lt;code&gt;OSAgentNode&lt;/code&gt; TVars&lt;/td&gt;&lt;td&gt;&lt;code&gt;GET /v1/agents&lt;/code&gt; has slug, description, tool names only&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;G7. &lt;strong&gt;Config parity.&lt;/strong&gt; &lt;code&gt;locateAgentsExeConfig&lt;/code&gt;, &lt;code&gt;initArgParserArgs&lt;/code&gt;,
&lt;code&gt;resolveAgentFiles&lt;/code&gt;, &lt;code&gt;--params-file&lt;/code&gt; handling and the default-directory
fallback live in &lt;code&gt;app/Main.hs&lt;/code&gt; and are not in a library. The server cannot
load agents “like the TUI does”.&lt;/p&gt;
&lt;p&gt;G8. &lt;strong&gt;Identity.&lt;/strong&gt; The TUI’s &lt;code&gt;ConversationId&lt;/code&gt; is independent of its
&lt;code&gt;SessionId&lt;/code&gt; (see the comment in &lt;code&gt;spawnConversationIO&lt;/code&gt;); the server derives
one from the other. &lt;code&gt;AgentId&lt;/code&gt; is random per load; the slug is the stable
name. There are two &lt;code&gt;ConversationId&lt;/code&gt; types (&lt;code&gt;Base&lt;/code&gt; and &lt;code&gt;OS.Core.Types&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;G9. &lt;strong&gt;Spawn semantics differ.&lt;/strong&gt; The TUI’s &lt;code&gt;spawn-session&lt;/code&gt; hook resolves a
slug against the roster of root agents; the server resolves helpers of the
calling node.&lt;/p&gt;
&lt;p&gt;G10. &lt;strong&gt;Sub-agent runs are not sessions.&lt;/strong&gt; A &lt;code&gt;prompt_agent_*&lt;/code&gt; call runs its
child inside the tool call, so the child produces no &lt;code&gt;SessionEvent&lt;/code&gt; and
cannot be &lt;code&gt;cancelRun&lt;/code&gt;’d or subscribed to on its own. Only the TUI sees it,
through &lt;code&gt;OSEvent_Subcall*&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;G11. &lt;strong&gt;Volatile per-session state.&lt;/strong&gt; Secret params (&lt;code&gt;lsParams&lt;/code&gt;), watches and
the run &lt;code&gt;Async&lt;/code&gt; are lost on restart or eviction. A client protocol needs a
“resupply secrets” step, or durable encrypted storage.&lt;/p&gt;
&lt;p&gt;G12. &lt;strong&gt;No CORS.&lt;/strong&gt; &lt;code&gt;checkOrigin&lt;/code&gt; in &lt;code&gt;AgentsServer.Api&lt;/code&gt; refuses non-loopback
&lt;code&gt;Origin&lt;/code&gt;s when auth is off and lets everything through when it is on, but
the server never emits &lt;code&gt;Access-Control-Allow-*&lt;/code&gt; headers and does not answer
preflight &lt;code&gt;OPTIONS&lt;/code&gt;. A browser page served by another local web app (a
different port is a different origin) cannot call the API or open the SSE
stream directly; it has to proxy through its own backend.&lt;/p&gt;
&lt;p&gt;G13. &lt;strong&gt;Service packaging.&lt;/strong&gt; The server itself is service-ready: SIGTERM and
SIGINT trigger a graceful stop with &lt;code&gt;--shutdown-grace&lt;/code&gt;, logs are JSON lines
on stderr, every path is a flag, &lt;code&gt;recoverOnStartup&lt;/code&gt; runs at boot. But there
is no unit file, no install target, no &lt;code&gt;bundling/&lt;/code&gt; entry and no
documentation for running it under systemd.&lt;/p&gt;
&lt;h4 id="integration-modes-as-of-2026-09-23"&gt;Integration modes, as of 2026-09-23&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Mode&lt;/th&gt;&lt;th&gt;Status&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;server-side web app calls the API and renders its own chat&lt;/td&gt;&lt;td&gt;works&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;browser chat UI on another origin talks to the service directly&lt;/td&gt;&lt;td&gt;blocked by G12&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;web app proxies the API under its own origin&lt;/td&gt;&lt;td&gt;works&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;MCP client (&lt;code&gt;ask_&amp;lt;slug&amp;gt;&lt;/code&gt; tools, blocking, no session continuity)&lt;/td&gt;&lt;td&gt;works, coarse&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;another agents-exe agent uses it as an OpenAPI toolbox&lt;/td&gt;&lt;td&gt;works&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;deferred tool calls executed by the web app's own workers&lt;/td&gt;&lt;td&gt;works&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TUI attached from elsewhere&lt;/td&gt;&lt;td&gt;not started&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="design"&gt;Design&lt;/h3&gt;
&lt;h4 id="1-the-protocol-module"&gt;1. The protocol module&lt;/h4&gt;
&lt;p&gt;A library module, &lt;code&gt;System.Agents.Protocol&lt;/code&gt;, owning two sum types with JSON
instances. The HTTP layer, the SSE encoder, the in-process client and the
socket client all speak these; nothing else defines a wire format.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Command&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;CreateSession&lt;/span&gt;   {&lt;span class="ot"&gt; agent ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;,&lt;span class="ot"&gt; message ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;NewMessage&lt;/span&gt;,&lt;span class="ot"&gt; run ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;RunMode&lt;/span&gt;,&lt;span class="ot"&gt; params ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;ParamName&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;,&lt;span class="ot"&gt; parent ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; }&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PostMessage&lt;/span&gt;     {&lt;span class="ot"&gt; session ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;,&lt;span class="ot"&gt; message ::&lt;/span&gt; &lt;span class="dt"&gt;NewMessage&lt;/span&gt;,&lt;span class="ot"&gt; run ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;RunMode&lt;/span&gt;,&lt;span class="ot"&gt; params ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;ParamName&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt; }&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Resume&lt;/span&gt;          {&lt;span class="ot"&gt; session ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;,&lt;span class="ot"&gt; mode ::&lt;/span&gt; &lt;span class="dt"&gt;RunMode&lt;/span&gt;,&lt;span class="ot"&gt; params ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;ParamName&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt; }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;CompleteCall&lt;/span&gt;    {&lt;span class="ot"&gt; token ::&lt;/span&gt; &lt;span class="dt"&gt;ContinuationToken&lt;/span&gt;,&lt;span class="ot"&gt; result ::&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;,&lt;span class="ot"&gt; resume ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;,&lt;span class="ot"&gt; params ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;ParamName&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt; }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;CancelRun&lt;/span&gt;       &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;CancelAttached&lt;/span&gt;  &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Pause&lt;/span&gt;           &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SendMail&lt;/span&gt;        {&lt;span class="ot"&gt; session ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;,&lt;span class="ot"&gt; body ::&lt;/span&gt; &lt;span class="dt"&gt;MailBody&lt;/span&gt;,&lt;span class="ot"&gt; priority ::&lt;/span&gt; &lt;span class="dt"&gt;Priority&lt;/span&gt; }   &lt;span class="co"&gt;-- StopRun, CancelCalls, Resume, AgentMessage, …&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ForkSession&lt;/span&gt;     {&lt;span class="ot"&gt; session ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;,&lt;span class="ot"&gt; atTurn ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;,&lt;span class="ot"&gt; agent ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; }   &lt;span class="co"&gt;-- newest-first index; turns have no id&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ListSessions&lt;/span&gt;    &lt;span class="dt"&gt;SessionQuery&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;GetSession&lt;/span&gt;      &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ListAgents&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;GetAgent&lt;/span&gt;        &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeleteSession&lt;/span&gt;   {&lt;span class="ot"&gt; session ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;,&lt;span class="ot"&gt; mode ::&lt;/span&gt; &lt;span class="dt"&gt;DeleteMode&lt;/span&gt; }&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Subscribe&lt;/span&gt;       {&lt;span class="ot"&gt; scope ::&lt;/span&gt; &lt;span class="dt"&gt;SubscribeScope&lt;/span&gt;,&lt;span class="ot"&gt; after ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;EventSeq&lt;/span&gt; }&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Event&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Event&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; evSeq     ::&lt;/span&gt; &lt;span class="dt"&gt;EventSeq&lt;/span&gt;          &lt;span class="co"&gt;-- total order per server&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; evSession ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;   &lt;span class="co"&gt;-- Nothing for server-wide events&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; evBody    ::&lt;/span&gt; &lt;span class="dt"&gt;EventBody&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;EventBody&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunStarted&lt;/span&gt; &lt;span class="dt"&gt;RunMode&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;RunStopped&lt;/span&gt; &lt;span class="dt"&gt;SessionStatus&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionFailed&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionUpdated&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Turn&lt;/span&gt;)&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;CallsDeferred&lt;/span&gt; [&lt;span class="dt"&gt;DeferredCallView&lt;/span&gt;]&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TextDelta&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallStarted&lt;/span&gt; … &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallProgressed&lt;/span&gt; &lt;span class="dt"&gt;ToolCallActivity&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallCompleted&lt;/span&gt; …&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SubcallStarted&lt;/span&gt; {&lt;span class="ot"&gt; parent ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;,&lt;span class="ot"&gt; child ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;,&lt;span class="ot"&gt; slug ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;,&lt;span class="ot"&gt; depth ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; }&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SubcallCompleted&lt;/span&gt; … &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SubcallFailed&lt;/span&gt; …&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionCreated&lt;/span&gt; &lt;span class="dt"&gt;SessionMeta&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionDeleted&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MailAccepted&lt;/span&gt; &lt;span class="dt"&gt;Envelope&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MailRejected&lt;/span&gt; &lt;span class="dt"&gt;SendError&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AgentsChanged&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NewMessage&lt;/code&gt; gains &lt;code&gt;Maybe&lt;/code&gt; semantics through &lt;code&gt;CreateSession.message&lt;/code&gt;:
&lt;code&gt;Nothing&lt;/code&gt; creates an idle session with no turn (G2). The runner stores it
with status &lt;code&gt;ready&lt;/code&gt; and no run.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ForkSession&lt;/code&gt; is new runner work (G6): copy the session up to &lt;code&gt;atTurn&lt;/code&gt;,
set &lt;code&gt;forkedFromSessionId&lt;/code&gt;, optionally rebind &lt;code&gt;smAgent&lt;/code&gt;. This also covers
“continue with another agent”: a fork at the head with a new agent.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SendMail&lt;/code&gt; generalizes &lt;code&gt;sendControlMail&lt;/code&gt;. It is how the TUI posts
&lt;code&gt;StopRun&lt;/code&gt; on quit instead of &lt;code&gt;killThread&lt;/code&gt;, and how a client sends
&lt;code&gt;AgentMessage&lt;/code&gt; mail on behalf of another session.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OSEvent&lt;/code&gt; is retired as a public type. &lt;code&gt;ToolCallActivity&lt;/code&gt; and the
&lt;code&gt;Subcall*&lt;/code&gt; payloads move into &lt;code&gt;EventBody&lt;/code&gt;; the unused constructors are
dropped. &lt;code&gt;Session.Async.Engine&lt;/code&gt; and &lt;code&gt;OneShotTool&lt;/code&gt; emit through a runner
hook (&lt;code&gt;ctxEmit :: Maybe (EventBody -&amp;gt; IO ())&lt;/code&gt;) instead of &lt;code&gt;ctxEventQueue&lt;/code&gt;,
and the runner sets it (G3). &lt;code&gt;SubcallProgress&lt;/code&gt; no longer carries a whole
&lt;code&gt;Session&lt;/code&gt;: a child that is a real session (see §4) emits its own
&lt;code&gt;SessionUpdated&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-sequence-numbers-and-replay-g5"&gt;2. Sequence numbers and replay (G5)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The runner stamps every event with a monotonically increasing &lt;code&gt;EventSeq&lt;/code&gt;
and keeps a bounded in-memory ring (say the last 4096 events).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Subscribe { after = Just n }&lt;/code&gt; replays from the ring when &lt;code&gt;n&lt;/code&gt; is inside
it. When it is not, the server answers with a &lt;code&gt;snapshot&lt;/code&gt; per session in
scope (as today) followed by live events, and the client re-fetches
&lt;code&gt;GetSession&lt;/code&gt; for anything it cares about. This is the SSE &lt;code&gt;Last-Event-ID&lt;/code&gt;
contract.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SubscribeScope = OneSession SessionId | Owner (Maybe Text) | All&lt;/code&gt;. &lt;code&gt;All&lt;/code&gt;
needs an admin owner when auth is on.
&lt;/li&gt;
&lt;li&gt;Persisting the event log is deferred (see Decisions). The stored session
plus &lt;code&gt;session_mail&lt;/code&gt; already lets a client rebuild state; the ring only
needs to cover reconnection hiccups.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-runnerclient-one-interface-two-implementations"&gt;3. &lt;code&gt;RunnerClient&lt;/code&gt;: one interface, two implementations&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;RunnerClient&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunnerClient&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; rcCommand   ::&lt;/span&gt; &lt;span class="dt"&gt;Command&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt; &lt;span class="dt"&gt;Reply&lt;/span&gt;)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; rcSubscribe ::&lt;/span&gt; &lt;span class="dt"&gt;SubscribeScope&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;EventSeq&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Event&lt;/span&gt;, &lt;span class="dt"&gt;IO&lt;/span&gt; ())   &lt;span class="co"&gt;-- next, close&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;inProcessClient ::&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;RunnerClient&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;httpClient      ::&lt;/span&gt; &lt;span class="dt"&gt;BaseUrl&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;BearerToken&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;RunnerClient&lt;/span&gt;   &lt;span class="co"&gt;-- HTTP + SSE&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;socketClient    ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;RunnerClient&lt;/span&gt;                       &lt;span class="co"&gt;-- Unix socket, same framing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The TUI depends only on &lt;code&gt;RunnerClient&lt;/code&gt;. &lt;code&gt;agents-exe tui&lt;/code&gt; builds
&lt;code&gt;inProcessClient&lt;/code&gt; over a runner it starts itself; &lt;code&gt;agents-exe tui --attach&lt;/code&gt;
builds &lt;code&gt;httpClient&lt;/code&gt; or &lt;code&gt;socketClient&lt;/code&gt;. No TUI code knows which.&lt;/p&gt;
&lt;h4 id="4-the-tui-as-a-client-g1-g6-g8-g9-g10"&gt;4. The TUI as a client (G1, G6, G8, G9, G10)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Conversation&lt;/code&gt; in the TUI becomes: &lt;code&gt;SessionId&lt;/code&gt;, the latest &lt;code&gt;Session&lt;/code&gt; and
&lt;code&gt;SessionMeta&lt;/code&gt; (from &lt;code&gt;GetSession&lt;/code&gt; and &lt;code&gt;SessionUpdated&lt;/code&gt;), derived views
(tool-call views, signals, usage), unread markers. No &lt;code&gt;ThreadId&lt;/code&gt;, no
&lt;code&gt;BChan&lt;/code&gt;, no callbacks, no &lt;code&gt;TuiAgent&lt;/code&gt; with TVars.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Core&lt;/code&gt; loses &lt;code&gt;coreWorld&lt;/code&gt;, &lt;code&gt;coreOSEventQueue&lt;/code&gt;, &lt;code&gt;coreMailRouter&lt;/code&gt;,
&lt;code&gt;coreBufferedMessages&lt;/code&gt;, &lt;code&gt;corePausedConversations&lt;/code&gt;. The agent list is
&lt;code&gt;ListAgents&lt;/code&gt; plus &lt;code&gt;AgentsChanged&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Send = &lt;code&gt;PostMessage&lt;/code&gt; when the session is idle. While a run is active, send
appends to a TUI-local draft (§5) rather than posting a discrete queued
message; the draft is posted as one message when the run stops. “Send
now” posts the draft at once (it becomes mail, folded at the next R1);
an interrupt (&lt;code&gt;PostMessage&lt;/code&gt; with &lt;code&gt;nmInterrupt&lt;/code&gt;) bypasses the draft as
today. Unread mail from other senders is shown read-only next to it (see
Decisions, D3).
&lt;/li&gt;
&lt;li&gt;Pause = &lt;code&gt;Pause&lt;/code&gt;; unpause = &lt;code&gt;SendMail Control Resume&lt;/code&gt;. &lt;code&gt;Paused&lt;/code&gt; becomes a
&lt;code&gt;SessionStatus&lt;/code&gt; detail the server reports, not a TUI-local flag.
&lt;/li&gt;
&lt;li&gt;Interrupt and hard cancel are already commands (&lt;code&gt;PostMessage&lt;/code&gt; with
&lt;code&gt;nmInterrupt&lt;/code&gt;, &lt;code&gt;CancelAttached&lt;/code&gt;). Quit = &lt;code&gt;SendMail StopRun&lt;/code&gt; for every
session the TUI started in embedded mode, and nothing when attached.
&lt;/li&gt;
&lt;li&gt;Fork = &lt;code&gt;ForkSession&lt;/code&gt;. Continue with another agent = fork at the head.
&lt;/li&gt;
&lt;li&gt;Subcall visibility: a &lt;code&gt;prompt_agent_*&lt;/code&gt; call spawns a real child session via
&lt;code&gt;spawnSession&lt;/code&gt; (the server already links &lt;code&gt;smParent&lt;/code&gt;), so the child shows
up through &lt;code&gt;SessionCreated&lt;/code&gt; + its own events. The TUI’s spawn-roster
question (G9) goes away: the server resolves helpers, and &lt;code&gt;CreateSession&lt;/code&gt;
with a &lt;code&gt;parent&lt;/code&gt; covers the “spawn any root as a child” case the TUI has
today.
&lt;/li&gt;
&lt;li&gt;Deferred calls: the TUI gains a pending-calls view and &lt;code&gt;CompleteCall&lt;/code&gt;,
which the server already supports.
&lt;/li&gt;
&lt;li&gt;Sessions history tab = &lt;code&gt;ListSessions&lt;/code&gt;, refreshed by &lt;code&gt;SessionCreated&lt;/code&gt;,
&lt;code&gt;SessionUpdated&lt;/code&gt;, &lt;code&gt;SessionDeleted&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ConversationId&lt;/code&gt; in the TUI = &lt;code&gt;sessionIdToConversationId sid&lt;/code&gt;, as on the
server (G8).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;OS.*&lt;/code&gt; ECS layer is left in place for tool-call entities inside the
engine; the TUI stops constructing a &lt;code&gt;World&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="5-the-draft-buffer-g6-queued-messages-a-ui-concern"&gt;5. The draft buffer (G6, queued messages): a UI concern&lt;/h4&gt;
&lt;p&gt;Three messages typed in a row while the LLM is busy are almost always one
message being elaborated. So the TUI keeps, per conversation, &lt;strong&gt;one editable
draft with append semantics&lt;/strong&gt; instead of a queue of discrete messages, and
posts it whole when it is the user’s turn. The kernel never sees a draft: it
only ever receives real messages (&lt;code&gt;PostMessage&lt;/code&gt;) and interrupts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Where it lives:&lt;/strong&gt; in the TUI’s &lt;code&gt;Conversation&lt;/code&gt; state only. It is not
persisted and does not survive a detach; a second client attached to the
same session does not see it. That is fine: it is unsent text, like the
contents of the composer.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Editing:&lt;/strong&gt; the queue tab becomes a draft editor. Collapsed, it shows the
draft’s first line and size; expanded, it is a text editor over the whole
draft. Sending while busy appends a paragraph; the user can rewrite or
clear it at will.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When it ships:&lt;/strong&gt; on &lt;code&gt;RunStopped&lt;/code&gt; with a status that accepts input, the
TUI posts the draft as one &lt;code&gt;PostMessage&lt;/code&gt; and clears it. “Send now” from
the editor posts it immediately; the server turns it into &lt;code&gt;UserMessage&lt;/code&gt;
mail and R1 folds it into the next user turn, which fires after each round
of tool results too, so an elaboration typed during a tool call reaches
the model at the next completion. A paused session keeps the draft until
it is resumed.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What the LLM sees:&lt;/strong&gt; unchanged from the mailbox spec. R1 emits one tool
message per call, then a user message with the folded mail. For a
provider that rejects a user message directly after tool results, the
agent opts into &lt;code&gt;mailInToolResult: true&lt;/code&gt;: R1 then appends the folded
mail as a trailing text block of the last tool result of that round, with
the same &lt;code&gt;[mail …]&lt;/code&gt; header. This is a property of mail folding, not of
drafts, and applies to attached (sync) calls; detached and deferred
results already arrive as mail of their own.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="6-agents-exe-serve-and-config-parity-g7"&gt;6. &lt;code&gt;agents-exe serve&lt;/code&gt; and config parity (G7)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Move from &lt;code&gt;app/Main.hs&lt;/code&gt; into a library module (&lt;code&gt;System.Agents.CLI.Config&lt;/code&gt;
or similar): &lt;code&gt;locateAgentsExeConfig&lt;/code&gt;, config parsing, &lt;code&gt;agentsFiles&lt;/code&gt; plus
&lt;code&gt;agentsDirectories&lt;/code&gt; expansion, the default-directory fallback,
&lt;code&gt;resolveAgentFiles&lt;/code&gt; for &lt;code&gt;--agent&lt;/code&gt;, &lt;code&gt;--params-file&lt;/code&gt;, and the sessions-store
choice.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HostConfig&lt;/code&gt; gains a constructor from that config, so &lt;code&gt;withHost&lt;/code&gt; can be
fed either explicit &lt;code&gt;--agent-file&lt;/code&gt;s or the resolved config.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-exe serve&lt;/code&gt; = the current &lt;code&gt;agents-server&lt;/code&gt; main, with config
loading in front. &lt;code&gt;agents-server&lt;/code&gt; keeps working as the same code with
flags only. The SQLite session backend becomes the default for the TUI
too; the file store stays readable through a composite backend for old
&lt;code&gt;conv.*.json&lt;/code&gt; history.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--socket PATH&lt;/code&gt; on &lt;code&gt;serve&lt;/code&gt; for a local, token-free attach; &lt;code&gt;--bind&lt;/code&gt;/&lt;code&gt;--port&lt;/code&gt;
as today for HTTP.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="7-http-surface-additions"&gt;7. HTTP surface additions&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Route&lt;/th&gt;&lt;th&gt;Command&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions&lt;/code&gt; with no &lt;code&gt;prompt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;CreateSession { message = Nothing }&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/fork&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;ForkSession&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/pause&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Pause&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/mail&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;SendMail&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions/:id/mail?unread=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;inbox listing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/events?scope=&amp;amp;after=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Subscribe&lt;/code&gt; across sessions, with &lt;code&gt;Last-Event-ID&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/agents/:slug&lt;/code&gt;&lt;/td&gt;&lt;td&gt;extended with model, system prompt, tool activation&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;GET /v1/sessions/:id/events&lt;/code&gt; stays, gains &lt;code&gt;Last-Event-ID&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="phases"&gt;Phases&lt;/h3&gt;
&lt;p&gt;Phases 0 and 1 need nothing and make the service usable from a local web
app on their own. Phase 2 needs nothing either. Phase 3 needs Phase 2.
Phase 4 needs 1, 2 and 3. Phase 5 needs only Phase 2.&lt;/p&gt;
&lt;h4 id="phase-0-service-readiness-g12-g13--done"&gt;Phase 0: service readiness (G12, G13) — done&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;--cors-origin ORIGIN&lt;/code&gt; on &lt;code&gt;agents-server&lt;/code&gt;, repeatable, &lt;code&gt;*&lt;/code&gt; allowed only
without auth: emits &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; (echoing the matched
origin), &lt;code&gt;-Allow-Methods&lt;/code&gt;, &lt;code&gt;-Allow-Headers&lt;/code&gt; (&lt;code&gt;Authorization&lt;/code&gt;,
&lt;code&gt;Content-Type&lt;/code&gt;), &lt;code&gt;-Expose-Headers&lt;/code&gt; (&lt;code&gt;Location&lt;/code&gt;), &lt;code&gt;-Max-Age&lt;/code&gt;, and answers
preflight &lt;code&gt;OPTIONS&lt;/code&gt; with 204 before auth and before &lt;code&gt;checkOrigin&lt;/code&gt;. An
origin listed here passes &lt;code&gt;checkOrigin&lt;/code&gt; even with auth off. The SSE route
keeps working cross-origin through &lt;code&gt;?access_token=&lt;/code&gt; since &lt;code&gt;EventSource&lt;/code&gt;
cannot set headers. Docs: a “Running as a service” section in
&lt;code&gt;documentation/agents-server.md&lt;/code&gt; with a systemd unit, and the CORS flag in the flag
table and the authentication section. Also add the undocumented
&lt;code&gt;cancel-attached&lt;/code&gt;, &lt;code&gt;pause&lt;/code&gt;, &lt;code&gt;interrupt&lt;/code&gt;, &lt;code&gt;tool.started&lt;/code&gt; and
&lt;code&gt;tool.completed&lt;/code&gt; to the same doc. Tests: preflight, allowed and refused
origins, SSE with &lt;code&gt;access_token&lt;/code&gt; from an allowed origin.&lt;/p&gt;
&lt;h4 id="phase-1-agents-exe-serve-and-config-parity-g7--done"&gt;Phase 1: &lt;code&gt;agents-exe serve&lt;/code&gt; and config parity (G7) — done&lt;/h4&gt;
&lt;p&gt;Landed as &lt;code&gt;System.Agents.CLI.ConfigLoader&lt;/code&gt; (not &lt;code&gt;CLI.Config&lt;/code&gt;: the TUI
library already owns that module name), &lt;code&gt;hostConfigFromResolved&lt;/code&gt;,
&lt;code&gt;agents-exe serve&lt;/code&gt; reusing the global &lt;code&gt;--agent-file&lt;/code&gt;/&lt;code&gt;--agent&lt;/code&gt;/&lt;code&gt;--params-file&lt;/code&gt;
flags, and &lt;code&gt;--socket&lt;/code&gt;. The Unix listener stops accepting on SIGTERM and
unlinks its file but does not drain in-flight requests through
&lt;code&gt;--shutdown-grace&lt;/code&gt;; only the TCP listener does.&lt;/p&gt;
&lt;p&gt;Original scope:&lt;/p&gt;
&lt;p&gt;Config loading into the library (§6); &lt;code&gt;serve&lt;/code&gt; subcommand on &lt;code&gt;agents-exe&lt;/code&gt;;
&lt;code&gt;--socket&lt;/code&gt;. The &lt;code&gt;agents-server&lt;/code&gt; executable stays as the flags-only entry
point over the same code. Docs: &lt;code&gt;documentation/agents-server.md&lt;/code&gt; gains the config
section; &lt;code&gt;documentation/cli-commands.md&lt;/code&gt; gains &lt;code&gt;serve&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="phase-2-the-protocol-in-the-library"&gt;Phase 2: the protocol, in the library&lt;/h4&gt;
&lt;p&gt;Split in three sequential steps: 2a the &lt;code&gt;Protocol&lt;/code&gt; types with JSON, event
sequence numbers, the ring and replay, the cross-session feed, and the
server re-implemented on them; 2b the missing runner operations
(&lt;code&gt;listSessions&lt;/code&gt;, &lt;code&gt;sendMail&lt;/code&gt;, create with no message, &lt;code&gt;forkSession&lt;/code&gt;) and
their routes; 2c &lt;code&gt;ctxEmit&lt;/code&gt; replacing &lt;code&gt;ctxEventQueue&lt;/code&gt; so subcall and
tool-activity events reach the runner stream, and &lt;code&gt;mailInToolResult&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;2a landed as &lt;code&gt;System.Agents.Protocol&lt;/code&gt; (&lt;code&gt;Event { seq, session_id, owner, body }&lt;/code&gt;, &lt;code&gt;EventBody&lt;/code&gt; with the old &lt;code&gt;SessionEvent&lt;/code&gt; kinds plus
&lt;code&gt;session.created&lt;/code&gt; / &lt;code&gt;session.deleted&lt;/code&gt;, JSON for &lt;code&gt;NewMessage&lt;/code&gt;, &lt;code&gt;RunMode&lt;/code&gt;,
&lt;code&gt;RunnerError&lt;/code&gt;, &lt;code&gt;DeleteMode&lt;/code&gt;, &lt;code&gt;DeletionPlan&lt;/code&gt;, &lt;code&gt;SubscribeScope&lt;/code&gt;), a 4096-event
ring in the runner, &lt;code&gt;subscribe&lt;/code&gt;/&lt;code&gt;subscribeSTM&lt;/code&gt; taking a scope and an
&lt;code&gt;after&lt;/code&gt;, &lt;code&gt;Last-Event-ID&lt;/code&gt; and &lt;code&gt;?after=&lt;/code&gt; on the session stream, and
&lt;code&gt;GET /v1/events?scope=owner|all&lt;/code&gt;. Deviations from the sketch: &lt;code&gt;evSession&lt;/code&gt;
and &lt;code&gt;evOwner&lt;/code&gt; are always set, also on the server-wide events, because the
JSON merges them with the embedded &lt;code&gt;SessionMeta&lt;/code&gt; fields; &lt;code&gt;RunnerError&lt;/code&gt;’s
decoder is lossy (only the code survives, by design of the existing
&lt;code&gt;{error, message}&lt;/code&gt; shape); the snapshot fallback on an unavailable replay
keeps the pre-existing tiny gap between snapshot and re-subscribe.&lt;/p&gt;
&lt;p&gt;2b landed: &lt;code&gt;createSessionAs*&lt;/code&gt; take &lt;code&gt;Maybe NewMessage&lt;/code&gt; (promptless
&lt;code&gt;POST /v1/sessions&lt;/code&gt; creates an idle &lt;code&gt;ready&lt;/code&gt; session), &lt;code&gt;listSessions&lt;/code&gt; on
the runner, &lt;code&gt;sendMail&lt;/code&gt;/&lt;code&gt;listMail&lt;/code&gt; with &lt;code&gt;POST&lt;/code&gt;/&lt;code&gt;GET /v1/sessions/:id/mail&lt;/code&gt;,
and &lt;code&gt;forkSession&lt;/code&gt; with &lt;code&gt;POST /v1/sessions/:id/fork&lt;/code&gt;. Deviation: &lt;code&gt;Turn&lt;/code&gt; has
no id of its own, so forks are addressed by a 0-based newest-first turn
index (&lt;code&gt;at_turn&lt;/code&gt;), exactly as the TUI’s &lt;code&gt;handleForkAtTurn&lt;/code&gt; does, and the
error is &lt;code&gt;UnknownTurn SessionId Int&lt;/code&gt; (&lt;code&gt;unknown_turn&lt;/code&gt;). The &lt;code&gt;Command&lt;/code&gt;
sketch’s &lt;code&gt;atTurn :: TurnId&lt;/code&gt; is wrong until turns get ids.&lt;/p&gt;
&lt;p&gt;2c landed: &lt;code&gt;ctxEmit :: Maybe (OSEmission -&amp;gt; IO ())&lt;/code&gt; next to &lt;code&gt;ctxEventQueue&lt;/code&gt;
(an intermediate &lt;code&gt;OSEmission&lt;/code&gt; type avoids a &lt;code&gt;Session.Base&lt;/code&gt; → &lt;code&gt;Protocol&lt;/code&gt;
import cycle; the runner converts it to &lt;code&gt;EventBody&lt;/code&gt;), the four kinds
&lt;code&gt;subcall.started&lt;/code&gt; / &lt;code&gt;subcall.completed&lt;/code&gt; / &lt;code&gt;subcall.failed&lt;/code&gt; /
&lt;code&gt;tool.progressed&lt;/code&gt;, the nine dead &lt;code&gt;OSEvent&lt;/code&gt; constructors deleted, and
&lt;code&gt;mailInToolResult&lt;/code&gt;. Deviations: subcall events are stamped with the
&lt;em&gt;parent&lt;/em&gt; as &lt;code&gt;session_id&lt;/code&gt; (so a subscriber of the parent sees them) and
carry the child as &lt;code&gt;child_session_id&lt;/code&gt;. &lt;strong&gt;Open gap:&lt;/strong&gt; &lt;code&gt;mailInToolResult&lt;/code&gt; is
implemented in the synchronous step path only; the server always runs
agents asynchronously, so it has no effect on server sessions until the
async path (&lt;code&gt;runStepMAsync&lt;/code&gt;) folds mail the same way. Tracked for Phase 5.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;System.Agents.Protocol&lt;/code&gt; with &lt;code&gt;Command&lt;/code&gt;, &lt;code&gt;Event&lt;/code&gt;, &lt;code&gt;EventBody&lt;/code&gt;, JSON
instances, and codecs for &lt;code&gt;NewMessage&lt;/code&gt;, &lt;code&gt;RunMode&lt;/code&gt;, &lt;code&gt;RunnerError&lt;/code&gt;,
&lt;code&gt;UserToolResponse&lt;/code&gt; views. &lt;code&gt;AgentsServer.Api&lt;/code&gt; re-implemented on top of it (no
behaviour change; &lt;code&gt;eventFrame&lt;/code&gt; goes away). Runner gains &lt;code&gt;EventSeq&lt;/code&gt; stamping
and the ring, &lt;code&gt;listSessions&lt;/code&gt;, &lt;code&gt;sendMail&lt;/code&gt;, &lt;code&gt;createSession&lt;/code&gt; with no message,
&lt;code&gt;forkSession&lt;/code&gt;. &lt;code&gt;ctxEmit&lt;/code&gt; replaces &lt;code&gt;ctxEventQueue&lt;/code&gt;; &lt;code&gt;Engine&lt;/code&gt; and
&lt;code&gt;OneShotTool&lt;/code&gt; emit through it. &lt;code&gt;mailInToolResult&lt;/code&gt; folding at R1 (§5). Tests: JSON round trips, replay from
the ring, fork, empty create, &lt;code&gt;mailInToolResult&lt;/code&gt; folding.&lt;/p&gt;
&lt;h4 id="phase-3-the-tui-on-the-in-process-runner"&gt;Phase 3: the TUI on the in-process runner&lt;/h4&gt;
&lt;p&gt;Split in three sequential steps: 3a &lt;code&gt;RunnerClient&lt;/code&gt; and &lt;code&gt;inProcessClient&lt;/code&gt;
in the library plus a serializable agent descriptor (&lt;code&gt;ListAgents&lt;/code&gt; /
&lt;code&gt;GetAgent&lt;/code&gt; with model, prompt and tool activation, which also fixes the
&lt;code&gt;GET /v1/agents&lt;/code&gt; gap); 3b the TUI’s startup, Agents tab, History tab and
conversation layer rewritten on &lt;code&gt;RunnerClient&lt;/code&gt; (the large step); 3c
subcall visibility and tool-call activity from runner events, the
pending-calls view with &lt;code&gt;CompleteCall&lt;/code&gt;, and retiring &lt;code&gt;OSEvent&lt;/code&gt;,
&lt;code&gt;ctxEventQueue&lt;/code&gt; and the TUI’s event bridge.&lt;/p&gt;
&lt;p&gt;3a landed (a78d280..bb4e003): &lt;code&gt;AgentDescriptor&lt;/code&gt; (model, prompt, tools with
&lt;code&gt;Activation&lt;/code&gt;, parameters, helpers) served by &lt;code&gt;GET /v1/agents&lt;/code&gt;; &lt;code&gt;Command&lt;/code&gt;
and &lt;code&gt;Reply&lt;/code&gt;; &lt;code&gt;System.Agents.Host.Client&lt;/code&gt; with &lt;code&gt;RunnerClient&lt;/code&gt;,
&lt;code&gt;Subscription&lt;/code&gt;, &lt;code&gt;inProcessClient owner runner&lt;/code&gt; and one typed helper per
operation. The owner is the client’s identity, not a &lt;code&gt;Command&lt;/code&gt; field, so a
command cannot spoof another owner.&lt;/p&gt;
&lt;p&gt;3b is itself split in four, because Brick’s single &lt;code&gt;TuiState&lt;/code&gt;/&lt;code&gt;AppEvent&lt;/code&gt;
means old and new conversation models cannot coexist: 3b-i the new
&lt;code&gt;Conversation&lt;/code&gt;/&lt;code&gt;Core&lt;/code&gt;/&lt;code&gt;AppEvent&lt;/code&gt; types and the startup on &lt;code&gt;Host&lt;/code&gt; +
&lt;code&gt;SessionRunner&lt;/code&gt; + &lt;code&gt;inProcessClient&lt;/code&gt;, with handlers stubbed so the shape
compiles; 3b-ii the event bridge (&lt;code&gt;subscribeAll&lt;/code&gt; → &lt;code&gt;AppEvent&lt;/code&gt;) and the
command dispatch; 3b-iii the draft buffer and the History tab; 3b-iv
render and keymap cleanup, unit tests, smoke test. Known regression to
accept until Phase 5: &lt;code&gt;AppEvent_SubcallProgress&lt;/code&gt; carried the child’s whole
&lt;code&gt;Session&lt;/code&gt;; the runner stream has no equivalent, so a subcall shows start,
completion and failure only.&lt;/p&gt;
&lt;p&gt;3b landed (f73c018..d2887c6). The TUI is a &lt;code&gt;RunnerClient&lt;/code&gt; over an
in-process runner: promptless &lt;code&gt;createSession&lt;/code&gt; then &lt;code&gt;postMessage&lt;/code&gt;; one
&lt;code&gt;subscribeAll&lt;/code&gt; bridge thread feeding Brick; pause/resume, interrupt,
hard cancel, fork, restore (fork when the selected agent differs), F5 and
quit (&lt;code&gt;StopRun&lt;/code&gt; mail, no &lt;code&gt;killThread&lt;/code&gt;) all go through the client; the
draft buffer replaces the queue (Ctrl+A edit, Ctrl+G send now, Ctrl+D
clear; “edit” pulls the draft back into the composer); History refreshes
from events with a per-session cache and Loading/error states;
&lt;code&gt;HostConfig.hcLegacySessionDirs&lt;/code&gt; composites old &lt;code&gt;conv.*.json&lt;/code&gt; directories
as a read fallback for both the TUI and &lt;code&gt;serve&lt;/code&gt;. Runner fix along the
way: &lt;code&gt;postMessage&lt;/code&gt; accepts the first message of an empty &lt;code&gt;ready&lt;/code&gt; session.
An end-to-end pty script against a fake OpenAI endpoint lives in
&lt;code&gt;checks/phase3b-iv-e2e/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;3c landed (c5f017f, 5eeb4b0): &lt;code&gt;OSEvent&lt;/code&gt; and &lt;code&gt;ctxEventQueue&lt;/code&gt; are gone;
&lt;code&gt;OSEmission&lt;/code&gt; + &lt;code&gt;ctxEmit&lt;/code&gt; is the one emission mechanism, with
&lt;code&gt;queueEmitter&lt;/code&gt; for local consumers; new event kind &lt;code&gt;hook.failed&lt;/code&gt;; the
per-step subcall progress snapshot is gone with no successor until Phase
5. The TUI has a Pending panel and &lt;code&gt;answer-pending&lt;/code&gt; (Ctrl+Y) that
completes the oldest deferred call through &lt;code&gt;completeCall&lt;/code&gt; with
auto-resume. &lt;code&gt;UserToolResponse&lt;/code&gt; has no error form, so there is no
&lt;code&gt;fail-pending&lt;/code&gt;. Open: no selection among several pending calls; no UI
for &lt;code&gt;hook.failed&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;inProcessClient&lt;/code&gt;; the TUI conversation layer rewritten on &lt;code&gt;RunnerClient&lt;/code&gt;
(§4). &lt;code&gt;agents-exe tui&lt;/code&gt; starts a &lt;code&gt;Host&lt;/code&gt; + &lt;code&gt;SessionRunner&lt;/code&gt; over the SQLite
backend chosen from config (Phase 1), with the file store composited in for history.
Feature parity checklist: new, continue, fork, send, draft editor (§5), pause,
interrupt, hard cancel, quit, subcall visibility, tool-call activity, F5
tools refresh, export, attachments, plus the new pending-calls view. Remove
&lt;code&gt;coreWorld&lt;/code&gt;, &lt;code&gt;coreOSEventQueue&lt;/code&gt;, &lt;code&gt;coreMailRouter&lt;/code&gt;, &lt;code&gt;coreBufferedMessages&lt;/code&gt;,
&lt;code&gt;corePausedConversations&lt;/code&gt;, &lt;code&gt;Loop&lt;/code&gt; usage, &lt;code&gt;OneShot.nodeToAgent&lt;/code&gt; usage in the
TUI.&lt;/p&gt;
&lt;h4 id="phase-4-attach--done"&gt;Phase 4: attach — done&lt;/h4&gt;
&lt;p&gt;Landed (20522f2..4e03ec9): &lt;code&gt;System.Agents.Host.Client.Http.httpClient&lt;/code&gt;
over &lt;code&gt;http(s)://&lt;/code&gt; and &lt;code&gt;unix://&lt;/code&gt; URLs with bearer token, SSE parsing,
transparent reconnect with &lt;code&gt;Last-Event-ID&lt;/code&gt; (backoff 100 ms to 5 s, 45 s
stall timeout, duplicates dropped), &lt;code&gt;AllSessions&lt;/code&gt; falling back to the
owner scope on 403; &lt;code&gt;agents-exe tui --attach URL|PATH&lt;/code&gt; with &lt;code&gt;--token&lt;/code&gt; /
&lt;code&gt;--token-file&lt;/code&gt;; &lt;code&gt;POST /v1/sessions&lt;/code&gt; takes &lt;code&gt;parent&lt;/code&gt;; &lt;code&gt;GET /v1/sessions/:id&lt;/code&gt;
takes &lt;code&gt;wait&lt;/code&gt;/&lt;code&gt;timeout&lt;/code&gt;; streams send an &lt;code&gt;Agents-Replay&lt;/code&gt; header and flush
headers at once (a warp header-buffering bug had hung the attached TUI);
the chat page follows &lt;code&gt;GET /v1/events&lt;/code&gt;. Open: with &lt;code&gt;--attach&lt;/code&gt;, &lt;code&gt;app/Main.hs&lt;/code&gt;
still resolves local agent files, so &lt;code&gt;--agent SLUG&lt;/code&gt; can fail when the slug
is unknown locally.&lt;/p&gt;
&lt;p&gt;Original scope:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;httpClient&lt;/code&gt; (HTTP + SSE with &lt;code&gt;Last-Event-ID&lt;/code&gt;) and &lt;code&gt;socketClient&lt;/code&gt;;
&lt;code&gt;agents-exe tui --attach URL|PATH&lt;/code&gt;. The chat page moves to &lt;code&gt;GET /v1/events&lt;/code&gt;
for its session list. Tests: a TUI-less client test that runs the server,
attaches, creates, interrupts, forks and replays after a dropped stream.&lt;/p&gt;
&lt;h4 id="phase-5-sub-agents-as-sessions--done-with-two-documented-gaps"&gt;Phase 5: sub-agents as sessions — done, with two documented gaps&lt;/h4&gt;
&lt;p&gt;Landed (d7850d0..771c988): &lt;code&gt;ctxRunSubagent&lt;/code&gt; hook, installed by
&lt;code&gt;Runner.newAgent&lt;/code&gt;, runs &lt;code&gt;prompt_agent_*&lt;/code&gt; as a real child session
(&lt;code&gt;createSessionForNode&lt;/code&gt;, &lt;code&gt;parent&lt;/code&gt; = the calling session, helper resolved
by slug anywhere under the calling root) and awaits it; cancelling the
parent’s call cancels the child; &lt;code&gt;subcall.started&lt;/code&gt; carries the real
child id, so live progress is the child’s own &lt;code&gt;session.updated&lt;/code&gt;.
&lt;code&gt;mailInToolResult&lt;/code&gt; now folds on the async path too. &lt;code&gt;tui --attach&lt;/code&gt; no
longer resolves local agent files or creates the default config.
Gaps: (1) a &lt;code&gt;prompt_agent_*&lt;/code&gt; call with any narrowing (&lt;code&gt;bindings&lt;/code&gt;,
&lt;code&gt;with&lt;/code&gt;, &lt;code&gt;as&lt;/code&gt;, own or inherited) or whose helper is not declared under
the root still runs in-tool, because &lt;code&gt;ToolExecutionContext&lt;/code&gt; cannot name
a narrowed &lt;code&gt;OSAgentNode&lt;/code&gt; without a module cycle; (2) a &lt;code&gt;PartialUserTurn&lt;/code&gt;
shown mid-round does not yet carry that round’s mail in its placeholder
when &lt;code&gt;mailInToolResult&lt;/code&gt; is on. The fake endpoint in &lt;code&gt;checks/&lt;/code&gt; is a fixed
responder, so no end-to-end test exercises a sub-agent through the TUI.&lt;/p&gt;
&lt;p&gt;Original scope:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prompt_agent_*&lt;/code&gt; spawns through &lt;code&gt;spawnSession&lt;/code&gt; and waits on the child’s
&lt;code&gt;RunStopped&lt;/code&gt; (or its mail), so children are cancellable and observable on
their own and &lt;code&gt;SubcallProgress&lt;/code&gt; with an embedded &lt;code&gt;Session&lt;/code&gt; disappears. This
touches &lt;code&gt;OneShotTool&lt;/code&gt; and the async engine; it is the riskiest phase and is
why it is last.&lt;/p&gt;
&lt;h3 id="remaining-after-phase-5"&gt;Remaining after Phase 5&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;G10 residue: done. Narrowed (&lt;code&gt;bindings&lt;/code&gt;, &lt;code&gt;with&lt;/code&gt;, &lt;code&gt;as&lt;/code&gt;, own or inherited) and
undeclared-helper &lt;code&gt;prompt_agent_*&lt;/code&gt; calls now run as runner sessions: the hook
gets a &lt;code&gt;SubagentNarrowing&lt;/code&gt; and the tool’s own node (as a &lt;code&gt;Dynamic&lt;/code&gt;, which
avoids the module cycle). A narrowed child is pinned live (never evicted);
the narrowing is not persisted, so after a restart a resumed narrowed child
runs un-narrowed (bindings may be secret).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mailInToolResult&lt;/code&gt;: done – a partial turn holds the round’s mail out of its query (&lt;code&gt;pMailInToolResult&lt;/code&gt;) and renders it into the last placeholder (&lt;code&gt;partialTurnForLlm&lt;/code&gt;); folded once when the round completes.
&lt;/li&gt;
&lt;li&gt;G11: secret params, watches and the run handle are volatile (D7 stands);
since 2026-09-25 &lt;code&gt;recoverOnStartup&lt;/code&gt; fails the running calls of a session
whose required params were lost, with a &lt;code&gt;params_required&lt;/code&gt; detail.
Since 2026-09-27, watches are also recovered: a &lt;code&gt;session_watches&lt;/code&gt; table
(SQLite via &lt;code&gt;System.Agents.Session.WatchStore&lt;/code&gt;, Postgres via
&lt;code&gt;System.Agents.Postgres.mkPostgresWatchStore&lt;/code&gt;, both modeled directly on
&lt;code&gt;session_mail&lt;/code&gt;/&lt;code&gt;MailStore&lt;/code&gt;) persists each active &lt;code&gt;watch-session&lt;/code&gt;
registration (watcher, &lt;code&gt;WatchRequest&lt;/code&gt;, absolute deadline) alongside the
in-memory &lt;code&gt;WatchHandle&lt;/code&gt;; &lt;code&gt;serverWatchSession&lt;/code&gt; writes the row before
starting to forward, &lt;code&gt;serverUnwatchSession&lt;/code&gt; and the forwarding loop’s own
TTL expiry both delete it, and &lt;code&gt;recoverOnStartup&lt;/code&gt; (via the new
&lt;code&gt;recoverWatches&lt;/code&gt;) re-registers every row whose deadline has not yet
passed and drops the rest, exactly as an in-process TTL timeout would.
A &lt;code&gt;WatchRequest&lt;/code&gt; carries no secret, so unlike session parameters this
needed no client resupply step – D7’s “durable storage” branch applies
here, not its “resupplied by the client” one. Events raised while no
process was watching are not replayed; a recovered watch only sees
events from the moment it is re-registered, same as any other live
subscriber.
The run handle (&lt;code&gt;lsRun&lt;/code&gt;/&lt;code&gt;Async&lt;/code&gt;) turned out not to need new work: eviction
already refuses to drop a &lt;code&gt;LiveSession&lt;/code&gt; with an active run or a running
background call (&lt;code&gt;evictIdle&lt;/code&gt;’s &lt;code&gt;lsRun&lt;/code&gt;/&lt;code&gt;hasRunningCalls&lt;/code&gt; checks), so it
is never actually lost to eviction; and a process restart was already
covered by &lt;code&gt;recoverOnStartup&lt;/code&gt;’s existing orphaned/&lt;code&gt;params_required&lt;/code&gt;
handling above. This is a deviation from the literal G11 wording (“the
run &lt;code&gt;Async&lt;/code&gt;… [is] lost on restart or eviction”) only in that the
eviction half of that claim no longer held by the time this phase
started – no behavior change was needed there, only watches.
(&lt;code&gt;feat/g11-watch-recovery&lt;/code&gt;, full &lt;code&gt;cabal test&lt;/code&gt; suite green: 1248 tests in
&lt;code&gt;agents-tests&lt;/code&gt;, 32 in &lt;code&gt;agents-server-tests&lt;/code&gt;, 7 in &lt;code&gt;agents-postgres-tests&lt;/code&gt;
including a migration-inventory test updated for the new table.)
&lt;/li&gt;
&lt;li&gt;TUI: selection among several pending calls (&lt;code&gt;select-pending&lt;/code&gt;, Ctrl+O) and
&lt;code&gt;fail-pending&lt;/code&gt; (Ctrl+W) are done; a failed call completes with the text
&lt;code&gt;Error: &amp;lt;reason&amp;gt;&lt;/code&gt; rather than a new &lt;code&gt;UserToolResponse&lt;/code&gt; variant. Still no view
for &lt;code&gt;hook.failed&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Service packaging: docs only, no unit file shipped, no &lt;code&gt;bundling/&lt;/code&gt; entry.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;checks/lib/fake_llm.py&lt;/code&gt; scripts multi-turn answers (text and tool calls,
matched on request index, system prompt, last message or offered tools);
pty end-to-end checks now cover a sub-agent call as a child session
(&lt;code&gt;checks/phase5-subagent-e2e&lt;/code&gt;) and deferred calls answered, failed or picked
from the Pending panel (&lt;code&gt;checks/phase5-pending-e2e&lt;/code&gt;). Not covered yet:
interrupts, and the same flows with &lt;code&gt;tui --attach&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;D8’s out-of-scope items: multi-server Postgres, mid-&lt;code&gt;RunAsync&lt;/code&gt; durability,
per-owner API keys.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="decisions-proposed"&gt;Decisions (proposed)&lt;/h3&gt;
&lt;p&gt;D1. &lt;strong&gt;The runner is the OS.&lt;/strong&gt; The ECS &lt;code&gt;World&lt;/code&gt; is an engine-internal detail
for tool-call entities. &lt;code&gt;OS.Persistence&lt;/code&gt;, &lt;code&gt;OS.Interfaces&lt;/code&gt; remnants and the
unused &lt;code&gt;OSEvent&lt;/code&gt; constructors are deleted rather than wired.&lt;/p&gt;
&lt;p&gt;D2. &lt;strong&gt;One wire format, defined once, in the library.&lt;/strong&gt; No JSON in
&lt;code&gt;examples/agents-server&lt;/code&gt; beyond what the servant routes need to reference
the &lt;code&gt;Protocol&lt;/code&gt; types.&lt;/p&gt;
&lt;p&gt;D3. &lt;strong&gt;Drafts are a UI concern; the kernel only knows messages and
interrupts.&lt;/strong&gt; Mail stays append-only and immutable. The TUI keeps one
editable draft per conversation with append semantics (§5), posted as one
&lt;code&gt;PostMessage&lt;/code&gt; when it is the user’s turn. Nothing about drafts crosses the
wire or is stored. Discrete queued messages, and deleting or reordering
them, are dropped: successive messages while the model is busy are treated
as one message being elaborated. Mail from other sessions and tool results
are shown read-only.&lt;/p&gt;
&lt;p&gt;D4. &lt;strong&gt;&lt;code&gt;SessionId&lt;/code&gt; is the conversation.&lt;/strong&gt; &lt;code&gt;ConversationId&lt;/code&gt; is always derived
from it, in every front-end.&lt;/p&gt;
&lt;p&gt;D5. &lt;strong&gt;The event ring is in memory; the event log is not persisted.&lt;/strong&gt;
Replay covers reconnects; a client that is behind by more than the ring
refetches sessions. Revisit only if a use case needs an audit trail (then
persist &lt;code&gt;Event&lt;/code&gt; rows in the store, keyed by &lt;code&gt;EventSeq&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;D6. &lt;strong&gt;Embedded mode is the same code as attached mode.&lt;/strong&gt; The TUI never gets
a privileged path to runtime internals again; anything it needs is a
&lt;code&gt;Command&lt;/code&gt; or an &lt;code&gt;Event&lt;/code&gt;, which keeps the web page and API clients at parity.&lt;/p&gt;
&lt;p&gt;D7. &lt;strong&gt;Secrets are resupplied by the client.&lt;/strong&gt; No durable secret storage in
this spec; &lt;code&gt;lsParams&lt;/code&gt; stays volatile and the TUI resupplies from its
&lt;code&gt;--params-file&lt;/code&gt; on &lt;code&gt;CreateSession&lt;/code&gt;/&lt;code&gt;PostMessage&lt;/code&gt;, as the web page does today.&lt;/p&gt;
&lt;p&gt;D8. &lt;strong&gt;Out of scope:&lt;/strong&gt; several servers on one Postgres, mid-tool-call
durability for &lt;code&gt;RunAsync&lt;/code&gt; calls, per-owner API keys. They are documented as
unsupported in &lt;code&gt;documentation/agents-server.md&lt;/code&gt; and are not needed for attach.
(Several servers on one Postgres was done since, with run leases: see
&lt;code&gt;todos/web-server-embedding.md&lt;/code&gt;, Remaining later work.)&lt;/p&gt;
&lt;h3 id="related-docs"&gt;Related docs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;todos/web-server-embedding.md&lt;/code&gt;, &lt;code&gt;.progress.md&lt;/code&gt;: the Host/Runner and the
HTTP server this builds on.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;todos/session-mailbox.md&lt;/code&gt;: mail, interrupts, control messages, watches.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/agents-server.md&lt;/code&gt;: the current API; sections to update are marked in
Phases 0 and 1.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/tui.md&lt;/code&gt;: TUI features that form the parity checklist of Phase 2.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/OS-API.md&lt;/code&gt;: the ECS layer; its &lt;code&gt;OS.Interfaces&lt;/code&gt; section is stale and
goes with D1.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-os-as-standalone-server.html" rel="alternate"/><summary type="text">Status: proposal, 2026-09-23, revised the same day after checking service</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-durable-workflows-howto.html</id><title type="text">Durable Workflows How-To</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/durable-workflows-howto.md"&gt;&lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="durable-workflows-how-to"&gt;Durable Workflows How-To&lt;/h2&gt;
&lt;p&gt;This guide shows how to exercise and extend the durable-workflow features in
&lt;code&gt;agents-exe&lt;/code&gt;.  Durable workflows let an agent turn pause after some tool calls,
persist its state, and resume later when external results arrive.&lt;/p&gt;
&lt;p&gt;The canonical example flow is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The user asks a question.
&lt;/li&gt;
&lt;li&gt;The LLM replies with three tool calls.
&lt;/li&gt;
&lt;li&gt;The runtime executes one call immediately and defers the other two.
&lt;/li&gt;
&lt;li&gt;The process yields (and can even be restarted).
&lt;/li&gt;
&lt;li&gt;External workers complete the deferred calls.
&lt;/li&gt;
&lt;li&gt;The runtime wakes the session with the results.
&lt;/li&gt;
&lt;li&gt;The LLM receives all three results and continues.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This guide covers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#running-the-demonstrator"&gt;A ready-to-run demonstrator&lt;/a&gt; that exercises the
flow without calling a real LLM.
&lt;/li&gt;
&lt;li&gt;&lt;a href="#core-concepts"&gt;Core concepts&lt;/a&gt; behind durable execution.
&lt;/li&gt;
&lt;li&gt;&lt;a href="#cli-commands-for-operators"&gt;CLI commands&lt;/a&gt; for operating durable sessions.
&lt;/li&gt;
&lt;li&gt;&lt;a href="#building-your-own-durable-agent"&gt;Building your own durable agent&lt;/a&gt; in
Haskell.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To run durable agents behind an HTTP API, with sessions in SQLite, see
&lt;a href="/agents-exe/docs-agents-server.html"&gt;agents-server.md&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="running-the-demonstrator"&gt;Running the demonstrator&lt;/h3&gt;
&lt;p&gt;The repository contains a self-contained executable called
&lt;code&gt;durable-workflow-demo&lt;/code&gt;.  It uses a mock LLM so you can run it without API
keys.&lt;/p&gt;
&lt;p&gt;Build and run:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cabal&lt;/span&gt; run durable-workflow-demo&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;You should see output similar to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Durable workflow demonstrator
=============================

Step 1: run the async scheduler on the LLM turn.
  [executing in-process] fetch_local
Yielded partial turn:
  completed: 1
    - fetch_local: result from fetch_local
  deferred: 2
    - fetch_remote_a token: 550e8400-e29b-41d4-a716-446655440000
    - fetch_remote_b token: 6ba7b810-9dad-11d1-80b4-00c04fd430c8

Step 2: complete the deferred calls from the outside world.
  providing result for token 550e8400-e29b-41d4-a716-446655440000
  providing result for token 6ba7b810-9dad-11d1-80b4-00c04fd430c8
Turn is now complete.

Step 3: resume the session until the LLM produces a final answer.

=== Final LLM response ===
All three calls are complete. Results:
- fetch_local: result from fetch_local
- fetch_remote_a: external result for fetch_remote_a
- fetch_remote_b: external result for fetch_remote_b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The source is in &lt;code&gt;examples/durable-workflow-demo/Main.hs&lt;/code&gt; and is heavily
commented.  It is the best starting point for adapting the workflow to your
own agents.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="core-concepts"&gt;Core concepts&lt;/h3&gt;
&lt;p&gt;Durable workflows are built from four composable layers.&lt;/p&gt;
&lt;h4 id="1-execution-mode"&gt;1. Execution mode&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Agent.ctxExecutionMode&lt;/code&gt; is either &lt;code&gt;Synchronous&lt;/code&gt; (default) or &lt;code&gt;Asynchronous&lt;/code&gt;.
Only asynchronous agents yield partial turns.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;asyncAgent &lt;span class="ot"&gt;=&lt;/span&gt; agent{ctxExecutionMode &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Asynchronous&lt;/span&gt;}&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;asyncAgent &lt;span class="ot"&gt;=&lt;/span&gt; withExecutionMode &lt;span class="dt"&gt;Asynchronous&lt;/span&gt; agent&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="2-tool-call-policy"&gt;2. Tool-call policy&lt;/h4&gt;
&lt;p&gt;A &lt;code&gt;ToolCallPolicy&lt;/code&gt; is a pure function that decides, for every tool call,
whether to run it synchronously, defer it, run it asynchronously, or isolate
it:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;policy ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LlmToolCall&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolCallDisposition&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;policy _ctx call&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; callName call &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;fetch_local&amp;quot;&lt;/span&gt;  &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunSync&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; callName call &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_command&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunIsolated&lt;/span&gt; (&lt;span class="dt"&gt;Docker&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;agents-exe/bash-runner:latest&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt;                       &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Defer&lt;/span&gt; (&lt;span class="dt"&gt;Reason&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;waiting for external service&amp;quot;&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Dispositions can be decorated with timeouts, retries, cache keys, or labels:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Decorate&lt;/span&gt; [&lt;span class="dt"&gt;WithTimeout&lt;/span&gt; &lt;span class="dv"&gt;30&lt;/span&gt;, &lt;span class="dt"&gt;WithRetries&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;] &lt;span class="dt"&gt;RunSync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Agents loaded from JSON can declare the same policy without Haskell code; see
&lt;a href="#configuring-an-agent-for-durable-mode"&gt;Configuring an agent for durable mode&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="3-pluggable-executor"&gt;3. Pluggable executor&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;ToolExecutor&lt;/code&gt; decouples &lt;em&gt;how&lt;/em&gt; a call runs from the session loop.  The
runtime provides &lt;code&gt;inProcessExecutor&lt;/code&gt;, &lt;code&gt;yieldingExecutor&lt;/code&gt;, &lt;code&gt;cachingExecutor&lt;/code&gt;,
&lt;code&gt;isolatedExecutor&lt;/code&gt;, and &lt;code&gt;mkDurableExecutor&lt;/code&gt; to compose them.&lt;/p&gt;
&lt;p&gt;For most use cases you only need to set &lt;code&gt;ctxToolCallPolicy&lt;/code&gt;; the session loop
falls back to the agent’s native &lt;code&gt;toolCall&lt;/code&gt; for synchronous calls.&lt;/p&gt;
&lt;h4 id="4-persistence-and-wakeresume"&gt;4. Persistence and wake/resume&lt;/h4&gt;
&lt;p&gt;When a call is deferred, the runtime optionally stores a serialisable
&lt;code&gt;ToolContinuationSnapshot&lt;/code&gt; in a &lt;code&gt;ContinuationStore&lt;/code&gt; and emits a
&lt;code&gt;PartialUserTurn&lt;/code&gt;.  Later:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wakeSession&lt;/code&gt; injects external results.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resumeSession&lt;/code&gt; continues execution until completion or the next yield.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionBackend&lt;/code&gt; (file, SQLite, or composite) stores session state across
process restarts.
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="cli-commands-for-operators"&gt;CLI commands for operators&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;agents-exe session&lt;/code&gt; command group creates and operates on stored
sessions.  These commands load sessions through the configured file-based
&lt;code&gt;SessionStore&lt;/code&gt; and use the first supplied &lt;code&gt;--agent-file&lt;/code&gt; when execution needs
to advance.  Every command that advances execution forces the agent into
asynchronous mode.&lt;/p&gt;
&lt;h4 id="configuring-an-agent-for-durable-mode"&gt;Configuring an agent for durable mode&lt;/h4&gt;
&lt;p&gt;To defer calls from the CLI, declare a tool-call policy in the agent JSON.  The
policy and execution mode are applied everywhere the agent runs: &lt;code&gt;run&lt;/code&gt;, the
TUI, the &lt;code&gt;session&lt;/code&gt; commands, and sub-agents.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;executionMode&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;asynchronous&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;toolCallPolicyConfig&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runSync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;fetch_remote_a&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;disposition&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;defer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;external worker&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;fetch_remote_b&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;disposition&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;defer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;external worker&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;build_project&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;disposition&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runAsync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Rules match on the exact tool name; calls that match no rule get &lt;code&gt;default&lt;/code&gt;.
Available disposition tags are &lt;code&gt;runSync&lt;/code&gt;, &lt;code&gt;runAsync&lt;/code&gt;, &lt;code&gt;runIsolated&lt;/code&gt; (with a
&lt;code&gt;spec&lt;/code&gt;), &lt;code&gt;defer&lt;/code&gt; (with a &lt;code&gt;reason&lt;/code&gt;), and &lt;code&gt;decorate&lt;/code&gt; (with &lt;code&gt;decorators&lt;/code&gt; and
&lt;code&gt;inner&lt;/code&gt;).  Without &lt;code&gt;toolCallPolicyConfig&lt;/code&gt;, every call runs synchronously and
nothing is ever deferred.&lt;/p&gt;
&lt;p&gt;See &lt;a href="/agents-exe/docs-async-tool-calls.html"&gt;async-tool-calls.md&lt;/a&gt; for the related
&lt;code&gt;asyncYieldStrategy&lt;/code&gt;, &lt;code&gt;maxConcurrency&lt;/code&gt;, and &lt;code&gt;asyncCallTimeoutSeconds&lt;/code&gt; fields.&lt;/p&gt;
&lt;h4 id="walkthrough"&gt;Walkthrough&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 1. Create a session holding the initial prompt.  The LLM is not called yet.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json session start &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Fetch the local and remote data, then summarise it&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# session-id: &amp;lt;session-id&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 2. Advance until the turn yields on deferred calls.&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json session resume &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 3. See what is waiting on the outside world.&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session pending &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 4. Provide each deferred result.&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session complete &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;token&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; result.txt&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 5. Let the LLM continue with all results.&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json session resume &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;agents-exe run&lt;/code&gt; can start the same flow: when a turn waits on deferred calls
it stops, stores the session, and prints a JSON report with the session id
and continuation tokens.  Continue it with &lt;code&gt;session complete&lt;/code&gt; and
&lt;code&gt;session resume&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The TUI (&lt;code&gt;agents-exe tui&lt;/code&gt;) can also answer deferred calls directly, without
the &lt;code&gt;session&lt;/code&gt; CLI: a run that stops on deferred calls shows a Pending panel
listing each call, and &lt;code&gt;Ctrl+Y&lt;/code&gt; (&lt;code&gt;answer-pending&lt;/code&gt;) puts the message editor
into “answer mode” for the selected one (&lt;code&gt;Ctrl+O&lt;/code&gt; moves the selection; &lt;code&gt;Ctrl+W&lt;/code&gt;
fails it instead) — type the result and send it, which
calls the same &lt;code&gt;completeCall&lt;/code&gt; mechanism (with &lt;code&gt;autoResume&lt;/code&gt; set) the server’s
own &lt;code&gt;GET /v1/sessions/:id/pending&lt;/code&gt; workers use, so the run resumes on its
own. See &lt;code&gt;documentation/tui.md&lt;/code&gt;’s “Pending calls” section.&lt;/p&gt;
&lt;h4 id="start-a-new-session"&gt;Start a new session&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json session start &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json session start &lt;span class="at"&gt;--step&lt;/span&gt; &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Creates a new asynchronous session whose first turn contains the prompt, stores
it, and prints its &lt;code&gt;session-id&lt;/code&gt;.  By default no scheduling happens, which
leaves every step to an external process or operator.  With &lt;code&gt;--step&lt;/code&gt;, it also
runs one scheduling step right away.  It accepts the same prompt options as
&lt;code&gt;run&lt;/code&gt; (&lt;code&gt;--prompt&lt;/code&gt;, &lt;code&gt;--file&lt;/code&gt;, media attachments, and so on).&lt;/p&gt;
&lt;h4 id="run-exactly-one-step"&gt;Run exactly one step&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json session step &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Runs a single scheduling step and prints the resulting session state: a turn
waiting for the LLM, the LLM’s tool calls, a yielded partial turn, or the
final answer.&lt;/p&gt;
&lt;h4 id="pause-after-one-async-step"&gt;Pause after one async step&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json session pause &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Runs one asynchronous step and persists the resulting session, like &lt;code&gt;step&lt;/code&gt;.
If the turn yields, it prints the continuation tokens for deferred calls.&lt;/p&gt;
&lt;h4 id="resume-until-completion-or-next-yield"&gt;Resume until completion or next yield&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json session resume &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Calls &lt;code&gt;resumeSession&lt;/code&gt; and persists after each yield.&lt;/p&gt;
&lt;h4 id="list-pending-deferred-calls"&gt;List pending deferred calls&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session pending &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Shows each deferred call’s tool name, call id, continuation token, and
disposition.&lt;/p&gt;
&lt;h4 id="inject-an-external-result"&gt;Inject an external result&lt;/h4&gt;
&lt;p&gt;Create a result file.  JSON is parsed as a &lt;code&gt;UserToolResponse&lt;/code&gt;; anything else
is treated as plain text.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# JSON result&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;42&amp;quot;}&amp;#39;&lt;/span&gt; &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; result.json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session complete &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;token&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; result.json&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Plain-text result&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;42&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; result.txt&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; session complete &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;token&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; result.txt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;complete&lt;/code&gt; scans all sessions in the store to find the one containing the
token.&lt;/p&gt;
&lt;h4 id="run-deferred-isolated-calls"&gt;Run deferred isolated calls&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./my-agent.json session run-isolated &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;If the agent has &lt;code&gt;ctxDeploymentRunner&lt;/code&gt; configured, this executes deferred
&lt;code&gt;RunIsolated&lt;/code&gt; calls through the runner and injects their results back into the
session.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="building-your-own-durable-agent"&gt;Building your own durable agent&lt;/h3&gt;
&lt;p&gt;The demo is a minimal Haskell program.  The key pieces are reproduced below.&lt;/p&gt;
&lt;h4 id="1-make-the-agent-asynchronous-and-set-a-policy"&gt;1. Make the agent asynchronous and set a policy&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Base&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;myPolicy ::&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicy&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;myPolicy _ctx call&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; callName call &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;fetch_local&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunSync&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt;                      &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Defer&lt;/span&gt; (&lt;span class="dt"&gt;Reason&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;external&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;agent&amp;#39; &lt;span class="ot"&gt;=&lt;/span&gt; agent&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { ctxExecutionMode &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Asynchronous&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , ctxToolCallPolicy &lt;span class="ot"&gt;=&lt;/span&gt; myPolicy&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="2-run-the-async-scheduler"&gt;2. Run the async scheduler&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Step&lt;/span&gt; (runStepM)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(_agent, result) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runStepM convId agent&amp;#39; session0&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; result &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Left&lt;/span&gt; final      &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Session completed immediately.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Right&lt;/span&gt; session1  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Session yielded.&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="3-wake-with-external-results"&gt;3. Wake with external results&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Wake&lt;/span&gt; (wakeSession)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; responses &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ (token, &lt;span class="dt"&gt;TextResponse&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;external answer&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;|&lt;/span&gt; (token, _call) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; deferredCalls&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;session2 &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; wakeSession session1 responses&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="4-resume"&gt;4. Resume&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Wake&lt;/span&gt; (resumeSession)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;final &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; resumeSession convId agent&amp;#39; session2&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; final &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Left&lt;/span&gt; (llmTurn, _session) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;print&lt;/span&gt; (llmTurn&lt;span class="op"&gt;.&lt;/span&gt;llmResponse&lt;span class="op"&gt;.&lt;/span&gt;responseText)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Right&lt;/span&gt; session3           &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Yielded again.&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="5-add-durable-storage"&gt;5. Add durable storage&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Async&lt;/span&gt; (mkSqliteContinuationStore)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.SessionStore&lt;/span&gt; (mkSqliteSessionStore)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Database.SQLite.Simple&lt;/span&gt; (open)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;conn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; open &lt;span class="st"&gt;&amp;quot;.agents-durable.db&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;backend &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; mkSqliteSessionStore conn&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;store   &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; mkSqliteContinuationStore conn&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; durableAgent &lt;span class="ot"&gt;=&lt;/span&gt; withDurableWorkflows backend store agent&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;withDurableWorkflows&lt;/code&gt; is a convenience combinator that installs both a
session backend and a continuation store.&lt;/p&gt;
&lt;h4 id="6-add-a-tool-cache"&gt;6. Add a tool cache&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Tools.Cache&lt;/span&gt; (mkSqliteToolCache)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;cache &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; mkSqliteToolCache &lt;span class="st"&gt;&amp;quot;.agents-cache.db&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; cachedAgent &lt;span class="ot"&gt;=&lt;/span&gt; withToolCache agent&amp;#39; cache&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Cached synchronous calls are skipped on resume if their result is already in
the cache.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="isolated-execution"&gt;Isolated execution&lt;/h3&gt;
&lt;p&gt;To run a tool call outside the current process, provide a &lt;code&gt;DeploymentRunner&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Session.Base&lt;/span&gt; (dockerRunner, localProcessRunner)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runner &lt;span class="ot"&gt;=&lt;/span&gt; localProcessRunner &lt;span class="st"&gt;&amp;quot;./worker.sh&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runner &lt;span class="ot"&gt;=&lt;/span&gt; dockerRunner &lt;span class="st"&gt;&amp;quot;agents-exe/bash-runner:latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;isolatedAgent &lt;span class="ot"&gt;=&lt;/span&gt; withDeploymentRunner runner durableAgent&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The worker receives a stable JSON envelope on stdin and must print a result
envelope on stdout.  See &lt;code&gt;System.Agents.Session.Isolation&lt;/code&gt; for the envelope
schema, or look at the worker script in &lt;code&gt;test/DurableWorkflowTests.hs&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="testing"&gt;Testing&lt;/h3&gt;
&lt;p&gt;The durable-workflow implementation is covered by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test/DurableWorkflowTests.hs&lt;/code&gt; — policy, wake/resume, cache, backends,
isolation envelopes, and integration.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test/DurableWorkflowDeterminismTests.hs&lt;/code&gt; — resume-twice and edge-case
tests.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test/SessionDurableTests.hs&lt;/code&gt; — CLI helper tests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Run them with:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cabal&lt;/span&gt; test agents-tests&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="further-reading"&gt;Further reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;todos/durable-workflows.md&lt;/code&gt; — design plan and architectural decisions.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;todos/durable-workflows.progress.md&lt;/code&gt; — implementation progress.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;todos/durable-workflows-cli-start-plan.md&lt;/code&gt; — design of &lt;code&gt;session start&lt;/code&gt; and
&lt;code&gt;session step&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;examples/durable-workflow-demo/Main.hs&lt;/code&gt; — runnable mock-LLM demo.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/cli-commands.md&lt;/code&gt; — full CLI reference, including &lt;code&gt;agents session&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/sessions.md&lt;/code&gt; — session storage and multi-location stores.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/async-tool-calls.md&lt;/code&gt; — background tool calls in the same process,
with progress, cancellation and partial answers.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/agents-server.md&lt;/code&gt; — the same flow over HTTP, with sessions in SQLite
and live events.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-durable-workflows-howto.html" rel="alternate"/><summary type="text">This guide shows how to exercise and extend the durable-workflow features in `agents-exe`. Durable workflows let an agent turn pause after some tool calls, persist its state, and resume later when external results arrive. The canonical exam</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs.html</id><title type="text">Specs</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;h2 id="specs"&gt;Specs&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;todos/&lt;/code&gt; directory holds the design documents behind the larger
features (durable workflows, asynchronous tool calls, the session mailbox,
partial application of tool arguments, the standalone server) and their
progress notes. Most start with a &lt;strong&gt;Status&lt;/strong&gt; line saying what of it has
shipped, which is reproduced here. These pages are generated from the
&lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/../tree/main/todos"&gt;agents-exe repository&lt;/a&gt;: the repository is the
canonical source, and may be ahead of what is published here.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-async-tool-calls.html"&gt;&lt;strong&gt;Asynchronous / Interruptible Tool Calls&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; no status line yet
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-async-tool-calls-progress.html"&gt;&lt;strong&gt;Async Tool Calls Implementation Progress&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; no status line yet
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-bash-tools-v2.html"&gt;&lt;strong&gt;Spec: bash tools v2, long-running tool processes&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; proposal, 2026-09-25, from issue &lt;a href="/agents-exe/hashtags/539.html"&gt;&lt;span class="hashtag" data-hashtag="539"&gt;#539&lt;/span&gt;&lt;/a&gt; and a robot-chat conversation
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-durable-workflows-cli-start-plan.html"&gt;&lt;strong&gt;Plan: Durable execution from the CLI&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; no status line yet
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-durable-workflows.html"&gt;&lt;strong&gt;Plan: Durable Workflows for agents-exe&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; no status line yet
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-durable-workflows.progress.html"&gt;&lt;strong&gt;Durable Workflows — Implementation Progress&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; no status line yet
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-os-as-standalone-server.html"&gt;&lt;strong&gt;Spec: the OS as a standalone server (TUI and web UI as clients)&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; proposal, 2026-09-23, revised the same day after checking service
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-salmon-preview-deployment.html"&gt;&lt;strong&gt;Spec: a salmon-driven preview deployment of agents-server&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; proposal, 2026-10-03. Nothing implemented. A design pass with a
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-session-mailbox.html"&gt;&lt;strong&gt;Spec: the session mailbox (agent-to-agent mail, suspended tool calls, interrupts, tool-call wrappers)&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; proposal, 2026-09-22. Nothing implemented. Supersedes the designs in
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-tool-partial-application.html"&gt;&lt;strong&gt;Spec: partial application of tool arguments&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; Phases 1-7 and §8.4 (&lt;code&gt;derive_agent&lt;/code&gt;) done as of 2026-09-21. Phase 1 done
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-web-server-embedding.html"&gt;&lt;strong&gt;Spec: embedding agents-exe in a web server&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; proposed (2026-09-18)
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs-web-server-embedding.progress.html"&gt;&lt;strong&gt;Web server embedding — Implementation Progress&lt;/strong&gt;&lt;/a&gt;, &lt;em&gt;Status:&lt;/em&gt; no status line yet
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs.html" rel="alternate"/><summary type="text">The design documents under todos/, each headed by a Status line saying what of it has shipped.</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-OS-API.html</id><title type="text">OS Model API Reference</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/OS-API.md"&gt;&lt;code&gt;documentation/OS-API.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="os-model-api-reference"&gt;OS Model API Reference&lt;/h2&gt;
&lt;p&gt;Complete API reference for the Entity-Component-System (ECS) based OS architecture.&lt;/p&gt;
&lt;h3 id="table-of-contents"&gt;Table of Contents&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#core-ecs-types"&gt;Core ECS Types&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#world-operations"&gt;World Operations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#agent-operations"&gt;Agent Operations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#toolbox-operations"&gt;Toolbox Operations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#resource-management"&gt;Resource Management&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#concurrent-access"&gt;Concurrent Access&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#conversation-tracking"&gt;Conversation Tracking&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#os-events"&gt;OS Events&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#persistence-layer"&gt;Persistence Layer&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3 id="core-ecs-types"&gt;Core ECS Types&lt;/h3&gt;
&lt;h4 id="entityid"&gt;EntityId&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Unique identifier for any entity in the system.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; {&lt;span class="ot"&gt; unEntityId ::&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt; }&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Ord&lt;/span&gt;, &lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Hashable&lt;/span&gt;, &lt;span class="dt"&gt;FromJSON&lt;/span&gt;, &lt;span class="dt"&gt;ToJSON&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Generate a new unique EntityId.&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;newEntityId ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eid1 &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newEntityId  &lt;span class="co"&gt;-- Unique ID&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eid2 &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newEntityId  &lt;span class="co"&gt;-- Different unique ID&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;assert (eid1 &lt;span class="op"&gt;/=&lt;/span&gt; eid2)  &lt;span class="co"&gt;-- True&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="phantom-typed-entity-ids"&gt;Phantom-Typed Entity IDs&lt;/h4&gt;
&lt;p&gt;Phantom types provide compile-time safety for entity operations:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; {&lt;span class="ot"&gt; unAgentId ::&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; }&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; {&lt;span class="ot"&gt; unToolboxId ::&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; }&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; {&lt;span class="ot"&gt; unConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; }&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt; {&lt;span class="ot"&gt; unTurnId ::&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ToolCallId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCallId&lt;/span&gt; {&lt;span class="ot"&gt; unToolCallId ::&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; {&lt;span class="ot"&gt; unResourceId ::&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newEntityId&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; agentId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; eid&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; toolboxId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; eid  &lt;span class="co"&gt;-- Same underlying ID, different type&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Type-safe: Can&amp;#39;t mix up IDs&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;useAgent agentId       &lt;span class="co"&gt;-- OK&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;useAgent toolboxId     &lt;span class="co"&gt;-- Compile error!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="component-typeclass"&gt;Component Typeclass&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Type-level identifier for component types.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt; {&lt;span class="ot"&gt; unComponentTypeId ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; }&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | A component is any data type that can be attached to an entity.&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;class&lt;/span&gt; &lt;span class="dt"&gt;Component&lt;/span&gt; a &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;    componentId ::&lt;/span&gt; &lt;span class="dt"&gt;Proxy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Creating a custom component:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;MyComponent&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;MyComponent&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; mcValue ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mcName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;FromJSON&lt;/span&gt; &lt;span class="dt"&gt;MyComponent&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;ToJSON&lt;/span&gt; &lt;span class="dt"&gt;MyComponent&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Choose a unique ID (check existing IDs to avoid collisions)&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;Component&lt;/span&gt; &lt;span class="dt"&gt;MyComponent&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    componentId _ &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt; &lt;span class="dv"&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="world-operations"&gt;World Operations&lt;/h3&gt;
&lt;h4 id="creating-and-managing-worlds"&gt;Creating and Managing Worlds&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | The world contains all component stores.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; {&lt;span class="ot"&gt; componentStores ::&lt;/span&gt; &lt;span class="dt"&gt;HashMap&lt;/span&gt; &lt;span class="dt"&gt;ComponentTypeId&lt;/span&gt; (&lt;span class="dt"&gt;TVar&lt;/span&gt; &lt;span class="dt"&gt;Any&lt;/span&gt;) }&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Create an empty world.&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;newWorld ::&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Register a component store for a component type.&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;registerComponentStore ::&lt;/span&gt; (&lt;span class="dt"&gt;Component&lt;/span&gt; a, &lt;span class="dt"&gt;Typeable&lt;/span&gt; a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Proxy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Data.Proxy&lt;/span&gt; (&lt;span class="dt"&gt;Proxy&lt;/span&gt;(&lt;span class="op"&gt;..&lt;/span&gt;))&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create world with agent components&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;world &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    w &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newWorld&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    w&amp;#39; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; registerComponentStore w (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentConfig&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    w&amp;#39;&amp;#39; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; registerComponentStore w&amp;#39; (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentState&lt;/span&gt;)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; w&amp;#39;&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="entity-operations"&gt;Entity Operations&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Create a new entity.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;createEntity ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Check if an entity exists (has any component).&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;entityExists ::&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Get all entities with a specific component.&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;allEntitiesWithComponent ::&lt;/span&gt; (&lt;span class="dt"&gt;Component&lt;/span&gt; a, &lt;span class="dt"&gt;Typeable&lt;/span&gt; a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; [&lt;span class="dt"&gt;EntityId&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createEntity&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;exists &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; entityExists world eid  &lt;span class="co"&gt;-- False&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; setComponent world eid (&lt;span class="dt"&gt;AgentConfig&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;test&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;exists&amp;#39; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; entityExists world eid  &lt;span class="co"&gt;-- True&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find all agents&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;agentIds &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; allEntitiesWithComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentConfig&lt;/span&gt; world&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="component-operations"&gt;Component Operations&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Get a component for an entity.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getComponent ::&lt;/span&gt; (&lt;span class="dt"&gt;Component&lt;/span&gt; a, &lt;span class="dt"&gt;Typeable&lt;/span&gt; a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Set a component for an entity.&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;setComponent ::&lt;/span&gt; (&lt;span class="dt"&gt;Component&lt;/span&gt; a, &lt;span class="dt"&gt;Typeable&lt;/span&gt; a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Modify a component for an entity.&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;modifyComponent ::&lt;/span&gt; (&lt;span class="dt"&gt;Component&lt;/span&gt; a, &lt;span class="dt"&gt;Typeable&lt;/span&gt; a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Remove a component from an entity.&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;removeComponent ::&lt;/span&gt; (&lt;span class="dt"&gt;Component&lt;/span&gt; a, &lt;span class="dt"&gt;Typeable&lt;/span&gt; a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Check if an entity has a specific component.&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;hasComponent ::&lt;/span&gt; (&lt;span class="dt"&gt;Component&lt;/span&gt; a, &lt;span class="dt"&gt;Typeable&lt;/span&gt; a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Set component&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; setComponent world eid &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { agentName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentModel &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;key1&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentSystemPrompt &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;You are helpful&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Get component&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;mConfig &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; getComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentConfig&lt;/span&gt; world eid&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; mConfig &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;No agent config&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Just&lt;/span&gt; config &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Agent: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;++&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt; config&lt;span class="op"&gt;.&lt;/span&gt;agentName&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Modify component&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; modifyComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentConfig&lt;/span&gt; world eid &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;\&lt;/span&gt;c &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; c { agentName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;renamed-agent&amp;quot;&lt;/span&gt; }&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check and remove&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;hasIt &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; hasComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentConfig&lt;/span&gt; world eid&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;when hasIt &lt;span class="op"&gt;$&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; removeComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentConfig&lt;/span&gt; world eid&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="agent-operations"&gt;Agent Operations&lt;/h3&gt;
&lt;h4 id="agent-configuration"&gt;Agent Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; agentName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                    &lt;span class="co"&gt;-- ^ Human-readable name&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentModel ::&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt;            &lt;span class="co"&gt;-- ^ LLM configuration&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentSystemPrompt ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;            &lt;span class="co"&gt;-- ^ System instructions&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentToolboxBindings ::&lt;/span&gt; [&lt;span class="dt"&gt;ToolboxBindingSpec&lt;/span&gt;]  &lt;span class="co"&gt;-- ^ Bound toolboxes&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; modelFlavor ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;      &lt;span class="co"&gt;-- ^ Provider (openai, mistral, etc.)&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; modelUrl ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;         &lt;span class="co"&gt;-- ^ API endpoint&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; modelName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;        &lt;span class="co"&gt;-- ^ Model identifier&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; modelApiKeyId ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;    &lt;span class="co"&gt;-- ^ Key reference&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="agent-state"&gt;Agent State&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentState&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; agentStatus ::&lt;/span&gt; &lt;span class="dt"&gt;AgentStatus&lt;/span&gt;           &lt;span class="co"&gt;-- ^ Current status&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentCurrentConversation ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; agentCreatedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AgentStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentIdle&lt;/span&gt;                           &lt;span class="co"&gt;-- ^ Available for work&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AgentBusy&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt;                    &lt;span class="co"&gt;-- ^ Executing a turn&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AgentError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                     &lt;span class="co"&gt;-- ^ Error state&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example: Creating an Agent&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;createAgent ::&lt;/span&gt; &lt;span class="dt"&gt;OS&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;createAgent os config &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    eid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createEntity&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    now &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getCurrentTime&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        setComponent (osWorld os) eid config&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        setComponent (osWorld os) eid &lt;span class="dt"&gt;AgentState&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            { agentStatus &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentIdle&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , agentCurrentConversation &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , agentCreatedAt &lt;span class="ot"&gt;=&lt;/span&gt; now&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; eid&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Usage&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; config &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { agentName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;coder-agent&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentModel &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai-key&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentSystemPrompt &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;You are a helpful coding assistant&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;agentId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createAgent os config&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="toolbox-operations"&gt;Toolbox Operations&lt;/h3&gt;
&lt;h4 id="toolbox-configuration"&gt;Toolbox Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolboxConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; toolboxName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;           &lt;span class="co"&gt;-- ^ Human-readable name&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolboxType ::&lt;/span&gt; &lt;span class="dt"&gt;ToolboxType&lt;/span&gt;    &lt;span class="co"&gt;-- ^ Type of toolbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolboxSettings ::&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;      &lt;span class="co"&gt;-- ^ Type-specific settings&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolboxType&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeBash&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeMCP&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeOpenAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypePostgREST&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeSqlite&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeSystem&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeDeveloper&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeLua&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeSkills&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="toolbox-state"&gt;Toolbox State&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolboxState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxState&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; toolboxScope ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceScope&lt;/span&gt;     &lt;span class="co"&gt;-- ^ Resource lifetime scope&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolboxStatus ::&lt;/span&gt; &lt;span class="dt"&gt;ToolboxStatus&lt;/span&gt;    &lt;span class="co"&gt;-- ^ Current status&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolboxResourceRef ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt;  &lt;span class="co"&gt;-- ^ Associated resource&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolboxStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxInitializing&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxReady&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxDisposed&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="resource-scope"&gt;Resource Scope&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ResourceScope&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ScopeGlobal&lt;/span&gt;                       &lt;span class="co"&gt;-- ^ Global/program scope&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ScopeAgent&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt;                &lt;span class="co"&gt;-- ^ Per-agent scope&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ScopeConversation&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;  &lt;span class="co"&gt;-- ^ Per-conversation scope&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example: Creating Toolboxes&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create a bash toolbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; bashConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { toolboxName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash-tools&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , toolboxType &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeBash&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , toolboxSettings &lt;span class="ot"&gt;=&lt;/span&gt; object [&lt;span class="st"&gt;&amp;quot;directory&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./tools&amp;quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;bashId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createToolbox os bashConfig&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create a SQLite toolbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; sqliteConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { toolboxName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;memory-db&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , toolboxType &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxTypeSqlite&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , toolboxSettings &lt;span class="ot"&gt;=&lt;/span&gt; object &lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ &lt;span class="st"&gt;&amp;quot;path&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./memory.db&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="st"&gt;&amp;quot;access&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;readwrite&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sqliteId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createToolbox os sqliteConfig&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Bind toolboxes to agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; agentConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ unToolboxId bashId&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , unToolboxId sqliteId&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="resource-management"&gt;Resource Management&lt;/h3&gt;
&lt;h4 id="resource-types"&gt;Resource Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ResourceType&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SqliteResource&lt;/span&gt; &lt;span class="dt"&gt;SqliteConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;LuaResource&lt;/span&gt; &lt;span class="dt"&gt;LuaConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;HttpResource&lt;/span&gt; &lt;span class="dt"&gt;HttpConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;CustomResource&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ResourceHandle&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ResourceHandle&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; handleId ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; handleCleanup ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; handleAccess ::&lt;/span&gt; (&lt;span class="dt"&gt;ResourceAccessor&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; a&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ResourceInfo&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ResourceInfo&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; resourceId ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resourceScope ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceScope&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resourceType ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceType&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resourceCreatedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="resource-context"&gt;Resource Context&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ResourceContext&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ResourceContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; contextScope ::&lt;/span&gt; [&lt;span class="dt"&gt;ScopeLevel&lt;/span&gt;]      &lt;span class="co"&gt;-- ^ Active scope path&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; contextRegistry ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceRegistry&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ScopeLevel&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ProgramScope&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AgentScope&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxScope&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ConversationScope&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TurnScope&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallScope&lt;/span&gt; &lt;span class="dt"&gt;ToolCallId&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="resource-operations"&gt;Resource Operations&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Create a new resource.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;createResource ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ResourceContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ResourceType&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ResourceHandle&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Cleanup all resources in a scope.&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;cleanupScope ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceRegistry&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ScopeLevel&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Check if a resource is valid in given scopes.&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;isResourceValid ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceScope&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;ScopeLevel&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Access a resource with a function.&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withResource ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceRegistry&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;ResourceAccessor&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Get total resource count.&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getResourceCount ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceRegistry&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example: Resource Lifecycle&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Resources&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create registry and context&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;registry &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically newResourceRegistry&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; ctx &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ResourceContext&lt;/span&gt; [&lt;span class="dt"&gt;ProgramScope&lt;/span&gt;] registry&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create SQLite resource&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;rid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createResource ctx (&lt;span class="dt"&gt;SqliteResource&lt;/span&gt; config) &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;rid &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    conn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; openConnection config&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&gt;ResourceHandle&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { handleId &lt;span class="ot"&gt;=&lt;/span&gt; rid&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , handleCleanup &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Closing SQLite connection&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            closeConnection conn&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , handleAccess &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;f &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; f (&lt;span class="dt"&gt;SqliteAccessor&lt;/span&gt; conn)&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Use the resource&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; withResource registry rid &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;accessor &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; accessor &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;SqliteAccessor&lt;/span&gt; conn &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; queryDatabase conn &lt;span class="st"&gt;&amp;quot;SELECT * FROM table&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Later, cleanup all agent resources&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;cleanupScope registry (&lt;span class="dt"&gt;AgentScope&lt;/span&gt; agentId)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="concurrent-access"&gt;Concurrent Access&lt;/h3&gt;
&lt;h4 id="access-patterns"&gt;Access Patterns&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AccessPattern&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ExclusiveAccess&lt;/span&gt;      &lt;span class="co"&gt;-- ^ Single accessor (TMVar)&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ReadWriteAccess&lt;/span&gt;      &lt;span class="co"&gt;-- ^ Multiple readers, single writer (RWLock)&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PoolAccess&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;       &lt;span class="co"&gt;-- ^ Bounded pool (TBQueue)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StatelessAccess&lt;/span&gt;      &lt;span class="co"&gt;-- ^ No synchronization needed&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AccessControl&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AccessControl&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; accessPattern ::&lt;/span&gt; &lt;span class="dt"&gt;AccessPattern&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; accessTimeout ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;NominalDiffTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="resource-monad"&gt;Resource Monad&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Monad for resource operations.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; {&lt;span class="ot"&gt; unResourceM ::&lt;/span&gt; &lt;span class="dt"&gt;ReaderT&lt;/span&gt; &lt;span class="dt"&gt;ResourceContext&lt;/span&gt; (&lt;span class="dt"&gt;ExceptT&lt;/span&gt; &lt;span class="dt"&gt;ResourceError&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt;) a }&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Functor&lt;/span&gt;, &lt;span class="dt"&gt;Applicative&lt;/span&gt;, &lt;span class="dt"&gt;Monad&lt;/span&gt;, &lt;span class="dt"&gt;MonadIO&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Run a ResourceM computation.&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;runResourceM ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ResourceError&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Resource errors.&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ResourceError&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ResourceNotFound&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ResourceBusy&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ResourceClosed&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ResourceAccessTimeout&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="dt"&gt;NominalDiffTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ResourceInvalidAccess&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="access-operations"&gt;Access Operations&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Execute with exclusive access.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withExclusive ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Execute with read access.&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withRead ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Execute with write access.&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withWrite ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Execute with pooled resource.&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withPooled ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Execute without synchronization.&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withStateless ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example: Concurrent Access Patterns&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Concurrent&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- SQLite with WAL mode (supports concurrent reads)&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sqliteRid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createSqliteResource ctx config &lt;span class="dt"&gt;True&lt;/span&gt;  &lt;span class="co"&gt;-- WAL mode enabled&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Multiple concurrent reads (safe)&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;forConcurrently_ [&lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;..&lt;/span&gt;&lt;span class="dv"&gt;10&lt;/span&gt;] &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;_ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runResourceM ctx &lt;span class="op"&gt;$&lt;/span&gt; withRead sqliteRid &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        queryData&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;print&lt;/span&gt; result&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Exclusive write (blocks readers)&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runResourceM ctx &lt;span class="op"&gt;$&lt;/span&gt; withWrite sqliteRid &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    modifyData&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Lua interpreter (requires exclusive access)&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;luaRid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createLuaResource ctx config&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runResourceM ctx &lt;span class="op"&gt;$&lt;/span&gt; withExclusive luaRid &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    runScript &lt;span class="st"&gt;&amp;quot;return 1 + 1&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- HTTP connection pool&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;httpRid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createHttpPool ctx &lt;span class="dv"&gt;10&lt;/span&gt;  &lt;span class="co"&gt;-- 10 connections&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;results &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; forConcurrently urls &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;url &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    runResourceM ctx &lt;span class="op"&gt;$&lt;/span&gt; withPooled httpRid &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        fetchUrl url&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="initialization-helpers"&gt;Initialization Helpers&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Initialize access control.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;initAccessControl ::&lt;/span&gt; &lt;span class="dt"&gt;AccessPattern&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;NominalDiffTime&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AccessControl&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Initialize SQLite access (WAL mode flag).&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;initSqliteAccess ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;SqliteAccess&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Initialize Lua access.&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;initLuaAccess ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;LuaAccess&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Initialize HTTP access.&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;initHttpAccess ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;HttpAccess&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="conversation-tracking"&gt;Conversation Tracking&lt;/h3&gt;
&lt;h4 id="conversation-components"&gt;Conversation Components&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ConversationConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; conversationTitle ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationMetadata ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ConversationState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationState&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; conversationAgentId ::&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationStatus ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationStartedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationLastActivity ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ConversationStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationActive&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ConversationPaused&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ConversationCompleted&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ConversationError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="turn-components"&gt;Turn Components&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;TurnConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TurnConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; turnConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; turnParentTurnId ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;TurnState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TurnState&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; turnStatus ::&lt;/span&gt; &lt;span class="dt"&gt;TurnStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; turnStartedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; turnCompletedAt ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;TurnStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TurnStarting&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TurnProcessing&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TurnWaitingForTools&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TurnCompleted&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TurnError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tool-call-components"&gt;Tool Call Components&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolCallConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCallConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; toolCallTurnId ::&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolCallParentId ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ToolCallId&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolCallName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolCallInput ::&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolCallState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCallState&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; toolCallStatus ::&lt;/span&gt; &lt;span class="dt"&gt;ToolCallStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolCallResult ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolCallStartedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolCallCompletedAt ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolCallStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPending&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallExecuting&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallCompleted&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallFailed&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Generic&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="lineage-tracking"&gt;Lineage Tracking&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; {&lt;span class="ot"&gt; unLineage ::&lt;/span&gt; [&lt;span class="dt"&gt;LineageFrame&lt;/span&gt;] }&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;LineageFrame&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;LineageFrame&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; frameType ::&lt;/span&gt; &lt;span class="dt"&gt;FrameType&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; frameEntityId ::&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; frameTimestamp ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    } &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;FrameType&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ProgramFrame&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AgentFrame&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolboxFrame&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ConversationFrame&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TurnFrame&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallFrame&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Enum&lt;/span&gt;, &lt;span class="dt"&gt;Bounded&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="lineage-operations"&gt;Lineage Operations&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Empty lineage.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;emptyLineage ::&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Push a frame onto the lineage.&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;pushLineage ::&lt;/span&gt; &lt;span class="dt"&gt;FrameType&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Get lineage depth.&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;lineageDepth ::&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Get the most recent frame.&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;lineageHead ::&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;LineageFrame&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Get the oldest frame.&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;lineageRoot ::&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;LineageFrame&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Build context from lineage.&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;buildLineageContext ::&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LineageContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Find frames by type.&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;findFramesByType ::&lt;/span&gt; &lt;span class="dt"&gt;FrameType&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;LineageFrame&lt;/span&gt;]&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Check if in specific context.&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;isInConversation ::&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;isInTurn ::&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;currentFrameType ::&lt;/span&gt; &lt;span class="dt"&gt;Lineage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;FrameType&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example: Conversation and Lineage&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;convId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createEntity&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;now &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getCurrentTime&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;lastActivity &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newTVarIO now&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world convId &lt;span class="dt"&gt;ConversationConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { conversationTitle &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;My Chat&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , conversationMetadata &lt;span class="ot"&gt;=&lt;/span&gt; Map.empty&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world convId &lt;span class="dt"&gt;ConversationState&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { conversationAgentId &lt;span class="ot"&gt;=&lt;/span&gt; agentId&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , conversationStatus &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationActive&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , conversationStartedAt &lt;span class="ot"&gt;=&lt;/span&gt; now&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , conversationLastActivity &lt;span class="ot"&gt;=&lt;/span&gt; lastActivity&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create turn&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;turnId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createEntity&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world turnId &lt;span class="dt"&gt;TurnConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { turnConversationId &lt;span class="ot"&gt;=&lt;/span&gt; convId&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , turnParentTurnId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world turnId &lt;span class="dt"&gt;TurnState&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { turnStatus &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TurnStarting&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , turnStartedAt &lt;span class="ot"&gt;=&lt;/span&gt; now&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , turnCompletedAt &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Build lineage&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; lineage &lt;span class="ot"&gt;=&lt;/span&gt; pushLineage &lt;span class="dt"&gt;ConversationFrame&lt;/span&gt; (unConversationId convId) now &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              pushLineage &lt;span class="dt"&gt;TurnFrame&lt;/span&gt; (unTurnId turnId) now &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              emptyLineage&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check depth&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;print&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; lineageDepth lineage  &lt;span class="co"&gt;-- 2&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Find conversation frames&lt;/span&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; convFrames &lt;span class="ot"&gt;=&lt;/span&gt; findFramesByType &lt;span class="dt"&gt;ConversationFrame&lt;/span&gt; lineage&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="os-events"&gt;OS Events&lt;/h3&gt;
&lt;p&gt;Subcall lifecycle and tool-call activity are reported through a single
emission mechanism, &lt;code&gt;OSEmission&lt;/code&gt; (&lt;code&gt;System.Agents.OS.Events&lt;/code&gt;), and the
session runner (&lt;code&gt;System.Agents.Host.Runner&lt;/code&gt;) is the mechanism’s one
consumer that matters in practice: it turns each &lt;code&gt;OSEmission&lt;/code&gt; into an
&lt;code&gt;EventBody&lt;/code&gt; (&lt;code&gt;System.Agents.Protocol&lt;/code&gt;) and publishes it on the owning
session’s event stream, which every runner client (the in-process TUI, the
HTTP/SSE server) subscribes to. There is no more &lt;code&gt;OSEvent&lt;/code&gt; type or
&lt;code&gt;ctxEventQueue&lt;/code&gt;; &lt;code&gt;System.Agents.Session.Base.Agent.ctxEmit&lt;/code&gt; /
&lt;code&gt;System.Agents.Tools.Context.ToolExecutionContext.ctxEmit&lt;/code&gt; is the one hook
(see &lt;code&gt;todos/os-as-standalone-server.md&lt;/code&gt;, Phase 2c and Phase 3c).&lt;/p&gt;
&lt;h4 id="osemission-type"&gt;OSEmission Type&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | The single in-library event emission type.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;OSEmission&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EmitSubcallStarted&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="co"&gt;-- ^ Parent session id, child session id, the helper&amp;#39;s slug, call depth.&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EmitSubcallCompleted&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="co"&gt;-- ^ Child session id, the subcall&amp;#39;s result text (when it succeeded).&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EmitSubcallFailed&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="co"&gt;-- ^ Child session id, the failure message.&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EmitToolCallActivity&lt;/span&gt; &lt;span class="dt"&gt;ToolCallActivity&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EmitError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="co"&gt;-- ^ A hook (e.g. a before/after tool-call command hook) failed&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="co"&gt;-- outside of the normal tool-call result path. Not a session&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="co"&gt;-- failure: the run continues.&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ToolCallActivity&lt;/code&gt; (also in &lt;code&gt;System.Agents.OS.Events&lt;/code&gt;) carries a tool
call’s session/conversation/tool-call ids, the LLM provider’s own call id
when known, the tool name, a &lt;code&gt;ToolCallPhase&lt;/code&gt; (&lt;code&gt;ToolCallStarted&lt;/code&gt;,
&lt;code&gt;ToolCallProgressed Value&lt;/code&gt;, &lt;code&gt;ToolCallCompleted&lt;/code&gt;, &lt;code&gt;ToolCallFailed Text&lt;/code&gt;,
&lt;code&gt;ToolCallCancelled&lt;/code&gt;) and a timestamp.&lt;/p&gt;
&lt;h4 id="subcall-event-lifecycle"&gt;Subcall Event Lifecycle&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Parent Conversation
       │
       ▼ triggers agent call
┌───────────────────────────┐
│ EmitSubcallStarted         │ ctxEmit'd when the subcall begins
│ - parent session id        │
│ - child session id         │
│ - agent slug                │
│ - depth                    │
└──────────────┬─────────────┘
               │
               ▼
        Agent execution
               │
               ▼ (completion)
┌───────────────────────────┐
│ EmitSubcallCompleted        │ ctxEmit'd on success
│ - child session id         │
│ - result                   │
└─────────────────────────────┘
               │
               ▼ (or failure)
┌───────────────────────────┐
│ EmitSubcallFailed           │ ctxEmit'd on error
│ - child session id         │
│ - error                    │
└─────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Phase 3c retires the old &lt;code&gt;OSEvent_SubcallProgress&lt;/code&gt; (it used to carry a
whole &lt;code&gt;Session&lt;/code&gt;, snapshotted after every step, purely for the TUI’s
benefit): there is no runner-event equivalent. Phase 5 gives a real
sub-agent session its own &lt;code&gt;SessionUpdated&lt;/code&gt; events instead, once
&lt;code&gt;prompt_agent_*&lt;/code&gt; spawns through &lt;code&gt;spawnSession&lt;/code&gt; rather than running inline.&lt;/p&gt;
&lt;h4 id="the-runners-event-stream"&gt;The Runner’s Event Stream&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;System.Agents.Host.Runner.toEventBody&lt;/code&gt; is the one place that converts
&lt;code&gt;OSEmission&lt;/code&gt; into &lt;code&gt;Protocol.EventBody&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;toEventBody ::&lt;/span&gt; &lt;span class="dt"&gt;OSEmission&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EventBody&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;toEventBody &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EmitSubcallStarted&lt;/span&gt; parent child slug depth &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SubcallStarted&lt;/span&gt; parent child slug depth&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EmitSubcallCompleted&lt;/span&gt; child result &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SubcallCompleted&lt;/span&gt; child result&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EmitSubcallFailed&lt;/span&gt; child msg &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SubcallFailed&lt;/span&gt; child msg&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EmitToolCallActivity&lt;/span&gt; activity &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolCallProgressed&lt;/span&gt; activity&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EmitError&lt;/span&gt; msg &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;HookFailed&lt;/span&gt; msg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;newAgent&lt;/code&gt; installs &lt;code&gt;withEmit (emit runner sid . toEventBody)&lt;/code&gt; on every
root agent it builds, so every emission from that session (and its
subcalls, which inherit &lt;code&gt;ctxEmit&lt;/code&gt; the same way they inherit &lt;code&gt;ctxWorld&lt;/code&gt;)
ends up on &lt;code&gt;sid&lt;/code&gt;’s own event stream, wire-encoded with &lt;code&gt;kind&lt;/code&gt;
&lt;code&gt;subcall.started&lt;/code&gt; / &lt;code&gt;subcall.completed&lt;/code&gt; / &lt;code&gt;subcall.failed&lt;/code&gt; /
&lt;code&gt;tool.progressed&lt;/code&gt; / &lt;code&gt;hook.failed&lt;/code&gt; (see &lt;code&gt;documentation/agents-server.md&lt;/code&gt;’s event
table for the full list, including the runner’s own &lt;code&gt;run.*&lt;/code&gt;/&lt;code&gt;session.*&lt;/code&gt;
kinds that do not originate from &lt;code&gt;OSEmission&lt;/code&gt; at all).&lt;/p&gt;
&lt;h4 id="using-ctxemit-outside-a-runner"&gt;Using ctxEmit Outside a Runner&lt;/h4&gt;
&lt;p&gt;A local (non-runner) consumer that used to drain &lt;code&gt;ctxEventQueue&lt;/code&gt; –
a CLI path, a test – installs &lt;code&gt;System.Agents.OS.Events.queueEmitter&lt;/code&gt;
(or &lt;code&gt;newQueueEmitter&lt;/code&gt;, which also allocates the queue) as &lt;code&gt;ctxEmit&lt;/code&gt;
instead, and reads emissions back off the queue:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Events&lt;/span&gt; (newQueueEmitter, &lt;span class="dt"&gt;OSEmission&lt;/span&gt; (&lt;span class="op"&gt;..&lt;/span&gt;))&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(queue, emitter) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newQueueEmitter&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; agent&amp;#39; &lt;span class="ot"&gt;=&lt;/span&gt; agent{ctxEmit &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; emitter}&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- ... run agent&amp;#39; ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;emissions &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; flushTQueue queue&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="toolexecutioncontext-extensions"&gt;ToolExecutionContext Extensions&lt;/h4&gt;
&lt;p&gt;For subcall visibility, the &lt;code&gt;ToolExecutionContext&lt;/code&gt; includes OS integration
fields:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { &lt;span class="co"&gt;-- ... existing fields ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxWorld ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Optional OS World for ECS operations. When present, subcalls&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- can insert entities and components into the OS.&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxEmit ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;OSEmission&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ())&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Optional emission hook. When present, subcalls emit events to&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- notify a runner (or other local consumer) of their lifecycle.&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxParentConversation ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Optional parent conversation ID for subcalls. When present,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- indicates this context is for a nested agent invocation.&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Helper Functions:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Get the subcall depth (0 if not a subcall).&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getSubcallDepth ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Check if this context represents a subcall.&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;isSubcallContext ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Create a nested context for subcall execution.&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mkSubcallContext ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tui-integration"&gt;TUI Integration&lt;/h4&gt;
&lt;p&gt;In the TUI, runner &lt;code&gt;Event&lt;/code&gt;s are turned into &lt;code&gt;AppEvent&lt;/code&gt;s by
&lt;code&gt;bridgeRunnerEvents&lt;/code&gt; (&lt;code&gt;System.Agents.TUI.Core&lt;/code&gt;), which maps each
&lt;code&gt;EventBody&lt;/code&gt; kind onto its &lt;code&gt;AppEvent&lt;/code&gt; counterpart – &lt;code&gt;subcall.started&lt;/code&gt; /
&lt;code&gt;subcall.completed&lt;/code&gt; / &lt;code&gt;subcall.failed&lt;/code&gt; / &lt;code&gt;tool.progressed&lt;/code&gt; map straight
across, translating &lt;code&gt;SessionId&lt;/code&gt; to &lt;code&gt;ConversationId&lt;/code&gt; (they are the same
UUID). &lt;code&gt;hook.failed&lt;/code&gt; has no dedicated view yet (it is not a session
failure, so it is not surfaced as one); see &lt;code&gt;documentation/tui.md&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="persistence-layer"&gt;Persistence Layer&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Removed.&lt;/strong&gt; &lt;code&gt;System.Agents.OS.Persistence&lt;/code&gt; was deleted (D1 in &lt;code&gt;todos/os-as-standalone-server.md&lt;/code&gt;): sessions persist through the runner’s &lt;code&gt;SessionBackend&lt;/code&gt; (SQLite or Postgres), not through ECS components.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3 id="common-patterns"&gt;Common Patterns&lt;/h3&gt;
&lt;h4 id="pattern-1-agent-with-multiple-toolboxes"&gt;Pattern 1: Agent with Multiple Toolboxes&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;createFullAgent ::&lt;/span&gt; &lt;span class="dt"&gt;OS&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;ToolboxId&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;createFullAgent os name toolboxes &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; config &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { agentName &lt;span class="ot"&gt;=&lt;/span&gt; name&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , agentModel &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , agentSystemPrompt &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;You are helpful&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; unToolboxId toolboxes&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    createAgent os config&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Usage&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;bashTb &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createToolbox os bashConfig&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sqlTb &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createToolbox os sqliteConfig&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;httpTb &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createToolbox os httpConfig&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;agentId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createFullAgent os &lt;span class="st"&gt;&amp;quot;multi-tool-agent&amp;quot;&lt;/span&gt; [bashTb, sqlTb, httpTb]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-2-forking-a-conversation"&gt;Pattern 2: Forking a Conversation&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;forkConversation ::&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;forkConversation world convId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Get original config&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Just&lt;/span&gt; config &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; getComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;ConversationConfig&lt;/span&gt; world (unConversationId convId)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create new conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    newConvId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createEntity&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    now &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getCurrentTime&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    lastActivity &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newTVarIO now&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        setComponent world newConvId config&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        setComponent world newConvId &lt;span class="dt"&gt;ConversationState&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            { conversationAgentId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , conversationStatus &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationActive&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , conversationStartedAt &lt;span class="ot"&gt;=&lt;/span&gt; now&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , conversationLastActivity &lt;span class="ot"&gt;=&lt;/span&gt; lastActivity&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Copy turn history&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    turns &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getConversationTurns world convId&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    forM_ turns &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;turnId &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Just&lt;/span&gt; turnConfig &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; getComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;TurnConfig&lt;/span&gt; world (unTurnId turnId)&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        newTurnId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createEntity&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        atomically &lt;span class="op"&gt;$&lt;/span&gt; setComponent world newTurnId turnConfig&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            { turnConversationId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; newConvId&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; newConvId&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-3-resource-pool-with-timeout"&gt;Pattern 3: Resource Pool with Timeout&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withPooledTimeout ::&lt;/span&gt; &lt;span class="dt"&gt;ResourceContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;NominalDiffTime&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceM&lt;/span&gt; a&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;withPooledTimeout ctx rid timeout action &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    currentTimeout &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getResourceTimeout rid&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Temporarily set timeout&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    updateResourceTimeout rid (&lt;span class="dt"&gt;Just&lt;/span&gt; timeout)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; withPooled rid action&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Restore original timeout&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    updateResourceTimeout rid currentTimeout&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; result&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="pattern-4-transaction-with-multiple-components"&gt;Pattern 4: Transaction with Multiple Components&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;updateAgentAndToolbox ::&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolboxId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolboxConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;updateAgentAndToolbox world agentId toolboxId agentConfig toolboxConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Both updates happen atomically&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world (unAgentId agentId) agentConfig&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world (unToolboxId toolboxId) toolboxConfig&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Usage&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; updateAgentAndToolbox world agentId toolboxId newAgentConfig newToolboxConfig&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="type-index"&gt;Type Index&lt;/h3&gt;
&lt;h4 id="core-types"&gt;Core Types&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;EntityId&lt;/code&gt; - Base entity identifier
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AgentId&lt;/code&gt;, &lt;code&gt;ToolboxId&lt;/code&gt;, &lt;code&gt;ConversationId&lt;/code&gt;, &lt;code&gt;TurnId&lt;/code&gt;, &lt;code&gt;ToolCallId&lt;/code&gt;, &lt;code&gt;ResourceId&lt;/code&gt; - Phantom-typed IDs
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ComponentTypeId&lt;/code&gt; - Component type identifier
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;World&lt;/code&gt; - ECS world container
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="component-types"&gt;Component Types&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AgentConfig&lt;/code&gt;, &lt;code&gt;AgentState&lt;/code&gt;, &lt;code&gt;AgentStatus&lt;/code&gt; - Agent components
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolboxConfig&lt;/code&gt;, &lt;code&gt;ToolboxState&lt;/code&gt;, &lt;code&gt;ToolboxBinding&lt;/code&gt; - Toolbox components
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ConversationConfig&lt;/code&gt;, &lt;code&gt;ConversationState&lt;/code&gt;, &lt;code&gt;ConversationStatus&lt;/code&gt; - Conversation components
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TurnConfig&lt;/code&gt;, &lt;code&gt;TurnState&lt;/code&gt;, &lt;code&gt;TurnStatus&lt;/code&gt; - Turn components
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolCallConfig&lt;/code&gt;, &lt;code&gt;ToolCallState&lt;/code&gt;, &lt;code&gt;ToolCallStatus&lt;/code&gt; - Tool call components
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Message&lt;/code&gt;, &lt;code&gt;MessageRole&lt;/code&gt; - Message components
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Lineage&lt;/code&gt;, &lt;code&gt;LineageFrame&lt;/code&gt;, &lt;code&gt;FrameType&lt;/code&gt; - Lineage components
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="resource-types-1"&gt;Resource Types&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ResourceType&lt;/code&gt;, &lt;code&gt;ResourceHandle&lt;/code&gt;, &lt;code&gt;ResourceInfo&lt;/code&gt; - Resource definitions
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResourceContext&lt;/code&gt;, &lt;code&gt;ScopeLevel&lt;/code&gt;, &lt;code&gt;ResourceScope&lt;/code&gt; - Scope management
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResourceRegistry&lt;/code&gt; - Resource storage
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="concurrent-types"&gt;Concurrent Types&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AccessPattern&lt;/code&gt;, &lt;code&gt;AccessControl&lt;/code&gt; - Access patterns
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResourceM&lt;/code&gt; - Resource monad
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResourceError&lt;/code&gt; - Error types
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SyncPrimitive&lt;/code&gt;, &lt;code&gt;ExclusiveLock&lt;/code&gt;, &lt;code&gt;ReadWriteLock&lt;/code&gt;, &lt;code&gt;PoolLock&lt;/code&gt; - Lock types
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="event-types"&gt;Event Types&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OSEmission&lt;/code&gt; - the single emission type: subcall lifecycle, tool-call activity, hook failures
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToolCallActivity&lt;/code&gt;, &lt;code&gt;ToolCallPhase&lt;/code&gt; - background tool-call activity payloads
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionProgress&lt;/code&gt; - Session progress tracking
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="persistence-types"&gt;Persistence Types&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PersistenceHandle&lt;/code&gt;, &lt;code&gt;PersistenceBackendType&lt;/code&gt; - Backend types
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Persistable&lt;/code&gt; - Persistence typeclass
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EntityQuery&lt;/code&gt; - Query specification
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-OS-API.html" rel="alternate"/><summary type="text">Complete API reference for the Entity-Component-System (ECS) based OS architecture. ## Table of Contents 1. [Core ECS Types](#core-ecs-types) 2. [World Operations](#world-operations) 3. [Agent Operations](#agent-operations) 4. [Toolbox Oper</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/specs-durable-workflows-cli-start-plan.html</id><title type="text">Plan: Durable execution from the CLI</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/todos/durable-workflows-cli-start-plan.md"&gt;&lt;code&gt;todos/durable-workflows-cli-start-plan.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="plan-durable-execution-from-the-cli"&gt;Plan: Durable execution from the CLI&lt;/h2&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;
&lt;p&gt;Make the durable-workflow execution mode accessible from the CLI in one-shot
form, so a user can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start a brand-new session with a prompt using &lt;code&gt;agents session start ...&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Have the agent run until it yields (partial turn, deferred tool calls) or
completes.
&lt;/li&gt;
&lt;li&gt;Inspect pending calls with &lt;code&gt;agents session pending&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Complete deferred calls with &lt;code&gt;agents session complete&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Resume with &lt;code&gt;agents session resume&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Iterate step by step, either letting the LLM continue or injecting tool
results on behalf of the user.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This closes the gap between the existing &lt;code&gt;run&lt;/code&gt; command (fully synchronous,
runs to completion) and the &lt;code&gt;session pause/resume/...&lt;/code&gt; commands (which only
operate on already-existing sessions).&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="decisions-on-open-questions"&gt;Decisions on open questions&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Question&lt;/th&gt;&lt;th&gt;Decision&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;How many steps should &lt;code&gt;session start&lt;/code&gt; run?&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Zero by default&lt;/strong&gt;, with an optional &lt;code&gt;--step&lt;/code&gt; flag to run exactly one scheduling step. The goal is to forfeit as much scheduling as possible to external processes/users.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;How is the initial turn created?&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Option B&lt;/strong&gt;: construct the initial &lt;code&gt;UserTurn&lt;/code&gt; directly in &lt;code&gt;session start&lt;/code&gt; with the prompt and media, then persist the session.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Isolated execution?&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Out of scope&lt;/strong&gt; for this milestone. Only &lt;code&gt;RunSync&lt;/code&gt;, &lt;code&gt;RunAsync&lt;/code&gt;, and &lt;code&gt;Defer&lt;/code&gt; are supported.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Policy language?&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Keep it simple&lt;/strong&gt;: exact tool-name rules plus a default disposition.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Continuation store?&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Keep it simple&lt;/strong&gt;: rely on the file-based &lt;code&gt;SessionStore&lt;/code&gt; and the in-memory partial turn. A SQLite continuation store can be added later.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h3 id="current-state-and-gaps"&gt;Current state and gaps&lt;/h3&gt;
&lt;h4 id="what-already-works"&gt;What already works&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The library has full durable-workflow primitives:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ToolCallPolicy&lt;/code&gt;, &lt;code&gt;ToolCallDisposition&lt;/code&gt; (&lt;code&gt;RunSync&lt;/code&gt;, &lt;code&gt;RunAsync&lt;/code&gt;, &lt;code&gt;Defer&lt;/code&gt;,
&lt;code&gt;RunIsolated&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;runAsync&lt;/code&gt; in &lt;code&gt;System.Agents.Session.Loop&lt;/code&gt; runs an async agent until it
yields a &lt;code&gt;PartialUserTurn&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resumeSession&lt;/code&gt; and &lt;code&gt;wakeSession&lt;/code&gt; in &lt;code&gt;System.Agents.Session.Wake&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SessionBackend&lt;/code&gt;, &lt;code&gt;ContinuationStore&lt;/code&gt;, and CLI commands
&lt;code&gt;session pause/resume/pending/complete/run-isolated&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The existing &lt;code&gt;run&lt;/code&gt; command already accepts prompts, media, session files,
and thinking-output options.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="what-is-missing"&gt;What is missing&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No CLI command to create a new session in async mode.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;run&lt;/code&gt; always uses &lt;code&gt;mainOneShotTextWithThinking&lt;/code&gt;, which creates a
synchronous agent and calls &lt;code&gt;Loop.run&lt;/code&gt; to completion.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session pause/resume/...&lt;/code&gt; require an existing &lt;code&gt;SessionId&lt;/code&gt;; they cannot
start from a user prompt.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No way to configure a durable policy from the agent JSON file.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Base.Agent&lt;/code&gt; (the JSON config type) has no fields for
&lt;code&gt;executionMode&lt;/code&gt;, &lt;code&gt;toolCallPolicy&lt;/code&gt;, &lt;code&gt;toolExecutor&lt;/code&gt;, &lt;code&gt;continuationStore&lt;/code&gt;,
&lt;code&gt;deploymentRunner&lt;/code&gt;, or &lt;code&gt;sessionBackend&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The CLI’s &lt;code&gt;withAgentForSession&lt;/code&gt; builds the runtime agent with
&lt;code&gt;defaultToolCallPolicy&lt;/code&gt;, so even in async mode every call runs
synchronously and no yielding occurs.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No shared parser for &lt;code&gt;run&lt;/code&gt;-like options in the &lt;code&gt;session&lt;/code&gt; command group.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;parseOneShotOptions&lt;/code&gt; is only used by &lt;code&gt;run&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session start&lt;/code&gt; should accept the same prompt/media/thinking options.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No single-step scheduler command wired to the CLI.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;runAsync&lt;/code&gt; exists in the library but is not used by any CLI handler.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handlePause&lt;/code&gt; calls &lt;code&gt;runStepM&lt;/code&gt; once on an existing session, but it does
not create the initial user turn from a prompt.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3 id="proposed-cli-additions"&gt;Proposed CLI additions&lt;/h3&gt;
&lt;h4 id="new-command-agents-session-start"&gt;New command: &lt;code&gt;agents session start&lt;/code&gt;&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Create a session with an initial UserTurn, do not call the LLM yet.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents&lt;/span&gt; session start &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; my-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Research the weather in Paris and New York&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Same, but also run one scheduling step (e.g. ask the LLM and possibly&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# execute the first batch of tool calls).&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents&lt;/span&gt; session start &lt;span class="at"&gt;--step&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; my-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Research the weather in Paris and New York&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Semantics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creates a fresh &lt;code&gt;Session&lt;/code&gt; with &lt;code&gt;sessionVersion = Just 2&lt;/code&gt; and
&lt;code&gt;sessionExecutionMode = Just Asynchronous&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Constructs an initial &lt;code&gt;UserTurn&lt;/code&gt; containing the prompt (and any media
attachments).
&lt;/li&gt;
&lt;li&gt;Loads the agent, applies the durable configuration from the agent file
(see below), and sets &lt;code&gt;ctxExecutionMode = Asynchronous&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;By default, persists the session immediately without calling the LLM.
&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;--step&lt;/code&gt;, calls &lt;code&gt;runStepM&lt;/code&gt; exactly once before persisting.
&lt;/li&gt;
&lt;li&gt;Prints:
&lt;ul&gt;
&lt;li&gt;the new &lt;code&gt;session-id&lt;/code&gt;;
&lt;/li&gt;
&lt;li&gt;the current state (&lt;code&gt;UserTurn&lt;/code&gt;, &lt;code&gt;LlmTurn&lt;/code&gt;, &lt;code&gt;PartialUserTurn&lt;/code&gt;, or
completed);
&lt;/li&gt;
&lt;li&gt;continuation tokens for any deferred calls.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the session completes after the optional step, the final LLM response is
printed as well.&lt;/p&gt;
&lt;h4 id="new-command-agents-session-step"&gt;New command: &lt;code&gt;agents session step&lt;/code&gt;&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents&lt;/span&gt; session step &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;session-id&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Runs exactly one scheduling step on an existing session and persists the
result. This is the workhorse for manual iteration:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;session start -p &amp;quot;...&amp;quot;&lt;/code&gt; → session with &lt;code&gt;UserTurn&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session step &amp;lt;id&amp;gt;&lt;/code&gt; → LLM produces tool calls (&lt;code&gt;LlmTurn&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session step &amp;lt;id&amp;gt;&lt;/code&gt; → sync tools run, async/deferred calls yield
(&lt;code&gt;PartialUserTurn&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session complete &amp;lt;token&amp;gt; result.json&lt;/code&gt; → inject external result.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session step &amp;lt;id&amp;gt;&lt;/code&gt; → woken results processed, possibly another LLM turn.
&lt;/li&gt;
&lt;li&gt;Repeat until completion.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;session step&lt;/code&gt; is functionally similar to the existing &lt;code&gt;session pause&lt;/code&gt;, but
named for iteration rather than interruption. The existing &lt;code&gt;session pause&lt;/code&gt;
can be kept for backward compatibility.&lt;/p&gt;
&lt;h4 id="reuse-run-options"&gt;Reuse &lt;code&gt;run&lt;/code&gt; options&lt;/h4&gt;
&lt;p&gt;Both &lt;code&gt;session start&lt;/code&gt; and &lt;code&gt;session step&lt;/code&gt; should accept the same prompt-script
options as &lt;code&gt;run&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents&lt;/span&gt; session start &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; my-agent.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--prompt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Summarize&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--file&lt;/span&gt; report.md &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--media&lt;/span&gt; screenshot.png &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--thinking&lt;/span&gt; stderr&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The cleanest way is to extract a shared parser type, e.g.
&lt;code&gt;OneShotPromptOptions&lt;/code&gt;, from &lt;code&gt;System.Agents.CLI.OneShot&lt;/code&gt; and reuse it for
&lt;code&gt;run&lt;/code&gt;, &lt;code&gt;session start&lt;/code&gt;, and (for prompt injection) future commands.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="agent-configuration-for-durable-mode"&gt;Agent configuration for durable mode&lt;/h3&gt;
&lt;p&gt;To make durable execution usable without writing Haskell, the agent JSON
config needs to expose at least the following fields.&lt;/p&gt;
&lt;h4 id="minimal-viable-config"&gt;Minimal viable config&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-durable-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;executionMode&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;asynchronous&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;toolCallPolicy&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runSync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_command&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;disposition&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;defer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;approval required&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;fetch_remote&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;disposition&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runAsync&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="proposed-json-schema-additions-to-systemagentsbaseagent"&gt;Proposed JSON schema additions to &lt;code&gt;System.Agents.Base.Agent&lt;/code&gt;&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; executionMode ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ExecutionMode&lt;/span&gt;        &lt;span class="co"&gt;-- default Synchronous&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolCallPolicyConfig ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicyConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Only &lt;code&gt;executionMode&lt;/code&gt; and &lt;code&gt;toolCallPolicyConfig&lt;/code&gt; are in scope for this
milestone.&lt;/p&gt;
&lt;h4 id="tool-call-policy-config-design"&gt;Tool-call policy config design&lt;/h4&gt;
&lt;p&gt;A declarative policy config that the runtime turns into a &lt;code&gt;ToolCallPolicy&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicyConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicyConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; tpcDefaultDisposition ::&lt;/span&gt; &lt;span class="dt"&gt;ToolCallDisposition&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tpcRules ::&lt;/span&gt; [&lt;span class="dt"&gt;ToolCallPolicyRule&lt;/span&gt;]&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicyRule&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicyRule&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; tprToolName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;           &lt;span class="co"&gt;-- exact match&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; tprDisposition ::&lt;/span&gt; &lt;span class="dt"&gt;ToolCallDisposition&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The runtime combinator:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;buildToolCallPolicy ::&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicyConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolCallPolicy&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;buildToolCallPolicy cfg _ctx call &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    fromMaybe cfg&lt;span class="op"&gt;.&lt;/span&gt;tpcDefaultDisposition &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        find ((&lt;span class="op"&gt;==&lt;/span&gt; callName call) &lt;span class="op"&gt;.&lt;/span&gt; tprToolName) cfg&lt;span class="op"&gt;.&lt;/span&gt;tpcRules&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="where-the-policy-is-applied"&gt;Where the policy is applied&lt;/h4&gt;
&lt;p&gt;In &lt;code&gt;System.Agents.CLI.SessionDurable.withAgentForSession&lt;/code&gt;, after building the
runtime agent from the OS tree, inspect the JSON &lt;code&gt;Agent&lt;/code&gt; config:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; agent&amp;#39; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;maybe&lt;/span&gt; agent (withExecutionMode &lt;span class="dt"&gt;Asynchronous&lt;/span&gt;) (executionMode jsonAgent)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; agent&amp;#39;&amp;#39; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;maybe&lt;/span&gt; agent&amp;#39; (withToolCallPolicy &lt;span class="op"&gt;.&lt;/span&gt; buildToolCallPolicy) (toolCallPolicyConfig jsonAgent)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This makes &lt;code&gt;session start&lt;/code&gt;, &lt;code&gt;session step&lt;/code&gt;, &lt;code&gt;session pause&lt;/code&gt;, and
&lt;code&gt;session resume&lt;/code&gt; all use the same durable configuration.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="implementation-steps"&gt;Implementation steps&lt;/h3&gt;
&lt;h4 id="step-1--shared-prompt-options"&gt;Step 1 — Shared prompt options&lt;/h4&gt;
&lt;p&gt;Refactor &lt;code&gt;System.Agents.CLI.OneShot&lt;/code&gt; so that the prompt/media/thinking
options are reusable:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;PromptScriptOptions&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;PromptScriptOptions&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; psoPromptScript ::&lt;/span&gt; &lt;span class="dt"&gt;PromptScript&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; psoMediaFiles ::&lt;/span&gt; [&lt;span class="dt"&gt;MediaReference&lt;/span&gt;]&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; psoThinkingOutput ::&lt;/span&gt; &lt;span class="dt"&gt;OneShot.ThinkingOutput&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;parsePromptScriptOptions ::&lt;/span&gt; &lt;span class="dt"&gt;Parser&lt;/span&gt; &lt;span class="dt"&gt;PromptScriptOptions&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Update &lt;code&gt;OneShotOptions&lt;/code&gt; to contain &lt;code&gt;PromptScriptOptions&lt;/code&gt; plus
&lt;code&gt;sessionFile&lt;/code&gt;. Update &lt;code&gt;parseOneShotOptions&lt;/code&gt; accordingly.&lt;/p&gt;
&lt;h4 id="step-2--add-durable-config-fields-to-json-agent"&gt;Step 2 — Add durable config fields to JSON Agent&lt;/h4&gt;
&lt;p&gt;In &lt;code&gt;System.Agents.Base.Agent&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;executionMode :: Maybe ExecutionMode&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;toolCallPolicyConfig :: Maybe ToolCallPolicyConfig&lt;/code&gt; with JSON
instances.
&lt;/li&gt;
&lt;li&gt;Keep defaults backward-compatible (&lt;code&gt;Nothing&lt;/code&gt; = synchronous, default
policy).
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="step-3--build-policy-from-config"&gt;Step 3 — Build policy from config&lt;/h4&gt;
&lt;p&gt;In &lt;code&gt;System.Agents.CLI.SessionDurable&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;buildToolCallPolicy&lt;/code&gt; / &lt;code&gt;applyAgentDurableConfig&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;withAgentForSession&lt;/code&gt; to read the JSON agent config and apply
durable settings to the runtime agent.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="step-4--implement-session-start"&gt;Step 4 — Implement &lt;code&gt;session start&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;In &lt;code&gt;System.Agents.CLI.SessionDurable&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;SessionStart PromptScriptOptions Bool&lt;/code&gt; command (the &lt;code&gt;Bool&lt;/code&gt; is
whether to run one step).
&lt;/li&gt;
&lt;li&gt;Implement &lt;code&gt;handleStart&lt;/code&gt;:
&lt;ol&gt;
&lt;li&gt;Load agent tree and build runtime agent (with durable config).
&lt;/li&gt;
&lt;li&gt;Interpret the prompt script (aliases, files, shell, media).
&lt;/li&gt;
&lt;li&gt;Create a fresh &lt;code&gt;Session&lt;/code&gt; (version 2, async mode).
&lt;/li&gt;
&lt;li&gt;Construct the initial &lt;code&gt;UserTurn&lt;/code&gt; with the prompt/media.
&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;--step&lt;/code&gt;, call &lt;code&gt;runStepM&lt;/code&gt; exactly once.
&lt;/li&gt;
&lt;li&gt;Persist the resulting session.
&lt;/li&gt;
&lt;li&gt;Print session id, current turn state, and any deferred tokens.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="step-5--implement-session-step"&gt;Step 5 — Implement &lt;code&gt;session step&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;In &lt;code&gt;System.Agents.CLI.SessionDurable&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;SessionStep SessionId&lt;/code&gt; command.
&lt;/li&gt;
&lt;li&gt;Implement &lt;code&gt;handleStep&lt;/code&gt;:
&lt;ol&gt;
&lt;li&gt;Load the existing session.
&lt;/li&gt;
&lt;li&gt;Load the agent and apply durable config.
&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;runStepM&lt;/code&gt; exactly once.
&lt;/li&gt;
&lt;li&gt;Persist the resulting session.
&lt;/li&gt;
&lt;li&gt;Print the new turn state and any deferred tokens.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is very close to the existing &lt;code&gt;handlePause&lt;/code&gt;; consider sharing the
implementation.&lt;/p&gt;
&lt;h4 id="step-6--wire-the-parsers"&gt;Step 6 — Wire the parsers&lt;/h4&gt;
&lt;p&gt;In &lt;code&gt;app/Main.hs&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;SessionStart&lt;/code&gt; and &lt;code&gt;SessionStep&lt;/code&gt; constructors to
&lt;code&gt;SessionDurableCommand&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;step&lt;/code&gt; subcommand parsers reusing
&lt;code&gt;parsePromptScriptOptions&lt;/code&gt; / &lt;code&gt;parseSessionIdArgument&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Update help text: &lt;code&gt;Operate durable sessions: start, step, pause, resume, ...&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="step-7--tests"&gt;Step 7 — Tests&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Unit tests for &lt;code&gt;ToolCallPolicyConfig&lt;/code&gt; JSON parsing.
&lt;/li&gt;
&lt;li&gt;Unit tests for &lt;code&gt;buildToolCallPolicy&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Integration test exercising the full iterative flow:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;session start -p &amp;quot;...&amp;quot;&lt;/code&gt; creates a session with a &lt;code&gt;UserTurn&lt;/code&gt;;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session step &amp;lt;id&amp;gt;&lt;/code&gt; produces an &lt;code&gt;LlmTurn&lt;/code&gt; with tool calls;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session step &amp;lt;id&amp;gt;&lt;/code&gt; runs sync tools and defers one call
(&lt;code&gt;PartialUserTurn&lt;/code&gt;);
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session pending &amp;lt;id&amp;gt;&lt;/code&gt; lists the deferred token;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session complete &amp;lt;token&amp;gt; result.json&lt;/code&gt; injects the result;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;session step &amp;lt;id&amp;gt;&lt;/code&gt; processes the result and produces a final response.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="suggested-first-milestone"&gt;Suggested first milestone&lt;/h3&gt;
&lt;p&gt;The smallest vertical slice that proves the design:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Extract shared &lt;code&gt;PromptScriptOptions&lt;/code&gt; from &lt;code&gt;run&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;executionMode&lt;/code&gt; and &lt;code&gt;toolCallPolicyConfig&lt;/code&gt; to the JSON &lt;code&gt;Agent&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Implement &lt;code&gt;buildToolCallPolicy&lt;/code&gt; and apply it in &lt;code&gt;withAgentForSession&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;agents session start&lt;/code&gt; that creates a session with an initial
&lt;code&gt;UserTurn&lt;/code&gt; and optionally runs one step.
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;agents session step&lt;/code&gt; for single-step iteration.
&lt;/li&gt;
&lt;li&gt;Write one integration test exercising the full flow above.
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3 id="related-docs"&gt;Related docs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;todos/durable-workflows.md&lt;/code&gt; — original design plan.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;todos/durable-workflows.progress.md&lt;/code&gt; — implementation progress.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation/durable-workflows-howto.md&lt;/code&gt; — user-facing how-to.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/System/Agents/CLI/SessionDurable.hs&lt;/code&gt; — existing session command
handlers.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/System/Agents/Session/Loop.hs&lt;/code&gt; — &lt;code&gt;runAsync&lt;/code&gt; and &lt;code&gt;runStepM&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/specs-durable-workflows-cli-start-plan.html" rel="alternate"/><summary type="text">Status: no status line yet</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-MIGRATION-OS.html</id><title type="text">OS Model Migration Guide</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/MIGRATION-OS.md"&gt;&lt;code&gt;documentation/MIGRATION-OS.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="os-model-migration-guide"&gt;OS Model Migration Guide&lt;/h2&gt;
&lt;p&gt;Complete migration guide for transitioning from the legacy Runtime-based architecture to the new ECS-based OS Model.&lt;/p&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;p&gt;The Agents framework has migrated from a &lt;strong&gt;Runtime-per-agent&lt;/strong&gt; model to an &lt;strong&gt;Entity-Component-System (ECS)&lt;/strong&gt; architecture. This change provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Better concurrency control&lt;/strong&gt; via STM-based component access
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource lifecycle management&lt;/strong&gt; with scoped cleanup
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unified agent/toolbox/conversation tracking&lt;/strong&gt; in a single World
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subcall visibility&lt;/strong&gt; for multi-agent hierarchies
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persistence layer&lt;/strong&gt; with pluggable backends
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="architecture-comparison"&gt;Architecture Comparison&lt;/h3&gt;
&lt;h4 id="legacy-runtime-model-pre-os"&gt;Legacy Runtime Model (Pre-OS)&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│   Agent A       │  │   Agent B       │  │   Agent C       │
│ ┌─────────────┐ │  │ ┌─────────────┐ │  │ ┌─────────────┐ │
│ │   Runtime   │ │  │ │   Runtime   │ │  │ │   Runtime   │ │
│ │ ┌─────────┐ │ │  │ │ ┌─────────┐ │ │  │ │ ┌─────────┐ │ │
│ │ │ Session │ │ │  │ │ │ Session │ │ │  │ │ │ Session │ │ │
│ │ │ Tools   │ │ │  │ │ │ Tools   │ │ │  │ │ │ Tools   │ │ │
│ │ │ LLM     │ │ │  │ │ │ LLM     │ │ │  │ │ │ LLM     │ │ │
│ │ └─────────┘ │ │  │ │ └─────────┘ │ │  │ │ └─────────┘ │ │
│ └─────────────┘ │  │ └─────────────┘ │  │ └─────────────┘ │
└─────────────────┘  └─────────────────┘  └─────────────────┘
       │                    │                    │
       └────────────────────┼────────────────────┘
                            │
                    ┌───────▼───────┐
                    │  AgentTree    │
                    │  (references) │
                    └───────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="new-os-model-ecs"&gt;New OS Model (ECS)&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                           OS                                │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                        World                          │  │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐  │  │
│  │  │ AgentStore  │ │ToolboxStore │ │ ConversationStore│  │  │
│  │  │  (TVar)     │ │  (TVar)     │ │    (TVar)       │  │  │
│  │  ├─────────────┤ ├─────────────┤ ├─────────────────┤  │  │
│  │  │ AgentConfig │ │ToolboxConfig│ │ ConversationCfg │  │  │
│  │  │ AgentState  │ │ToolboxState │ │ ConversationState│  │  │
│  │  │ ...         │ │ ...         │ │ ...             │  │  │
│  │  └─────────────┘ └─────────────┘ └─────────────────┘  │  │
│  └───────────────────────────────────────────────────────┘  │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                   ResourceRegistry                    │  │
│  │    (SQLite, Lua, HTTP pools with scoped cleanup)      │  │
│  └───────────────────────────────────────────────────────┘  │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                   EventQueue (TQueue)                 │  │
│  │          (OSEvents for TUI visibility)                │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="migration-phases"&gt;Migration Phases&lt;/h3&gt;
&lt;p&gt;The migration was implemented in three phases:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PhaseOldOnly ──► PhaseDual ──► PhaseNewOnly
(removed)        (default)     (available)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PhaseOldOnly&lt;/strong&gt;: Only legacy Runtime (removed as of March 2026)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PhaseDual&lt;/strong&gt;: Both Runtime and OS available (current default)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PhaseNewOnly&lt;/strong&gt;: Only OS Model (available for testing)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="key-changes"&gt;Key Changes&lt;/h3&gt;
&lt;h4 id="1-agent-creation"&gt;1. Agent Creation&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Legacy:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create runtime directly&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runtime &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newRuntime tracer config tools&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;New (OS Model):&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Initialize OS&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;os &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initializeOS defaultOSConfig&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create agent in OS&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;agentId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createAgent os &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { agentName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentModel &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ModelConfig&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;key1&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentSystemPrompt &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;You are helpful&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="2-toolbox-registration"&gt;2. Toolbox Registration&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Legacy:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Tools passed to Runtime constructor&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; tools &lt;span class="ot"&gt;=&lt;/span&gt; bashTools &lt;span class="op"&gt;++&lt;/span&gt; mcpTools &lt;span class="op"&gt;++&lt;/span&gt; ioTools&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runtime &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newRuntime tracer config tools&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;New:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Toolboxes created as entities in the World&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;bashId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createToolbox os bashConfig&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sqlId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createToolbox os sqliteConfig&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Bound to agent via agentToolboxBindings&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; agentConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ unToolboxId bashId&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , unToolboxId sqlId&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="3-resource-management"&gt;3. Resource Management&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Legacy:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Manual resource tracking&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;connections &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newTVarIO []&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Cleanup handled per-runtime&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;New:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Resources&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create registry&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;registry &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically newResourceRegistry&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; ctx &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ResourceContext&lt;/span&gt; [&lt;span class="dt"&gt;ProgramScope&lt;/span&gt;] registry&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create scoped resource&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;rid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createResource ctx (&lt;span class="dt"&gt;SqliteResource&lt;/span&gt; config) &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;rid &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    conn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; openConnection config&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&gt;ResourceHandle&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { handleId &lt;span class="ot"&gt;=&lt;/span&gt; rid&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , handleCleanup &lt;span class="ot"&gt;=&lt;/span&gt; closeConnection conn&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , handleAccess &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;f &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; f (&lt;span class="dt"&gt;SqliteAccessor&lt;/span&gt; conn)&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Automatic cleanup&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;cleanupScope registry (&lt;span class="dt"&gt;AgentScope&lt;/span&gt; agentId)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="4-conversation-tracking"&gt;4. Conversation Tracking&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Legacy:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Session managed separately&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;session &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; loadSession sessionPath&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Conversation ID tracked in Session type&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;New:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Conversation is a first-class entity&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;convId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createEntity&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world convId &lt;span class="dt"&gt;ConversationConfig&lt;/span&gt;{&lt;span class="op"&gt;...&lt;/span&gt;}&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world convId &lt;span class="dt"&gt;ConversationState&lt;/span&gt;{&lt;span class="op"&gt;...&lt;/span&gt;}&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Link to agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; modifyComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentState&lt;/span&gt; world (unAgentId agentId) &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;\&lt;/span&gt;s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; s { agentCurrentConversation &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; (&lt;span class="dt"&gt;ConversationId&lt;/span&gt; convId) }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="5-subcall-visibility"&gt;5. Subcall Visibility&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Legacy:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Subcalls invisible to TUI&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; turnAgentRuntimeIntoIOTool agent prompt&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- No visibility into subcall conversation&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;New:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Subcalls visible as OSEvents&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; turnAgentRuntimeIntoIOTool agent prompt&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- OSEvent_SubcallStarted, OSEvent_SubcallProgress, &lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- OSEvent_SubcallCompleted emitted&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- TUI displays subcall as separate conversation&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="compatibility-layer"&gt;Compatibility Layer&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;System.Agents.OS.Compat.Runtime&lt;/code&gt; module provides a compatibility bridge:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Compat.Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Run existing Runtime code with OS backend&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;withCompatOS &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;compat &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Use compatRuntime for legacy code&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; runtime &lt;span class="ot"&gt;=&lt;/span&gt; compatRuntime compat&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Or use OS directly&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; os &lt;span class="ot"&gt;=&lt;/span&gt; compatOS compat&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Both are kept in sync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="compatibility-patterns"&gt;Compatibility Patterns&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Pattern 1: Runtime Bridge&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;bridge &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newRuntimeBridge agentId os&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runWithBridge bridge &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Legacy Runtime code&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; listTools&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    callTool &lt;span class="st"&gt;&amp;quot;my-tool&amp;quot;&lt;/span&gt; args&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Pattern 2: Dual Initialization&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Initialize both&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runtime &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newRuntime tracer config tools&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;os &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runtimeToOS runtime&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Use whichever is appropriate&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;useRuntime runtime  &lt;span class="co"&gt;-- Legacy code&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;useOS os            &lt;span class="co"&gt;-- New code&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Pattern 3: Migration Wrapper&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Wrap Runtime operations with OS event emission&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;wrappedCallTool ctx tool args &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Emit subcall events if in OS context&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; ctxEventQueue ctx &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Just&lt;/span&gt; q &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; emitSubcallStart q&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Execute tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; callTool tool args&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Emit completion&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; ctxEventQueue ctx &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Just&lt;/span&gt; q &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; emitSubcallComplete q result&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; result&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="module-mapping"&gt;Module Mapping&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Legacy Module&lt;/th&gt;&lt;th&gt;New OS Module&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Runtime&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Main entry point&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Runtime.Runtime&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Agents&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Agent operations&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Base&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Conversation&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Conversation tracking&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Session.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Conversation.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Conversation types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.AgentTree&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.AgentTree&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Multi-agent hierarchy&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Core&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ECS core types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Resources&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Resource management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Concurrent&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Concurrent access&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Events&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OS event system&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="type-mapping"&gt;Type Mapping&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Legacy Type&lt;/th&gt;&lt;th&gt;New Type&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Runtime&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;OS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Contains World, not just config&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Session&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Conversation&lt;/code&gt; + &lt;code&gt;Turn&lt;/code&gt; + &lt;code&gt;ToolCall&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Split into components&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AgentId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;AgentId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Now wraps &lt;code&gt;EntityId&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SessionId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;ConversationId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Now wraps &lt;code&gt;EntityId&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;EntityId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Base identifier type&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;ToolboxId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Phantom-typed EntityId&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;TurnId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Phantom-typed EntityId&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;ToolCallId&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Phantom-typed EntityId&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(new)&lt;/td&gt;&lt;td&gt;&lt;code&gt;World&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ECS world container&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="step-by-step-migration"&gt;Step-by-Step Migration&lt;/h3&gt;
&lt;h4 id="step-1-update-imports"&gt;Step 1: Update Imports&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Before&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Runtime.Runtime&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- After&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.OS.Agents&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;OSAgents&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="step-2-initialize-os-instead-of-runtime"&gt;Step 2: Initialize OS Instead of Runtime&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Before&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runtime &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newRuntime tracer config tools&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- After&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;os &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initializeOS defaultOSConfig&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;agentId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createAgent os agentConfig&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create toolboxes and bind to agent&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;toolboxId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createToolbox os toolboxConfig&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="step-3-update-agent-configuration"&gt;Step 3: Update Agent Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Before&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;config &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { slug &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , toolDirectory &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./tools&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- After&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;config &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { agentName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentModel &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentSystemPrompt &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , agentToolboxBindings &lt;span class="ot"&gt;=&lt;/span&gt; [unToolboxId bashId, unToolboxId sqliteId]&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="step-4-use-resource-context"&gt;Step 4: Use Resource Context&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Before&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;conn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; openConnection config&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Cleanup handled manually&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- After&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;rid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createResource ctx (&lt;span class="dt"&gt;SqliteResource&lt;/span&gt; config) &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;rid &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    conn &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; openConnection config&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&gt;ResourceHandle&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { handleId &lt;span class="ot"&gt;=&lt;/span&gt; rid&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , handleCleanup &lt;span class="ot"&gt;=&lt;/span&gt; closeConnection conn&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , handleAccess &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;f &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; f (&lt;span class="dt"&gt;SqliteAccessor&lt;/span&gt; conn)&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Automatic cleanup on scope exit&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;cleanupScope registry scope&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="step-5-update-subcall-handling"&gt;Step 5: Update Subcall Handling&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Before&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; turnAgentRuntimeIntoIOTool agent prompt&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- After&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Ensure ToolExecutionContext has event queue&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; ctx&amp;#39; &lt;span class="ot"&gt;=&lt;/span&gt; ctx { ctxEventQueue &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; eventQueue }&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; turnAgentRuntimeIntoIOTool agent prompt&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Events automatically emitted&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="testing-migration"&gt;Testing Migration&lt;/h3&gt;
&lt;h4 id="unit-tests"&gt;Unit Tests&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Test OS operations directly&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;spec ::&lt;/span&gt; &lt;span class="dt"&gt;Spec&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;spec &lt;span class="ot"&gt;=&lt;/span&gt; describe &lt;span class="st"&gt;&amp;quot;OS Core&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    it &lt;span class="st"&gt;&amp;quot;creates agents&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        os &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initializeOS testConfig&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        agentId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createAgent os testAgentConfig&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        mConfig &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            getComponent &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentConfig&lt;/span&gt; (osWorld os) (unAgentId agentId)&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        mConfig &lt;span class="ot"&gt;`shouldSatisfy`&lt;/span&gt; isJust&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="integration-tests"&gt;Integration Tests&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Test full agent lifecycle&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;spec ::&lt;/span&gt; &lt;span class="dt"&gt;Spec&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;spec &lt;span class="ot"&gt;=&lt;/span&gt; describe &lt;span class="st"&gt;&amp;quot;Agent Lifecycle&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    it &lt;span class="st"&gt;&amp;quot;runs conversation&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        os &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initializeOS testConfig&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        agentId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createAgent os testAgentConfig&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Create conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        convId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; startConversation os agentId&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Add user message&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        addMessage os convId &lt;span class="dt"&gt;UserRole&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Hello!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Run agent turn&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runAgentTurn os agentId convId&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Verify response&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        messages &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getConversationMessages os convId&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;length&lt;/span&gt; messages &lt;span class="ot"&gt;`shouldBe`&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="troubleshooting"&gt;Troubleshooting&lt;/h3&gt;
&lt;h4 id="issue-entity-not-found-errors"&gt;Issue: “Entity not found” errors&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Trying to access entity that doesn’t exist in World.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Check entity creation and component registration:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Verify entity exists&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;exists &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; entityExists world eid&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;when (&lt;span class="fu"&gt;not&lt;/span&gt; exists) &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Entity not found&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check component store registered&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;hasStore &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; hasComponentStore &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;MyComponent&lt;/span&gt; world&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;when (&lt;span class="fu"&gt;not&lt;/span&gt; hasStore) &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Component store not registered&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="issue-stm-deadlock"&gt;Issue: STM deadlock&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Nested STM transactions with external IO.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Use &lt;code&gt;atomically&lt;/code&gt; only for pure STM, run IO separately:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Bad: IO inside atomically&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;atomically &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    val &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getComponent world eid&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class="op"&gt;$&lt;/span&gt; expensiveOp val  &lt;span class="co"&gt;-- DON&amp;#39;T DO THIS&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    setComponent world eid result&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Good: Separate IO&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;mVal &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; getComponent world eid&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; mVal &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Just&lt;/span&gt; val &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        result &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; expensiveOp val&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        atomically &lt;span class="op"&gt;$&lt;/span&gt; setComponent world eid result&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="issue-resource-leaks"&gt;Issue: Resource leaks&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Not cleaning up resources properly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Use &lt;code&gt;bracket&lt;/code&gt; or &lt;code&gt;ResourceT&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Control.Exception&lt;/span&gt; (bracket)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Using bracket&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;bracket &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (createResource ctx config mkHandle)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="op"&gt;\&lt;/span&gt;rid &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; cleanupResource registry rid)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="op"&gt;\&lt;/span&gt;rid &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        withResource registry rid &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;accessor &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            useResource accessor&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Or use cleanupScope for batch cleanup&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;cleanupScope registry (&lt;span class="dt"&gt;AgentScope&lt;/span&gt; agentId)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="issue-subcall-not-visible-in-tui"&gt;Issue: Subcall not visible in TUI&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Event queue not configured in ToolExecutionContext.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Ensure context includes event queue:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Check if event queue exists&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; ctxEventQueue ctx &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Warning: No event queue, subcall won&amp;#39;t be visible&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Just&lt;/span&gt; q &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Event queue configured&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- When creating context, include event queue&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ctx &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , ctxEventQueue &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; eventQueue  &lt;span class="co"&gt;-- Required for visibility&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="performance-considerations"&gt;Performance Considerations&lt;/h3&gt;
&lt;h4 id="stm-contention"&gt;STM Contention&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Many threads competing for same TVar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Use granular component stores:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Good: Separate TVars per component type&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;agentStore ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="dt"&gt;AgentConfig&lt;/span&gt;)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;toolboxStore ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; &lt;span class="dt"&gt;ToolboxConfig&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Bad: Single TVar for everything&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;allComponents ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;EntityId&lt;/span&gt; (&lt;span class="dt"&gt;AgentConfig&lt;/span&gt;, &lt;span class="dt"&gt;ToolboxConfig&lt;/span&gt;, &lt;span class="op"&gt;...&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="resource-pool-sizing"&gt;Resource Pool Sizing&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Too few connections in pool causes contention.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Size pools based on expected concurrency:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- HTTP pool: size = expected concurrent requests&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;httpRid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createHttpPool ctx &lt;span class="dv"&gt;20&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- SQLite with WAL: can have many readers&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sqliteRid &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createSqliteResource ctx config &lt;span class="dt"&gt;True&lt;/span&gt;  &lt;span class="co"&gt;-- WAL mode&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="snapshot-frequency"&gt;Snapshot Frequency&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Too frequent snapshots impact performance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Configure snapshot intervals:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;config &lt;span class="ot"&gt;=&lt;/span&gt; defaultOSConfig&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { osSnapshotInterval &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; (secondsToNominalDiffTime &lt;span class="dv"&gt;60&lt;/span&gt;)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , osMaxSnapshotsPerEntity &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;10&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="future-directions"&gt;Future Directions&lt;/h3&gt;
&lt;h4 id="query-system"&gt;Query System&lt;/h4&gt;
&lt;p&gt;Planned: ECS-style queries for efficient entity filtering:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Query all busy agents&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;busyAgents &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; query world &lt;span class="op"&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    select &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;AgentState&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    where_ (&lt;span class="op"&gt;\&lt;/span&gt;s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; agentStatus s &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="dt"&gt;AgentBusy&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Query conversations with recent activity&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;recentConvs &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; query world &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    select &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="dt"&gt;ConversationState&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    where_ (&lt;span class="op"&gt;\&lt;/span&gt;s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; conversationLastActivity s &lt;span class="op"&gt;&amp;gt;&lt;/span&gt; cutoffTime)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="distributed-os"&gt;Distributed OS&lt;/h4&gt;
&lt;p&gt;Planned: Multi-process OS with shared state:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Initialize distributed OS&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;os &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initializeDistributedOS &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { osNodeId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;node-1&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , osCluster &lt;span class="ot"&gt;=&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;node-1&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;node-2&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;node-3&amp;quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , osConsensus &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RaftConsensus&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="persistence-evolution"&gt;Persistence Evolution&lt;/h4&gt;
&lt;p&gt;Planned: Event sourcing for complete history:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Replay from event log&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;events &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; loadEvents backend&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;world &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; foldM applyEvent emptyWorld events&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Where applyEvent applies each event to world state&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="references"&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-OS-API.html"&gt;OS API Reference&lt;/a&gt; - Complete API documentation
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-architecture.html"&gt;Architecture Overview&lt;/a&gt; - System architecture
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-CHANGELOG-OS-MIGRATION.html"&gt;CHANGELOG-OS-MIGRATION.md&lt;/a&gt; - Detailed change log
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="summary"&gt;Summary&lt;/h3&gt;
&lt;p&gt;The OS Model migration provides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Better concurrency&lt;/strong&gt; via STM-based ECS
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource safety&lt;/strong&gt; via scoped lifecycle management
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visibility&lt;/strong&gt; via OS events for subcalls
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexibility&lt;/strong&gt; via pluggable persistence
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing&lt;/strong&gt; via clean separation of concerns
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For new code, use the OS Model directly. For legacy code, use the compatibility layer during migration.&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-MIGRATION-OS.html" rel="alternate"/><summary type="text">Complete migration guide for transitioning from the legacy Runtime-based architecture to the new ECS-based OS Model. ## Overview The Agents framework has migrated from a **Runtime-per-agent** model to an **Entity-Component-System (ECS)** ar</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-tools.html</id><title type="text">Tool System</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/tools.md"&gt;&lt;code&gt;documentation/tools.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="tool-system"&gt;Tool System&lt;/h2&gt;
&lt;p&gt;&lt;img src="/agents-exe/gen/images/agent-tree.dot.png" alt="What an agent can call: helper agents, executable tools, MCP servers and OpenAPI operations all reach the model as functions." /&gt;&lt;/p&gt;
&lt;p&gt;The tool system provides agents with the ability to execute external commands, call APIs, and interact with other agents. Tools are dynamically registered and exposed to the LLM via the OpenAI function calling API.&lt;/p&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────┐
│                       Tool System                               │
├────────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐            │
│  │ Bash Tools  │  │  MCP Tools  │  │ OpenAPI     │            │
│  │ (scripts)   │  │ (servers)   │  │ (REST APIs) │            │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘            │
│         │                │                │                    │
│         └────────────────┴────────────────┘                    │
│                          │                                      │
│                   ┌──────▼──────┐                              │
│                   │  Toolbox    │                              │
│                   │  (merging)  │                              │
│                   └──────┬──────┘                              │
│                          │                                      │
│                   ┌──────▼──────┐                              │
│                   │ ToolRegistration│                           │
│                   │ (LLM schema) │                              │
│                   └─────────────┘                              │
└────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="tool-types"&gt;Tool Types&lt;/h3&gt;
&lt;p&gt;The framework supports multiple tool types:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Tool Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Use Case&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Bash Tools&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Executable scripts&lt;/td&gt;&lt;td&gt;External commands, system integration&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;MCP Tools&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;MCP servers&lt;/td&gt;&lt;td&gt;Standardized tool protocols&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OpenAPI Tools&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;REST APIs&lt;/td&gt;&lt;td&gt;API integrations&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;PostgREST Tools&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Database endpoints&lt;/td&gt;&lt;td&gt;Database queries&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;SQLite Tools&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;SQLite databases&lt;/td&gt;&lt;td&gt;Local SQL queries&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;System Tools&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;System information&lt;/td&gt;&lt;td&gt;Runtime context, session introspection, command execution&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Developer Tools&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Development utilities&lt;/td&gt;&lt;td&gt;File editing with multi-turn sessions, agent validation/creation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;IO Tools&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Haskell functions&lt;/td&gt;&lt;td&gt;In-process operations&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Lua Tools&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Lua scripts&lt;/td&gt;&lt;td&gt;Embedded scripting&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Skills&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Progressive disclosure&lt;/td&gt;&lt;td&gt;Procedural knowledge&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="media-types-and-multi-modal-support"&gt;Media Types and Multi-Modal Support&lt;/h3&gt;
&lt;p&gt;The framework supports media attachments and multi-modal responses for LLM interactions.&lt;/p&gt;
&lt;h4 id="media-type-classification"&gt;Media Type Classification&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- System.Agents.Media.Types&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;MediaType&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;MediaImage&lt;/span&gt; &lt;span class="dt"&gt;ImageType&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaAudio&lt;/span&gt; &lt;span class="dt"&gt;AudioType&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaVideo&lt;/span&gt; &lt;span class="dt"&gt;VideoType&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaApplication&lt;/span&gt; &lt;span class="dt"&gt;ApplicationType&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaText&lt;/span&gt; &lt;span class="dt"&gt;TextSubtype&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ImageType&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ImagePNG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ImageJPEG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ImageGIF&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ImageWebP&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ImageSVG&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AudioType&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AudioMPEG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioWAV&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioOGG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioMP3&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioAAC&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AudioFLAC&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;VideoType&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;VideoMP4&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;VideoWebM&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;VideoOGG&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;VideoAVI&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;VideoMOV&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ApplicationType&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AppPDF&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppJSON&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppXML&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppOctetStream&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppZip&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;TextSubtype&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TextPlain&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TextHTML&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TextCSS&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TextCSV&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TextMarkdown&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="media-attachments"&gt;Media Attachments&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; mediaMimeType ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;        &lt;span class="co"&gt;-- e.g., &amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mediaBase64Data ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;      &lt;span class="co"&gt;-- Base64-encoded content&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mediaFilename ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;  &lt;span class="co"&gt;-- Optional filename&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="content-parts-for-mixed-responses"&gt;Content Parts for Mixed Responses&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ContentPart&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TextPart&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaPart&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="declaring-media-output-in-scripts"&gt;Declaring Media Output in Scripts&lt;/h4&gt;
&lt;p&gt;Tools can declare their output media type in the describe output:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="bu"&gt;[&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;describe&amp;quot;&lt;/span&gt; &lt;span class="bu"&gt;]&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;        &amp;quot;slug&amp;quot;: &amp;quot;generate_chart&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;        &amp;quot;description&amp;quot;: &amp;quot;Generates a chart image&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;        &amp;quot;args&amp;quot;: [...],&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;        &amp;quot;output-media-type&amp;quot;: &amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    }&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;exit&lt;/span&gt; 0&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Generate and output PNG image to stdout&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;./generate-chart&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Supported media types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Images&lt;/strong&gt;: &lt;code&gt;image/png&lt;/code&gt;, &lt;code&gt;image/jpeg&lt;/code&gt;, &lt;code&gt;image/gif&lt;/code&gt;, &lt;code&gt;image/webp&lt;/code&gt;, &lt;code&gt;image/svg+xml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audio&lt;/strong&gt;: &lt;code&gt;audio/mpeg&lt;/code&gt;, &lt;code&gt;audio/wav&lt;/code&gt;, &lt;code&gt;audio/ogg&lt;/code&gt;, &lt;code&gt;audio/mp3&lt;/code&gt;, &lt;code&gt;audio/aac&lt;/code&gt;, &lt;code&gt;audio/flac&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video&lt;/strong&gt;: &lt;code&gt;video/mp4&lt;/code&gt;, &lt;code&gt;video/webm&lt;/code&gt;, &lt;code&gt;video/ogg&lt;/code&gt;, &lt;code&gt;video/avi&lt;/code&gt;, &lt;code&gt;video/quicktime&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documents&lt;/strong&gt;: &lt;code&gt;application/pdf&lt;/code&gt;, &lt;code&gt;application/json&lt;/code&gt;, &lt;code&gt;application/xml&lt;/code&gt;, &lt;code&gt;application/zip&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generic&lt;/strong&gt;: &lt;code&gt;application/octet-stream&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tool-result-types-with-media"&gt;Tool Result Types with Media&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;CallResult&lt;/span&gt; call&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="co"&gt;-- | Successful execution with optional media type hint&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;BlobToolSuccess&lt;/span&gt; call &lt;span class="dt"&gt;ByteString&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;MediaType&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="co"&gt;-- ... other constructors&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;UserToolResponse&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TextResponse&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                    &lt;span class="co"&gt;-- Plain UTF-8 text&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;JsonResponse&lt;/span&gt; &lt;span class="dt"&gt;Aeson.Value&lt;/span&gt;             &lt;span class="co"&gt;-- Structured JSON data&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MediaResponse&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;        &lt;span class="co"&gt;-- Single binary media&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MixedResponse&lt;/span&gt; [&lt;span class="dt"&gt;ContentPart&lt;/span&gt;]          &lt;span class="co"&gt;-- Multi-modal content&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="tool-registration"&gt;Tool Registration&lt;/h3&gt;
&lt;p&gt;All tools are registered using the &lt;code&gt;ToolRegistration&lt;/code&gt; type:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; innerTool ::&lt;/span&gt; &lt;span class="dt"&gt;Tool&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; declareTool ::&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.Tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; findTool ::&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolCall&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;Tool&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.ToolCall&lt;/span&gt;)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="registration-flow"&gt;Registration Flow&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Tool sources (bash, MCP, OpenAPI, System, Developer) generate &lt;code&gt;ToolRegistration&lt;/code&gt; values
&lt;/li&gt;
&lt;li&gt;Registrations are combined into a single list
&lt;/li&gt;
&lt;li&gt;The list is passed to the LLM API as available functions
&lt;/li&gt;
&lt;li&gt;When the LLM calls a function, the executor is invoked
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="bash-tools"&gt;Bash Tools&lt;/h3&gt;
&lt;p&gt;Bash tools are executable scripts stored in the agent’s tool directory.&lt;/p&gt;
&lt;h4 id="script-requirements"&gt;Script Requirements&lt;/h4&gt;
&lt;p&gt;Scripts must support a &lt;code&gt;describe&lt;/code&gt; subcommand that outputs JSON:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="bu"&gt;[&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="ot"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;describe&amp;quot;&lt;/span&gt; &lt;span class="bu"&gt;]&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;        &amp;quot;slug&amp;quot;: &amp;quot;my-tool&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;        &amp;quot;description&amp;quot;: &amp;quot;What this tool does&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;        &amp;quot;args&amp;quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;                &amp;quot;name&amp;quot;: &amp;quot;input&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;                &amp;quot;description&amp;quot;: &amp;quot;Input parameter&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;                &amp;quot;backing_type&amp;quot;: &amp;quot;string&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;                &amp;quot;arity&amp;quot;: &amp;quot;single&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;                &amp;quot;mode&amp;quot;: &amp;quot;dashdashspace&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;        ],&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;        &amp;quot;empty-result&amp;quot;: {&amp;quot;tag&amp;quot;: &amp;quot;AddMessage&amp;quot;, &amp;quot;contents&amp;quot;: &amp;quot;No results&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    }&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;exit&lt;/span&gt; 0&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Main execution&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;input&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Result for: &lt;/span&gt;&lt;span class="va"&gt;$input&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="scriptinfo-schema"&gt;ScriptInfo Schema&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ScriptInfo&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ScriptInfo&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; scriptArgs ::&lt;/span&gt; [&lt;span class="dt"&gt;ScriptArg&lt;/span&gt;]&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; scriptSlug ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; scriptDescription ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; scriptEmptyResultBehavior ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;EmptyResultBehavior&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; scriptOutputMediaType ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;  &lt;span class="co"&gt;-- NEW: Media type for binary output&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ScriptArg&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ScriptArg&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; argName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; argDescription ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; argType ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; argBackingType ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; argArity ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;  &lt;span class="co"&gt;-- &amp;quot;single&amp;quot;, &amp;quot;optional&amp;quot;, &amp;quot;multiple&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; argMode ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;   &lt;span class="co"&gt;-- &amp;quot;dashdashspace&amp;quot;, &amp;quot;space&amp;quot;, etc.&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="environment-variables"&gt;Environment Variables&lt;/h4&gt;
&lt;p&gt;When a bash tool runs, it receives context via environment variables:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Variable&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_SESSION_ID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Current session UUID&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_CONVERSATION_ID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Conversation UUID&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_TURN_ID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Current turn UUID&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_AGENT_ID&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Agent UUID (if available)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AGENT_SESSION_JSON&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Full session as JSON&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;A &lt;code&gt;FileSystemDirectory&lt;/code&gt;/&lt;code&gt;SingleTool&lt;/code&gt; toolbox description can also carry a
&lt;code&gt;Bindings&lt;/code&gt; list, tying an argument to a fixed value or to an agent
parameter — the argument disappears from the tool’s schema entirely, and
the model never sees or chooses the value. A parameter’s value can also be
passed as an environment variable only (&lt;code&gt;&amp;quot;mode&amp;quot;: &amp;quot;env&amp;quot;&lt;/code&gt;), the one way to
bind a &lt;code&gt;secret&lt;/code&gt; parameter safely. See
&lt;a href="/agents-exe/docs-parameters-and-bindings.html"&gt;Parameters, Bindings &amp;amp; Narrowing Sub-Agents&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="bash-toolbox"&gt;Bash Toolbox&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;BashToolbox&lt;/code&gt; module manages script discovery and execution:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Toolbox&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Toolbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; tools ::&lt;/span&gt; &lt;span class="dt"&gt;BackgroundVal&lt;/span&gt; [&lt;span class="dt"&gt;ToolRegistration&lt;/span&gt;]&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; triggerReload ::&lt;/span&gt; &lt;span class="dt"&gt;STM&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;initializeBackroundToolbox ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ToolboxError&lt;/span&gt; &lt;span class="dt"&gt;Toolbox&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hot reloading&lt;/strong&gt;: File changes trigger automatic reload
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Background thread&lt;/strong&gt;: Non-blocking tool discovery
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error isolation&lt;/strong&gt;: Failed scripts don’t break other tools
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="mcp-tools"&gt;MCP Tools&lt;/h3&gt;
&lt;p&gt;Model Context Protocol (MCP) tools connect to external servers that provide dynamic tool listings.&lt;/p&gt;
&lt;h4 id="mcp-server-types"&gt;MCP Server Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;McpServerDescription&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;McpSimpleBinary&lt;/span&gt; &lt;span class="dt"&gt;McpSimpleBinaryConfiguration&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;McpSimpleBinaryConfiguration&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;McpSimpleBinaryConfiguration&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; name ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; executable ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; args ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="mcp-client-runtime"&gt;MCP Client Runtime&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; procHandle ::&lt;/span&gt; &lt;span class="dt"&gt;ProcessHandle&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; stdinHandle ::&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; stdoutHandle ::&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; toolsList ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; [&lt;span class="dt"&gt;ToolDescription&lt;/span&gt;]&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; callResults ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;CallId&lt;/span&gt; &lt;span class="dt"&gt;Value&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="mcp-tool-flow"&gt;MCP Tool Flow&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;1. Start MCP server process
2. Initialize connection
3. Query available tools
4. Register tools with LLM
5. On LLM call:
   a. Send tool_call message to MCP server
   b. Wait for response
   c. Return result to LLM
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="mcp-protocol-messages"&gt;MCP Protocol Messages&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Tool&lt;/span&gt; &lt;span class="er"&gt;list&lt;/span&gt; &lt;span class="er"&gt;request&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;jsonrpc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;method&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools/list&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Tool&lt;/span&gt; &lt;span class="er"&gt;list&lt;/span&gt; &lt;span class="er"&gt;response&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;jsonrpc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read_file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Read a file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="dt"&gt;&amp;quot;inputSchema&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="er"&gt;...&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt; &lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Tool&lt;/span&gt; &lt;span class="er"&gt;call&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;jsonrpc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;method&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools/call&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;params&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read_file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arguments&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/tmp/foo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}},&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="openapi-tools"&gt;OpenAPI Tools&lt;/h3&gt;
&lt;p&gt;OpenAPI tools convert REST API specifications into LLM-callable tools.&lt;/p&gt;
&lt;h4 id="openapi-server-configuration"&gt;OpenAPI Server Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;mcpServers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="er"&gt;...&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;openApiToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAPIServer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;SpecUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.example.com/openapi.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;BaseUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.example.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Headers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;X-API-Version&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;${API_TOKEN}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This description can also carry a &lt;code&gt;Bindings&lt;/code&gt; list, same as a bash toolbox —
see &lt;a href="/agents-exe/docs-parameters-and-bindings.html"&gt;Parameters, Bindings &amp;amp; Narrowing Sub-Agents&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="conversion-process"&gt;Conversion Process&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Load and parse OpenAPI spec&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;convertOpenAPIToTools ::&lt;/span&gt; &lt;span class="dt"&gt;OpenAPISpec&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;OpenAPITool&lt;/span&gt;]&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Convert operation to tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;convertOperation ::&lt;/span&gt; &lt;span class="dt"&gt;Path&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Method&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Operation&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OpenAPITool&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Build tool parameters from OpenAPI parameters&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;buildToolParameters ::&lt;/span&gt; &lt;span class="dt"&gt;Operation&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolParameters&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Convert to OpenAI tool format&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;toOpenAITool ::&lt;/span&gt; &lt;span class="dt"&gt;OpenAPITool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.Tool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="schema-resolution"&gt;Schema Resolution&lt;/h4&gt;
&lt;p&gt;The OpenAPI module handles &lt;code&gt;$ref&lt;/code&gt; references:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;resolveSchema ::&lt;/span&gt; &lt;span class="dt"&gt;Schema&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Components&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Schema&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;dereferenceSpec ::&lt;/span&gt; &lt;span class="dt"&gt;OpenAPISpec&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;OpenAPISpec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Supports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Internal references (&lt;code&gt;#/components/schemas/Foo&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;Nested references
&lt;/li&gt;
&lt;li&gt;Array item references
&lt;/li&gt;
&lt;li&gt;anyOf/allOf compositions
&lt;/li&gt;
&lt;li&gt;Circular reference detection
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="name-normalization"&gt;Name Normalization&lt;/h4&gt;
&lt;p&gt;OpenAPI operation IDs are normalized for LLM compatibility:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Original: &amp;quot;pets.getById&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Normalized: &amp;quot;pets_getById&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Original: &amp;quot;/users/{id}/posts&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Normalized: &amp;quot;_users__id__posts&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;NameMapping&lt;/code&gt; type tracks bidirectional mapping:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;NameMapping&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;NameMapping&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; nmOriginal ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; nmNormalized ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="postgrest-tools"&gt;PostgREST Tools&lt;/h3&gt;
&lt;p&gt;PostgREST tools generate database query tools from PostgREST APIs.&lt;/p&gt;
&lt;h4 id="configuration"&gt;Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;postgrestToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;PostgRESTServer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;SpecUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;http://localhost:3000/&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;BaseUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;http://localhost:3000&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This description can also carry a &lt;code&gt;Bindings&lt;/code&gt; list, same as a bash toolbox —
see &lt;a href="/agents-exe/docs-parameters-and-bindings.html"&gt;Parameters, Bindings &amp;amp; Narrowing Sub-Agents&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="generated-tools"&gt;Generated Tools&lt;/h4&gt;
&lt;p&gt;For each table endpoint, the following tools are generated:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;HTTP Method&lt;/th&gt;&lt;th&gt;Tool Name Pattern&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GET&lt;/td&gt;&lt;td&gt;&lt;code&gt;postgrest_{name}_get_{table}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Query with filters&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;POST&lt;/td&gt;&lt;td&gt;&lt;code&gt;postgrest_{name}_post_{table}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Insert rows&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PUT&lt;/td&gt;&lt;td&gt;&lt;code&gt;postgrest_{name}_put_{table}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Update rows&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PATCH&lt;/td&gt;&lt;td&gt;&lt;code&gt;postgrest_{name}_patch_{table}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Partial update&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;DELETE&lt;/td&gt;&lt;td&gt;&lt;code&gt;postgrest_{name}_delete_{table}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Delete rows&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="tool-parameters"&gt;Tool Parameters&lt;/h4&gt;
&lt;p&gt;PostgREST tools use structured parameter groups:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;filters&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;column_name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;filter_value&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;subset&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;limit&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;offset&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;columns&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;id,name,email&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;ranking&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;order&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;created_at.desc&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;New Item&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;42&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="sqlite-tools"&gt;SQLite Tools&lt;/h3&gt;
&lt;p&gt;SQLite tools provide SQL query capabilities against SQLite databases.&lt;/p&gt;
&lt;h4 id="configuration-1"&gt;Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;builtinToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SqliteToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;analytics&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Analytics database&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Versioning&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SqliteReadOnly&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./analytics.db&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tool-interface"&gt;Tool Interface&lt;/h4&gt;
&lt;p&gt;Each SQLite toolbox exposes a single &lt;code&gt;sqlite_{name}_query&lt;/code&gt; tool:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sql&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SELECT * FROM users WHERE active = 1 LIMIT 10&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sql&lt;/code&gt; (string, required): SQL query to execute
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Security:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read-only queries are encouraged
&lt;/li&gt;
&lt;li&gt;Write operations are allowed but logged
&lt;/li&gt;
&lt;li&gt;No DDL by default (configurable)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="file-sandbox-system"&gt;File Sandbox System&lt;/h3&gt;
&lt;p&gt;The file sandbox system provides secure, configurable file access control for tools that need to read from or write to the filesystem. It is used by the System Toolbox (for &lt;code&gt;attach-file&lt;/code&gt;), Developer Toolbox (for &lt;code&gt;read-file-range&lt;/code&gt;, &lt;code&gt;write-file-range&lt;/code&gt;, &lt;code&gt;patch-file&lt;/code&gt;), and Lua Toolbox (for the &lt;code&gt;fs&lt;/code&gt; module).&lt;/p&gt;
&lt;h4 id="overview-1"&gt;Overview&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                    File Sandbox System                           │
├─────────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │ SystemToolbox│  │DeveloperToolbox│  │ LuaToolbox │             │
│  │ (attach-file)│  │(read/write/   │  │ (fs.*)     │             │
│  │              │  │ patch-file)   │  │            │             │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘             │
│         │                 │                  │                    │
│         └─────────────────┼──────────────────┘                    │
│                           │                                       │
│                    ┌──────▼──────┐                                │
│                    │ FileSandbox │                                │
│                    │  (validate) │                                │
│                    └──────┬──────┘                                │
│                           │                                       │
│                    ┌──────▼──────┐                                │
│                    │PathPredicate│                                │
│                    │  (access)   │                                │
│                    └─────────────┘                                │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="filesandboxconfig"&gt;FileSandboxConfig&lt;/h4&gt;
&lt;p&gt;Each sandboxed toolbox accepts an optional &lt;code&gt;FileSandbox&lt;/code&gt; configuration, either
inline (below) or as a reference to a &lt;a href="#named-sandboxes"&gt;named sandbox&lt;/a&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;FileSandboxConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;FileSandboxConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; fsbPredicate ::&lt;/span&gt; &lt;span class="dt"&gt;PathPredicate&lt;/span&gt;     &lt;span class="co"&gt;-- Defines allowed file paths&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; fsbMaxFileSize ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Integer&lt;/span&gt;   &lt;span class="co"&gt;-- Max file size in bytes (Nothing = no limit)&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; fsbName ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;             &lt;span class="co"&gt;-- Human-readable name for the sandbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Default Configuration (Secure by Default):&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;defaultFileSandboxConfig ::&lt;/span&gt; &lt;span class="dt"&gt;FileSandboxConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;defaultFileSandboxConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;FileSandboxConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { fsbPredicate &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AlwaysDeny&lt;/span&gt;          &lt;span class="co"&gt;-- Deny all access by default&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , fsbMaxFileSize &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; (&lt;span class="dv"&gt;50&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="dv"&gt;1024&lt;/span&gt; &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="dv"&gt;1024&lt;/span&gt;)  &lt;span class="co"&gt;-- 50MB default limit&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , fsbName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="named-sandboxes"&gt;Named Sandboxes&lt;/h4&gt;
&lt;p&gt;A sandbox can be written once, under a name, in the agent’s &lt;code&gt;fileSandboxes&lt;/code&gt;
map, and referenced from any builtin toolbox of that agent with
&lt;code&gt;{&amp;quot;ref&amp;quot;: &amp;quot;&amp;lt;name&amp;gt;&amp;quot;}&lt;/code&gt; in place of the inline definition:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;coder&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;fileSandboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;project&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;fsbMaxFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10485760&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;scratch&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/tmp/scratch&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;builtinToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DeveloperToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;dev&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Development tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;read-file-range&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;patch-file&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;ref&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;project&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;LuaToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;lua&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Lua orchestration&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;MaxMemoryMB&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;256&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;MaxExecutionTimeSeconds&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;300&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;AllowedTools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;AllowedHosts&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;ref&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;project&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SystemToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;system&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;System context&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;attach-file&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;ref&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;scratch&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The value of &lt;code&gt;FileSandbox&lt;/code&gt; is therefore one of two things:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Form&lt;/th&gt;&lt;th&gt;JSON&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Inline&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"fsbPredicate": ..., "fsbMaxFileSize": ..., "fsbName": ...}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The sandbox itself, as before. Existing agent files need no change.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Reference&lt;/td&gt;&lt;td&gt;&lt;code&gt;{"ref": "project"}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The sandbox declared as &lt;code&gt;project&lt;/code&gt; in this agent's &lt;code&gt;fileSandboxes&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resolution happens when the agent’s toolboxes are loaded.&lt;/strong&gt; Each reference
is replaced by the named definition, and the toolbox then behaves exactly as
if the definition had been written inline.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An undeclared name is an error&lt;/strong&gt;, not an empty sandbox: the agent fails to
load with a message naming the toolbox and the missing sandbox, and
&lt;code&gt;validate-agent&lt;/code&gt; reports it too.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ref&lt;/code&gt; stands alone.&lt;/strong&gt; An object carrying both &lt;code&gt;ref&lt;/code&gt; and inline fields is
refused, so that a sandbox is never silently widened or narrowed at the
place it is used.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The name is the default &lt;code&gt;fsbName&lt;/code&gt;.&lt;/strong&gt; A referenced sandbox that sets no
&lt;code&gt;fsbName&lt;/code&gt; is named after its key in &lt;code&gt;fileSandboxes&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Each toolbox gets its own sandbox instance&lt;/strong&gt; built from the shared
definition: the rules are shared, nothing else is.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fileSandboxes&lt;/code&gt; is optional; an agent without it loads as before.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What this does and does not do.&lt;/strong&gt; Naming a sandbox changes where the rules
are written, not what is enforced. The enforcement is the one described in
this section: a path predicate and a size limit checked by the builtin tools
that take a &lt;code&gt;FileSandbox&lt;/code&gt; (&lt;code&gt;attach-file&lt;/code&gt; and &lt;code&gt;list-directory&lt;/code&gt; in the System
Toolbox, the file capabilities of the Developer Toolbox, the Lua &lt;code&gt;fs&lt;/code&gt; module).
It is not an operating-system sandbox: bash tools, MCP servers,
&lt;code&gt;execute-command&lt;/code&gt; and &lt;code&gt;build-command&lt;/code&gt; run as ordinary processes and are not
confined by it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scope.&lt;/strong&gt; &lt;code&gt;fileSandboxes&lt;/code&gt; belongs to one agent file; a name declared in one
agent is not visible from another, including its sub-agents. To share one
definition across several agent files, use an &lt;a href="/agents-exe/docs-agent-templates.html"&gt;agent template&lt;/a&gt;
library: define the sandbox once there and either pass it inline to each
toolbox or put it in the &lt;code&gt;fileSandboxes&lt;/code&gt; of each agent.&lt;/p&gt;
&lt;h4 id="pathpredicate-dsl"&gt;PathPredicate DSL&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;PathPredicate&lt;/code&gt; DSL provides a rich, composable language for defining file access permissions:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;PathPredicate&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;FileExactly&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;              &lt;span class="co"&gt;-- Exact file match&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DirectoryExactly&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;         &lt;span class="co"&gt;-- Exact directory match (contents not included)&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DirectoryRecursive&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;       &lt;span class="co"&gt;-- Directory and all subdirectories&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DirectoryShallow&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;         &lt;span class="co"&gt;-- Directory contents only (not subdirectories)&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;FilePattern&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;                &lt;span class="co"&gt;-- Glob pattern on filename (*, ? wildcards)&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;FileExtension&lt;/span&gt; [&lt;span class="dt"&gt;String&lt;/span&gt;]            &lt;span class="co"&gt;-- File extension whitelist (no leading dot)&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;FileSizeLessThan&lt;/span&gt; &lt;span class="dt"&gt;Integer&lt;/span&gt;          &lt;span class="co"&gt;-- Maximum file size in bytes&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ChildOf&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;                  &lt;span class="co"&gt;-- Path within a parent directory&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;And&lt;/span&gt; &lt;span class="dt"&gt;PathPredicate&lt;/span&gt; &lt;span class="dt"&gt;PathPredicate&lt;/span&gt;   &lt;span class="co"&gt;-- Logical AND&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Or&lt;/span&gt; &lt;span class="dt"&gt;PathPredicate&lt;/span&gt; &lt;span class="dt"&gt;PathPredicate&lt;/span&gt;    &lt;span class="co"&gt;-- Logical OR&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Not&lt;/span&gt; &lt;span class="dt"&gt;PathPredicate&lt;/span&gt;                 &lt;span class="co"&gt;-- Logical NOT&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Any&lt;/span&gt; [&lt;span class="dt"&gt;PathPredicate&lt;/span&gt;]               &lt;span class="co"&gt;-- OR of all predicates&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;All&lt;/span&gt; [&lt;span class="dt"&gt;PathPredicate&lt;/span&gt;]               &lt;span class="co"&gt;-- AND of all predicates&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AlwaysAllow&lt;/span&gt;                       &lt;span class="co"&gt;-- Allow all (use sparingly)&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AlwaysDeny&lt;/span&gt;                        &lt;span class="co"&gt;-- Deny all (secure default)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="predicate-examples"&gt;Predicate Examples&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Allow specific files and directories:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Any&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileExactly&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./package.yaml&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileExactly&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./README.md&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Allow only Haskell source files under 1MB:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;And&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileExtension&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;hs&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;lhs&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileSizeLessThan&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1048576&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Allow any file in project except build artifacts:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;And&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./my-project&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Not&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./my-project/dist&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Glob pattern matching:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Any&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FilePattern&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;*.md&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FilePattern&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;test-*.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="path-handling"&gt;Path Handling&lt;/h4&gt;
&lt;p&gt;All paths are canonicalized before validation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Symlinks are resolved&lt;/strong&gt; - The predicate is applied to the canonical path
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relative paths are resolved&lt;/strong&gt; - Relative paths in predicates are resolved relative to the current working directory
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Path normalization&lt;/strong&gt; - &lt;code&gt;..&lt;/code&gt; and &lt;code&gt;.&lt;/code&gt; components are resolved, duplicate slashes removed
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The predicate applies to the canonical path, not the symlink path. This prevents symlink traversal attacks where a symlink inside an allowed directory points outside the sandbox.&lt;/p&gt;
&lt;h4 id="security-features"&gt;Security Features&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Feature&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Default Deny&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;All access is denied unless explicitly allowed (&lt;code&gt;AlwaysDeny&lt;/code&gt; is default)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Immutable&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Sandboxes cannot be modified after creation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Canonicalization&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;All paths are canonicalized before validation (resolves symlinks, &lt;code&gt;..&lt;/code&gt;, etc.)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Size Limits&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Optional file size limits prevent resource exhaustion&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Composable&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Predicates can be combined with logical operators for complex rules&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="system-toolbox-builtin"&gt;System Toolbox (Builtin)&lt;/h3&gt;
&lt;p&gt;The System Toolbox provides agents with contextual information about the running system through a configurable set of capabilities.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;get-tool-call-status&lt;/code&gt;, &lt;code&gt;list-running-tool-calls&lt;/code&gt; and &lt;code&gt;cancel-tool-call&lt;/code&gt;
capabilities only do something for agents that run tool calls in the
background; see &lt;a href="/agents-exe/docs-async-tool-calls.html"&gt;async-tool-calls.md&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="capabilities"&gt;Capabilities&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Capability&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;date&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Current UTC/local time and timezone info&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;operating-system&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OS name, version, kernel, architecture&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;env-vars&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Filtered environment variables&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;running-user&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Username, UID, GID, home, shell&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hostname&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Machine hostname&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;working-directory&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Current working directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;process-info&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Process ID, parent PID, process name&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;uptime&lt;/code&gt;&lt;/td&gt;&lt;td&gt;System uptime&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;attach-file&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Attach a file to the conversation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;list-directory&lt;/code&gt;&lt;/td&gt;&lt;td&gt;List directory contents with metadata&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;execute-command&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Execute shell commands with optional filter approval&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;get-tool-call-status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Status, progress and result of one of the agent's own tool calls&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;list-running-tool-calls&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Tool calls still running in the background&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;cancel-tool-call&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Stop a running background tool call&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;list-sessions&lt;/code&gt;&lt;/td&gt;&lt;td&gt;List accessible sessions (requires session introspection config)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;search-sessions&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Full-text search across sessions (requires session introspection config)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;read-session&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Read session content (requires session introspection config)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;get-session-stats&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Get session statistics (requires session introspection config)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="configuration-2"&gt;Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;builtinToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SystemToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;system&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;System context and information&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;operating-system&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;running-user&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;hostname&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;attach-file&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;list-directory&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;execute-command&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;EnvVarFilter&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./project&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbMaxFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;52428800&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;system-sandbox&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;CommandFilter&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/approval-script.sh&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="attach-file-capability"&gt;Attach-File Capability&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;attach-file&lt;/code&gt; capability allows the agent to attach files to the conversation for multi-modal LLM interactions:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Tool accepts:&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;{&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="st"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;attach-file&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="st"&gt;&amp;quot;filepath&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/image.png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Returns:&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- MediaAttachment with base64-encoded content&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Supported file types:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Images&lt;/strong&gt;: PNG, JPEG, GIF, WEBP, SVG
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audio&lt;/strong&gt;: MP3, WAV, OGG, AAC, FLAC
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video&lt;/strong&gt;: MP4, WEBM, MOV, AVI
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documents&lt;/strong&gt;: PDF, JSON, XML
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generic&lt;/strong&gt;: Any file (as octet-stream)
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limits:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maximum file size: 50MB
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sandbox Behavior:&lt;/strong&gt;
When &lt;code&gt;attach-file&lt;/code&gt; is enabled, a file sandbox must be configured to specify which files can be attached. If no sandbox is configured, the capability will deny all file access.&lt;/p&gt;
&lt;h4 id="list-directory-capability"&gt;List-Directory Capability&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;list-directory&lt;/code&gt; capability lists directory contents with metadata:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Input:&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;list-directory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;recursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;include_hidden&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Output:&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;entries&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Main.hs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;size&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1234&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;modified&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2024-01-15T10:30:00Z&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Utils&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;directory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;size&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;modified&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2024-01-14T08:00:00Z&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;total&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="execute-command-capability"&gt;Execute-Command Capability&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;execute-command&lt;/code&gt; capability allows the agent to execute arbitrary shell commands with an optional approval filter:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Input:&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;execute-command&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;command&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;ls -la&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Output:&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;command&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;ls -la&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;exitCode&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;stdout&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;stderr&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;duration&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fl"&gt;0.123&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Command Filter:&lt;/strong&gt;
When &lt;code&gt;CommandFilter&lt;/code&gt; is configured, every command is first passed to the filter on stdin. The filter must output a JSON acceptance object:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Allowed:&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;acceptance&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;allowed&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;note&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Safe command&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Refused:&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;acceptance&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;refused&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;note&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Command contains dangerous operations&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Any non-JSON output, missing fields, or non-zero exit code rejects the command.&lt;/p&gt;
&lt;h4 id="session-introspection-capabilities"&gt;Session Introspection Capabilities&lt;/h4&gt;
&lt;p&gt;The System Toolbox supports session introspection capabilities that allow agents to query, search, and read other sessions from the session store. This enables cross-session analysis and context sharing.&lt;/p&gt;
&lt;h5 id="session-introspection-scope"&gt;Session Introspection Scope&lt;/h5&gt;
&lt;p&gt;Access control is managed through &lt;code&gt;SessionIntrospectionScope&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Scope&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;parents-only&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Can only see parent sessions (ancestors via forkedFromSessionId)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;children-only&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Can only see child sessions (descendants)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;subtree&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Parents + current + children (default)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;all&lt;/code&gt;&lt;/td&gt;&lt;td&gt;All sessions (requires explicit opt-in)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h5 id="configuration-with-session-introspection"&gt;Configuration with Session Introspection&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SystemToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;system&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;System information and session memory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;hostname&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;list-sessions&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;search-sessions&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;read-session&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;get-session-stats&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;SessionIntrospectionScope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;subtree&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;SessionIntrospectionMaxResults&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;50&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;SessionIntrospectionIncludeToolOutputs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="list-sessions"&gt;list-sessions&lt;/h5&gt;
&lt;p&gt;Lists accessible sessions based on the configured scope.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;list-sessions&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;sessionId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;conversationId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;modificationTime&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2024-01-15T10:30:00Z&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;turnCount&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;15&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;isParent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;isChild&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;isLocked&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;idle&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;totalAccessible&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;42&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="search-sessions"&gt;search-sessions&lt;/h5&gt;
&lt;p&gt;Performs full-text search across accessible sessions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;search-sessions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;query&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;error handling pattern&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;query&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;error handling pattern&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;results&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;sessionId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;conversationId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;turnCount&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;15&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;preview&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;...context around match...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;matchType&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;totalMatches&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;subtree&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="read-session"&gt;read-session&lt;/h5&gt;
&lt;p&gt;Reads session content with optional slicing and filtering.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-session&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;session_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;target-session-uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;take_n&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;include_thinking&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;include_tool_responses&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;session_id&lt;/code&gt; (string, required): Session UUID to read
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;take_n&lt;/code&gt; (number, optional): Take last N turns (alternative to offset/limit)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drop_n&lt;/code&gt; (number, optional): Drop first N turns
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;offset&lt;/code&gt; (number, optional): Starting turn index (0-based)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;limit&lt;/code&gt; (number, optional): Max turns to return
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;include_thinking&lt;/code&gt; (boolean, optional): Include LLM thinking/reasoning (default: false)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;include_tool_responses&lt;/code&gt; (boolean, optional): Include tool call responses (default: false)
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessionId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;target-session-uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;conversationId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;totalTurns&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;25&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;returnedTurns&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Turn 1: [User] ...&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;Turn 2: [LLM] ...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;format&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;condensed-text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;subtree&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;access&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;granted&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="get-session-stats"&gt;get-session-stats&lt;/h5&gt;
&lt;p&gt;Returns aggregate statistics about accessible sessions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;get-session-stats&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;totalSessions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;42&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;totalTurnsAcrossAllSessions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;850&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;subtree&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;note&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Use SessionPrint.calculateStatistics for detailed per-session stats&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="configuration-fields"&gt;Configuration Fields&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Name&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Unique name for this toolbox instance&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Description&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Human-readable description&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Capabilities&lt;/code&gt;&lt;/td&gt;&lt;td&gt;[string]&lt;/td&gt;&lt;td&gt;List of enabled capabilities&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;EnvVarFilter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string?&lt;/td&gt;&lt;td&gt;Optional substring filter for env vars&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SessionIntrospectionScope&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string?&lt;/td&gt;&lt;td&gt;Scope of accessible sessions (default: "subtree")&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SessionIntrospectionMaxResults&lt;/code&gt;&lt;/td&gt;&lt;td&gt;number?&lt;/td&gt;&lt;td&gt;Max sessions to return (default: 50)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SessionIntrospectionIncludeToolOutputs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;boolean?&lt;/td&gt;&lt;td&gt;Include tool outputs in read operations (default: true)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;FileSandbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;object?&lt;/td&gt;&lt;td&gt;File sandbox for attach-file/list-directory capabilities (default: deny all); inline or &lt;code&gt;{"ref": name}&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;CommandFilter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string?&lt;/td&gt;&lt;td&gt;Optional command approval filter for execute-command&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="security-considerations"&gt;Security Considerations&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Capability-based access&lt;/strong&gt;: Only enabled capabilities are exposed
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session scope enforcement&lt;/strong&gt;: Strict access control via &lt;code&gt;SessionIntrospectionScope&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ScopeAll requires explicit opt-in&lt;/strong&gt;: Must be explicitly configured, never default
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Env var filtering&lt;/strong&gt;: Use &lt;code&gt;EnvVarFilter&lt;/code&gt; to limit variable exposure
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read-only&lt;/strong&gt;: System tools gather information but cannot modify the system
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command filtering&lt;/strong&gt;: Use &lt;code&gt;CommandFilter&lt;/code&gt; to control command execution
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Linux-focused&lt;/strong&gt;: Initial implementation targets Linux systems
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="llm-tool-interface"&gt;LLM Tool Interface&lt;/h4&gt;
&lt;p&gt;The system toolbox exposes a single tool named &lt;code&gt;system_{name}_system_info&lt;/code&gt; with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parameter&lt;/strong&gt;: &lt;code&gt;capability&lt;/code&gt; (string) - Which system info to retrieve
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Additional parameters&lt;/strong&gt;: Vary by capability (see individual capability documentation)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Returns&lt;/strong&gt;: JSON object with the requested information
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example tool call:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Example response:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;utc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2024-01-15T10:30:00.123456Z&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;local&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2024-01-15T11:30:00.123456&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;timezone&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;CET&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;timezoneOffset&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;+0100&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;executionTime&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fl"&gt;0.001&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="developer-toolbox"&gt;Developer Toolbox&lt;/h3&gt;
&lt;p&gt;The Developer Toolbox provides utilities for writing and validating agents and tools, with advanced file editing capabilities including multi-turn edit sessions.&lt;/p&gt;
&lt;h4 id="capabilities-1"&gt;Capabilities&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Capability&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;show-spec&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Displays specification documentation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;validate-agent&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Validates an agent JSON configuration file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;create-agent&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Creates a new agent configuration&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;create-tool&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Creates a new tool script&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;show-spec&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Displays specification documentation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;read-file-range&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Reads specific line ranges from a file (supports session reads and metadata-only)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;write-file-range&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Replaces line ranges with multi-turn session support&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;patch-file&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Applies a unified diff patch to a file with rich error context&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="configuration-3"&gt;Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;builtinToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DeveloperToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;dev&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Development utilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;show-spec&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;validate-agent&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;create-agent&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;create-tool&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-file-range&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;write-file-range&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;patch-file&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbMaxFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;developer-sandbox&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="file-sandbox-for-developer-tools"&gt;File Sandbox for Developer Tools&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;read-file-range&lt;/code&gt;, &lt;code&gt;write-file-range&lt;/code&gt;, and &lt;code&gt;patch-file&lt;/code&gt; capabilities require a file sandbox to be configured. These capabilities operate on file content and need explicit permission to access the filesystem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: Allow editing source files only:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Any&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./test&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileExactly&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./package.yaml&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;fsbMaxFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10485760&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Security Note:&lt;/strong&gt; The write capabilities (&lt;code&gt;write-file-range&lt;/code&gt;, &lt;code&gt;patch-file&lt;/code&gt;) validate write access against the sandbox. For new files, the parent directory must be within the sandbox. For existing files, the file itself must be within the sandbox.&lt;/p&gt;
&lt;h4 id="tool-interface-1"&gt;Tool Interface&lt;/h4&gt;
&lt;p&gt;The developer toolbox exposes a single tool named &lt;code&gt;developer_{name}_developer_tools&lt;/code&gt; with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parameter&lt;/strong&gt;: &lt;code&gt;capability&lt;/code&gt; (string) - Which operation to perform
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Additional parameters&lt;/strong&gt; vary by capability
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="show-spec"&gt;show-spec&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;show-spec&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;spec_name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash-tools&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Specs:&lt;/strong&gt; &lt;code&gt;bash-tools&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt; Returns the embedded specification documentation as text.&lt;/p&gt;
&lt;h5 id="read-file-range"&gt;read-file-range&lt;/h5&gt;
&lt;p&gt;Reads specific line ranges from a file and returns them with line numbers. Supports reading from staged sessions and metadata-only queries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-file-range&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;ranges&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;1-10,20-30&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;session_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sess-abc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;metadata_only&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Parameter&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Required&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;path&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Path to the file to read&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ranges&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Line ranges (e.g., &lt;code&gt;"1-10"&lt;/code&gt;, &lt;code&gt;"5"&lt;/code&gt;, &lt;code&gt;"head"&lt;/code&gt;, &lt;code&gt;"tail"&lt;/code&gt;, &lt;code&gt;"1-5,20-30"&lt;/code&gt;). Omit to read entire file.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;session_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Read from an in-progress write-file-range session's staged buffer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;metadata_only&lt;/code&gt;&lt;/td&gt;&lt;td&gt;boolean&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Return only metadata (path, line counts, snapshot ref) without content&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Range Formats:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Single line: &lt;code&gt;&amp;quot;5&amp;quot;&lt;/code&gt; - Reads line 5
&lt;/li&gt;
&lt;li&gt;Line range: &lt;code&gt;&amp;quot;1-10&amp;quot;&lt;/code&gt; - Reads lines 1 through 10
&lt;/li&gt;
&lt;li&gt;Multiple ranges: &lt;code&gt;&amp;quot;1-5,20-30&amp;quot;&lt;/code&gt; - Reads lines 1-5 and 20-30
&lt;/li&gt;
&lt;li&gt;Head: &lt;code&gt;&amp;quot;head&amp;quot;&lt;/code&gt; - Reads from beginning (no-op for read)
&lt;/li&gt;
&lt;li&gt;Tail: &lt;code&gt;&amp;quot;tail&amp;quot;&lt;/code&gt; - Reads to end (no-op for read)
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Returns (full content):&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;1&lt;/span&gt;&lt;span class="ch"&gt;\t&lt;/span&gt;&lt;span class="st"&gt;def hello():&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;2&lt;/span&gt;&lt;span class="ch"&gt;\t&lt;/span&gt;&lt;span class="st"&gt;    print(&amp;#39;Hello, World!&amp;#39;)&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;3&lt;/span&gt;&lt;span class="ch"&gt;\t&lt;/span&gt;&lt;span class="st"&gt;    return True&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;linesRead&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;totalLineCount&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;50&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;totalFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1234&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;rangesParsed&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;1-3&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;snapshotRef&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;a1b2c3d4...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Returns (metadata_only: true):&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;linesRead&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;totalLineCount&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;50&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;totalFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;1234&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;rangesParsed&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;snapshotRef&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;a1b2c3d4...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;metadataOnly&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The content includes line numbers prepended with a tab separator in the format &lt;code&gt;{line_num}\t{line_content}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reading from Staged Sessions:&lt;/strong&gt;
When &lt;code&gt;session_id&lt;/code&gt; is provided, the read is served from the session’s in-memory buffer rather than disk. This allows inspecting pending edits before committing:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-file-range&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src/File.hs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;session_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sess-abc&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="write-file-range"&gt;write-file-range&lt;/h5&gt;
&lt;p&gt;Replaces specific lines in a file with new content. Supports &lt;strong&gt;multi-turn edit sessions&lt;/strong&gt; for complex multi-step edits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;write-file-range&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;ranges&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;1-2,5-6&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contentBlocks&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;new content for lines 1-2&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;new content for lines 5-6&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;session_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sess-abc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;expected_snapshot_ref&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;a1b2c3d4...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;commit&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Parameter&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Required&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;path&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Path to the file to modify&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ranges&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Range specs: &lt;code&gt;N&lt;/code&gt; replace line N, &lt;code&gt;N-M&lt;/code&gt; replace lines N-M, &lt;code&gt;N+&lt;/code&gt; insert after line N, &lt;code&gt;head&lt;/code&gt; prepend, &lt;code&gt;tail&lt;/code&gt; append, &lt;code&gt;whole&lt;/code&gt; overwrite file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;contentBlocks&lt;/code&gt;&lt;/td&gt;&lt;td&gt;array[string]&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Array of content blocks, one per range. Use empty strings to delete lines.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;session_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Continue an existing edit session&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;expected_snapshot_ref&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Optimistic locking: only proceed if file matches this snapshot&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;commit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;boolean&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;If true, write to disk and close session. If false, stage changes.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Range Formats:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;N&lt;/code&gt; - &lt;strong&gt;Replace&lt;/strong&gt; line N (e.g., &lt;code&gt;5&lt;/code&gt; replaces line 5)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;N-M&lt;/code&gt; - &lt;strong&gt;Replace&lt;/strong&gt; lines N through M (e.g., &lt;code&gt;1-10&lt;/code&gt; replaces lines 1-10)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;N+&lt;/code&gt; - &lt;strong&gt;Insert after&lt;/strong&gt; line N (e.g., &lt;code&gt;54+&lt;/code&gt; inserts after line 54)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;head&lt;/code&gt; - Prepend content before line 1 (use this to create new files)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tail&lt;/code&gt; - Append content after the last line
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;whole&lt;/code&gt; - Replace the entire file
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; &lt;code&gt;N&lt;/code&gt; and &lt;code&gt;N+&lt;/code&gt; are not interchangeable. Use &lt;code&gt;54+&lt;/code&gt; to insert after line 54; using &lt;code&gt;54&lt;/code&gt; will replace line 54.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Multi-Turn Edit Sessions:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For complex edits, use sessions to stage changes across multiple turns before committing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Turn 1 (start session):
  {
    &amp;quot;capability&amp;quot;: &amp;quot;write-file-range&amp;quot;,
    &amp;quot;path&amp;quot;: &amp;quot;./src/File.hs&amp;quot;,
    &amp;quot;ranges&amp;quot;: &amp;quot;10-20&amp;quot;,
    &amp;quot;contentBlocks&amp;quot;: [&amp;quot;new code...&amp;quot;],
    &amp;quot;commit&amp;quot;: false
  }
  -&amp;gt; returns sessionId: &amp;quot;sess-abc&amp;quot;, sessionStatus: &amp;quot;staged&amp;quot;

Turn 2 (continue, still using ORIGINAL line numbers):
  {
    &amp;quot;capability&amp;quot;: &amp;quot;write-file-range&amp;quot;,
    &amp;quot;path&amp;quot;: &amp;quot;./src/File.hs&amp;quot;,
    &amp;quot;session_id&amp;quot;: &amp;quot;sess-abc&amp;quot;,
    &amp;quot;ranges&amp;quot;: &amp;quot;100-110&amp;quot;,
    &amp;quot;contentBlocks&amp;quot;: [&amp;quot;more code...&amp;quot;],
    &amp;quot;commit&amp;quot;: false
  }
  -&amp;gt; sessionStatus: &amp;quot;staged&amp;quot;

Turn N (commit to disk):
  {
    &amp;quot;capability&amp;quot;: &amp;quot;write-file-range&amp;quot;,
    &amp;quot;path&amp;quot;: &amp;quot;./src/File.hs&amp;quot;,
    &amp;quot;session_id&amp;quot;: &amp;quot;sess-abc&amp;quot;,
    &amp;quot;ranges&amp;quot;: &amp;quot;200-210&amp;quot;,
    &amp;quot;contentBlocks&amp;quot;: [&amp;quot;final code...&amp;quot;],
    &amp;quot;commit&amp;quot;: true
  }
  -&amp;gt; writes to disk, sessionStatus: &amp;quot;committed&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Session Rules:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sessions expire after 1 hour of inactivity
&lt;/li&gt;
&lt;li&gt;Edits within a session must not overlap (in original coordinates)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;whole&lt;/code&gt; range not supported while session is open
&lt;/li&gt;
&lt;li&gt;Commit fails if file changed on disk since session started
&lt;/li&gt;
&lt;li&gt;Reusing a &lt;code&gt;session_id&lt;/code&gt; after commit returns an “already committed” error
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Optimistic Locking:&lt;/strong&gt;
Use &lt;code&gt;expected_snapshot_ref&lt;/code&gt; to prevent conflicts:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;write-file-range&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src/File.hs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;ranges&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;1-10&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contentBlocks&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;new content&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;expected_snapshot_ref&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;a1b2c3d4...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;commit&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The operation fails if the file’s current snapshot doesn’t match, allowing retry with fresh content.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;rangesModified&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;linesWritten&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;6&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;beforeSnapshotRef&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;a1b2c3d4...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;afterSnapshotRef&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;e5f6g7h8...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessionId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sess-abc&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessionNetDelta&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessionCommitted&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sessionStatus&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;committed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="patch-file"&gt;patch-file&lt;/h5&gt;
&lt;p&gt;Applies a unified diff patch to a file atomically with context validation and rich error reporting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;capability&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;patch-file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;patch&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;--- a/src/File.hs&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;+++ b/src/File.hs&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;@@ -10,5 +10,6 @@ import Foo&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;+import Data.Text (Text)&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;@@ -100,5 +101,5 @@ func1 x =&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;-  oldBody&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;+  newBody&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;expected_snapshot_ref&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;a1b2c3d4...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Parameter&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Required&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;path&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Path to the file to patch&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;patch&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Unified diff patch content&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;expected_snapshot_ref&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Optimistic locking: only proceed if file matches&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Patch Format:&lt;/strong&gt;
Follows standard unified diff format:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;File headers (&lt;code&gt;---&lt;/code&gt; and &lt;code&gt;+++&lt;/code&gt; lines) are ignored
&lt;/li&gt;
&lt;li&gt;Hunk headers start with &lt;code&gt;@@&lt;/code&gt; (e.g., &lt;code&gt;@@ -10,5 +11,6 @@&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;Context lines have no prefix
&lt;/li&gt;
&lt;li&gt;Removed lines start with &lt;code&gt;-&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Added lines start with &lt;code&gt;+&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Atomic application:&lt;/strong&gt; All hunks are validated before any changes are applied
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context validation:&lt;/strong&gt; Each hunk’s context lines must match exactly
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overlap detection:&lt;/strong&gt; Hunks that would overlap are rejected
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bottom-to-top application:&lt;/strong&gt; Hunks are applied in descending line order to avoid line number shifts
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rich errors:&lt;/strong&gt; Context-mismatch errors include expected/actual lines for debugging
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Rich Error Context:&lt;/strong&gt;
When a context mismatch occurs, the error includes both expected and actual lines:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Context mismatch at line 100&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;expected&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;import Foo&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;import Bar&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;import Foo&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;import Baz&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Context doesn&amp;#39;t match&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/file&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;hunksApplied&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;hunksRejected&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;linesChanged&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;beforeSnapshotRef&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;a1b2c3d4...&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;afterSnapshotRef&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;e5f6g7h8...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Error Responses:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Context mismatch at line 100: Context doesn&amp;#39;t match&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;expected&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;context line 1&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;context line 2&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;different line 1&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;different line 2&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="range-specification-types"&gt;Range Specification Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Range specification for file operations.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;RangeSpec&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Lines&lt;/span&gt; (&lt;span class="dt"&gt;Int&lt;/span&gt;, &lt;span class="dt"&gt;Int&lt;/span&gt;)  &lt;span class="co"&gt;-- ^ 1-based, inclusive line range (start, end)&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Head&lt;/span&gt;              &lt;span class="co"&gt;-- ^ Before line 1 (prepend)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Tail&lt;/span&gt;              &lt;span class="co"&gt;-- ^ After last line (append)&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Result of a read file range operation.&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ReadFileRangeResult&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ReadFileRangeResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; readFilePath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; readFileContent ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; readFileLinesRead ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; readFileTotalLines ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; readFileTotalSize ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; readFileRangesParsed ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; readFileSnapshotRef ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SnapshotRef&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; readFileSessionId ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; readFileMetadataOnly ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Result of a write file range operation.&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;WriteFileRangeResult&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;WriteFileRangeResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; writeFilePath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; writeFileRangesModified ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; writeFileLinesWritten ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; writeFileBeforeSnapshotRef ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SnapshotRef&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; writeFileAfterSnapshotRef ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SnapshotRef&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; writeFileSessionId ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; writeFileSessionNetDelta ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; writeFileSessionCommitted ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; writeFileSessionStatus ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;  &lt;span class="co"&gt;-- &amp;quot;staged&amp;quot; or &amp;quot;committed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Result of a patch file operation.&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;PatchResult&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;PatchResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; patchFilePath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; patchHunksApplied ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; patchHunksRejected ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; patchLinesChanged ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; patchBeforeSnapshotRef ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SnapshotRef&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; patchAfterSnapshotRef ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;SnapshotRef&lt;/span&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Patch error with rich context.&lt;/span&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;PatchError&lt;/span&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;PatchParseError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PatchContextMismatch&lt;/span&gt;&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        {&lt;span class="ot"&gt; patchMismatchLine ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; patchMismatchMessage ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; patchMismatchExpected ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="51"&gt;&lt;a href="#51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; patchMismatchActual ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="52"&gt;&lt;a href="#52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="53"&gt;&lt;a href="#53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PatchHunkOverlap&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="54"&gt;&lt;a href="#54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PatchFileNotFound&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="55"&gt;&lt;a href="#55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PatchInvalidLineNumber&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="snapshot-system"&gt;Snapshot System&lt;/h4&gt;
&lt;p&gt;The Developer Toolbox uses a snapshot system for optimistic locking and file restoration:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Snapshot reference (MD5 hash of content).&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;SnapshotRef&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SnapshotRef&lt;/span&gt; {&lt;span class="ot"&gt; unSnapshotRef ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; }&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Ord&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Snapshot with metadata.&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Snapshot&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Snapshot&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; snapshotContent ::&lt;/span&gt; &lt;span class="dt"&gt;ByteString&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; snapshotCreatedAt ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Create snapshot from content.&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;makeSnapshot ::&lt;/span&gt; &lt;span class="dt"&gt;ByteString&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Snapshot&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Get reference for a snapshot.&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;snapshotRef ::&lt;/span&gt; &lt;span class="dt"&gt;Snapshot&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SnapshotRef&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Snapshots are automatically taken during read operations and returned in results. Use &lt;code&gt;expected_snapshot_ref&lt;/code&gt; for optimistic locking in write operations.&lt;/p&gt;
&lt;h4 id="generated-templates"&gt;Generated Templates&lt;/h4&gt;
&lt;h5 id="bash-tool-template"&gt;Bash Tool Template&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# my-tool - A bash tool for agents-exe&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;set&lt;/span&gt; &lt;span class="at"&gt;-euo&lt;/span&gt; pipefail&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${1&lt;/span&gt;&lt;span class="op"&gt;:-&lt;/span&gt;&lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ss"&gt;describe&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;cat&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;lt;&amp;#39;DESCRIBE_EOF&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;slug&amp;quot;: &amp;quot;my-tool&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;description&amp;quot;: &amp;quot;Tool my-tool - describe what this tool does&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;args&amp;quot;: [],&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;empty-result&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    &amp;quot;tag&amp;quot;: &amp;quot;AddMessage&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;    &amp;quot;contents&amp;quot;: &amp;quot;--no output--&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;DESCRIBE_EOF&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ss"&gt;run&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;# &lt;/span&gt;&lt;span class="al"&gt;TODO&lt;/span&gt;&lt;span class="co"&gt;: Implement tool logic&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Tool my-tool executed&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="pp"&gt;*&lt;/span&gt;&lt;span class="kw"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Usage: my-tool &amp;lt;describe|run&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;esac&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h5 id="python-tool-template"&gt;Python Tool Template&lt;/h5&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#!/usr/bin/env python3&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; json&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; sys&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="im"&gt;import&lt;/span&gt; os&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; describe():&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;return&lt;/span&gt; {&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;my-tool&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;Tool my-tool - describe what this tool does&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;: [],&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;empty-result&amp;quot;&lt;/span&gt;: {&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;AddMessage&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;: &lt;span class="st"&gt;&amp;quot;--no output--&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; run():&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;# &lt;/span&gt;&lt;span class="al"&gt;TODO&lt;/span&gt;&lt;span class="co"&gt;: Implement tool logic&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="bu"&gt;print&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;Tool my-tool executed&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;def&lt;/span&gt; main():&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="bu"&gt;len&lt;/span&gt;(sys.argv) &lt;span class="op"&gt;&amp;lt;&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;:&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="bu"&gt;print&lt;/span&gt;(&lt;span class="ss"&gt;f&amp;quot;Usage: &lt;/span&gt;&lt;span class="sc"&gt;{&lt;/span&gt;sys&lt;span class="sc"&gt;.&lt;/span&gt;argv[&lt;span class="dv"&gt;0&lt;/span&gt;]&lt;span class="sc"&gt;}&lt;/span&gt;&lt;span class="ss"&gt; &amp;lt;describe|run&amp;gt;&amp;quot;&lt;/span&gt;, &lt;span class="bu"&gt;file&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;sys.stderr)&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    command &lt;span class="op"&gt;=&lt;/span&gt; sys.argv[&lt;span class="dv"&gt;1&lt;/span&gt;]&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;if&lt;/span&gt; command &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;describe&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="bu"&gt;print&lt;/span&gt;(json.dumps(describe()))&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;elif&lt;/span&gt; command &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;run&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        run()&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;else&lt;/span&gt;:&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="bu"&gt;print&lt;/span&gt;(&lt;span class="ss"&gt;f&amp;quot;Unknown command: &lt;/span&gt;&lt;span class="sc"&gt;{&lt;/span&gt;command&lt;span class="sc"&gt;}&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="bu"&gt;file&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;sys.stderr)&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="va"&gt;__name__&lt;/span&gt; &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    sys.exit(main())&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="lua-tools"&gt;Lua Tools&lt;/h3&gt;
&lt;p&gt;Lua tools provide embedded scripting capabilities through a sandboxed Lua interpreter. This enables agents to orchestrate complex workflows by combining multiple tools through Lua scripts.&lt;/p&gt;
&lt;h4 id="recursive-language-models-lrm-with-lua"&gt;Recursive Language Models (LRM) with Lua&lt;/h4&gt;
&lt;p&gt;The Lua toolbox enables a powerful pattern called &lt;strong&gt;Recursive Language Models (LRM)&lt;/strong&gt;. By configuring an agent to reference itself in &lt;code&gt;extraAgents&lt;/code&gt; and granting the Lua toolbox permission to call the resulting &lt;code&gt;io_prompt_agent_{slug}&lt;/code&gt; tool, you create an agent that can recursively invoke itself for complex reasoning tasks.&lt;/p&gt;
&lt;h4 id="configuration-4"&gt;Configuration&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;local_lrmlua&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;KimiV1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.moonshot.ai/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;kimi&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;kimi-k2.5&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;The main agent, capable of reasoning.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;You are a helpful software agent trying to solve user requests&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;local_lrmlua&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;kimi-10.lrmlua.json&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;bashToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SingleTool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;Path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./tools/askuser/ask-user.bash&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;builtinToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;LuaToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;lua&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Sandboxed Lua interpreter&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;MaxMemoryMB&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;256&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;MaxExecutionTimeSeconds&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;300&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;AllowedTools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;bash_ask_user&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;io_prompt_agent_local_lrmlua&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;sqlite_shared_working_memory_query&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;AllowedHosts&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Any&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./repro-cases&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileExactly&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./README.md&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;&amp;quot;fsbMaxFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10485760&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="51"&gt;&lt;a href="#51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;&amp;quot;fsbName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;lua-fs-sandbox&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="52"&gt;&lt;a href="#52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="53"&gt;&lt;a href="#53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="54"&gt;&lt;a href="#54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="55"&gt;&lt;a href="#55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="56"&gt;&lt;a href="#56" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SqliteToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="57"&gt;&lt;a href="#57" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="58"&gt;&lt;a href="#58" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;shared_working_memory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="59"&gt;&lt;a href="#59" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;A base to help you coordinate large works.&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="60"&gt;&lt;a href="#60" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;Versioning&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SqliteReadWrite&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./dev-memory.db&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="61"&gt;&lt;a href="#61" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="62"&gt;&lt;a href="#62" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="63"&gt;&lt;a href="#63" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="64"&gt;&lt;a href="#64" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="65"&gt;&lt;a href="#65" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="luatoolbox-configuration-fields"&gt;LuaToolbox Configuration Fields&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Name&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Unique name for this toolbox instance (used as tool prefix)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Description&lt;/code&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;Human-readable description&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;MaxMemoryMB&lt;/code&gt;&lt;/td&gt;&lt;td&gt;integer&lt;/td&gt;&lt;td&gt;Maximum Lua heap memory in megabytes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;MaxExecutionTimeSeconds&lt;/code&gt;&lt;/td&gt;&lt;td&gt;integer&lt;/td&gt;&lt;td&gt;Maximum script execution time in seconds&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AllowedTools&lt;/code&gt;&lt;/td&gt;&lt;td&gt;[string]&lt;/td&gt;&lt;td&gt;Whitelist of tool names Lua scripts can call via the portal&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AllowedHosts&lt;/code&gt;&lt;/td&gt;&lt;td&gt;[string]&lt;/td&gt;&lt;td&gt;Whitelist of network hosts accessible to Lua HTTP module&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;FileSandbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;object?&lt;/td&gt;&lt;td&gt;File sandbox configuration for Lua &lt;code&gt;fs&lt;/code&gt; module; inline or &lt;code&gt;{"ref": name}&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="file-sandbox-for-lua"&gt;File Sandbox for Lua&lt;/h4&gt;
&lt;p&gt;The Lua &lt;code&gt;fs&lt;/code&gt; module uses the unified file sandbox system. When &lt;code&gt;FileSandbox&lt;/code&gt; is configured, all filesystem operations (&lt;code&gt;fs.read&lt;/code&gt;, &lt;code&gt;fs.write&lt;/code&gt;, &lt;code&gt;fs.list&lt;/code&gt;, etc.) are validated against the sandbox.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Migration from &lt;code&gt;allowedPaths&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The legacy &lt;code&gt;allowedPaths&lt;/code&gt; field no longer exists and is ignored if present.
Use &lt;code&gt;FileSandbox&lt;/code&gt; instead:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;Old&lt;/span&gt; &lt;span class="er"&gt;(removed,&lt;/span&gt; &lt;span class="er"&gt;ignored)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;allowedPaths&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./data&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./scripts&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;//&lt;/span&gt; &lt;span class="er"&gt;New&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Any&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./data&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./scripts&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="security-features-1"&gt;Security Features&lt;/h4&gt;
&lt;p&gt;The Lua toolbox provides a sandboxed execution environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory limits&lt;/strong&gt;: a script whose Lua heap grows past &lt;code&gt;MaxMemoryMB&lt;/code&gt; fails with a memory-limit error (&lt;code&gt;0&lt;/code&gt; disables the limit)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeout enforcement&lt;/strong&gt;: Scripts that exceed &lt;code&gt;MaxExecutionTimeSeconds&lt;/code&gt; are terminated
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Path sandboxing&lt;/strong&gt;: Filesystem access restricted to &lt;code&gt;FileSandbox&lt;/code&gt; configuration
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host whitelisting&lt;/strong&gt;: HTTP requests limited to &lt;code&gt;allowedHosts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool whitelist&lt;/strong&gt;: Only tools in &lt;code&gt;allowedTools&lt;/code&gt; can be called through the portal
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dangerous functions removed&lt;/strong&gt;: &lt;code&gt;os.execute&lt;/code&gt;, &lt;code&gt;io.popen&lt;/code&gt;, &lt;code&gt;loadfile&lt;/code&gt;, &lt;code&gt;dofile&lt;/code&gt;, etc. are removed
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Empty whitelist = no access&lt;/strong&gt;: Secure defaults - empty lists mean no access
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="lua-standard-library-modules"&gt;Lua Standard Library Modules&lt;/h4&gt;
&lt;p&gt;All modules are pre-registered as &lt;strong&gt;global variables&lt;/strong&gt; - no &lt;code&gt;require()&lt;/code&gt; needed.
Simply use the module name directly (e.g., &lt;code&gt;json.encode()&lt;/code&gt;, &lt;code&gt;text.split()&lt;/code&gt;).&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Module&lt;/th&gt;&lt;th&gt;Functions&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;json.encode&lt;/code&gt;, &lt;code&gt;json.decode&lt;/code&gt;&lt;/td&gt;&lt;td&gt;JSON manipulation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;http&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;http.get&lt;/code&gt;, &lt;code&gt;http.post&lt;/code&gt;, &lt;code&gt;http.request&lt;/code&gt;&lt;/td&gt;&lt;td&gt;HTTP requests (host-restricted)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;time&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;time.now&lt;/code&gt;, &lt;code&gt;time.sleep&lt;/code&gt;, &lt;code&gt;time.format&lt;/code&gt;, &lt;code&gt;time.diff&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Time utilities&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;fs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;fs.read&lt;/code&gt;, &lt;code&gt;fs.write&lt;/code&gt;, &lt;code&gt;fs.list&lt;/code&gt;, &lt;code&gt;fs.exists&lt;/code&gt;&lt;/td&gt;&lt;td&gt;File system (sandboxed)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;text&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;text.split&lt;/code&gt;, &lt;code&gt;text.trim&lt;/code&gt;, &lt;code&gt;text.upper&lt;/code&gt;, &lt;code&gt;text.lower&lt;/code&gt;, &lt;code&gt;text.find&lt;/code&gt;, &lt;code&gt;text.gsub&lt;/code&gt;, &lt;code&gt;text.startswith&lt;/code&gt;, &lt;code&gt;text.endswith&lt;/code&gt;, &lt;code&gt;text.len&lt;/code&gt;, &lt;code&gt;text.sub&lt;/code&gt;&lt;/td&gt;&lt;td&gt;String utilities&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tools&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;tools.call&lt;/code&gt;, &lt;code&gt;tools.list&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Tool portal integration&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="fs-module-and-sandbox"&gt;fs Module and Sandbox&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;fs&lt;/code&gt; module respects the file sandbox configuration:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- These operations are validated against the fileSandbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;local&lt;/span&gt; &lt;span class="va"&gt;content&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;fs&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;read&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./data/file.txt&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;      &lt;span class="co"&gt;-- Must be in sandbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;fs&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;write&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./output/result.txt&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;          &lt;span class="co"&gt;-- Must be in sandbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;local&lt;/span&gt; &lt;span class="va"&gt;files&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;fs&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;list&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./scripts&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;               &lt;span class="co"&gt;-- Must be in sandbox&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;local&lt;/span&gt; &lt;span class="va"&gt;exists&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;fs&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;exists&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./README.md&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;          &lt;span class="co"&gt;-- Must be in sandbox&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Sandbox Validation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fs.read&lt;/code&gt;: Validates read permission via &lt;code&gt;validateFileRead&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fs.write&lt;/code&gt;: Validates write permission via &lt;code&gt;validateFileWrite&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fs.list&lt;/code&gt;, &lt;code&gt;fs.exists&lt;/code&gt;, &lt;code&gt;fs.isdir&lt;/code&gt;, &lt;code&gt;fs.isfile&lt;/code&gt;: Validates access permission
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fs.mkdir&lt;/code&gt;: Validates write permission on parent directory
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fs.patch&lt;/code&gt;: Validates write permission on the file
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="example-lua-script"&gt;Example Lua Script&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Modules are pre-loaded as globals and available via require()&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Read a file (validated against fileSandbox)&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;local&lt;/span&gt; &lt;span class="va"&gt;content&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;fs&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;read&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./repro-cases/input.json&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="kw"&gt;not&lt;/span&gt; &lt;span class="va"&gt;content&lt;/span&gt; &lt;span class="cf"&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;span class="fu"&gt;error&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Failed to read file&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Call the recursive agent for complex reasoning&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;local&lt;/span&gt; &lt;span class="va"&gt;reasoning_result&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;tools&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;call&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;io_prompt_agent_local_lrmlua&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="va"&gt;what&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Analyze this codebase structure and identify potential refactoring opportunities&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Process the result&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="va"&gt;reasoning_result&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="va"&gt;status&lt;/span&gt; &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt; &lt;span class="cf"&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;local&lt;/span&gt; &lt;span class="va"&gt;analysis&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;json&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;decode&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="va"&gt;reasoning_result&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="va"&gt;result_txt&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Query the shared working memory&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;local&lt;/span&gt; &lt;span class="va"&gt;db_result&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;tools&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;call&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;sqlite_shared_working_memory_query&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="va"&gt;sql&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;INSERT INTO analysis_results (content) VALUES (&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;..&lt;/span&gt; &lt;span class="va"&gt;analysis&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="va"&gt;summary&lt;/span&gt; &lt;span class="op"&gt;..&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;#39;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Write results (validated against fileSandbox)&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="va"&gt;fs&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;write&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./repro-cases/output.json&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="va"&gt;json&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;encode&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="va"&gt;analysis&lt;/span&gt;&lt;span class="op"&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="va"&gt;success&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;true&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="va"&gt;analysis&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;analysis&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="va"&gt;stored&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;db_result&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="va"&gt;status&lt;/span&gt; &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="va"&gt;success&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;error&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;reasoning_result&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="va"&gt;error&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tool-naming"&gt;Tool Naming&lt;/h4&gt;
&lt;p&gt;The Lua toolbox exposes a single tool named &lt;code&gt;lua_{name}_execute&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;script&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;return json.encode({status=&amp;#39;ok&amp;#39;})&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;timeout&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;60&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Note: Modules (&lt;code&gt;json&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;fs&lt;/code&gt;, &lt;code&gt;http&lt;/code&gt;, &lt;code&gt;tools&lt;/code&gt;) are available as pre-loaded global variables.&lt;/p&gt;
&lt;h4 id="error-handling"&gt;Error Handling&lt;/h4&gt;
&lt;p&gt;Lua script errors are captured and returned to the LLM:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ScriptError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;LuaRuntimeError&lt;/span&gt; [&lt;span class="dt"&gt;Aeson.Value&lt;/span&gt;]      &lt;span class="co"&gt;-- Syntax or runtime error&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TimeoutError&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;                   &lt;span class="co"&gt;-- Script exceeded time limit&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MemoryError&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;                    &lt;span class="co"&gt;-- Script exceeded memory limit&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SandboxError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                  &lt;span class="co"&gt;-- Attempted sandbox violation&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolInvocationError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;           &lt;span class="co"&gt;-- Error calling another tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;InitializationError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;           &lt;span class="co"&gt;-- Failed to initialize Lua state&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="skills-system"&gt;Skills System&lt;/h3&gt;
&lt;p&gt;The Skills system provides procedural knowledge and executable capabilities via progressive disclosure, following the &lt;a href="https://agentskills.io"&gt;agentskills.io&lt;/a&gt; specification.&lt;/p&gt;
&lt;h4 id="overview-2"&gt;Overview&lt;/h4&gt;
&lt;p&gt;Skills are packages of related functionality that can be dynamically enabled/disabled during a session. They implement progressive disclosure:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Initially&lt;/strong&gt;: Only metadata tools are visible (describe, enable, disable, list)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;After enable&lt;/strong&gt;: Script tools become available for execution
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Session Start
      │
      ▼
┌─────────────┐
│ skill_list  │  ← Always available
│ skill_desc  │  ← Always available
│ skill_enable│  ← Always available
└──────┬──────┘
       │
       ▼ (user calls skill_enable_pdf-processing)
┌─────────────┐
│ skill_list  │
│ skill_desc  │
│ skill_enable│
│ skill_pdf_* │  ← NEW: Script tools now visible
└─────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="skill-structure"&gt;Skill Structure&lt;/h4&gt;
&lt;p&gt;A skill directory contains:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;skill-directory/
├── SKILL.md          # Frontmatter + instructions
├── scripts/          # Executable scripts
│   ├── extract-text.sh
│   └── convert.sh
└── references/       # Documentation (optional)
    └── api-docs.md
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="skillmd-format"&gt;SKILL.md Format&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="an"&gt;name:&lt;/span&gt;&lt;span class="co"&gt; pdf-processing&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="an"&gt;description:&lt;/span&gt;&lt;span class="co"&gt; Extract and manipulate PDF files&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="an"&gt;license:&lt;/span&gt;&lt;span class="co"&gt; MIT&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="an"&gt;compatibility:&lt;/span&gt;&lt;span class="co"&gt; Linux, macOS&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="an"&gt;metadata:&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;  author: team-pdf&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;  version: &amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;# PDF Processing&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;This skill provides tools for working with PDF documents.&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;## Usage&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;Enable the skill, then use the available script tools...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="skill-types-systemagentstoolsskillstypes"&gt;Skill Types (&lt;code&gt;System.Agents.Tools.Skills.Types&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Validated skill name (1-64 chars, lowercase, digits, hyphens)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;SkillName&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SkillName&lt;/span&gt; {&lt;span class="ot"&gt; unSkillName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; }&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Complete skill with metadata, instructions, scripts, and references&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Skill&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Skill&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; skillMetadata ::&lt;/span&gt; &lt;span class="dt"&gt;SkillMetadata&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; skillInstructions ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; skillPath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; skillScripts ::&lt;/span&gt; [&lt;span class="dt"&gt;ScriptInfo&lt;/span&gt;]&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; skillReferences ::&lt;/span&gt; [&lt;span class="dt"&gt;ReferenceInfo&lt;/span&gt;]&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Metadata from SKILL.md frontmatter&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SkillMetadata&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SkillMetadata&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; smName ::&lt;/span&gt; &lt;span class="dt"&gt;SkillName&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smDescription ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smLicense ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smCompatibility ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; smMetadata ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Script following the describe/run protocol&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ScriptInfo&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ScriptInfo&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; siName ::&lt;/span&gt; &lt;span class="dt"&gt;ScriptName&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; siPath ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; siDescription ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; siArgs ::&lt;/span&gt; [&lt;span class="dt"&gt;ScriptArgInfo&lt;/span&gt;]&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="skill-state"&gt;Skill State&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Session state tracking which skills and scripts are enabled&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;SkillsSessionState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SkillsSessionState&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; sssActiveSkills ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;SkillName&lt;/span&gt; &lt;span class="dt"&gt;SkillScriptsState&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Script state within a skill&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;SkillScriptsState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;ScriptName&lt;/span&gt; &lt;span class="dt"&gt;ScriptState&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ScriptState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Enabled&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Disabled&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Monoid instance for folding over session turns&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;Monoid&lt;/span&gt; &lt;span class="dt"&gt;SkillsSessionState&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;mempty&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SkillsSessionState&lt;/span&gt; Map.empty&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Later state overrides earlier state&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="toolbox-integration-systemagentstoolsskillstoolbox"&gt;Toolbox Integration (&lt;code&gt;System.Agents.Tools.Skills.Toolbox&lt;/code&gt;)&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Compute all available skill tools from session state&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;computeSkillTools ::&lt;/span&gt; &lt;span class="dt"&gt;SkillsStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;ToolRegistration&lt;/span&gt;]&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;computeSkillTools store session &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; state &lt;span class="ot"&gt;=&lt;/span&gt; foldSession session&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Always available&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        metaTools &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;concatMap&lt;/span&gt; makeMetaTools (allSkills store)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Available only when enabled&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        scriptTools &lt;span class="ot"&gt;=&lt;/span&gt; &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;concatMap&lt;/span&gt; (makeScriptToolsForSkill state store) &lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                      (sssActiveSkills state)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="kw"&gt;in&lt;/span&gt; listTool &lt;span class="op"&gt;++&lt;/span&gt; metaTools &lt;span class="op"&gt;++&lt;/span&gt; scriptTools&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Tool naming convention&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;skill2LLMName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SkillName&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolName&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- skill_describe_pdf-processing&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- skill_enable_pdf-processing&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- skill_pdf-processing_extract-text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="generated-tools-1"&gt;Generated Tools&lt;/h4&gt;
&lt;p&gt;For each skill, these tools are generated:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Tool&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;th&gt;Always Available&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;skill_list&lt;/code&gt;&lt;/td&gt;&lt;td&gt;List all skills&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;skill_describe_{name}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Get skill metadata&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;skill_enable_{name}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Enable skill scripts&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;skill_disable_{name}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Disable skill scripts&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;skill_{name}_{script}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Execute script&lt;/td&gt;&lt;td&gt;No (requires enable)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="skill-sources"&gt;Skill Sources&lt;/h4&gt;
&lt;p&gt;Skills can be loaded from:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;SkillSource&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SkillDirectory&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;           &lt;span class="co"&gt;-- Local directory&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SkillGitRepo&lt;/span&gt; &lt;span class="dt"&gt;GitUrl&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Subdirectory&lt;/span&gt;)  &lt;span class="co"&gt;-- Git repository&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Configuration:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;skillSources&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SkillDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./skills&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SkillGitRepo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt; &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://github.com/org/skills-repo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;subdir&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;pdf-tools&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;autoEnableSkills&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;core-utils&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="progressive-disclosure-benefits"&gt;Progressive Disclosure Benefits&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reduced context window&lt;/strong&gt;: Only relevant tools visible
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discoverability&lt;/strong&gt;: Users learn about skills organically
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modularity&lt;/strong&gt;: Skills are self-contained packages
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safety&lt;/strong&gt;: Scripts only accessible after explicit enable
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auditability&lt;/strong&gt;: State changes tracked in session
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="tool-validation-systemagentstoolsvalidation"&gt;Tool Validation (&lt;code&gt;System.Agents.Tools.Validation&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;Tool input validation helps LLMs self-correct when they make incorrect tool calls.&lt;/p&gt;
&lt;h4 id="validation-types"&gt;Validation Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Single validation error with context&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ValidationError&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ValidationError&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; errorPath ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;       &lt;span class="co"&gt;-- JSON path (e.g., &amp;quot;user.name&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; errorMessage ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;    &lt;span class="co"&gt;-- Human-readable description&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Validation configuration&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ValidationConfig&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ValidationConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; allowExtraProperties ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; strictMode ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="validation-function"&gt;Validation Function&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Validate tool input against its schema&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;validateToolInput ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [&lt;span class="dt"&gt;ParamProperty&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;  &lt;span class="co"&gt;-- Tool schema&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Aeson.Value&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;      &lt;span class="co"&gt;-- Input value&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [&lt;span class="dt"&gt;ValidationError&lt;/span&gt;]   &lt;span class="co"&gt;-- Empty if valid&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Example usage:&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; errors &lt;span class="ot"&gt;=&lt;/span&gt; validateToolInput toolSchema inputValue&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; errors &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; proceedWithToolCall&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    errs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; returnValidationErrors errs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="supported-validations"&gt;Supported Validations&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Check&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Required fields&lt;/td&gt;&lt;td&gt;Ensures required properties are present&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Type checking&lt;/td&gt;&lt;td&gt;Validates string, number, boolean, enum, object&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Enum values&lt;/td&gt;&lt;td&gt;Checks string is in allowed values list&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Nested objects&lt;/td&gt;&lt;td&gt;Recursively validates nested structures&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Extra properties&lt;/td&gt;&lt;td&gt;Optionally rejects unknown properties&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="cli-check-tool-call"&gt;CLI: check-tool-call&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Validate a tool call payload&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;filepath&amp;quot;: &amp;quot;/path/to/file&amp;quot;}&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ex"&gt;agents-exe&lt;/span&gt; check-tool-call &lt;span class="at"&gt;--tool&lt;/span&gt; ./tools/read-file.sh&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Example output (invalid):&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Tool call validation failed for &amp;#39;read-file&amp;#39; with 2 errors:&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 1. filepath: Required property missing&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 2. content: Required property missing&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Please correct these issues and try again.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="error-formatting"&gt;Error Formatting&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;formatValidationErrors ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;ValidationError&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Produces:&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Tool call validation failed for &amp;#39;tool-name&amp;#39; with 2 errors:&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 1. filters.status: Invalid enum value: pending. Allowed: active, inactive&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- 2. user.age: Expected number but got string&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;--&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Please correct these issues and try again.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="tool-portal-systemagentstoolportal"&gt;Tool Portal (&lt;code&gt;System.Agents.ToolPortal&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;The Tool Portal enables inter-toolbox communication, allowing tools to invoke other tools through a controlled callback mechanism.&lt;/p&gt;
&lt;h4 id="use-cases"&gt;Use Cases&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lua scripts&lt;/strong&gt; calling other tools via &lt;code&gt;tools.call()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orchestration tools&lt;/strong&gt; that coordinate multiple operations
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composite tools&lt;/strong&gt; that build on existing tools
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="portal-types"&gt;Portal Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Tool portal callback type&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;ToolPortal&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolCall&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ToolResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Portal execution errors&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;PortalError&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;PortalToolNotFound&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PortalToolNotAllowed&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PortalInvalidArguments&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PortalExecutionError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="creating-a-portal"&gt;Creating a Portal&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.ToolPortal&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create portal from registered tools&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; portal &lt;span class="ot"&gt;=&lt;/span&gt; makeToolPortal tracer registrations&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create context with portal&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; ctx &lt;span class="ot"&gt;=&lt;/span&gt; mkPortalContext&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        sessId convId turnId mAgentId mSession&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        callStack maxDepth (&lt;span class="dt"&gt;Just&lt;/span&gt; portal) allowedTools&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="lua-integration"&gt;Lua Integration&lt;/h4&gt;
&lt;p&gt;Lua scripts can call tools through the portal:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;local&lt;/span&gt; &lt;span class="va"&gt;tools&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;require&lt;/span&gt;&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Call another tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;local&lt;/span&gt; &lt;span class="va"&gt;result&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;tools&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;call&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;read_file&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="va"&gt;filepath&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/file&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Access result&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;print&lt;/span&gt;&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="va"&gt;result&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="va"&gt;data&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;print&lt;/span&gt;&lt;span class="op"&gt;(&lt;/span&gt;&lt;span class="va"&gt;result&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="va"&gt;duration&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="security"&gt;Security&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tool whitelist&lt;/strong&gt;: Only allowed tools can be called
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No nested portals&lt;/strong&gt;: Prevents infinite recursion
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Execution tracking&lt;/strong&gt;: Each portal call is timed and logged
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimal context&lt;/strong&gt;: Portal tools execute without their own portal
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="portal-result"&gt;Portal Result&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolResult&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; resultData ::&lt;/span&gt; &lt;span class="dt"&gt;Aeson.Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultDuration ::&lt;/span&gt; &lt;span class="dt"&gt;NominalDiffTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; resultTraceId ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="io-tools"&gt;IO Tools&lt;/h3&gt;
&lt;p&gt;IO tools are Haskell functions that run within the agent process.&lt;/p&gt;
&lt;h4 id="definition"&gt;Definition&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;IOToolBuilder&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentSlug&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;exampleTool ::&lt;/span&gt; &lt;span class="dt"&gt;IOToolBuilder&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;exampleTool slug agentId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolRegistration&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { innerTool &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , declareTool &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;OpenAI.Tool&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        { toolName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;example&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , toolDescription &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;An example tool&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , toolParamProperties &lt;span class="ot"&gt;=&lt;/span&gt; [&lt;span class="op"&gt;...&lt;/span&gt;]&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , findTool &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;call &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="use-cases-1"&gt;Use Cases&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Agent-to-agent calls (via &lt;code&gt;turnAgentRuntimeIntoIOTool&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;Direct system integration
&lt;/li&gt;
&lt;li&gt;Performance-critical operations
&lt;/li&gt;
&lt;li&gt;Stateful operations
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="io-tool-with-context"&gt;IO Tool with Context&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ioTool ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;Aeson.FromJSON&lt;/span&gt; llmArg) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;IOTools.IOScript&lt;/span&gt; llmArg &lt;span class="dt"&gt;ByteString&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Tool&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;IOScript&lt;/span&gt; arg result &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;IOScript&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; description ::&lt;/span&gt; &lt;span class="dt"&gt;IOScriptDescription&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ioRun ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; arg &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; result&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="tool-execution-context"&gt;Tool Execution Context&lt;/h3&gt;
&lt;p&gt;Tools receive execution context for recursion tracking:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; ctxSessionId ::&lt;/span&gt; &lt;span class="dt"&gt;SessionId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxTurnId ::&lt;/span&gt; &lt;span class="dt"&gt;TurnId&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxAgentId ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;AgentId&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxFullSession ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxCallStack ::&lt;/span&gt; [&lt;span class="dt"&gt;CallStackEntry&lt;/span&gt;]&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxMaxDepth ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxToolPortal ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ToolPortal&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxAllowedTools ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;CallStackEntry&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;CallStackEntry&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; callAgentSlug ::&lt;/span&gt; &lt;span class="dt"&gt;AgentSlug&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; callConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; callDepth ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="recursion-control"&gt;Recursion Control&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;pushAgentContext ::&lt;/span&gt; &lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;AgentSlug&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RecursionError&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Prevents infinite loops by tracking call depth and failing when &lt;code&gt;maxDepth&lt;/code&gt; is exceeded.&lt;/p&gt;
&lt;h4 id="os-integration-subcall-visibility"&gt;OS Integration (Subcall Visibility)&lt;/h4&gt;
&lt;p&gt;For TUI visibility of subcall conversations, the context includes OS integration fields:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { &lt;span class="co"&gt;-- ... existing fields ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxWorld ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ OS World for ECS operations. Enables subcall conversations&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- to be tracked as first-class entities in the OS.&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxEventQueue ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;TQueue&lt;/span&gt; &lt;span class="dt"&gt;OSEvent&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Event queue for OS event emission. Enables the TUI to receive&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- notifications about subcall lifecycle (start, progress, completion).&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; ctxParentConversation ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Parent conversation ID for nested agent calls.&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Helper Functions:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Create a nested context for subcall execution.&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mkSubcallContext ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;World&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;TQueue&lt;/span&gt; &lt;span class="dt"&gt;OSEvent&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Get the subcall depth (0 for root conversations).&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getSubcallDepth ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Check if this context is for a subcall.&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;isSubcallContext ::&lt;/span&gt; &lt;span class="dt"&gt;ToolExecutionContext&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="tool-result-types"&gt;Tool Result Types&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;CallResult&lt;/span&gt; call&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;BlobToolSuccess&lt;/span&gt; call &lt;span class="dt"&gt;ByteString&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;MediaType&lt;/span&gt;)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;JsonToolSuccess&lt;/span&gt; call &lt;span class="dt"&gt;Aeson.Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolSkipped&lt;/span&gt; call&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;BashToolError&lt;/span&gt; call &lt;span class="dt"&gt;BashError&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;IOToolError&lt;/span&gt; call &lt;span class="dt"&gt;IOToolError&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;McpToolError&lt;/span&gt; call &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OpenAPIToolError&lt;/span&gt; call &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PostgRESToolError&lt;/span&gt; call &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SqliteToolError&lt;/span&gt; call &lt;span class="dt"&gt;SqliteError&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SystemToolError&lt;/span&gt; call &lt;span class="dt"&gt;SystemInfoError&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeveloperToolError&lt;/span&gt; call &lt;span class="dt"&gt;ValidationError&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;McpToolResult&lt;/span&gt; call &lt;span class="dt"&gt;McpToolResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OpenAPIToolResult&lt;/span&gt; call &lt;span class="dt"&gt;OpenAI.ToolResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PostgRESToolResult&lt;/span&gt; call &lt;span class="dt"&gt;OpenAI.ToolResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SqliteToolResult&lt;/span&gt; call &lt;span class="dt"&gt;SqliteQueryResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SystemToolResult&lt;/span&gt; call &lt;span class="dt"&gt;SystemQueryResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeveloperToolResult&lt;/span&gt; call &lt;span class="dt"&gt;ValidationResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeveloperToolSpecResult&lt;/span&gt; call &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeveloperToolAgentValidationResult&lt;/span&gt; call &lt;span class="dt"&gt;AgentValidationResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeveloperToolCreateResult&lt;/span&gt; call &lt;span class="dt"&gt;CreateResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeveloperToolReadFileRangeResult&lt;/span&gt; call &lt;span class="dt"&gt;ReadFileRangeResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeveloperToolWriteFileRangeResult&lt;/span&gt; call &lt;span class="dt"&gt;WriteFileRangeResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DeveloperToolPatchResult&lt;/span&gt; call &lt;span class="dt"&gt;PatchResult&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;LuaToolResult&lt;/span&gt; call &lt;span class="dt"&gt;Aeson.Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;LuaToolError&lt;/span&gt; call &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="tool-schema"&gt;Tool Schema&lt;/h3&gt;
&lt;p&gt;Tools expose JSON Schema for LLM function calling:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ParamProperty&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ParamProperty&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; propertyKey ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; propertyType ::&lt;/span&gt; &lt;span class="dt"&gt;ParamType&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; propertyDescription ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; propertyRequired ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ParamType&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;NullParamType&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StringParamType&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;BoolParamType&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;NumberParamType&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EnumParamType&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OpaqueParamType&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MultipleParamType&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ObjectParamType&lt;/span&gt; [&lt;span class="dt"&gt;ParamProperty&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Example JSON Schema:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;object&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;filename&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Name of the file to read&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;lines&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;integer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Number of lines to read&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;filename&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="naming-conventions"&gt;Naming Conventions&lt;/h3&gt;
&lt;p&gt;Tools are named according to their type and toolbox:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Tool Type&lt;/th&gt;&lt;th&gt;Naming Pattern&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bash&lt;/td&gt;&lt;td&gt;&lt;code&gt;bash_{slug}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bash_read_file&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;MCP&lt;/td&gt;&lt;td&gt;&lt;code&gt;mcp_{toolbox}_{name}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;mcp_filesystem_read_file&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OpenAPI&lt;/td&gt;&lt;td&gt;&lt;code&gt;openapi_{toolbox}_{operation}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;openapi_pets_getById&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PostgREST&lt;/td&gt;&lt;td&gt;&lt;code&gt;postgrest_{toolbox}_{method}_{table}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;postgrest_mydb_get_users&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SQLite&lt;/td&gt;&lt;td&gt;&lt;code&gt;sqlite_{toolbox}_query&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;sqlite_analytics_query&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;System&lt;/td&gt;&lt;td&gt;&lt;code&gt;system_{toolbox}_system_info&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;system_system_system_info&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Developer&lt;/td&gt;&lt;td&gt;&lt;code&gt;developer_{toolbox}_developer_tools&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;developer_dev_developer_tools&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Lua&lt;/td&gt;&lt;td&gt;&lt;code&gt;lua_{toolbox}_execute&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;lua_utils_execute&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;IO&lt;/td&gt;&lt;td&gt;&lt;code&gt;io_{slug}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;io_calculator&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;IO (Agent)&lt;/td&gt;&lt;td&gt;&lt;code&gt;io_prompt_agent_{slug}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;io_prompt_agent_helper&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Skill (meta)&lt;/td&gt;&lt;td&gt;&lt;code&gt;skill_{action}_{name}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;skill_describe_pdf-processing&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Skill (script)&lt;/td&gt;&lt;td&gt;&lt;code&gt;skill_{name}_{script}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;skill_pdf-processing_extract-text&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="combining-tool-sources"&gt;Combining Tool Sources&lt;/h3&gt;
&lt;p&gt;The runtime merges tools from all sources:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;newRuntime ::&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;Runtime&lt;/span&gt;)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;newRuntime &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Bash tools from tool directory&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    bashTools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; BashToolbox.initializeBackroundToolbox &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- IO tools from code&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; ioTools &lt;span class="ot"&gt;=&lt;/span&gt; [mk slug uid &lt;span class="op"&gt;|&lt;/span&gt; mk &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; mkIoTools]&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- MCP tools from configured servers&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    mcpTools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;mapM&lt;/span&gt; initializeMcpToolbox mcpConfigs&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- OpenAPI tools from specs&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    openApiTools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;mapM&lt;/span&gt; loadOpenApiTools openApiConfigs&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- PostgREST tools&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    postgrestTools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;mapM&lt;/span&gt; loadPostgRESTools prConfigs&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- SQLite tools from builtin toolboxes&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    sqliteTools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; readSqliteToolsRegistrations tracer sqliteToolboxes&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- System tools from builtin toolboxes&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    systemTools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; readSystemToolsRegistrations tracer systemToolboxes&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Developer tools from builtin toolboxes&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    devTools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; readDeveloperToolsRegistrations tracer devToolboxes&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Lua tools from builtin toolboxes&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    luaTools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; readLuaToolsRegistrations tracer luaToolboxes&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Skills tools from skill sources&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    skillsStore &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; loadSkillsFromSources skillSources&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; skillsTools &lt;span class="ot"&gt;=&lt;/span&gt; computeSkillTools skillsStore session&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Combine all&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; allTools &lt;span class="ot"&gt;=&lt;/span&gt; ioTools &lt;span class="op"&gt;++&lt;/span&gt; bashTools &lt;span class="op"&gt;++&lt;/span&gt; mcpTools &lt;span class="op"&gt;++&lt;/span&gt; openApiTools &lt;span class="op"&gt;++&lt;/span&gt; &lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                   postgrestTools &lt;span class="op"&gt;++&lt;/span&gt; sqliteTools &lt;span class="op"&gt;++&lt;/span&gt; systemTools &lt;span class="op"&gt;++&lt;/span&gt; &lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                   devTools &lt;span class="op"&gt;++&lt;/span&gt; luaTools &lt;span class="op"&gt;++&lt;/span&gt; skillsTools&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="error-handling-1"&gt;Error Handling&lt;/h3&gt;
&lt;h4 id="bash-tool-errors"&gt;Bash Tool Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ToolboxError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ToolboxDirectoryNotFound&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ScriptParseError&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ScriptExecutionError&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="mcp-errors"&gt;MCP Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;McpError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ProcessStartError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ProtocolError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ToolCallError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="openapi-errors"&gt;OpenAPI Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;OpenAPIError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SpecParseError&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SchemaResolutionError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ReferenceError&lt;/span&gt; &lt;span class="dt"&gt;RefPath&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="system-toolbox-errors"&gt;System Toolbox Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;QueryError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;CapabilityNotEnabledError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SystemInfoError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;FileNotFoundError&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;FileTooLargeError&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;UnsupportedFileTypeError&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionStoreNotConfiguredError&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionNotFoundError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;InvalidSessionIdError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionAccessDeniedError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;SessionIntrospectionScope&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;MissingParameterError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;CommandRefusedError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;InvalidFilterOutputError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="developer-toolbox-errors"&gt;Developer Toolbox Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;DeveloperToolError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;CapabilityNotEnabledError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ValidationError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;FileExistsError&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;InvalidTemplateError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;InvalidRangeError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;RangeOutOfBoundsError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PermissionError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PatchValidationError&lt;/span&gt; &lt;span class="dt"&gt;PatchError&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionNotFoundError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionExpiredError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;SessionAlreadyCommittedError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;RangeOverlapError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="patch-errors"&gt;Patch Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;PatchError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;PatchParseError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PatchContextMismatch&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        {&lt;span class="ot"&gt; patchMismatchLine ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; patchMismatchMessage ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; patchMismatchExpected ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; patchMismatchActual ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PatchHunkOverlap&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PatchFileNotFound&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PatchInvalidLineNumber&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="validation-errors"&gt;Validation Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ValidationError&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ValidationError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; errorPath ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; errorMessage ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="portal-errors"&gt;Portal Errors&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;PortalError&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;PortalToolNotFound&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PortalToolNotAllowed&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PortalInvalidArguments&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PortalExecutionError&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="best-practices"&gt;Best Practices&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Idempotency&lt;/strong&gt;: Tools should be safe to call multiple times
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear descriptions&lt;/strong&gt;: Help the LLM understand when to use each tool
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation&lt;/strong&gt;: Validate inputs before execution
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeouts&lt;/strong&gt;: Set reasonable timeouts for external calls
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logging&lt;/strong&gt;: Use the tracer for observability
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error messages&lt;/strong&gt;: Return clear error messages for LLM consumption
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parameter naming&lt;/strong&gt;: Use descriptive parameter names
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Required vs Optional&lt;/strong&gt;: Mark truly required parameters as required
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Progressive disclosure&lt;/strong&gt;: Use Skills for complex tool suites
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Portal safety&lt;/strong&gt;: Always whitelist tools for portal access
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recursive agents&lt;/strong&gt;: When using LRM pattern, set appropriate maxDepth to prevent infinite recursion
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lua security&lt;/strong&gt;: Always specify allowedTools, allowedPaths, and allowedHosts - empty means no access
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media output&lt;/strong&gt;: Declare &lt;code&gt;output-media-type&lt;/code&gt; for tools that produce binary content
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mixed responses&lt;/strong&gt;: Use &lt;code&gt;MixedResponse&lt;/code&gt; for rich multi-modal tool outputs
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File range operations&lt;/strong&gt;: Use &lt;code&gt;read-file-range&lt;/code&gt; and &lt;code&gt;write-file-range&lt;/code&gt; for precise file editing rather than reading/writing entire files
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Line numbers&lt;/strong&gt;: When using &lt;code&gt;read-file-range&lt;/code&gt;, the output includes line numbers to help LLMs understand file structure
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Range formatting&lt;/strong&gt;: Always use 1-based line numbers for ranges (e.g., “1-10” for lines 1 through 10)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Atomic file edits&lt;/strong&gt;: For complex multi-range edits, use &lt;code&gt;write-file-range&lt;/code&gt; with contentBlocks array
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Patch for context validation&lt;/strong&gt;: Use &lt;code&gt;patch-file&lt;/code&gt; when context validation is needed before applying changes
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session introspection&lt;/strong&gt;: Enable session introspection capabilities in SystemToolbox for cross-session analysis
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File sandbox configuration&lt;/strong&gt;: Always configure &lt;code&gt;FileSandbox&lt;/code&gt; for SystemToolbox (attach-file), DeveloperToolbox (read/write/patch), and LuaToolbox (fs module)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secure by default&lt;/strong&gt;: The default file sandbox denies all access (&lt;code&gt;AlwaysDeny&lt;/code&gt;). Explicitly configure allowed paths.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Path canonicalization&lt;/strong&gt;: The file sandbox canonicalizes all paths, so predicates apply to resolved paths (not symlink paths)
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-turn edit sessions&lt;/strong&gt;: Use &lt;code&gt;commit: false&lt;/code&gt; for staging multiple edits, then &lt;code&gt;commit: true&lt;/code&gt; to finalize
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimistic locking&lt;/strong&gt;: Use &lt;code&gt;expected_snapshot_ref&lt;/code&gt; to prevent conflicts when multiple agents edit the same file
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rich patch errors&lt;/strong&gt;: Patch context mismatches now include expected/actual lines for easier debugging
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command filtering&lt;/strong&gt;: Use &lt;code&gt;CommandFilter&lt;/code&gt; in SystemToolbox to control arbitrary command execution
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="example-complete-tool-configuration"&gt;Example: Complete Tool Configuration&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;file-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4o&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;A file management assistant with vision&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;You help users manage and analyze files.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;bashToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileSystemDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;Path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./extra-tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;mcpServers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;McpSimpleBinary&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;filesystem&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;executable&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/usr/bin/mcp-filesystem&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;--root&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/home/user&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;openApiToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAPIServer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;SpecUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.github.com/openapi.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;BaseUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.github.com&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;${GITHUB_TOKEN}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;postgrestToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;PostgRESTServer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;SpecUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;http://localhost:3000/&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;BaseUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;http://localhost:3000&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;builtinToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SqliteToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;analytics&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Analytics database&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Versioning&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SqliteReadOnly&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./analytics.db&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="51"&gt;&lt;a href="#51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="52"&gt;&lt;a href="#52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SystemToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="53"&gt;&lt;a href="#53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="54"&gt;&lt;a href="#54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;system&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="55"&gt;&lt;a href="#55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;System context and session memory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="56"&gt;&lt;a href="#56" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;hostname&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;working-directory&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;attach-file&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;list-directory&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;execute-command&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;list-sessions&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;search-sessions&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="57"&gt;&lt;a href="#57" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;EnvVarFilter&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="58"&gt;&lt;a href="#58" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;SessionIntrospectionScope&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;subtree&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="59"&gt;&lt;a href="#59" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;SessionIntrospectionMaxResults&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;50&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="60"&gt;&lt;a href="#60" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;SessionIntrospectionIncludeToolOutputs&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="61"&gt;&lt;a href="#61" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="62"&gt;&lt;a href="#62" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./project&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="63"&gt;&lt;a href="#63" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbMaxFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;52428800&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="64"&gt;&lt;a href="#64" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;system-sandbox&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="65"&gt;&lt;a href="#65" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="66"&gt;&lt;a href="#66" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;CommandFilter&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;/path/to/approval-script.sh&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="67"&gt;&lt;a href="#67" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="68"&gt;&lt;a href="#68" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="69"&gt;&lt;a href="#69" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="70"&gt;&lt;a href="#70" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DeveloperToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="71"&gt;&lt;a href="#71" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="72"&gt;&lt;a href="#72" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;dev&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="73"&gt;&lt;a href="#73" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Development utilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="74"&gt;&lt;a href="#74" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Capabilities&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;show-spec&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;validate-agent&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;create-agent&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;create-tool&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;read-file-range&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;write-file-range&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;patch-file&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="75"&gt;&lt;a href="#75" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="76"&gt;&lt;a href="#76" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="77"&gt;&lt;a href="#77" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Any&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="78"&gt;&lt;a href="#78" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="79"&gt;&lt;a href="#79" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./src&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="80"&gt;&lt;a href="#80" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./test&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="81"&gt;&lt;a href="#81" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;FileExactly&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./package.yaml&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="82"&gt;&lt;a href="#82" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="83"&gt;&lt;a href="#83" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="84"&gt;&lt;a href="#84" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbMaxFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10485760&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="85"&gt;&lt;a href="#85" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;developer-sandbox&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="86"&gt;&lt;a href="#86" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="87"&gt;&lt;a href="#87" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="88"&gt;&lt;a href="#88" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="89"&gt;&lt;a href="#89" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="90"&gt;&lt;a href="#90" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;LuaToolbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="91"&gt;&lt;a href="#91" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="92"&gt;&lt;a href="#92" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;lua&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="93"&gt;&lt;a href="#93" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Lua scripting tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="94"&gt;&lt;a href="#94" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;MaxMemoryMB&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;256&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="95"&gt;&lt;a href="#95" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;MaxExecutionTimeSeconds&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;300&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="96"&gt;&lt;a href="#96" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;AllowedTools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;bash_read_file&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sqlite_analytics_query&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;system_system_attach_file&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="97"&gt;&lt;a href="#97" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;AllowedHosts&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="98"&gt;&lt;a href="#98" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;FileSandbox&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="99"&gt;&lt;a href="#99" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbPredicate&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;DirectoryRecursive&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./scripts&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="100"&gt;&lt;a href="#100" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbMaxFileSize&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;10485760&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="101"&gt;&lt;a href="#101" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="dt"&gt;&amp;quot;fsbName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;lua-sandbox&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="102"&gt;&lt;a href="#102" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="103"&gt;&lt;a href="#103" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="104"&gt;&lt;a href="#104" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="105"&gt;&lt;a href="#105" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="106"&gt;&lt;a href="#106" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;skillSources&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="107"&gt;&lt;a href="#107" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;SkillDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./skills&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="108"&gt;&lt;a href="#108" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="109"&gt;&lt;a href="#109" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;autoEnableSkills&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;core-utils&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="110"&gt;&lt;a href="#110" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="111"&gt;&lt;a href="#111" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;helper&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;./helper.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="112"&gt;&lt;a href="#112" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="113"&gt;&lt;a href="#113" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="related-modules"&gt;Related Modules&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Module&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Media.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Media types for multi-modal support&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.Base&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Core tool types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.Context&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Tool execution context&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.Bash&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Bash script execution&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.BashToolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Bash tool management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.McpToolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;MCP server integration&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.OpenAPIToolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OpenAPI conversion&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.SqliteToolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;SQLite tools&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.SystemToolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;System information, session introspection, command execution&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.SystemToolbox.Directory&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Directory listing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.SystemToolbox.Execute&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Command execution&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.DeveloperToolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Development utilities, file editing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.DeveloperToolbox.Read&lt;/code&gt;&lt;/td&gt;&lt;td&gt;File reading with sessions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.DeveloperToolbox.Write&lt;/code&gt;&lt;/td&gt;&lt;td&gt;File writing with sessions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.DeveloperToolbox.Patch&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Patch application&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.LuaToolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Lua scripting&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.Skills.Toolbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Skills system&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.Skills.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Skill types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Tools.Validation&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Input validation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.ToolPortal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Inter-tool communication&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.ToolRegistration&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Tool registration&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.ToolSchema&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Schema definitions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.FileSandbox&lt;/code&gt;&lt;/td&gt;&lt;td&gt;File sandbox resource management&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.FileSandbox.Predicate&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Path predicate DSL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Events&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OS event types for subcall visibility&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-tools.html" rel="alternate"/><summary type="text">The tool system provides agents with the ability to execute external commands, call APIs, and interact with other agents. Tools are dynamically registered and exposed to the LLM via the OpenAI function calling API. ## Overview ``` ┌──</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-sqq-dag.html</id><title type="text">Analysis of Issue Dependencies and DAG-Aware Agent Processing</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/sqq-dag.md"&gt;&lt;code&gt;documentation/sqq-dag.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="analysis-of-issue-dependencies-and-dag-aware-agent-processing"&gt;Analysis of Issue Dependencies and DAG-Aware Agent Processing&lt;/h2&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;p&gt;This document analyzes the current interaction between &lt;code&gt;sqq-agent.sh&lt;/code&gt; and &lt;code&gt;create-issue.sh&lt;/code&gt;, focusing on how issue dependencies are handled and the resulting impact on parallel development and git branch management.&lt;/p&gt;
&lt;h3 id="current-state-analysis"&gt;Current State Analysis&lt;/h3&gt;
&lt;h4 id="1-issue-creation-create-issuesh"&gt;1. Issue Creation (&lt;code&gt;create-issue.sh&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mechanism:&lt;/strong&gt; The script takes a &lt;code&gt;dependencies&lt;/code&gt; argument (e.g., &lt;code&gt;#42,&amp;amp;#35;43&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Labeling Logic:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;No dependencies: Labeled &lt;code&gt;agents/to-be-taken&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Has dependencies: Labeled &lt;code&gt;agents/wait&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limitation:&lt;/strong&gt; The labeling is static at creation time. There is no automated process to monitor dependencies and “unlock” &lt;code&gt;agents/wait&lt;/code&gt; issues.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-task-fetching-sqq-agentsh-from_github"&gt;2. Task Fetching (&lt;code&gt;sqq-agent.sh from_github&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mechanism:&lt;/strong&gt; Queries GitHub for issues with the &lt;code&gt;agents/to-be-taken&lt;/code&gt; label.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limitation:&lt;/strong&gt; It is “blind” to any issue labeled &lt;code&gt;agents/wait&lt;/code&gt;. This requires manual intervention (human or another agent) to re-label issues once their dependencies are met.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-worktree-execution-sqq-agentsh-worktree_exec"&gt;3. Worktree Execution (&lt;code&gt;sqq-agent.sh worktree_exec&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Branching Strategy:&lt;/strong&gt; Always executes &lt;code&gt;git worktree add &amp;quot;$name&amp;quot; &amp;quot;origin/main&amp;quot;&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The “Context Loss” Problem:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;If Issue B depends on Issue A, Issue B &lt;em&gt;must&lt;/em&gt; have the code changes from Issue A to proceed correctly (e.g., using a new Type or API defined in A).
&lt;/li&gt;
&lt;li&gt;If Issue B is started before Issue A is merged into &lt;code&gt;main&lt;/code&gt;, Issue B will be missing critical context.
&lt;/li&gt;
&lt;li&gt;Currently, &lt;code&gt;sqq-agent.sh&lt;/code&gt; has no awareness of which branch a dependency might be residing in.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-the-unfinished-work-problem"&gt;4. The “Unfinished Work” Problem&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Users reported that merging multiple parallel PRs can lead to &lt;code&gt;main&lt;/code&gt; having “unfinished work” if dependencies aren’t respected.
&lt;/li&gt;
&lt;li&gt;Without a strict DAG (Directed Acyclic Graph) enforcement, agents might implement redundant or conflicting logic because they are both branching from an older state of &lt;code&gt;main&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="proposed-dag-aware-model"&gt;Proposed DAG-Aware Model&lt;/h3&gt;
&lt;p&gt;To resolve these issues, we propose a transition from a “label-polling” model to a “DAG-aware” model.&lt;/p&gt;
&lt;h4 id="1-automated-issue-promotion"&gt;1. Automated Issue Promotion&lt;/h4&gt;
&lt;p&gt;We need a “Manager” process (or an update to &lt;code&gt;from_github&lt;/code&gt;) that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lists all issues with &lt;code&gt;agents/wait&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Parses the dependency IDs from the issue description or metadata.
&lt;/li&gt;
&lt;li&gt;Checks the status of these dependencies via &lt;code&gt;gh issue view&lt;/code&gt; or &lt;code&gt;gh pr view&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Promotion Rule:&lt;/strong&gt; If all dependencies are “Closed” (or their associated PRs are “Merged”), the label is updated to &lt;code&gt;agents/to-be-taken&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="2-branch-chaining-optional-but-powerful"&gt;2. Branch Chaining (Optional but Powerful)&lt;/h4&gt;
&lt;p&gt;Instead of always branching from &lt;code&gt;main&lt;/code&gt;, the system could support “Branch Chaining”:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If Issue B depends on Issue A, and Issue A’s work is in branch &lt;code&gt;gh-A&lt;/code&gt;, Issue B could branch from &lt;code&gt;origin/gh-A&lt;/code&gt; instead of &lt;code&gt;origin/main&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pros:&lt;/strong&gt; Allows pipelined development without waiting for merges.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons:&lt;/strong&gt; Requires complex rebasing if Issue A is updated after Issue B starts.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-strict-sequential-processing-recommended"&gt;3. Strict Sequential Processing (Recommended)&lt;/h4&gt;
&lt;p&gt;Given the user requirement that “the processing of the second issue should wait for the first issue to be finalized”, a strict sequential approach is safer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule:&lt;/strong&gt; An issue is only promoted to &lt;code&gt;to-be-taken&lt;/code&gt; when all its dependencies are &lt;strong&gt;merged into &lt;code&gt;main&lt;/code&gt;&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;This ensures &lt;code&gt;origin/main&lt;/code&gt; always contains the necessary context for the next task.
&lt;/li&gt;
&lt;li&gt;This prevents “unfinished work” from polluting &lt;code&gt;main&lt;/code&gt; because each task starts from a “finalized” baseline.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="implementation-recommendations"&gt;Implementation Recommendations&lt;/h3&gt;
&lt;h4 id="short-term-fixes"&gt;Short-term Fixes:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Update &lt;code&gt;sqq-agent.sh&lt;/code&gt;:&lt;/strong&gt; Add a &lt;code&gt;promote_issues&lt;/code&gt; command that uses &lt;code&gt;gh issue list --label agents/wait&lt;/code&gt; and checks dependency status.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standardize Dependency Metadata:&lt;/strong&gt; Ensure &lt;code&gt;create-issue.sh&lt;/code&gt; stores dependencies in a machine-readable format (e.g., a specific line in the body like &lt;code&gt;Depends-on: &amp;amp;#35;123, &amp;amp;#35;124&lt;/code&gt;).
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="long-term-architecture"&gt;Long-term Architecture:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Centralized DAG State:&lt;/strong&gt; The &lt;code&gt;sqq&lt;/code&gt; queue database could be extended to store task dependencies directly, allowing the scheduler to respect the DAG without polling GitHub repeatedly.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature Branch Isolation:&lt;/strong&gt; Maintain the current practice of using &lt;code&gt;gh-&amp;lt;number&amp;gt;&lt;/code&gt; branches, but ensure the &lt;code&gt;BASE_BRANCH&lt;/code&gt; is dynamically determined if “Branch Chaining” is desired.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="summary-of-benefits"&gt;Summary of Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Zero Manual Intervention:&lt;/strong&gt; Issues flow from &lt;code&gt;wait&lt;/code&gt; -&amp;gt; &lt;code&gt;to-be-taken&lt;/code&gt; -&amp;gt; &lt;code&gt;taken&lt;/code&gt; -&amp;gt; &lt;code&gt;completed&lt;/code&gt; automatically.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistency:&lt;/strong&gt; Agents always work on top of the latest “finalized” code they depend on.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clean Main:&lt;/strong&gt; Prevents the “unfinished work” syndrome by ensuring a logical ordering of merges.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-sqq-dag.html" rel="alternate"/><summary type="text">## Overview This document analyzes the current interaction between `sqq-agent.sh` and `create-issue.sh`, focusing on how issue dependencies are handled and the resulting impact on parallel development and git branch management. ## Current S</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-tui.html</id><title type="text">Terminal UI (TUI)</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/tui.md"&gt;&lt;code&gt;documentation/tui.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="terminal-ui-tui"&gt;Terminal UI (TUI)&lt;/h2&gt;
&lt;p&gt;The Terminal UI provides an interactive, real-time interface for agent conversations with support for multiple agents, streaming responses, visual feedback, file attachments, clipboard integration, subcall conversation visibility, and a tabbed interface for organizing different views.&lt;/p&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│ Agents │ Chats │ History │ Help                                  │
├─────────────────────────────────────────────────────────────────┤
│  Agents                                                         │
│  ─────────────────────────────────────────────────────────────  │
│  file-assistant                                                 │
│  code-reviewer                                                  │
│  documenter                                                     │
│                                                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  # Slug: file-assistant                                         │
│  # Announce: A helpful file assistant                           │
│  # Model: claude-sonnet-4-20250514                              │
│                                                                 │
│  # Tools:                                                       │
│  - [A] read_file                                               │
│  - [A] write_file                                              │
│  - [D:bash] bash_command                                       │
│                                                                 │
├─────────────────────────────────────────────────────────────────┤
│ [Tab] Switch  [Enter] Send  [Ctrl+C] Quit  [Ctrl+[|]] Prev/Next │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="tabbed-interface"&gt;Tabbed Interface&lt;/h3&gt;
&lt;p&gt;The TUI features a tabbed interface with four main tabs:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Tab&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Content&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Agents&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Browse and select agents&lt;/td&gt;&lt;td&gt;Agent list and detailed agent information&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Chats&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Active conversations&lt;/td&gt;&lt;td&gt;Conversation list and message interface&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;History&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Past sessions&lt;/td&gt;&lt;td&gt;Session list and history view&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Help&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Keyboard shortcuts&lt;/td&gt;&lt;td&gt;Command reference and key bindings&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img src="/agents-exe/images/tui-agents-tab.png" alt="The Agents tab" /&gt;&lt;/p&gt;
&lt;h4 id="tab-navigation"&gt;Tab Navigation&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+[&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Switch to previous tab&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Switch to next tab&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="agents-tab"&gt;Agents Tab&lt;/h4&gt;
&lt;p&gt;The Agents tab displays:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Left sidebar&lt;/strong&gt;: List of available agents
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Main area&lt;/strong&gt;: Detailed agent information including:
&lt;ul&gt;
&lt;li&gt;Slug and announce text
&lt;/li&gt;
&lt;li&gt;Model name
&lt;/li&gt;
&lt;li&gt;Tools with activation status
&lt;/li&gt;
&lt;li&gt;System prompt
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="chats-tab"&gt;Chats Tab&lt;/h4&gt;
&lt;p&gt;The Chats tab is for active conversations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Left sidebar&lt;/strong&gt;: List of ongoing conversations with status indicators:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;⟳&lt;/code&gt; - Active (agent is processing)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;●&lt;/code&gt; - Waiting for input (unread)
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;⏸&lt;/code&gt; - Paused
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;📎&lt;/code&gt; - Has file attachments
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Main area&lt;/strong&gt;: Message editor, attachment list, the draft panel (when the conversation has unsent draft text), and conversation history
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="draft-unsent-text-while-the-session-is-busy"&gt;Draft (unsent text while the session is busy)&lt;/h5&gt;
&lt;p&gt;Typing a message while a conversation is active, paused, or blocked on
deferred calls does not post it right away: it is appended to that
conversation’s &lt;strong&gt;draft&lt;/strong&gt;, one editable, unsent buffer per conversation
(&lt;code&gt;todos/os-as-standalone-server.md&lt;/code&gt; §5, D3). Three messages sent in a row
while the model is thinking are almost always one message being
elaborated, so each send appends a new paragraph to the draft instead of
queuing a discrete message.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Collapsed view&lt;/strong&gt; (default, shown below the message editor whenever the
focused conversation has a non-empty draft): the draft’s first line plus
a size indicator (&lt;code&gt;N chars, M paragraphs&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Edit&lt;/strong&gt; (&lt;code&gt;Ctrl+A&lt;/code&gt;): loads the draft into the message editor (its
attachments join the composer’s) and clears it – the editor is a full
text editor over the whole draft text; further sends fold right back
into a draft, or post, the normal way.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Send now&lt;/strong&gt; (&lt;code&gt;Ctrl+G&lt;/code&gt;): posts the draft immediately, as one message,
and clears it.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear&lt;/strong&gt; (&lt;code&gt;Ctrl+D&lt;/code&gt;): discards the draft.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ships automatically&lt;/strong&gt;: once the session’s run stops with a status that
accepts input (idle or ready – not paused, not blocked on deferred
calls, not failed), the TUI posts the whole draft as a single message
and clears it. A paused conversation keeps its draft until it is resumed
and stops again.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The kernel never sees a draft: it only ever receives real messages and
interrupts. An interrupt (&lt;code&gt;Ctrl+U&lt;/code&gt;) always bypasses the draft and posts
straight through.&lt;/p&gt;
&lt;h4 id="history-tab"&gt;History Tab&lt;/h4&gt;
&lt;p&gt;The History tab shows saved sessions, across every backend the runner is
configured with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Left sidebar&lt;/strong&gt;: List of sessions (&lt;code&gt;Client.listSessions&lt;/code&gt;, newest
updated first), refreshed live as sessions are created, updated, or
deleted elsewhere – a burst of updates during a run coalesces into at
most one refresh per heartbeat, and the current selection is kept by
session id across a refresh.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Main area&lt;/strong&gt;: the selected session’s full turn history (fetched once
via &lt;code&gt;Client.getSession&lt;/code&gt; and cached by id), with the same usage summary,
signal metrics, and turn navigation/forking as the Chats tab.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="help-tab"&gt;Help Tab&lt;/h4&gt;
&lt;p&gt;The Help tab displays keyboard shortcuts and command reference for quick access to all TUI functionality.&lt;/p&gt;
&lt;h3 id="architecture"&gt;Architecture&lt;/h3&gt;
&lt;p&gt;The TUI is a client of the in-process runner (&lt;code&gt;System.Agents.Host.Runner.SessionRunner&lt;/code&gt;),
not a second agent runtime: &lt;code&gt;agents-exe tui&lt;/code&gt; opens a &lt;code&gt;System.Agents.Host.Host&lt;/code&gt;
the same way &lt;code&gt;agents-exe serve&lt;/code&gt; does and drives it through an in-process
&lt;code&gt;System.Agents.Host.Client.RunnerClient&lt;/code&gt; — every conversation action (new
message, pause, fork, cancel, …) is a &lt;code&gt;Command&lt;/code&gt; sent to the runner, and
every screen update comes from &lt;code&gt;Event&lt;/code&gt;s the runner emits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Embedded and attached.&lt;/strong&gt; &lt;code&gt;agents-exe tui&lt;/code&gt; (embedded) builds that client
over a runner in its own process. &lt;code&gt;agents-exe tui --attach URL|PATH&lt;/code&gt;
(attached) opens nothing locally and builds
&lt;code&gt;System.Agents.Host.Client.Http.httpClient&lt;/code&gt; instead: the same
&lt;code&gt;RunnerClient&lt;/code&gt;, over a running &lt;code&gt;agents-exe serve&lt;/code&gt;’s HTTP API and SSE event
feed, on TCP or its &lt;code&gt;--socket&lt;/code&gt;. Everything above the client is the same
code, so an attached TUI loses nothing: agents, chats, drafts, pause,
interrupt, hard cancel, fork, History, pending calls. What it shows
depends on the server version, though: &lt;code&gt;hook.failed&lt;/code&gt; and the subcall
events only reach it from a server that emits them. Differences that
follow from where the runner lives: the agents, API keys and database are
the server’s (&lt;code&gt;--db&lt;/code&gt; is refused with &lt;code&gt;--attach&lt;/code&gt;, and &lt;code&gt;--agent-file&lt;/code&gt; or
&lt;code&gt;--agent&lt;/code&gt; select nothing); &lt;code&gt;--params-file&lt;/code&gt;/&lt;code&gt;--set&lt;/code&gt; values are still sent
with every create and message (secrets are resupplied by the client, D7);
with &lt;code&gt;--auth-tokens&lt;/code&gt; on the server, pass &lt;code&gt;--token&lt;/code&gt;/&lt;code&gt;--token-file&lt;/code&gt;, and the
TUI then sees only that owner’s sessions. Quitting an embedded TUI stops
the runs it started (&lt;code&gt;StopRun&lt;/code&gt; mail) since its runner dies with it;
quitting an attached TUI leaves them running on the server. A dropped
event stream reconnects on its own with &lt;code&gt;Last-Event-ID&lt;/code&gt;, so nothing is
missed across a short network hiccup.&lt;/p&gt;
&lt;p&gt;Sessions live in the SQLite database at
&lt;code&gt;System.Agents.CLI.ConfigLoader.defaultServerDatabasePath&lt;/code&gt; (next to the
resolved sessions directory) unless overridden with &lt;code&gt;tui --db PATH&lt;/code&gt;. Old
sessions written by the pre-runner file store (&lt;code&gt;conv.&amp;lt;uuid&amp;gt;.json&lt;/code&gt;, under
the config’s &lt;code&gt;sessions&lt;/code&gt; read locations) stay readable: the host composites
them in as a read-only fallback (&lt;code&gt;Host.hcLegacySessionDirs&lt;/code&gt;) behind the
SQLite backend.&lt;/p&gt;
&lt;p&gt;Sub-agent calls (&lt;code&gt;prompt_agent_*&lt;/code&gt;) run as real sessions of their own
(&lt;code&gt;todos/os-as-standalone-server.md&lt;/code&gt;, Phase 5), so live progress for a
child is its own &lt;code&gt;session.updated&lt;/code&gt;/&lt;code&gt;text.delta&lt;/code&gt;/&lt;code&gt;tool.*&lt;/code&gt; stream, exactly
like the parent conversation — not a separate “subcall progress” event.
The TUI still gets &lt;code&gt;subcall.started&lt;/code&gt;/&lt;code&gt;subcall.completed&lt;/code&gt;/&lt;code&gt;subcall.failed&lt;/code&gt;
for the start/complete/fail transitions themselves (used to show the child
in the conversation list and its hierarchy), but token-by-token and
tool-by-tool progress in between now comes from subscribing to the child
session directly, the same as any other session. A sub-agent call made
with per-call narrowing (&lt;code&gt;bindings&lt;/code&gt;/&lt;code&gt;with&lt;/code&gt;/&lt;code&gt;as&lt;/code&gt;) still runs in-tool, with
no session and no live progress of its own, until that case is supported
the same way.&lt;/p&gt;
&lt;h4 id="component-structure"&gt;Component Structure&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                         TUI.Core                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐      │
│  │   TUI.Types  │───&amp;gt;│  TUI.Render  │───&amp;gt;│  TUI.Event   │      │
│  │   (state)    │    │  (display)   │    │  (input)     │      │
│  └──────────────┘    └──────────────┘    └──────────────┘      │
│         ▲                                            │          │
│         └────────────────────────────────────────────┘          │
│                      (event loop)                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="state-management"&gt;State Management&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- TUI.Types&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Tab&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AgentsTab&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ChatsTab&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;HistoryTab&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;HelpTab&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;UIState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UIState&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; _uiFocusRing ::&lt;/span&gt; &lt;span class="dt"&gt;FocusRing&lt;/span&gt; &lt;span class="dt"&gt;WidgetName&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _currentTab ::&lt;/span&gt; &lt;span class="dt"&gt;Tab&lt;/span&gt;           &lt;span class="co"&gt;-- Current active tab&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _helpContent ::&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]       &lt;span class="co"&gt;-- Help text lines&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _turnNavigation ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;TurnNavigationState&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ When Just, we are in turn navigation mode&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _attachedFiles ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; [&lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;]&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Media attachments per conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _attachmentDialogState ::&lt;/span&gt; &lt;span class="dt"&gt;AttachmentDialogState&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ File attachment dialog state&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _filePathInput ::&lt;/span&gt; &lt;span class="dt"&gt;Editor&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;WidgetName&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Editor for file path input&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _selectedAttachmentIndex ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Selected attachment index&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;TUIState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; _tuiCore ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; &lt;span class="dt"&gt;Core&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _tuiUI ::&lt;/span&gt; &lt;span class="dt"&gt;UIState&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _eventChan ::&lt;/span&gt; &lt;span class="dt"&gt;BChan&lt;/span&gt; &lt;span class="dt"&gt;AppEvent&lt;/span&gt;&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _sessionConfig ::&lt;/span&gt; &lt;span class="dt"&gt;SessionConfig&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="background-tool-calls"&gt;Background Tool Calls&lt;/h3&gt;
&lt;p&gt;Agents configured for asynchronous execution (see
&lt;a href="/agents-exe/docs-async-tool-calls.html"&gt;async-tool-calls.md&lt;/a&gt;) run tool calls in the background.
The TUI shows what is running, with the latest progress each tool reports:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Background tool calls running: run_tests

[Partial] &amp;gt; run the tests and the linter
  ✓ lint (call_1): completed
  ⏳ run_tests (call_2): running: 128 tests passed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Call states are &lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;deferred&lt;/code&gt;, &lt;code&gt;running&lt;/code&gt;, &lt;code&gt;completed&lt;/code&gt;,
&lt;code&gt;completed (delivered later)&lt;/code&gt; and &lt;code&gt;failed&lt;/code&gt;. “Delivered later” means the model
had already been answered with a placeholder for that call, and got the result
in a following message.&lt;/p&gt;
&lt;p&gt;While calls run in the background and the LLM has nothing to do, the
conversation still accepts input: whichever comes first — your message or the
results — is sent to the model.&lt;/p&gt;
&lt;p&gt;A conversation that waits on &lt;em&gt;deferred&lt;/em&gt; calls (completed by an external
worker) stops with a status message instead of waiting; see “Pending calls”
below to answer them from the TUI itself.&lt;/p&gt;
&lt;h3 id="pending-calls"&gt;Pending calls&lt;/h3&gt;
&lt;p&gt;When a run stops on deferred calls (&lt;code&gt;calls.deferred&lt;/code&gt;), the conversation’s
status becomes “blocked on deferred” and a Pending panel appears below the
Draft panel, listing each call’s tool name, a prefix of its continuation
token, and its arguments:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌ Pending (1) ──────────────────────────────────────┐
│ Ctrl+O: select next | Ctrl+Y: answer selected, ... │
│                                                     │
│ &amp;gt; bash_command (token a1b2c3d4): {&amp;quot;cmd&amp;quot;: &amp;quot;ls&amp;quot;}     │
│ - search (token 5e6f7a8b): {&amp;quot;q&amp;quot;: &amp;quot;todo&amp;quot;}           │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="/agents-exe/images/tui-pending-panel.png" alt="The Pending panel, with one deferred call" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;gt;&lt;/code&gt; marks the selected call, the first one with a continuation token until
you move it: &lt;code&gt;Ctrl+O&lt;/code&gt; (&lt;code&gt;select-pending&lt;/code&gt;) selects the next one, wrapping
around. &lt;code&gt;Ctrl+Y&lt;/code&gt; and &lt;code&gt;Ctrl+W&lt;/code&gt; act on the selected call.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ctrl+Y&lt;/code&gt; (&lt;code&gt;answer-pending&lt;/code&gt;) puts the message editor into “answer mode” for
the selected pending call; type the result and
send it (&lt;code&gt;Ctrl+Enter&lt;/code&gt;/the usual send trigger) the way you would any other
message. That calls &lt;code&gt;completeCall&lt;/code&gt; with &lt;code&gt;autoResume = true&lt;/code&gt;, the same
mechanism the server’s own &lt;code&gt;GET /v1/sessions/:id/pending&lt;/code&gt; workers use, so
the run resumes on its own — a fresh &lt;code&gt;run.started&lt;/code&gt;/&lt;code&gt;run.stopped&lt;/code&gt; pair
follows. The panel clears once the run starts again.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ctrl+W&lt;/code&gt; (&lt;code&gt;fail-pending&lt;/code&gt;) fails the selected call: it completes it (the same
&lt;code&gt;completeCall&lt;/code&gt;, &lt;code&gt;autoResume = true&lt;/code&gt;) with the text &lt;code&gt;Error: &amp;lt;reason&amp;gt;&lt;/code&gt;, where the
reason is what is in the message editor (which is cleared), or “the user
declined this call” when it is empty. &lt;code&gt;UserToolResponse&lt;/code&gt; has no dedicated
error form, so a failed call reaches the model as an ordinary text result that
reads as an error, the way a failing tool’s own error does. Selecting, answering
and failing work the same over an embedded runner and with &lt;code&gt;--attach&lt;/code&gt;, since
they only use &lt;code&gt;completeCall&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="subcall-conversation-visibility"&gt;Subcall Conversation Visibility&lt;/h3&gt;
&lt;p&gt;When agents call other agents as tools (via &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt;), the subcall conversations are now visible in the TUI with visual distinction and hierarchy tracking.&lt;/p&gt;
&lt;h4 id="visual-hierarchy"&gt;Visual Hierarchy&lt;/h4&gt;
&lt;p&gt;Subcall conversations are displayed with tree-branch styling to show parent-child relationships:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Conversations
├─ @file-assistant (⟳)                    -- Root conversation
│  ├─ @code-reviewer (⟳)                  -- Subcall depth 1
│  │  └─ @syntax-checker (●)              -- Subcall depth 2
│  └─ @documenter (●)                     -- Subcall depth 1
└─ @helper-agent (●)                      -- Another root conversation
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="conversation-indicators"&gt;Conversation Indicators&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Visual&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@slug&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Root conversation (depth 0)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;├─ @slug&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Subcall with siblings&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;└─ @slug&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Last subcall in branch&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;│&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Continuation line for parent with more children&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Dimmed text&lt;/td&gt;&lt;td&gt;Subcall conversation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Normal text&lt;/td&gt;&lt;td&gt;Root conversation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;⟳&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Active (processing)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;●&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Waiting for input&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;⏸&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Paused&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="subcall-event-flow"&gt;Subcall Event Flow&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Parent Agent (TUI visible)
       │
       ▼ calls helper agent
┌─────────────────────────┐
│ turnAgentRuntimeIntoIOTool
│ (OneShotTool.hs)        │
│                         │
│ 1. Insert into OS World │
│    - ConversationConfig │
│    - ConversationState  │
│    - Lineage (parent)   │
│                         │
│ 2. Emit SubcallStarted  │◄── OSEvent
│    (parentId, convId)   │
│                         │
│ 3. Run sub-agent        │
│                         │
│ 4. Emit SubcallProgress │◄── OSEvent (after each step)
│                         │
│ 5. Emit SubcallCompleted│◄── OSEvent (on success)
│    or SubcallFailed     │◄── OSEvent (on error)
└──────────┬──────────────┘
           │
           ▼ OS Event Queue
┌─────────────────────────┐
│   TUI Event Handler     │
│   (Event.hs)            │
│                         │
│ - Create conversation   │
│ - Show in list          │
│ - Update on progress    │
│ - Mark completed        │
└─────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="subcall-event-types"&gt;Subcall Event Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- OS Events (from System.Agents.OS.Events)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;OSEvent&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OSEvent_SubcallStarted&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        {&lt;span class="ot"&gt; subcallParentConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; subcallConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; subcallAgentSlug ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; subcallDepth ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OSEvent_SubcallProgress&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        {&lt;span class="ot"&gt; subcallProgressConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; subcallProgressSession ::&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OSEvent_SubcallCompleted&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        {&lt;span class="ot"&gt; subcallCompletedConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; subcallCompletedResult ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OSEvent_SubcallFailed&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        {&lt;span class="ot"&gt; subcallFailedConversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ,&lt;span class="ot"&gt; subcallFailedError ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- App Events (TUI internal)&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AppEvent&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppEvent_SubcallStarted&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppEvent_SubcallProgress&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppEvent_SubcallCompleted&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AppEvent_SubcallFailed&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="conversation-types"&gt;Conversation Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Conversation&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; conversationId ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationAgent ::&lt;/span&gt; &lt;span class="dt"&gt;TuiAgent&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationThreadId ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ThreadId&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationSession ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationName ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationChan ::&lt;/span&gt; &lt;span class="dt"&gt;BChan&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UserQuery&lt;/span&gt;)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationStatus ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationOnProgress ::&lt;/span&gt; &lt;span class="dt"&gt;OnSessionProgress&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationIsSubcall ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;      &lt;span class="co"&gt;-- ^ NEW: Is this a subcall?&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationParentId ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;  &lt;span class="co"&gt;-- ^ NEW: Parent conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; conversationSubcallDepth ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;    &lt;span class="co"&gt;-- ^ NEW: Nesting depth (0 = root)&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="rendering-subcall-hierarchy"&gt;Rendering Subcall Hierarchy&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Render conversations with tree structure&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;renderConversationForest ::&lt;/span&gt; [&lt;span class="dt"&gt;ConversationTree&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;Widget&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt;]&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;renderConversationForest trees &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;concatMap&lt;/span&gt; (renderTreeNode [] &lt;span class="dt"&gt;False&lt;/span&gt;) trees&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Build tree from flat list&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;buildConversationForest ::&lt;/span&gt; [&lt;span class="dt"&gt;Conversation&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;ConversationTree&lt;/span&gt;]&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;buildConversationForest convs &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="co"&gt;-- Find roots (no parent or orphaned)&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        isRoot c &lt;span class="ot"&gt;=&lt;/span&gt; conversationParentId c &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;||&lt;/span&gt; conversationParentId c &lt;span class="ot"&gt;`notElem`&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; (&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; conversationId) convs&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        roots &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;filter&lt;/span&gt; isRoot convs&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Build recursively&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        buildTree conv &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationTree&lt;/span&gt; conv &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;map&lt;/span&gt; buildTree (findChildren conv)&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        findChildren parent &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;filter&lt;/span&gt; (&lt;span class="op"&gt;\&lt;/span&gt;c &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; conversationParentId c &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; (conversationId parent)) convs&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; buildTree roots&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Make prefix with tree branches&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;makePrefix ::&lt;/span&gt; [&lt;span class="dt"&gt;Bool&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;makePrefix ancestorIsLasts isLast&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;null&lt;/span&gt; ancestorIsLasts &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;if&lt;/span&gt; isLast &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;└─&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;├─&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;let&lt;/span&gt; continuation &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;mconcat&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="fu"&gt;map&lt;/span&gt; (&lt;span class="op"&gt;\&lt;/span&gt;isLast&amp;#39; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;if&lt;/span&gt; isLast&amp;#39; &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;  &amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;│ &amp;quot;&lt;/span&gt;) ancestorIsLasts&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;in&lt;/span&gt; continuation &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; (&lt;span class="kw"&gt;if&lt;/span&gt; isLast &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;└─&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;├─&amp;quot;&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="visual-attributes"&gt;Visual Attributes&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;tui_appAttrMap ::&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AttrMap&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;tui_appAttrMap _ &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    attrMap Vty.defAttr&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="co"&gt;-- Subcall visual distinction&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          (subcallAttr, fg white &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; dim)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (subcallSelectedAttr, fg black &lt;span class="ot"&gt;`on`&lt;/span&gt; brightWhite &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; bold)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (treeBranchAttr, fg white &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; dim)&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (rootConversationAttr, defAttr)&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="file-attachments"&gt;File Attachments&lt;/h3&gt;
&lt;p&gt;The TUI supports attaching files to messages for multi-modal LLM interactions.&lt;/p&gt;
&lt;h4 id="attaching-files"&gt;Attaching Files&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Via File Path Input:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;Ctrl+F&lt;/code&gt; to open the file path input dialog
&lt;/li&gt;
&lt;li&gt;Type or paste the absolute path to the file
&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;Enter&lt;/code&gt; to attach, &lt;code&gt;Esc&lt;/code&gt; to cancel
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Via the file browser:&lt;/strong&gt; the dialog &lt;code&gt;Ctrl+F&lt;/code&gt; opens lists a directory, with
its current path under the listing.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;↑&lt;/code&gt; / &lt;code&gt;↓&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Move the cursor&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Open the directory under the cursor (&lt;code&gt;..&lt;/code&gt; goes up), or attach the file under it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Backspace&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Go to the parent directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Filter the listing by name; &lt;code&gt;Enter&lt;/code&gt; keeps the filter, &lt;code&gt;Esc&lt;/code&gt; stops searching&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Esc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Cancel (or stop a search in progress)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;A directory that cannot be read (for instance for lack of permission) is
reported under the listing; &lt;code&gt;Backspace&lt;/code&gt; leaves it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Supported file path formats:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/path/to/image.png                    # Auto-detect MIME type
image/png;/path/to/image.png          # Explicit MIME type
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="attachment-display"&gt;Attachment Display&lt;/h4&gt;
&lt;p&gt;Attached files are displayed below the message editor:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│ Message [2 attachments]                                     │
├─────────────────────────────────────────────────────────────┤
│ &amp;gt; Your message here...                                      │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│ Attachments (2) - Del/Backspace: remove | Ctrl+Shift+F: clear all│
│   📎 screenshot.png (image/png, 245KB)                     │
│ ▶ 📎 report.pdf (application/pdf, 1.2MB)                   │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="managing-attachments"&gt;Managing Attachments&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+F&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Open file path input dialog&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+Shift+F&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Clear all attachments&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Del&lt;/code&gt; / &lt;code&gt;Backspace&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Remove selected attachment&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Up&lt;/code&gt; / &lt;code&gt;Down&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Select attachment (when focus is on attachment list)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="supported-file-types"&gt;Supported File Types&lt;/h4&gt;
&lt;p&gt;The TUI can attach any file type. MIME type detection is automatic based on file extension:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Category&lt;/th&gt;&lt;th&gt;Extensions&lt;/th&gt;&lt;th&gt;MIME Types&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Images&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.png&lt;/code&gt;, &lt;code&gt;.jpg&lt;/code&gt;, &lt;code&gt;.jpeg&lt;/code&gt;, &lt;code&gt;.gif&lt;/code&gt;, &lt;code&gt;.webp&lt;/code&gt;, &lt;code&gt;.svg&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;image/png&lt;/code&gt;, &lt;code&gt;image/jpeg&lt;/code&gt;, &lt;code&gt;image/gif&lt;/code&gt;, &lt;code&gt;image/webp&lt;/code&gt;, &lt;code&gt;image/svg+xml&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Documents&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.pdf&lt;/code&gt;, &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.md&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;, &lt;code&gt;.xml&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;application/pdf&lt;/code&gt;, &lt;code&gt;text/plain&lt;/code&gt;, &lt;code&gt;text/markdown&lt;/code&gt;, &lt;code&gt;application/json&lt;/code&gt;, &lt;code&gt;application/xml&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Audio&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.mp3&lt;/code&gt;, &lt;code&gt;.wav&lt;/code&gt;, &lt;code&gt;.ogg&lt;/code&gt;, &lt;code&gt;.aac&lt;/code&gt;, &lt;code&gt;.flac&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;audio/mp3&lt;/code&gt;, &lt;code&gt;audio/wav&lt;/code&gt;, &lt;code&gt;audio/ogg&lt;/code&gt;, &lt;code&gt;audio/aac&lt;/code&gt;, &lt;code&gt;audio/flac&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Video&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.mp4&lt;/code&gt;, &lt;code&gt;.webm&lt;/code&gt;, &lt;code&gt;.mov&lt;/code&gt;, &lt;code&gt;.avi&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;video/mp4&lt;/code&gt;, &lt;code&gt;video/webm&lt;/code&gt;, &lt;code&gt;video/quicktime&lt;/code&gt;, &lt;code&gt;video/avi&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Archives&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.zip&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;application/zip&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Size Limit:&lt;/strong&gt; 50MB per file&lt;/p&gt;
&lt;h4 id="attachment-state"&gt;Attachment State&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Attachments are stored per conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;AttachedFiles&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; [&lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;]&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; mediaMimeType ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;        &lt;span class="co"&gt;-- e.g., &amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mediaBase64Data ::&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;      &lt;span class="co"&gt;-- Base64-encoded content&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; mediaFilename ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;  &lt;span class="co"&gt;-- Original filename&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Dialog state for file attachment&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;AttachmentDialogState&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AttachmentDialogClosed&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AttachmentDialogPathInput&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="attachment-flow"&gt;Attachment Flow&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;User presses Ctrl+F
       │
       ▼
┌──────────────────┐
│ Open path dialog │
│ (text input)     │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ User enters path │
│ Presses Enter    │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ Load file        │
│ Detect MIME type │
│ Base64 encode    │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ Add to           │
│ attachedFiles    │
│ map              │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ Render in        │
│ attachment list  │
└──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="clipboard-integration"&gt;Clipboard Integration&lt;/h3&gt;
&lt;p&gt;The TUI supports pasting content from the system clipboard, including images, file paths, and text.&lt;/p&gt;
&lt;h4 id="clipboard-pasting"&gt;Clipboard Pasting&lt;/h4&gt;
&lt;p&gt;Press &lt;code&gt;Ctrl+V&lt;/code&gt; to paste from clipboard:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Content Type&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Image&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Save to temp file and attach&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;File path&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Attach the file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Multiple file paths&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Attach all valid files&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Text&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Insert into message editor&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="platform-support"&gt;Platform Support&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Platform&lt;/th&gt;&lt;th&gt;Backend&lt;/th&gt;&lt;th&gt;Required Tools&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Linux (X11)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;xclip&lt;/code&gt; or &lt;code&gt;xsel&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;xclip&lt;/code&gt; or &lt;code&gt;xsel&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Linux (Wayland)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;wl-clipboard&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;wl-paste&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;macOS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Built-in&lt;/td&gt;&lt;td&gt;&lt;code&gt;pbpaste&lt;/code&gt; (included)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Windows&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;PowerShell&lt;/td&gt;&lt;td&gt;&lt;code&gt;powershell.exe&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="smart-content-detection"&gt;Smart Content Detection&lt;/h4&gt;
&lt;p&gt;The clipboard module automatically detects content type:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ClipboardContent&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ClipboardImage&lt;/span&gt; &lt;span class="dt"&gt;ByteString&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;    &lt;span class="co"&gt;-- Image data with MIME type&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ClipboardFilePath&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt;        &lt;span class="co"&gt;-- Single file path&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ClipboardText&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;                &lt;span class="co"&gt;-- Plain text&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ClipboardFilePaths&lt;/span&gt; [&lt;span class="dt"&gt;FilePath&lt;/span&gt;]     &lt;span class="co"&gt;-- Multiple file paths&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ClipboardUnknown&lt;/span&gt;                  &lt;span class="co"&gt;-- Unsupported content&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Detection order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check for image data (via magic bytes: PNG &lt;code&gt;\x89PNG&lt;/code&gt;, JPEG &lt;code&gt;\xFF\xD8\xFF&lt;/code&gt;, GIF &lt;code&gt;GIF87a/GIF89a&lt;/code&gt;, WebP &lt;code&gt;RIFF&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;Check for file paths (valid paths that exist)
&lt;/li&gt;
&lt;li&gt;Check for multiple file paths (one per line)
&lt;/li&gt;
&lt;li&gt;Fall back to plain text
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="clipboard-module"&gt;Clipboard Module&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- System.Agents.TUI.Clipboard&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Detect available backend&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;detectBackend ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ClipboardBackend&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Read clipboard content&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;readClipboard ::&lt;/span&gt; &lt;span class="dt"&gt;ClipboardBackend&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ByteString&lt;/span&gt;)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Detect content type&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;detectClipboardContent ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ClipboardContent&lt;/span&gt;)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Analyze and convert to action&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;analyzeContent ::&lt;/span&gt; &lt;span class="dt"&gt;ClipboardContent&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;ContentAction&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ContentAction&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AttachAsMedia&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PasteAsText&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;AttachMultipleFiles&lt;/span&gt; [&lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;]&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;IgnoreContent&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="image-pasting-from-clipboard"&gt;Image Pasting from Clipboard&lt;/h4&gt;
&lt;p&gt;When an image is pasted from clipboard:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Detect image format from magic bytes
&lt;/li&gt;
&lt;li&gt;Save to temporary file with appropriate extension
&lt;/li&gt;
&lt;li&gt;Create &lt;code&gt;MediaAttachment&lt;/code&gt; with detected MIME type
&lt;/li&gt;
&lt;li&gt;Attach to current conversation
&lt;/li&gt;
&lt;li&gt;Show status: “Attached from clipboard: image.png”
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Temporary file location:&lt;/strong&gt; &lt;code&gt;$TMPDIR/agents-exe-clipboard/clipboard-*.png&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Size limit:&lt;/strong&gt; 50MB for clipboard images&lt;/p&gt;
&lt;h4 id="file-drop-support-terminal-protocols"&gt;File Drop Support (Terminal Protocols)&lt;/h4&gt;
&lt;p&gt;The clipboard module also supports file drop events from modern terminals:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Protocol&lt;/th&gt;&lt;th&gt;Terminal&lt;/th&gt;&lt;th&gt;Support&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;iTerm2 File Drop&lt;/td&gt;&lt;td&gt;iTerm2 (macOS)&lt;/td&gt;&lt;td&gt;✅ Supported&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Kitty Graphics&lt;/td&gt;&lt;td&gt;Kitty&lt;/td&gt;&lt;td&gt;✅ Supported&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OSC 52&lt;/td&gt;&lt;td&gt;Various&lt;/td&gt;&lt;td&gt;✅ Read support&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="rendering"&gt;Rendering&lt;/h3&gt;
&lt;h4 id="tab-bar-rendering"&gt;Tab Bar Rendering&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- TUI.Render&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;renderTabBar ::&lt;/span&gt; &lt;span class="dt"&gt;Tab&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Widget&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;renderTabBar activeTab &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; tabs &lt;span class="ot"&gt;=&lt;/span&gt; [&lt;span class="dt"&gt;AgentsTab&lt;/span&gt;, &lt;span class="dt"&gt;ChatsTab&lt;/span&gt;, &lt;span class="dt"&gt;HistoryTab&lt;/span&gt;, &lt;span class="dt"&gt;HelpTab&lt;/span&gt;]&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        renderTab tab &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;let&lt;/span&gt; tabName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; tab &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="dt"&gt;AgentsTab&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; Agents &amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="dt"&gt;ChatsTab&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; Chats &amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="dt"&gt;HistoryTab&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; History &amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="dt"&gt;HelpTab&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; Help &amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                tabAttr &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;if&lt;/span&gt; tab &lt;span class="op"&gt;==&lt;/span&gt; activeTab &lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                          &lt;span class="kw"&gt;then&lt;/span&gt; activeTabAttr &lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                          &lt;span class="kw"&gt;else&lt;/span&gt; inactiveTabAttr&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;             &lt;span class="kw"&gt;in&lt;/span&gt; withAttr tabAttr &lt;span class="op"&gt;$&lt;/span&gt; txt tabName&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="kw"&gt;in&lt;/span&gt; hBox (intersperse separator &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; renderTab tabs)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="tab-specific-content"&gt;Tab-Specific Content&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;render_contentArea ::&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Widget&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;render_contentArea st &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; st &lt;span class="op"&gt;^.&lt;/span&gt; tuiUI &lt;span class="op"&gt;.&lt;/span&gt; currentTab &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;AgentsTab&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; renderAgentsTab st&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;ChatsTab&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; renderChatsTab st&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;HistoryTab&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; renderHistoryTab st&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;HelpTab&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; renderHelpTab st&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="attachment-list-rendering"&gt;Attachment List Rendering&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;render_attachmentPanel ::&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;MediaAttachment&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Widget&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;render_attachmentPanel st attachments &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    borderWithFocus&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        st&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;AttachmentListWidget&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        (&lt;span class="st"&gt;&amp;quot; Attachments (&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; Text.pack (&lt;span class="fu"&gt;show&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;length&lt;/span&gt; attachments) &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;) &amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;$&lt;/span&gt; vBox&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            [ txt &lt;span class="st"&gt;&amp;quot;Del/Backspace: remove | Ctrl+Shift+F: clear all&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , txt &lt;span class="st"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , vBox &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;zipWith&lt;/span&gt; (render_attachment_item selectedIdx) [&lt;span class="dv"&gt;0&lt;/span&gt; &lt;span class="op"&gt;..&lt;/span&gt;] attachments&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            ]&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;render_attachment_item ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;MediaAttachment&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Widget&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;render_attachment_item selectedIdx idx att &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; isSelected &lt;span class="ot"&gt;=&lt;/span&gt; selectedIdx &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; idx&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        marker &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;if&lt;/span&gt; isSelected &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;▶ &amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;  &amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        filename &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;maybe&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;unnamed&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;id&lt;/span&gt; att&lt;span class="op"&gt;.&lt;/span&gt;mediaFilename&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        mimeType &lt;span class="ot"&gt;=&lt;/span&gt; att&lt;span class="op"&gt;.&lt;/span&gt;mediaMimeType&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        sizeStr &lt;span class="ot"&gt;=&lt;/span&gt; formatAttachmentSize att&lt;span class="op"&gt;.&lt;/span&gt;mediaBase64Data&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="kw"&gt;in&lt;/span&gt; hBox&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         [ txt marker&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         , txt &lt;span class="st"&gt;&amp;quot;📎 &amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         , txt filename&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         , txt &lt;span class="st"&gt;&amp;quot; (&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         , withAttr attachmentSizeAttr &lt;span class="op"&gt;$&lt;/span&gt; txt mimeType&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         , txt &lt;span class="st"&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         , withAttr attachmentSizeAttr &lt;span class="op"&gt;$&lt;/span&gt; txt sizeStr&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         , txt &lt;span class="st"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="conversation-list-with-nesting"&gt;Conversation List with Nesting&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Render conversation list with subcall hierarchy&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;render_conversationList ::&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Widget&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;render_conversationList st &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; convs &lt;span class="ot"&gt;=&lt;/span&gt; Vector.toList (listElements (st &lt;span class="op"&gt;^.&lt;/span&gt; tuiUI &lt;span class="op"&gt;.&lt;/span&gt; conversationList))&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        forest &lt;span class="ot"&gt;=&lt;/span&gt; buildConversationForest convs&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        hasFocus &lt;span class="ot"&gt;=&lt;/span&gt; focusGetCurrent (st &lt;span class="op"&gt;^.&lt;/span&gt; tuiUI &lt;span class="op"&gt;.&lt;/span&gt; uiFocusRing) &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;ConversationListWidget&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        selectedId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; listSelectedElement (st &lt;span class="op"&gt;^.&lt;/span&gt; tuiUI &lt;span class="op"&gt;.&lt;/span&gt; conversationList) &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;Just&lt;/span&gt; (_, conv) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; (conversationId conv)&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="kw"&gt;in&lt;/span&gt; borderWithFocus&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            st&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;ConversationListWidget&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="st"&gt;&amp;quot;Conversations&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            ( viewport &lt;span class="dt"&gt;ConversationListWidget&lt;/span&gt; &lt;span class="dt"&gt;Both&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                vBox &lt;span class="op"&gt;$&lt;/span&gt; renderConversationForest st selectedId hasFocus forest&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            )&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;renderConversationForest ::&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;ConversationTree&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;Widget&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt;]&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;renderConversationForest st selectedId hasFocus trees &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;concatMap&lt;/span&gt; (&lt;span class="op"&gt;\&lt;/span&gt;(idx, tree) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; renderTreeNode st selectedId hasFocus [] (idx &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="fu"&gt;length&lt;/span&gt; trees &lt;span class="op"&gt;-&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;) tree) (&lt;span class="fu"&gt;zip&lt;/span&gt; [&lt;span class="dv"&gt;0&lt;/span&gt; &lt;span class="op"&gt;..&lt;/span&gt;] trees)&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;renderTreeNode ::&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;Bool&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationTree&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;Widget&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt;]&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;renderTreeNode st selectedId hasFocus ancestorIsLasts isLast (&lt;span class="dt"&gt;ConversationTree&lt;/span&gt; conv children) &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; isSelected &lt;span class="ot"&gt;=&lt;/span&gt; selectedId &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; (conversationId conv)&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        nodeWidget &lt;span class="ot"&gt;=&lt;/span&gt; renderNestedConversationItem st hasFocus isSelected ancestorIsLasts isLast conv&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        childWidgets &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;concatMap&lt;/span&gt; (&lt;span class="op"&gt;\&lt;/span&gt;(idx, child) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; renderTreeNode st selectedId hasFocus (ancestorIsLasts &lt;span class="op"&gt;++&lt;/span&gt; [isLast]) (idx &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="fu"&gt;length&lt;/span&gt; children &lt;span class="op"&gt;-&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;) child) (&lt;span class="fu"&gt;zip&lt;/span&gt; [&lt;span class="dv"&gt;0&lt;/span&gt; &lt;span class="op"&gt;..&lt;/span&gt;] children)&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="kw"&gt;in&lt;/span&gt; nodeWidget &lt;span class="op"&gt;:&lt;/span&gt; childWidgets&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="event-handling"&gt;Event Handling&lt;/h3&gt;
&lt;h4 id="tab-switching"&gt;Tab Switching&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- TUI.Event&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;tui_appHandleEvent tracer ev &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; ev &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- Tab switching&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;VtyEvent&lt;/span&gt; (&lt;span class="dt"&gt;Vty.EvKey&lt;/span&gt; (&lt;span class="dt"&gt;Vty.KChar&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;[&amp;#39;&lt;/span&gt;) [&lt;span class="dt"&gt;Vty.MCtrl&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            cycleTabBackward&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;VtyEvent&lt;/span&gt; (&lt;span class="dt"&gt;Vty.EvKey&lt;/span&gt; (&lt;span class="dt"&gt;Vty.KChar&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;]&amp;#39;&lt;/span&gt;) [&lt;span class="dt"&gt;Vty.MCtrl&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            cycleTabForward&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;cycleTabForward ::&lt;/span&gt; &lt;span class="dt"&gt;EventM&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;cycleTabForward &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    current &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; use (tuiUI &lt;span class="op"&gt;.&lt;/span&gt; currentTab)&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; next &lt;span class="ot"&gt;=&lt;/span&gt; nextTab current&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tuiUI &lt;span class="op"&gt;.&lt;/span&gt; currentTab &lt;span class="op"&gt;.=&lt;/span&gt; next&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Update focus ring for the new tab&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    mCurrentFocus &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; use (tuiUI &lt;span class="op"&gt;.&lt;/span&gt; uiFocusRing &lt;span class="op"&gt;.&lt;/span&gt; to focusGetCurrent)&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tuiUI &lt;span class="op"&gt;.&lt;/span&gt; uiFocusRing &lt;span class="op"&gt;.=&lt;/span&gt; buildFocusRingForTabPreserving next mCurrentFocus&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="subcall-event-handling"&gt;Subcall Event Handling&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Handle subcall events in both normal and navigation mode&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleNormalEvent tracer ev &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; ev &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;AppEvent&lt;/span&gt; (&lt;span class="dt"&gt;AppEvent_SubcallStarted&lt;/span&gt; parentId subcallId slug depth) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            handleSubcallStarted tracer parentId subcallId slug depth&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;AppEvent&lt;/span&gt; (&lt;span class="dt"&gt;AppEvent_SubcallProgress&lt;/span&gt; subcallId sess) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            handleSubcallProgress subcallId sess&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;AppEvent&lt;/span&gt; (&lt;span class="dt"&gt;AppEvent_SubcallCompleted&lt;/span&gt; subcallId result) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            handleSubcallCompleted subcallId result&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;AppEvent&lt;/span&gt; (&lt;span class="dt"&gt;AppEvent_SubcallFailed&lt;/span&gt; subcallId err) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            handleSubcallFailed subcallId err&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Create subcall conversation entry&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleSubcallStarted ::&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EventM&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleSubcallStarted _tracer parentId subcallId slug depth &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    agents &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; use (tuiUI &lt;span class="op"&gt;.&lt;/span&gt; agentList &lt;span class="op"&gt;.&lt;/span&gt; to listElements)&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; findAgentBySlug slug agents &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Just&lt;/span&gt; tuiAgent &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            inChan &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class="op"&gt;$&lt;/span&gt; newBChan &lt;span class="dv"&gt;100&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;let&lt;/span&gt; conv &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    { conversationId &lt;span class="ot"&gt;=&lt;/span&gt; subcallId&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationAgent &lt;span class="ot"&gt;=&lt;/span&gt; tuiAgent&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationThreadId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationSession &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;@&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; tuiSlug tuiAgent&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationChan &lt;span class="ot"&gt;=&lt;/span&gt; inChan&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationStatus &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ConversationStatus_Active&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationOnProgress &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;_ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationIsSubcall &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;True&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationParentId &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; parentId&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    , conversationSubcallDepth &lt;span class="ot"&gt;=&lt;/span&gt; depth&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    }&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            coreRef &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; use tuiCore&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            liftIO &lt;span class="op"&gt;$&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; modifyTVar coreRef &lt;span class="op"&gt;$&lt;/span&gt; appendConversation conv&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            tuiUI &lt;span class="op"&gt;.&lt;/span&gt; conversationList &lt;span class="op"&gt;%=&lt;/span&gt; listInsert &lt;span class="dv"&gt;0&lt;/span&gt; conv&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; showStatus &lt;span class="dt"&gt;StatusWarning&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Agent not found for subcall: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; slug&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Update subcall progress&lt;/span&gt;&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleSubcallProgress ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EventM&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleSubcallProgress subcallId sess &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    coreRef &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; use tuiCore&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    liftIO &lt;span class="op"&gt;$&lt;/span&gt; atomically &lt;span class="op"&gt;$&lt;/span&gt; modifyTVar coreRef &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;c &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        c { coreConversations &lt;span class="ot"&gt;=&lt;/span&gt; updateConversationSession subcallId sess (coreConversations c) }&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Mark subcall completed&lt;/span&gt;&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleSubcallCompleted ::&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EventM&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleSubcallCompleted subcallId _result &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    updateConversationStatus subcallId &lt;span class="dt"&gt;ConversationStatus_WaitingForInput&lt;/span&gt;&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    showStatus &lt;span class="dt"&gt;StatusInfo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Subcall completed&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="attachment-event-handling"&gt;Attachment Event Handling&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Handle Ctrl+F for file attachment&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;VtyEvent&lt;/span&gt; (&lt;span class="dt"&gt;Vty.EvKey&lt;/span&gt; (&lt;span class="dt"&gt;Vty.KChar&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;f&amp;#39;&lt;/span&gt;) [&lt;span class="dt"&gt;Vty.MCtrl&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    resetQuitConfirmation&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    openFilePathDialog&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Handle Ctrl+Shift+F to clear all attachments&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;VtyEvent&lt;/span&gt; (&lt;span class="dt"&gt;Vty.EvKey&lt;/span&gt; (&lt;span class="dt"&gt;Vty.KChar&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;F&amp;#39;&lt;/span&gt;) [&lt;span class="dt"&gt;Vty.MCtrl&lt;/span&gt;, &lt;span class="dt"&gt;Vty.MShift&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    resetQuitConfirmation&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    handleClearAllAttachments&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Handle clipboard paste&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;VtyEvent&lt;/span&gt; (&lt;span class="dt"&gt;Vty.EvKey&lt;/span&gt; (&lt;span class="dt"&gt;Vty.KChar&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;v&amp;#39;&lt;/span&gt;) [&lt;span class="dt"&gt;Vty.MCtrl&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    resetQuitConfirmation&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    handleClipboardPaste tracer&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="clipboard-paste-handler"&gt;Clipboard Paste Handler&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleClipboardPaste ::&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EventM&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleClipboardPaste _tracer &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    hasSupport &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; liftIO hasClipboardSupport&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;if&lt;/span&gt; &lt;span class="fu"&gt;not&lt;/span&gt; hasSupport&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;then&lt;/span&gt; showStatus &lt;span class="dt"&gt;StatusError&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Clipboard not available - install xclip, wl-clipboard, or pbpaste&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            mContent &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; liftIO detectClipboardContent&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;case&lt;/span&gt; mContent &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    showStatus &lt;span class="dt"&gt;StatusWarning&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Clipboard is empty or inaccessible&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="dt"&gt;Just&lt;/span&gt; content &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    action &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class="op"&gt;$&lt;/span&gt; analyzeContent content&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                    &lt;span class="kw"&gt;case&lt;/span&gt; action &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                        &lt;span class="dt"&gt;IgnoreContent&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            showStatus &lt;span class="dt"&gt;StatusWarning&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;No attachable content in clipboard&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                        &lt;span class="dt"&gt;PasteAsText&lt;/span&gt; text &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            editorContents &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; use (tuiUI &lt;span class="op"&gt;.&lt;/span&gt; messageEditor &lt;span class="op"&gt;.&lt;/span&gt; editContentsL)&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            &lt;span class="kw"&gt;let&lt;/span&gt; newContents &lt;span class="ot"&gt;=&lt;/span&gt; TextZipper.insertMany text editorContents&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            tuiUI &lt;span class="op"&gt;.&lt;/span&gt; messageEditor &lt;span class="op"&gt;.&lt;/span&gt; editContentsL &lt;span class="op"&gt;.=&lt;/span&gt; newContents&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            showStatus &lt;span class="dt"&gt;StatusInfo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Text pasted from clipboard&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                        &lt;span class="dt"&gt;AttachAsMedia&lt;/span&gt; attachment &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            mConv &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getFocusedConversation&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            &lt;span class="kw"&gt;case&lt;/span&gt; mConv &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; showStatus &lt;span class="dt"&gt;StatusError&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;No conversation selected&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                &lt;span class="dt"&gt;Just&lt;/span&gt; conv &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                    &lt;span class="kw"&gt;let&lt;/span&gt; convId &lt;span class="ot"&gt;=&lt;/span&gt; conversationId conv&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                    tuiUI &lt;span class="op"&gt;.&lt;/span&gt; attachedFiles &lt;span class="op"&gt;%=&lt;/span&gt; Map.insertWith (&lt;span class="op"&gt;\&lt;/span&gt;new old &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; old &lt;span class="op"&gt;++&lt;/span&gt; new) convId [attachment]&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                    &lt;span class="kw"&gt;let&lt;/span&gt; filename &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;maybe&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;unnamed&amp;quot;&lt;/span&gt; &lt;span class="fu"&gt;id&lt;/span&gt; attachment&lt;span class="op"&gt;.&lt;/span&gt;mediaFilename&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                    showStatus &lt;span class="dt"&gt;StatusInfo&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Attached from clipboard: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; filename&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                        &lt;span class="dt"&gt;AttachMultipleFiles&lt;/span&gt; attachments &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            mConv &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getFocusedConversation&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                            &lt;span class="kw"&gt;case&lt;/span&gt; mConv &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; showStatus &lt;span class="dt"&gt;StatusError&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;No conversation selected&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                &lt;span class="dt"&gt;Just&lt;/span&gt; conv &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                    &lt;span class="kw"&gt;let&lt;/span&gt; convId &lt;span class="ot"&gt;=&lt;/span&gt; conversationId conv&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                    tuiUI &lt;span class="op"&gt;.&lt;/span&gt; attachedFiles &lt;span class="op"&gt;%=&lt;/span&gt; Map.insertWith (&lt;span class="op"&gt;\&lt;/span&gt;new old &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; old &lt;span class="op"&gt;++&lt;/span&gt; new) convId attachments&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                                    showStatus &lt;span class="dt"&gt;StatusInfo&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Attached &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; Text.pack (&lt;span class="fu"&gt;show&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="fu"&gt;length&lt;/span&gt; attachments) &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; files from clipboard&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="turn-navigation"&gt;Turn Navigation&lt;/h3&gt;
&lt;p&gt;Turn navigation allows you to browse through conversation history turn-by-turn and fork new conversations from any point.&lt;/p&gt;
&lt;h4 id="entering-navigation-mode"&gt;Entering Navigation Mode&lt;/h4&gt;
&lt;p&gt;Press &lt;code&gt;Enter&lt;/code&gt; when focused on the Conversation view or Session view to enter turn navigation mode:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│ Conversation - Turn Navigation (3/8) [Enter:exit F:fork]    │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ -----------------------                                 │ │
│ │▶ &amp;lt; What is the best approach for...      ← SELECTED    │ │
│ │  + ...                                                  │ │
│ │                                                         │ │
│ │ -----------------------                                 │ │
│ │  &amp;lt; You could consider using...                          │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="navigation-controls"&gt;Navigation Controls&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Up&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Navigate to earlier turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Down&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Navigate to later turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;F&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Fork conversation at selected turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Exit navigation mode&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Esc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Exit navigation mode&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="forking-conversations"&gt;Forking Conversations&lt;/h4&gt;
&lt;p&gt;Forking creates a new conversation starting from the selected turn, preserving only the turns before it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Turn 0: User - &amp;quot;Hello!&amp;quot;
Turn 1: Assistant - &amp;quot;Hi there!&amp;quot;
Turn 2: User - &amp;quot;How do I...&amp;quot; ← Selected for fork
Turn 3: Assistant - &amp;quot;You can...&amp;quot;

Forking at Turn 2 creates new conversation with:
Turn 0: User - &amp;quot;Hello!&amp;quot;
Turn 1: Assistant - &amp;quot;Hi there!&amp;quot;
(New conversation starts here)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The original session remains untouched. The forked session has &lt;code&gt;forkedFromSessionId&lt;/code&gt; set to the original session’s ID.&lt;/p&gt;
&lt;h4 id="turn-navigation-types"&gt;Turn Navigation Types&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | State for turn-by-turn navigation&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;TurnNavigationState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TurnNavigationState&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; _navSession ::&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ The session being navigated&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _navSelectedTurnIndex ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Currently selected turn index (0-based)&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _navTotalTurns ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Total number of turns for display&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Widget name for turn navigation viewport&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;WidgetName&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TurnNavigationWidget&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ For viewport scrolling during turn navigation&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="message-queue-management"&gt;Message Queue Management&lt;/h3&gt;
&lt;p&gt;When a conversation is paused, you can manage queued messages - messages typed while the agent was processing.&lt;/p&gt;
&lt;h4 id="queue-management-ui"&gt;Queue Management UI&lt;/h4&gt;
&lt;p&gt;When paused with queued messages, the Chats tab shows a queue management panel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│ Message                                                      │
├─────────────────────────────────────────────────────────────┤
│ &amp;gt; User's typed message...                                   │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│ Queued Messages (2) - Ctrl+D: clear  Del: delete selected │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ▶ First queued message text...                          │ │
│ │   Second queued message that is longer...               │ │
│ └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Conversation                                                 │
│ ...existing conversation content...                          │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="queue-management-controls"&gt;Queue Management Controls&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+D&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Clear all queued messages&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Del&lt;/code&gt; / &lt;code&gt;Backspace&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Delete selected queued message&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Up&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Select previous message&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Down&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Select next message&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="activation"&gt;Activation&lt;/h4&gt;
&lt;p&gt;Queue management is only available when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The conversation status is &lt;code&gt;ConversationStatus_Paused&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;There are queued messages in the buffer
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To pause/unpause a conversation, press &lt;code&gt;Ctrl+E&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="queue-state"&gt;Queue State&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;UIState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UIState&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _uiBufferedMessages ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;]&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Copy of buffered messages from Core for UI rendering&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; _queuedMessagesFocus ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Index of currently selected queued message (Nothing = none selected)&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- The Core also maintains the source of truth&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Core&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Core&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; coreBufferedMessages ::&lt;/span&gt; &lt;span class="dt"&gt;TVar&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt; [&lt;span class="dt"&gt;Text&lt;/span&gt;])&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Buffered messages per conversation&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; corePausedConversations ::&lt;/span&gt; &lt;span class="dt"&gt;Set&lt;/span&gt; &lt;span class="dt"&gt;ConversationId&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ^ Set of paused conversation IDs&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="keyboard-shortcuts"&gt;Keyboard Shortcuts&lt;/h3&gt;
&lt;h4 id="navigation"&gt;Navigation&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Tab&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Cycle focus forward through widgets&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Shift+Tab&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Cycle focus backward through widgets&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+Z&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Toggle zoom mode for current widget&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="tabs"&gt;Tabs&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+[&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Switch to previous tab&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Switch to next tab&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="conversations"&gt;Conversations&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Start new conversation with selected agent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+C&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Continue restored session&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Meta+Enter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Send message&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+E&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Pause/unpause conversation&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="file-attachments-1"&gt;File Attachments&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+F&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Open file path input dialog&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+Shift+F&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Clear all attachments&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Del&lt;/code&gt; / &lt;code&gt;Backspace&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Remove selected attachment&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Up&lt;/code&gt; / &lt;code&gt;Down&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Select attachment (when focused)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="clipboard"&gt;Clipboard&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+V&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Paste from clipboard (images, files, text)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="turn-navigation-1"&gt;Turn Navigation&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Enter turn navigation mode (when on conversation)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Up/Down&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Navigate between turns (in navigation mode)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;F&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Fork conversation at selected turn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Enter/Esc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Exit turn navigation mode&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="queue-management-when-paused"&gt;Queue Management (when paused)&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+D&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Clear all queued messages&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Del&lt;/code&gt; / &lt;code&gt;Backspace&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Delete selected queued message&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Up/Down&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Select queued message&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="session-export"&gt;Session Export&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+P&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Export session to markdown file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;View session in external viewer (chronological)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+R&lt;/code&gt;&lt;/td&gt;&lt;td&gt;View session in external viewer (reverse)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="session-search-history-tab"&gt;Session Search (History Tab)&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Start search&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Next result&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Previous result&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Esc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Clear search&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h4 id="other"&gt;Other&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;F5&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Refresh tools for selected agent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Esc&lt;/code&gt;, &lt;code&gt;Ctrl+Q&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Quit application&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;h3 id="session-export-and-viewing"&gt;Session Export and Viewing&lt;/h3&gt;
&lt;p&gt;The TUI supports exporting and viewing session content in markdown format.&lt;/p&gt;
&lt;h4 id="export-to-markdown"&gt;Export to Markdown&lt;/h4&gt;
&lt;p&gt;Press &lt;code&gt;Ctrl+p&lt;/code&gt; to export the current session to a markdown file:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleDumpSessionToMarkdown ::&lt;/span&gt; &lt;span class="dt"&gt;EventM&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleDumpSessionToMarkdown &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    mSession &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; use (tuiCore &lt;span class="op"&gt;.&lt;/span&gt; coreSession)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    mConvId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getFocusedConversationId&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; (mSession, mConvId) &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        (&lt;span class="dt"&gt;Just&lt;/span&gt; session, &lt;span class="dt"&gt;Just&lt;/span&gt; (&lt;span class="dt"&gt;ConversationId&lt;/span&gt; cid)) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="kw"&gt;let&lt;/span&gt; markdown &lt;span class="ot"&gt;=&lt;/span&gt; formatSessionMarkdown &lt;span class="dt"&gt;Chronological&lt;/span&gt; session&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                fileName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;conv.&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt; cid &lt;span class="op"&gt;&amp;lt;.&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;md&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            liftIO &lt;span class="op"&gt;$&lt;/span&gt; TextIO.writeFile fileName markdown&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            showStatus &lt;span class="dt"&gt;StatusInfo&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Exported to &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; Text.pack fileName&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="view-with-external-viewer"&gt;View with External Viewer&lt;/h4&gt;
&lt;p&gt;The TUI can display session content using an external markdown viewer configured via the &lt;code&gt;AGENT_MD_VIEWER&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chronological Order (Oldest First):&lt;/strong&gt;
Press &lt;code&gt;Ctrl+t&lt;/code&gt; to view the session in chronological order (oldest messages first):&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;VtyEvent&lt;/span&gt; (&lt;span class="dt"&gt;Vty.EvKey&lt;/span&gt; (&lt;span class="dt"&gt;Vty.KChar&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;t&amp;#39;&lt;/span&gt;) [&lt;span class="dt"&gt;Vty.MCtrl&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    handleViewSessionWithExternalViewer &lt;span class="dt"&gt;Chronological&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Antichronological Order (Newest First):&lt;/strong&gt;
Press &lt;code&gt;Ctrl+r&lt;/code&gt; to view the session in reverse chronological order (newest messages first):&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;VtyEvent&lt;/span&gt; (&lt;span class="dt"&gt;Vty.EvKey&lt;/span&gt; (&lt;span class="dt"&gt;Vty.KChar&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;) [&lt;span class="dt"&gt;Vty.MCtrl&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    handleViewSessionWithExternalViewer &lt;span class="dt"&gt;Antichronological&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Set viewer (e.g., glow, bat, less)&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;export&lt;/span&gt; &lt;span class="va"&gt;AGENT_MD_VIEWER&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;glow -p&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Or use a pager&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;export&lt;/span&gt; &lt;span class="va"&gt;AGENT_MD_VIEWER&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;less -R&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# Then start TUI&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; tui &lt;span class="at"&gt;--agent-file&lt;/span&gt; agent.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="order-preference"&gt;Order Preference&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;OrderPreference&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Chronological&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Antichronological&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;formatSessionMarkdown ::&lt;/span&gt; &lt;span class="dt"&gt;OrderPreference&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Session&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text.Text&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;formatSessionMarkdown orderPref session &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; opts &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SessionPrintOptions&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            { &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , orderPreference &lt;span class="ot"&gt;=&lt;/span&gt; orderPref&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="kw"&gt;in&lt;/span&gt; formatSessionAsMarkdown opts session&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chronological (&lt;code&gt;Ctrl+t&lt;/code&gt;)&lt;/strong&gt;: Best for reviewing the full conversation from start to finish
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Antichronological (&lt;code&gt;Ctrl+r&lt;/code&gt;)&lt;/strong&gt;: Best when you care about recent changes and want to see the most recent messages first
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="session-search"&gt;Session Search&lt;/h3&gt;
&lt;p&gt;The History tab includes session search functionality for finding past conversations.&lt;/p&gt;
&lt;h4 id="search-interface"&gt;Search Interface&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│ Sessions                                [Search: database] │
│ ─────────────────────────────────────────────────────────  │
│  ▶ 2024-01-15 10:30 - database migration                  │
│    2024-01-14 15:20 - api design                          │
│  ▶ 2024-01-13 09:00 - database schema review              │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│ Session View                                                 │
│ ...selected session content...                              │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="search-features"&gt;Search Features&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Real-time filtering&lt;/strong&gt;: Sessions are filtered as you type
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full-text search&lt;/strong&gt;: Searches across session content
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Highlighting&lt;/strong&gt;: Matching terms are highlighted
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keyboard navigation&lt;/strong&gt;: &lt;code&gt;n&lt;/code&gt;/&lt;code&gt;N&lt;/code&gt; to jump between results
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="running-the-tui"&gt;Running the TUI&lt;/h3&gt;
&lt;h4 id="main-entry-point"&gt;Main Entry Point&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- TUI.Core&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;runTUI ::&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionStore&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;LoadedApiKeys&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;Props&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runTUI tracer store apiKeys propsList &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; config &lt;span class="ot"&gt;=&lt;/span&gt; fileSessionConfig store apiKeys&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    runTUIWithConfig tracer config propsList&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;runTUIWithConfig ::&lt;/span&gt; &lt;span class="dt"&gt;Tracer&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Trace&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionConfig&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;Props&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runTUIWithConfig tracer config props &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Load agent trees and create TuiAgents&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    trees &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;traverse&lt;/span&gt; loadAgentTree props&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; itrees &lt;span class="ot"&gt;=&lt;/span&gt; [tree &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Initialized&lt;/span&gt; tree &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; trees]&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create TUI agents from OS-native trees&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; tuiAgents &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; createTuiAgent itrees&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Load existing session files&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    loadedSessions &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; loadSessionFiles config&lt;span class="op"&gt;.&lt;/span&gt;sessionStore&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Collect tools from all agents&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    agentTools &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; collectAgentTools tuiAgents&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create event channel&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    evChan &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newBChan &lt;span class="dv"&gt;100&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create OS event queue for subcall visibility&lt;/span&gt;&lt;/span&gt;
&lt;span id="26"&gt;&lt;a href="#26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    osEventQueue &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newTQueueIO&lt;/span&gt;
&lt;span id="27"&gt;&lt;a href="#27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="28"&gt;&lt;a href="#28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Start the event bridge&lt;/span&gt;&lt;/span&gt;
&lt;span id="29"&gt;&lt;a href="#29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    startOSEventBridge osEventQueue evChan&lt;/span&gt;
&lt;span id="30"&gt;&lt;a href="#30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="31"&gt;&lt;a href="#31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create and initialize the OS World&lt;/span&gt;&lt;/span&gt;
&lt;span id="32"&gt;&lt;a href="#32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    world &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; atomically initWorld&lt;/span&gt;
&lt;span id="33"&gt;&lt;a href="#33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="34"&gt;&lt;a href="#34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create core state with World and EventQueue&lt;/span&gt;&lt;/span&gt;
&lt;span id="35"&gt;&lt;a href="#35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    core0 &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initCore (&lt;span class="dt"&gt;Just&lt;/span&gt; world) (&lt;span class="dt"&gt;Just&lt;/span&gt; osEventQueue)&lt;/span&gt;
&lt;span id="36"&gt;&lt;a href="#36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    coreTVar &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; newTVarIO core0&lt;/span&gt;
&lt;span id="37"&gt;&lt;a href="#37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="38"&gt;&lt;a href="#38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create UI state&lt;/span&gt;&lt;/span&gt;
&lt;span id="39"&gt;&lt;a href="#39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; ui0 &lt;span class="ot"&gt;=&lt;/span&gt; (initUIState defaultHelpContent tuiAgents [s &lt;span class="op"&gt;|&lt;/span&gt; (_, &lt;span class="dt"&gt;Just&lt;/span&gt; s) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; loadedSessions])&lt;/span&gt;
&lt;span id="40"&gt;&lt;a href="#40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                { _uiAgentTools &lt;span class="ot"&gt;=&lt;/span&gt; agentTools }&lt;/span&gt;
&lt;span id="41"&gt;&lt;a href="#41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="42"&gt;&lt;a href="#42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Create TUI state&lt;/span&gt;&lt;/span&gt;
&lt;span id="43"&gt;&lt;a href="#43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; st &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; coreTVar ui0 evChan config&lt;/span&gt;
&lt;span id="44"&gt;&lt;a href="#44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="45"&gt;&lt;a href="#45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Build and run the app&lt;/span&gt;&lt;/span&gt;
&lt;span id="46"&gt;&lt;a href="#46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; app &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;App&lt;/span&gt;&lt;/span&gt;
&lt;span id="47"&gt;&lt;a href="#47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            { appDraw &lt;span class="ot"&gt;=&lt;/span&gt; tui_appDraw&lt;/span&gt;
&lt;span id="48"&gt;&lt;a href="#48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , appChooseCursor &lt;span class="ot"&gt;=&lt;/span&gt; tui_appChooseCursor&lt;/span&gt;
&lt;span id="49"&gt;&lt;a href="#49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , appHandleEvent &lt;span class="ot"&gt;=&lt;/span&gt; tui_appHandleEvent tracer&lt;/span&gt;
&lt;span id="50"&gt;&lt;a href="#50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , appStartEvent &lt;span class="ot"&gt;=&lt;/span&gt; tui_appStartEvent&lt;/span&gt;
&lt;span id="51"&gt;&lt;a href="#51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            , appAttrMap &lt;span class="ot"&gt;=&lt;/span&gt; tui_appAttrMap&lt;/span&gt;
&lt;span id="52"&gt;&lt;a href="#52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id="53"&gt;&lt;a href="#53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="54"&gt;&lt;a href="#54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    void &lt;span class="op"&gt;$&lt;/span&gt; customMainWithDefaultVty (&lt;span class="dt"&gt;Just&lt;/span&gt; evChan) app st&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="screenshots-and-end-to-end-tests"&gt;Screenshots and end-to-end tests&lt;/h3&gt;
&lt;p&gt;The screenshots on this page are not taken by hand. The &lt;code&gt;agents-tui-e2e&lt;/code&gt;
test-suite runs the real &lt;code&gt;agents-exe tui&lt;/code&gt; in a pseudo-terminal with
&lt;a href="https://github.com/Tritlo/tuispec"&gt;tuispec&lt;/a&gt;, sends it keys, and compares the
screen with a baseline at the end of each step. The model is a fake
OpenAI-compatible endpoint the suite serves itself, with fixed answers, and
&lt;code&gt;HOME&lt;/code&gt; is a scratch directory: no API key, no network, none of your own
configuration.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Scenario&lt;/th&gt;&lt;th&gt;Keys&lt;/th&gt;&lt;th&gt;Snapshots&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;launch&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;td&gt;&lt;code&gt;agents-tab&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;chat&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Ctrl+N&lt;/code&gt;, &lt;code&gt;Ctrl+]&lt;/code&gt;, &lt;code&gt;Tab&lt;/code&gt; twice, a message, &lt;code&gt;Meta+Enter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;message-typed&lt;/code&gt;, &lt;code&gt;reply&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;pending&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Down&lt;/code&gt;, the same with an agent whose tool calls are deferred, then &lt;code&gt;Ctrl+Y&lt;/code&gt;, an answer, &lt;code&gt;Meta+Enter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;pending-panel&lt;/code&gt;, &lt;code&gt;pending-answered&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img src="/agents-exe/images/tui-reply.png" alt="A reply from the scripted model" /&gt;&lt;/p&gt;
&lt;p&gt;The suite is opt-in, behind the &lt;code&gt;tui-e2e&lt;/code&gt; cabal flag, so a plain &lt;code&gt;cabal test&lt;/code&gt;
neither builds tuispec nor needs a terminal:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# compare the screens with the baselines&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cabal&lt;/span&gt; test agents-tui-e2e &lt;span class="at"&gt;-ftui-e2e&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# accept the screens as the new baselines, after a deliberate UI change&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;TUISPEC_UPDATE_SNAPSHOTS&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;1 &lt;span class="ex"&gt;cabal&lt;/span&gt; test agents-tui-e2e &lt;span class="at"&gt;-ftui-e2e&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# the same, and render the screenshots again&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;TUISPEC_UPDATE_SNAPSHOTS&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;1 &lt;span class="va"&gt;AGENTS_TUI_E2E_PNG&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;1 &lt;span class="ex"&gt;cabal&lt;/span&gt; test agents-tui-e2e &lt;span class="at"&gt;-ftui-e2e&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Files, under &lt;code&gt;test/tui-snapshots/&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Path&lt;/th&gt;&lt;th&gt;Content&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;snapshots/&amp;lt;scenario&amp;gt;/&amp;lt;name&amp;gt;.ansi.txt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The baseline: what the terminal received, with session ids zeroed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;snapshots/&amp;lt;scenario&amp;gt;/&amp;lt;name&amp;gt;.txt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The same screen as plain text, to read a change in a diff&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;snapshots/&amp;lt;scenario&amp;gt;/&amp;lt;name&amp;gt;.meta.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The terminal size (100x30)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;png/&amp;lt;name&amp;gt;.png&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The screenshot, written only with &lt;code&gt;AGENTS_TUI_E2E_PNG&lt;/code&gt; set&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tests/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;What the last run captured, and a failure bundle per failed scenario; not tracked&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Two screens are equal when their cells are: characters and colours, at 100
columns by 30 rows. Session ids are random and the sidebar shows them, so they
are zeroed before comparing.&lt;/p&gt;
&lt;p&gt;The PNGs are drawn by &lt;code&gt;test/tui-e2e/render_png.py&lt;/code&gt; from the cells of the
baseline (characters and colours), the way a terminal would: on the grid of
the font’s advance, with the box-drawing characters as lines running from
edge to edge of their cell, so that borders are continuous. It needs &lt;code&gt;python3&lt;/code&gt;
with Pillow and a monospace TTF: DejaVu Sans Mono or Liberation Mono where
distributions install them, or the file &lt;code&gt;TUISPEC_FONT_PATH&lt;/code&gt; names. A glyph
that font lacks (the status icons of the conversation list: &lt;code&gt;⧗&lt;/code&gt;, &lt;code&gt;⏸&lt;/code&gt;) is taken
from Noto Sans Symbols 2, Noto Sans Math or DejaVu Sans when installed
(&lt;code&gt;fonts-noto-core&lt;/code&gt; on Debian and Ubuntu), and is the font’s missing-glyph box
otherwise. The comparison itself needs none of this. Linux only: tuispec
drives a PTY.&lt;/p&gt;
&lt;p&gt;The website shows the same files: &lt;code&gt;website/scripts/sync-repo-docs.sh&lt;/code&gt; copies
them into the site, so rendering them again and publishing is all it takes to
refresh the screenshots there.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AGENTS_EXE&lt;/code&gt; selects another binary than the one cabal just built. The
scenarios are in &lt;code&gt;test/tui-e2e/Main.hs&lt;/code&gt;; tuispec also has a JSON-RPC server
(&lt;code&gt;tuispec server&lt;/code&gt;) for driving the TUI from another program.&lt;/p&gt;
&lt;h3 id="styling"&gt;Styling&lt;/h3&gt;
&lt;h4 id="attributes"&gt;Attributes&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;tui_appAttrMap ::&lt;/span&gt; &lt;span class="dt"&gt;TuiState&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;AttrMap&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;tui_appAttrMap _ &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    attrMap Vty.defAttr&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ (headerAttr, fg white &lt;span class="ot"&gt;`on`&lt;/span&gt; blue)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (activeTabAttr, fg black &lt;span class="ot"&gt;`on`&lt;/span&gt; brightWhite &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; bold)&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (inactiveTabAttr, fg white &lt;span class="ot"&gt;`on`&lt;/span&gt; blue)&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (userAttr, fg cyan)&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (agentAttr, fg green)&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (toolAttr, fg yellow)&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (toolSuccessAttr, fg green)&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (toolErrorAttr, fg red)&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (systemAttr, fg magenta)&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (inputAttr, fg white)&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (queuedMessageAttr, fg yellow)&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (queuedMessageSelectedAttr, bg blue &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; bold)&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (selectedTurnAttr, bg blue &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; bold)&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (attachmentAttr, fg cyan)&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (attachmentSelectedAttr, bg blue &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; bold)&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (attachmentSizeAttr, fg white &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; dim)&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , &lt;span class="co"&gt;-- Subcall conversation attributes&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          (subcallAttr, fg white &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; dim)&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (subcallSelectedAttr, fg black &lt;span class="ot"&gt;`on`&lt;/span&gt; brightWhite &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; bold)&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (treeBranchAttr, fg white &lt;span class="ot"&gt;`withStyle`&lt;/span&gt; dim)&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , (rootConversationAttr, defAttr)&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="status-bar"&gt;Status Bar&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;render_statusBar ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;StatusMessage&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Widget&lt;/span&gt; &lt;span class="dt"&gt;N&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;render_statusBar &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; emptyWidget&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;render_statusBar (&lt;span class="dt"&gt;Just&lt;/span&gt; msg) &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    withAttr (statusAttr msg&lt;span class="op"&gt;.&lt;/span&gt;statusSeverity) &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        txt &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; statusText msg&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;StatusSeverity&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;StatusInfo&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StatusWarning&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;StatusError&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="best-practices"&gt;Best Practices&lt;/h3&gt;
&lt;h4 id="performance"&gt;Performance&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Limit scrollback&lt;/strong&gt;: Keep only last N messages in memory
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lazy rendering&lt;/strong&gt;: Don’t render off-screen content
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate limiting&lt;/strong&gt;: Throttle UI updates during streaming
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="user-experience"&gt;User Experience&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Visual feedback&lt;/strong&gt;: Show typing indicators and tool calls
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error handling&lt;/strong&gt;: Display errors without crashing
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Help text&lt;/strong&gt;: Always show keyboard shortcuts
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tab organization&lt;/strong&gt;: Group related functionality into logical tabs
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pause before queue management&lt;/strong&gt;: Queue management only works when paused to prevent accidental modifications
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="multi-agent-ui"&gt;Multi-Agent UI&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Clear indicators&lt;/strong&gt;: Show which agent is active
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Separate contexts&lt;/strong&gt;: Each agent maintains its own conversation
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy switching&lt;/strong&gt;: Tab between agents quickly
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subcall visibility&lt;/strong&gt;: Show nested agent calls with visual hierarchy
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="conversation-forking"&gt;Conversation Forking&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Non-destructive&lt;/strong&gt;: Original session always preserved
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear lineage&lt;/strong&gt;: Forked sessions track their origin
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent selection&lt;/strong&gt;: Current agent selection used for fork
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Navigation mode&lt;/strong&gt;: Enter navigation to review before forking
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="file-attachments-2"&gt;File Attachments&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Size limits&lt;/strong&gt;: Warn users about large files
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MIME detection&lt;/strong&gt;: Automatic type detection from extensions
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual feedback&lt;/strong&gt;: Show attachment count in UI
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Temporary cleanup&lt;/strong&gt;: Clipboard images are temporary files
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="clipboard-integration-1"&gt;Clipboard Integration&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Graceful degradation&lt;/strong&gt;: Handle missing clipboard tools gracefully
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Validate file paths before attachment
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Size limits&lt;/strong&gt;: Prevent memory issues with large clipboard content
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platform detection&lt;/strong&gt;: Auto-detect best clipboard backend
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="subcall-visibility"&gt;Subcall Visibility&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tree rendering&lt;/strong&gt;: Show parent-child relationships clearly
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual distinction&lt;/strong&gt;: Use different attributes for subcalls vs root conversations
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Event bridging&lt;/strong&gt;: Convert OS events to AppEvents for Brick integration
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orphan handling&lt;/strong&gt;: Handle async race conditions where child arrives before parent
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nesting depth&lt;/strong&gt;: Track and display recursion depth
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="customization"&gt;Customization&lt;/h3&gt;
&lt;h4 id="custom-event-handlers"&gt;Custom Event Handlers&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;customHandleEvent ::&lt;/span&gt; &lt;span class="dt"&gt;TUIState&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;BrickEvent&lt;/span&gt; () &lt;span class="dt"&gt;CustomEvent&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EventM&lt;/span&gt; () (&lt;span class="dt"&gt;Next&lt;/span&gt; &lt;span class="dt"&gt;TUIState&lt;/span&gt;)&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;customHandleEvent state ev &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; ev &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- Add custom shortcuts&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;VtyEvent&lt;/span&gt; (&lt;span class="dt"&gt;EvKey&lt;/span&gt; (&lt;span class="dt"&gt;KChar&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;s&amp;#39;&lt;/span&gt;) [&lt;span class="dt"&gt;MCtrl&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        liftIO &lt;span class="op"&gt;$&lt;/span&gt; saveSession state&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        continue &lt;span class="op"&gt;$&lt;/span&gt; state { status &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Ready&lt;/span&gt; }&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;VtyEvent&lt;/span&gt; (&lt;span class="dt"&gt;EvKey&lt;/span&gt; (&lt;span class="dt"&gt;KChar&lt;/span&gt; &lt;span class="ch"&gt;&amp;#39;l&amp;#39;&lt;/span&gt;) [&lt;span class="dt"&gt;MCtrl&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        newState &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class="op"&gt;$&lt;/span&gt; loadSession state&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        continue newState&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; handleEvent state ev  &lt;span class="co"&gt;-- Fall through to default&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4 id="custom-widgets"&gt;Custom Widgets&lt;/h4&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;customProgressBar ::&lt;/span&gt; &lt;span class="dt"&gt;Float&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Widget&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;customProgressBar progress &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; width &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;20&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        filled &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;round&lt;/span&gt; (progress &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="fu"&gt;fromIntegral&lt;/span&gt; width)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        bar &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;replicate&lt;/span&gt; filled &lt;span class="ch"&gt;&amp;#39;█&amp;#39;&lt;/span&gt; &lt;span class="op"&gt;++&lt;/span&gt; &lt;span class="fu"&gt;replicate&lt;/span&gt; (width &lt;span class="op"&gt;-&lt;/span&gt; filled) &lt;span class="ch"&gt;&amp;#39;░&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;in&lt;/span&gt; withAttr progressAttr &lt;span class="op"&gt;$&lt;/span&gt; str &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;[&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;++&lt;/span&gt; bar &lt;span class="op"&gt;++&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;]&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 id="related-modules"&gt;Related Modules&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Module&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.TUI.Core&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Main TUI application&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.TUI.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;TUI state and types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.TUI.Render&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Rendering functions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.TUI.Event&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Event handling&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.TUI.Clipboard&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Clipboard and drag-and-drop support&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.Media.Types&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Media attachment types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.SessionPrint&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Session formatting&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.OS.Events&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OS event types for subcall visibility&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;System.Agents.AgentTree.OneShotTool&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Subcall execution&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-tui.html" rel="alternate"/><summary type="text">The Terminal UI provides an interactive, real-time interface for agent conversations with support for multiple agents, streaming responses, visual feedback, file attachments, clipboard integration, subcall conversation visibility, and a tab</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-agents-server.html</id><title type="text">agents-server: agents over HTTP</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/agents-server.md"&gt;&lt;code&gt;documentation/agents-server.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="agents-server-agents-over-http"&gt;agents-server: agents over HTTP&lt;/h2&gt;
&lt;p&gt;&lt;img src="/agents-exe/gen/images/server-overview.dot.png" alt="The standalone server: clients reach one session runner through the HTTP API." /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;agents-server&lt;/code&gt; runs agents as a long-lived HTTP service. Sessions live in a
SQLite database rather than in files, so a web application can start
conversations, follow them live, complete deferred tool calls from its own
workers, and pick sessions up again after a restart.&lt;/p&gt;
&lt;p&gt;It uses the same agent files as &lt;code&gt;agents-exe&lt;/code&gt;, and the same durable-session
machinery as the &lt;code&gt;session&lt;/code&gt; CLI commands (see
&lt;a href="/agents-exe/docs-durable-workflows-howto.html"&gt;durable-workflows-howto.md&lt;/a&gt;): an agent can pause on
deferred tool calls, and the server resumes it when the results arrive.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Authentication is off by default.&lt;/strong&gt; Without &lt;code&gt;--auth-tokens&lt;/code&gt;, anyone who
can reach the server can run its agents, with its API keys. It binds to
&lt;code&gt;127.0.0.1&lt;/code&gt; by default. See &lt;a href="#authentication"&gt;Authentication&lt;/a&gt; before exposing
it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3 id="running-the-server"&gt;Running the server&lt;/h3&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cabal&lt;/span&gt; build agents-server&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cabal&lt;/span&gt; run agents-server &lt;span class="at"&gt;--&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./weather.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--api-keys&lt;/span&gt; ./secrets/keys.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--db&lt;/span&gt; ./agents-server.db &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--port&lt;/span&gt; 8080&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Flag&lt;/th&gt;&lt;th&gt;Default&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--agent-file FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(required)&lt;/td&gt;&lt;td&gt;A root agent file. Repeat it to serve several agents; each is addressed by its &lt;code&gt;slug&lt;/code&gt;, which must be unique.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--api-keys FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(required)&lt;/td&gt;&lt;td&gt;The API keys file, as for &lt;code&gt;agents-exe&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--db FILE\|URL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;agents-server.db&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Where sessions and continuation tokens live: a SQLite file, or a &lt;code&gt;postgresql://&lt;/code&gt; URL (see [Postgres](#postgres)). Created or migrated on start.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--bind HOST&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Address to listen on.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--port PORT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;8080&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Port to listen on.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--live-session-ttl SECONDS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;900&lt;/code&gt;&lt;/td&gt;&lt;td&gt;How long an idle session keeps its in-memory state (including background tool calls) before it is dropped. It is reloaded from the database on next use.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--shutdown-grace SECONDS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;&lt;td&gt;How long open requests get to finish on shutdown.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--auth-tokens FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Bearer tokens and their owners. See [Authentication](#authentication).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--admin-owners OWNER,…&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Owners allowed to store and delete agents over the API. Needs &lt;code&gt;--auth-tokens&lt;/code&gt;. See [Storing agents](#storing-agents).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--stream-tokens&lt;/code&gt;&lt;/td&gt;&lt;td&gt;off&lt;/td&gt;&lt;td&gt;Stream LLM answers: the events stream gets &lt;code&gt;text.delta&lt;/code&gt; events as the text arrives. See [Streaming answers](#streaming-answers).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--no-ui&lt;/code&gt;&lt;/td&gt;&lt;td&gt;off&lt;/td&gt;&lt;td&gt;Do not serve the chat page at &lt;code&gt;/&lt;/code&gt;. See [Finding your way around](#finding-your-way-around).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--cors-origin ORIGIN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Allow this origin to call the server cross-origin (a browser page on another host or port). Repeatable, or &lt;code&gt;*&lt;/code&gt; for any origin — refused at startup together with &lt;code&gt;--auth-tokens&lt;/code&gt;. See [Authentication](#authentication).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--socket PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Also listen on this Unix domain socket, in addition to &lt;code&gt;--bind&lt;/code&gt;/&lt;code&gt;--port&lt;/code&gt;. A stale file at the path is removed at start; the socket is created with mode &lt;code&gt;0600&lt;/code&gt;. Requests over it carry no &lt;code&gt;Origin&lt;/code&gt; header and need no bearer token beyond what &lt;code&gt;--auth-tokens&lt;/code&gt; imposes elsewhere: the socket, and who can reach it on the filesystem, is the trust boundary. Closed and unlinked on shutdown.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--owner-api-keys OWNER=FILE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;This owner's sessions call the LLM with the keys in &lt;code&gt;FILE&lt;/code&gt; instead of the ones in &lt;code&gt;--api-keys&lt;/code&gt;. Repeatable. Needs &lt;code&gt;--auth-tokens&lt;/code&gt;. See [API keys per owner](#api-keys-per-owner).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--isolate-tools docker:IMAGE\|process:PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Run bash and MCP tool calls outside the server process. See [Isolating tool calls](#isolating-tool-calls).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--set NAME=VALUE&lt;/code&gt;, &lt;code&gt;--set-json NAME=JSON&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Set a process-scope parameter value, shared by every session. Repeatable. See [Parameters](#parameters).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--pin NAME=VALUE&lt;/code&gt;, &lt;code&gt;--pin-json NAME=JSON&lt;/code&gt;&lt;/td&gt;&lt;td&gt;(none)&lt;/td&gt;&lt;td&gt;Like &lt;code&gt;--set&lt;/code&gt;, but sessions cannot override it. Repeatable. See [Parameters](#parameters).&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Sub-agents (&lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; calls) run as real sessions of their own:
the child is created, stored in the same database and linked to the calling
session as its parent (&lt;code&gt;smParent&lt;/code&gt; / &lt;code&gt;GET /v1/sessions?parent=&lt;/code&gt;), &lt;em&gt;before&lt;/em&gt;
the parent’s tool call returns — a client watching the parent’s &lt;code&gt;parent=&lt;/code&gt;
listing, or subscribing with &lt;code&gt;scope=owner&lt;/code&gt;/&lt;code&gt;scope=all&lt;/code&gt;, sees &lt;code&gt;session.created&lt;/code&gt;
for it right away, and the child’s own &lt;code&gt;session.updated&lt;/code&gt; events (its stream,
not the parent’s) show its progress live, the same as any other session.
The parent’s tool call waits for the child to stop and returns its final
answer as the tool result, same as before; cancelling the parent’s call
cancels the child (&lt;code&gt;cancelRun&lt;/code&gt;), and the child can also be cancelled,
inspected or subscribed to directly and independently through its own id.
&lt;code&gt;subcall.started&lt;/code&gt;/&lt;code&gt;subcall.completed&lt;/code&gt;/&lt;code&gt;subcall.failed&lt;/code&gt; (below) still appear
on the &lt;em&gt;parent’s&lt;/em&gt; stream for convenience, now carrying the child’s real
session id. A call with narrowing (&lt;code&gt;bindings&lt;/code&gt;/&lt;code&gt;with&lt;/code&gt;/&lt;code&gt;as&lt;/code&gt;) still runs
in-tool, inside the parent’s own call, with no session of its own — the
older behaviour, kept for that case until it is supported the same way.&lt;/p&gt;
&lt;h4 id="configuration"&gt;Configuration&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;agents-server&lt;/code&gt; itself only ever takes agent files from &lt;code&gt;--agent-file&lt;/code&gt;: it has
no config file of its own. &lt;code&gt;agents-exe serve&lt;/code&gt; is the same code (see
&lt;a href="#embedding-the-runner-in-your-own-program"&gt;Embedding the runner in your own program&lt;/a&gt;)
behind agents-exe’s own config loading: it reads &lt;code&gt;agents-exe.cfg.json&lt;/code&gt; and
resolves agent files the way the TUI and every other &lt;code&gt;agents-exe&lt;/code&gt; command do
(&lt;code&gt;agentsFiles&lt;/code&gt;, &lt;code&gt;agentsDirectories&lt;/code&gt;, the &lt;code&gt;~/.config/agents-exe/default&lt;/code&gt;
fallback, &lt;code&gt;--agent-file&lt;/code&gt;, &lt;code&gt;--agent SLUG&lt;/code&gt; to pick one agent by name), and
shares agents-exe’s global &lt;code&gt;--api-keys&lt;/code&gt;, &lt;code&gt;--set&lt;/code&gt;/&lt;code&gt;--pin&lt;/code&gt;/&lt;code&gt;--set-json&lt;/code&gt;/
&lt;code&gt;--pin-json&lt;/code&gt; and &lt;code&gt;--params-file&lt;/code&gt;. Its own flags are the rest of this table
(&lt;code&gt;--db&lt;/code&gt;, &lt;code&gt;--bind&lt;/code&gt;, &lt;code&gt;--port&lt;/code&gt;, &lt;code&gt;--live-session-ttl&lt;/code&gt;, &lt;code&gt;--shutdown-grace&lt;/code&gt;,
&lt;code&gt;--auth-tokens&lt;/code&gt;, &lt;code&gt;--stream-tokens&lt;/code&gt;, &lt;code&gt;--admin-owners&lt;/code&gt;, &lt;code&gt;--no-ui&lt;/code&gt;,
&lt;code&gt;--cors-origin&lt;/code&gt;, &lt;code&gt;--socket&lt;/code&gt;, &lt;code&gt;--owner-api-keys&lt;/code&gt;, &lt;code&gt;--isolate-tools&lt;/code&gt;); &lt;code&gt;--db&lt;/code&gt;
defaults next to the resolved sessions
directory instead of &lt;code&gt;./agents-server.db&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./weather.json serve &lt;span class="at"&gt;--port&lt;/span&gt; 8080&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# or, from a directory with an agents-exe.cfg.json:&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-exe&lt;/span&gt; serve &lt;span class="at"&gt;--port&lt;/span&gt; 8080&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;See &lt;a href="/agents-exe/docs-cli-commands.html#serve"&gt;cli-commands.md&lt;/a&gt; for the full flag list.&lt;/p&gt;
&lt;h4 id="finding-your-way-around"&gt;Finding your way around&lt;/h4&gt;
&lt;p&gt;The server describes itself, so a client that knows only its URL can start
using it:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Path&lt;/th&gt;&lt;th&gt;What it is&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A small chat page, for a person at this machine. Served on a loopback bind, or when &lt;code&gt;--auth-tokens&lt;/code&gt; is on; &lt;code&gt;--no-ui&lt;/code&gt; turns it off.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /openapi.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The whole API as an OpenAPI 3 document, generated from the routes.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /healthz&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Liveness and counters.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;None of the three needs a bearer token: they describe the server, not its
sessions or its agents.&lt;/p&gt;
&lt;p&gt;The OpenAPI document is the machine-readable reference, and it is generated
from the same servant types that route the requests, so it cannot drift from
the server. An agents-exe agent can use it directly as a toolbox:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;&amp;quot;openApiToolboxes&amp;quot;&lt;/span&gt;&lt;span class="er"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAPIServer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;SpecUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;http://127.0.0.1:8080/openapi.json&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The chat page is one self-contained HTML document with no build step and no
assets. It starts sessions, follows their event streams, offers a box to
complete deferred tool calls, and attaches files, so it doubles as a worked
example of the API. Its session list follows &lt;code&gt;GET /v1/events&lt;/code&gt; (see
&lt;a href="#following-every-session"&gt;Following every session&lt;/a&gt;), so sessions created,
deleted or changed by any other client (another tab, an attached TUI, a
script) show up without a reload.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attachments.&lt;/strong&gt; &lt;em&gt;Attach&lt;/em&gt; adds files to the next message, up to 20 MB in
total (the body limit is 32 MiB and base64 adds a third). They are sent as
the &lt;code&gt;media&lt;/code&gt; field described under
&lt;a href="#api-reference"&gt;API reference&lt;/a&gt;, and the agent’s model must accept them.&lt;/p&gt;
&lt;p&gt;A PDF is sent as a &lt;code&gt;file&lt;/code&gt; content part, text is inlined into the message,
and anything else is sent as an image. So images, PDFs and text files
(including CSV, JSON, YAML and Markdown) all work; audio and video depend
on the provider.&lt;/p&gt;
&lt;h4 id="an-agent-for-the-examples"&gt;An agent for the examples&lt;/h4&gt;
&lt;p&gt;The examples below use an agent that defers every tool call to an external
worker:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIAgentDescription&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;contents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;weather&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIv1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4o-mini&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;answers weather questions&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;You answer weather questions. Use get_weather.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;builtinToolboxes&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;mcpServers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;executionMode&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;asynchronous&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;toolCallPolicyConfig&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;defer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;weather service&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Agents without a &lt;code&gt;toolCallPolicyConfig&lt;/code&gt; run all their tools in the server
process and never wait on the outside world. The server always runs agents
in asynchronous mode.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="a-first-conversation"&gt;A first conversation&lt;/h3&gt;
&lt;p&gt;Ask a question and wait for the run to stop:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;curl&lt;/span&gt; &lt;span class="at"&gt;-s&lt;/span&gt; &lt;span class="at"&gt;-X&lt;/span&gt; POST &lt;span class="st"&gt;&amp;#39;localhost:8080/v1/sessions?wait=true&amp;#39;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="at"&gt;-d&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;agent&amp;quot;: &amp;quot;weather&amp;quot;, &amp;quot;prompt&amp;quot;: &amp;quot;Weather in Paris?&amp;quot;}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The LLM called &lt;code&gt;get_weather&lt;/code&gt;, which the policy defers, so the session is
waiting on the outside world (turns elided):&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;session_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;4ed40545-d192-4230-aed0-39cd09117123&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;weather&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;parent_session_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;owner&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;waiting_external&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;status_detail&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2026-09-19T07:31:55.703930717Z&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;updated_at&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2026-09-19T07:31:55.713658207Z&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;session&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;turns&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;pending&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tool_call_id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;017bb633-3306-4f95-8512-534427a4c030&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;continuation_token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;0dd070c1-eada-4669-9755-bb75a2783df1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;tool&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;get_weather&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="17"&gt;&lt;a href="#17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;disposition&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;defer&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;reason&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;weather service&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="18"&gt;&lt;a href="#18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;call&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="19"&gt;&lt;a href="#19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;call_1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="20"&gt;&lt;a href="#20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;function&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="21"&gt;&lt;a href="#21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;&amp;quot;function&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;get_weather&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arguments&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;{&lt;/span&gt;&lt;span class="ch"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="st"&gt;city&lt;/span&gt;&lt;span class="ch"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="st"&gt;: &lt;/span&gt;&lt;span class="ch"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="st"&gt;Paris&lt;/span&gt;&lt;span class="ch"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="st"&gt;}&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="22"&gt;&lt;a href="#22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="23"&gt;&lt;a href="#23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="24"&gt;&lt;a href="#24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="25"&gt;&lt;a href="#25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;A worker computes the result and posts it with the continuation token. The
session resumes on its own; with &lt;code&gt;wait=true&lt;/code&gt; the answer holds the LLM’s
final turn:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;curl&lt;/span&gt; &lt;span class="at"&gt;-s&lt;/span&gt; &lt;span class="at"&gt;-X&lt;/span&gt; POST &lt;span class="st"&gt;&amp;#39;localhost:8080/v1/continuations/0dd070c1-eada-4669-9755-bb75a2783df1?wait=true&amp;#39;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="at"&gt;-d&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;result&amp;quot;: &amp;quot;sunny, 24°C&amp;quot;}&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# 200, &amp;quot;status&amp;quot;: &amp;quot;idle&amp;quot;, &amp;quot;pending&amp;quot;: []&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Continue the conversation with another message:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;curl&lt;/span&gt; &lt;span class="at"&gt;-s&lt;/span&gt; &lt;span class="at"&gt;-X&lt;/span&gt; POST &lt;span class="st"&gt;&amp;#39;localhost:8080/v1/sessions/4ed40545-…/messages?wait=true&amp;#39;&lt;/span&gt; &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;     &lt;span class="at"&gt;-d&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&amp;quot;prompt&amp;quot;: &amp;quot;And tomorrow?&amp;quot;}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr /&gt;
&lt;h3 id="sessions-and-runs"&gt;Sessions and runs&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;session&lt;/strong&gt; is one conversation. A &lt;strong&gt;run&lt;/strong&gt; steps it in the background: it
calls the LLM, runs or defers tool calls, and stops when the LLM answers,
when only deferred calls remain, or after one step in &lt;code&gt;step&lt;/code&gt; mode. A session
has at most one run at a time.&lt;/p&gt;
&lt;p&gt;Each session has a &lt;code&gt;status&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Status&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;th&gt;What moves it on&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ready&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Can progress: a prompt or tool results are waiting for the LLM.&lt;/td&gt;&lt;td&gt;&lt;code&gt;resume&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;running&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A run is active.&lt;/td&gt;&lt;td&gt;Wait for it, or &lt;code&gt;cancel&lt;/code&gt; it.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;waiting_external&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Only deferred calls remain.&lt;/td&gt;&lt;td&gt;Post their results to &lt;code&gt;/v1/continuations/:token&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;idle&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The LLM answered.&lt;/td&gt;&lt;td&gt;Post a new message.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;paused&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Stopped by &lt;code&gt;pause&lt;/code&gt;.&lt;/td&gt;&lt;td&gt;&lt;code&gt;resume&lt;/code&gt;, or any mail if the agent's &lt;code&gt;resumeOnAnyMail&lt;/code&gt; option is set.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;failed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The last run failed; &lt;code&gt;status_detail&lt;/code&gt; says why.&lt;/td&gt;&lt;td&gt;&lt;code&gt;resume&lt;/code&gt; retries from the last stored version.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Every stored change increments the session’s &lt;code&gt;version&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="waiting-for-a-run"&gt;Waiting for a run&lt;/h4&gt;
&lt;p&gt;Endpoints that can start a run (create, messages, resume, continuations)
take two query parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wait=true|false&lt;/code&gt; (default &lt;code&gt;false&lt;/code&gt;). Without waiting, the server answers
as soon as the run has started. With &lt;code&gt;wait=true&lt;/code&gt;, it answers when the run
stops.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timeout=SECONDS&lt;/code&gt; (default &lt;code&gt;120&lt;/code&gt;, at most &lt;code&gt;600&lt;/code&gt;), used with &lt;code&gt;wait=true&lt;/code&gt;. When
it expires, the server answers with the current state (&lt;code&gt;status: &amp;quot;running&amp;quot;&lt;/code&gt;)
and the run carries on.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The answer is always the session as it is at that moment, including its
pending deferred calls. Creation answers &lt;code&gt;201&lt;/code&gt;. The other endpoints answer
&lt;code&gt;202&lt;/code&gt; while a run is still going and &lt;code&gt;200&lt;/code&gt; otherwise. A client that
disconnects while waiting does not cancel the run.&lt;/p&gt;
&lt;p&gt;How far a run goes is set in the body: &lt;code&gt;run&lt;/code&gt; on create and messages (&lt;code&gt;none&lt;/code&gt;,
&lt;code&gt;step&lt;/code&gt;, or &lt;code&gt;until_blocked&lt;/code&gt;, the default), &lt;code&gt;mode&lt;/code&gt; on resume (&lt;code&gt;step&lt;/code&gt; or
&lt;code&gt;until_blocked&lt;/code&gt;). With &lt;code&gt;run: &amp;quot;none&amp;quot;&lt;/code&gt;, the session is stored as &lt;code&gt;ready&lt;/code&gt; and
nothing runs until &lt;code&gt;resume&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="deferred-results-arriving-during-a-run"&gt;Deferred results arriving during a run&lt;/h4&gt;
&lt;p&gt;A result posted while a run is active is checked and queued, and the run
applies it before its next step. If the result makes the session able to
progress, a run about to stop keeps going instead. Posting with
&lt;code&gt;&amp;quot;resume&amp;quot;: false&lt;/code&gt; stores the result without starting a run; &lt;code&gt;resume&lt;/code&gt; later.
While a run is active the result is queued for it, and &lt;code&gt;resume&lt;/code&gt; is ignored:
the run applies it either way.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="mail"&gt;Mail&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;POST /v1/sessions/:id/mail&lt;/code&gt; generalizes the &lt;code&gt;interrupt&lt;/code&gt; flag on
&lt;code&gt;POST .../messages&lt;/code&gt;: any piece of mail, from a control instruction to a
message from another session, to a session that may not even be live in
this process (a stored, idle session still has its durable mailbox, and
gets one opened for it). Unlike &lt;code&gt;messages&lt;/code&gt;, this never refuses on a
session’s status: the mail just queues, folded into the session’s next
turn (or the current one, if a run is already going) the same way every
other mail is (see &lt;a href="#following-a-session-live"&gt;Following a session live&lt;/a&gt;
for the events a run produces along the way). A &lt;code&gt;paused&lt;/code&gt; session may wake
on it if the agent’s &lt;code&gt;resumeOnAnyMail&lt;/code&gt; option is set and the mail’s sender
is in its &lt;code&gt;wakeOn&lt;/code&gt; list (the same rule an ordinary message follows against
a paused session).&lt;/p&gt;
&lt;p&gt;The request body is &lt;code&gt;{body, priority?}&lt;/code&gt;. &lt;code&gt;priority&lt;/code&gt; is &lt;code&gt;&amp;quot;normal&amp;quot;&lt;/code&gt; (the
default) or &lt;code&gt;&amp;quot;interrupt&amp;quot;&lt;/code&gt;. &lt;code&gt;body&lt;/code&gt; is a &lt;code&gt;MailBody&lt;/code&gt;, tagged JSON:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;userMessage&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;query&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;are you there?&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;userMessage&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;query&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;look at this&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;media&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;mimeType&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;base64Data&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;agentMessage&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;status update&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;inReplyTo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;expectsReply&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;control&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;pause&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;control&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;resume&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;control&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;stopRun&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;control&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;cancelAllAttached&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;control&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;cancelCalls&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;toolCallIds&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;017bb633-…&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;toolCallFinished&lt;/code&gt;, &lt;code&gt;continuationResult&lt;/code&gt; and &lt;code&gt;watchedEvent&lt;/code&gt; are also valid
&lt;code&gt;MailBody&lt;/code&gt; tags (the async engine, &lt;code&gt;completeCall&lt;/code&gt;, and &lt;code&gt;watch-session&lt;/code&gt;
produce them respectively), but there is no reason to post one by hand over
this endpoint. &lt;code&gt;POST /v1/sessions/:id/mail&lt;/code&gt; answers &lt;code&gt;202&lt;/code&gt; with the mail’s
&lt;code&gt;Receipt&lt;/code&gt;: &lt;code&gt;{&amp;quot;id&amp;quot;: &amp;quot;&amp;lt;message id&amp;gt;&amp;quot;, &amp;quot;seq&amp;quot;: &amp;lt;int&amp;gt;, &amp;quot;duplicate&amp;quot;: false}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GET /v1/sessions/:id/mail?unread=true|false&lt;/code&gt; lists the session’s mail,
oldest first, as &lt;code&gt;{&amp;quot;mail&amp;quot;: [Envelope, …]}&lt;/code&gt;. &lt;code&gt;unread=true&lt;/code&gt; (default &lt;code&gt;false&lt;/code&gt;)
limits it to what is still unread past the session’s stored cursor – what
its next turn, or a run already going, has not folded in yet. An &lt;code&gt;Envelope&lt;/code&gt;
is:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2cdb9b15-…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;seq&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;from&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;owner&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;alice&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;priority&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;normal&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;hops&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;sentAt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2026-09-23T19:08:06Z&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;agentMessage&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;status update&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;inReplyTo&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;null&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;expectsReply&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;false&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;from&lt;/code&gt; (a &lt;code&gt;Sender&lt;/code&gt;) is one of &lt;code&gt;{&amp;quot;tag&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;owner&amp;quot;?}&lt;/code&gt; (a client’s own
mail, &lt;code&gt;owner&lt;/code&gt; set when the server authenticates callers – this is what
&lt;code&gt;POST .../mail&lt;/code&gt; always sends as), &lt;code&gt;{&amp;quot;tag&amp;quot;: &amp;quot;session&amp;quot;, &amp;quot;sessionId&amp;quot;, &amp;quot;agent&amp;quot;?}&lt;/code&gt;
(another session, e.g. &lt;code&gt;send-message&lt;/code&gt;), &lt;code&gt;{&amp;quot;tag&amp;quot;: &amp;quot;toolCall&amp;quot;, &amp;quot;toolCallId&amp;quot;}&lt;/code&gt;,
or &lt;code&gt;{&amp;quot;tag&amp;quot;: &amp;quot;system&amp;quot;, &amp;quot;source&amp;quot;}&lt;/code&gt; (the runner itself, e.g. &lt;code&gt;watch-session&lt;/code&gt;).&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="parameters"&gt;Parameters&lt;/h3&gt;
&lt;p&gt;An agent’s declared &lt;code&gt;parameters&lt;/code&gt; (see
&lt;a href="/agents-exe/docs-parameters-and-bindings.html"&gt;Parameters, Bindings &amp;amp; Narrowing Sub-Agents&lt;/a&gt;)
can be bound straight into tool arguments the model never sees — a tenant
id, an API token, anything the caller of this session knows and the model
does not need to. &lt;code&gt;agents-server&lt;/code&gt; is where a &lt;code&gt;session&lt;/code&gt;- or &lt;code&gt;message&lt;/code&gt;-scope
parameter actually varies per caller: give it a value in the same &lt;code&gt;params&lt;/code&gt;
object every request that can start a run accepts:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;curl -sS localhost:8080/v1/sessions \
    -d '{&amp;quot;agent&amp;quot;: &amp;quot;invoices-agent&amp;quot;, &amp;quot;prompt&amp;quot;: &amp;quot;how many invoices are overdue?&amp;quot;, &amp;quot;params&amp;quot;: {&amp;quot;tenant&amp;quot;: &amp;quot;acme-corp&amp;quot;}}'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;params&lt;/code&gt; is an object of parameter name to value; a &lt;code&gt;null&lt;/code&gt; value clears a
previously-set session-scope value. A &lt;code&gt;session&lt;/code&gt;-scope value is kept for the
life of the session: a non-secret one is stored with the session and comes
back after a restart or an idle eviction; a secret one lives only in this
process’s memory, so a client must resupply it after either, or the next
run that needs it fails with &lt;code&gt;params_required&lt;/code&gt;. A &lt;code&gt;message&lt;/code&gt;-scope value applies to that one run
only and is never stored. A secret value is never returned by any endpoint:
&lt;code&gt;GET /v1/sessions/:id&lt;/code&gt;’s own &lt;code&gt;params&lt;/code&gt; field only ever holds the
non-secret session-scope values (the current, actual values); &lt;code&gt;GET /v1/agents/:slug&lt;/code&gt;’s &lt;code&gt;parameters&lt;/code&gt; field describes the agent’s own
declarations generically — one entry per parameter, with &lt;code&gt;bound&lt;/code&gt; and
&lt;code&gt;pinned&lt;/code&gt; flags, never a value.&lt;/p&gt;
&lt;p&gt;A request whose &lt;code&gt;params&lt;/code&gt; do not check out is refused before anything runs:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Error&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;422 unknown_params&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A name the agent does not declare.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;403 forbidden_params&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A &lt;code&gt;process&lt;/code&gt;-scope parameter, or one pinned with &lt;code&gt;--pin&lt;/code&gt;/&lt;code&gt;--pin-json&lt;/code&gt; at server start: only the operator may set it.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;422 invalid_params&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A &lt;code&gt;secret&lt;/code&gt; parameter's value was not given as a string.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;422 params_required&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A required parameter has no value once this request's &lt;code&gt;params&lt;/code&gt; are applied — process value or default, session value, and message value combined. On a message or resume to an existing session (whose values lapsed, e.g. after a restart) the status is &lt;code&gt;409&lt;/code&gt; instead: supply them with &lt;code&gt;PUT /v1/sessions/:id/params&lt;/code&gt; or in the request's &lt;code&gt;params&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;--set NAME=VALUE&lt;/code&gt;, &lt;code&gt;--set-json NAME=JSON&lt;/code&gt;, &lt;code&gt;--pin NAME=VALUE&lt;/code&gt;, and
&lt;code&gt;--pin-json NAME=JSON&lt;/code&gt; on &lt;code&gt;agents-server&lt;/code&gt; itself set process-scope values
every session shares, the same flags and meaning as &lt;code&gt;agents-exe&lt;/code&gt; (except
&lt;code&gt;--params-file&lt;/code&gt;, which only &lt;code&gt;agents-exe&lt;/code&gt; has).&lt;/p&gt;
&lt;h4 id="whenunbound-expose-and-live-sessions"&gt;&lt;code&gt;whenUnbound: &amp;quot;expose&amp;quot;&lt;/code&gt; and live sessions&lt;/h4&gt;
&lt;p&gt;A binding’s argument marked &lt;code&gt;whenUnbound: &amp;quot;expose&amp;quot;&lt;/code&gt; reappears in a tool’s
schema for as long as its parameter is unbound &lt;em&gt;for that session&lt;/em&gt; — the
tool list a session sees changes the moment &lt;code&gt;params&lt;/code&gt; sets or clears the
value, with no agent rebuild or restart.&lt;/p&gt;
&lt;h4 id="setting-parameters-over-mcp"&gt;Setting parameters over MCP&lt;/h4&gt;
&lt;p&gt;A &lt;code&gt;tools/call&lt;/code&gt; sets parameters two ways, both string-keyed to the JSON
values requests use, and both scoped to that one call, like a
message-scope value: &lt;code&gt;Agents-Param-&amp;lt;name&amp;gt;: &amp;lt;value&amp;gt;&lt;/code&gt; request headers (every
value is a string), and/or &lt;code&gt;_meta.&amp;quot;agents-exe/params&amp;quot;&lt;/code&gt; on the call itself
(any JSON value; overrides a same-named header). Both go through the same
validation table above.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="following-a-session-live"&gt;Following a session live&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;GET /v1/sessions/:id/events&lt;/code&gt; is a
&lt;a href="https://html.spec.whatwg.org/multipage/server-sent-events.html"&gt;server-sent events&lt;/a&gt;
stream. Each frame carries an &lt;code&gt;id:&lt;/code&gt; line (the event’s sequence number, unique
and increasing per server) alongside the usual &lt;code&gt;event:&lt;/code&gt;/&lt;code&gt;data:&lt;/code&gt;. It first
sends a &lt;code&gt;snapshot&lt;/code&gt; of the session’s metadata (unless it is a replay – see
&lt;a href="#reconnecting"&gt;Reconnecting&lt;/a&gt; below), then one event per change:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Event&lt;/th&gt;&lt;th&gt;Data&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;snapshot&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Session metadata (the object above without &lt;code&gt;session&lt;/code&gt; and &lt;code&gt;pending&lt;/code&gt;).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;session.updated&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Session metadata after a stored change, plus &lt;code&gt;head_turn&lt;/code&gt;: the newest turn.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;run.started&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, mode}&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;calls.deferred&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, calls}&lt;/code&gt;: the run stopped on these deferred calls.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;run.stopped&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, status}&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;session.failed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, message}&lt;/code&gt;, followed by &lt;code&gt;run.stopped&lt;/code&gt; with status &lt;code&gt;failed&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;text.delta&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, text}&lt;/code&gt;: the next piece of the LLM's answer, with &lt;code&gt;--stream-tokens&lt;/code&gt; only.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tool.started&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, tool_call_id, tool}&lt;/code&gt;: a tool call still attached to the session (not deferred) started running.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tool.completed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, tool_call_id, tool, succeeded}&lt;/code&gt;: that call reached a final state. &lt;code&gt;succeeded&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt; for a failed or cancelled call. A call that both starts and finishes within one step is not reported (informational only; the stored session remains the source of truth).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tool.progressed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, tool_call_id, tool, phase, payload?, error?, provider_call_id?, at}&lt;/code&gt;: a background (async-engine) tool call's lifecycle -- &lt;code&gt;phase&lt;/code&gt; is one of &lt;code&gt;started&lt;/code&gt;, &lt;code&gt;progressed&lt;/code&gt; (with a &lt;code&gt;payload&lt;/code&gt;), &lt;code&gt;completed&lt;/code&gt;, &lt;code&gt;failed&lt;/code&gt; (with an &lt;code&gt;error&lt;/code&gt;), &lt;code&gt;cancelled&lt;/code&gt;. Reported for every phase, not only intermediate progress; complements &lt;code&gt;tool.started&lt;/code&gt;/&lt;code&gt;tool.completed&lt;/code&gt; above, which are derived separately by diffing the stored session.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;subcall.started&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, parent_session_id, child_session_id, agent, depth}&lt;/code&gt;: a &lt;code&gt;prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; call started a sub-agent run. &lt;code&gt;session_id&lt;/code&gt; (the event's own, top-level field) is the &lt;em&gt;parent&lt;/em&gt; -- the session actually running the call, whose stream this shows up on -- and &lt;code&gt;parent_session_id&lt;/code&gt; repeats it explicitly alongside &lt;code&gt;child_session_id&lt;/code&gt;, the sub-agent's own id. When the call runs as a real session (the common case), &lt;code&gt;child_session_id&lt;/code&gt; is a session a client can &lt;code&gt;GetSession&lt;/code&gt;/subscribe to on its own, already created (&lt;code&gt;session.created&lt;/code&gt; fired) by the time this event is reported; a still-narrowed call (&lt;code&gt;bindings&lt;/code&gt;/&lt;code&gt;with&lt;/code&gt;/&lt;code&gt;as&lt;/code&gt;) runs in-tool instead, and &lt;code&gt;child_session_id&lt;/code&gt; there is just the id generated for it, not a session of its own.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;subcall.completed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, child_session_id, result?}&lt;/code&gt;: that sub-agent run finished, with its result text when it produced one.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;subcall.failed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, child_session_id, message}&lt;/code&gt;: that sub-agent run failed.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;session.created&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, …}&lt;/code&gt; (full session metadata): a new session was created. Only seen on &lt;code&gt;GET /v1/events&lt;/code&gt; (below); a single session's own stream never reports its own creation.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;session.deleted&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id}&lt;/code&gt;: a session (and everything under it) was deleted. Only seen on &lt;code&gt;GET /v1/events&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hook.failed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{session_id, message}&lt;/code&gt;: a tool-call hook (a before/after command hook) failed outside of the normal tool-call result path. Not a session failure -- the run continues, unlike &lt;code&gt;session.failed&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;A typical run, from a &lt;code&gt;resume&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;id: 101
event: snapshot
data: {&amp;quot;session_id&amp;quot;:&amp;quot;4ed4…&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;ready&amp;quot;,&amp;quot;version&amp;quot;:1,…}

id: 102
event: session.updated
data: {&amp;quot;session_id&amp;quot;:&amp;quot;4ed4…&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;running&amp;quot;,&amp;quot;version&amp;quot;:2,&amp;quot;head_turn&amp;quot;:{…},…,&amp;quot;kind&amp;quot;:&amp;quot;session.updated&amp;quot;,&amp;quot;seq&amp;quot;:102}

id: 103
event: run.started
data: {&amp;quot;mode&amp;quot;:&amp;quot;until_blocked&amp;quot;,&amp;quot;session_id&amp;quot;:&amp;quot;4ed4…&amp;quot;,&amp;quot;kind&amp;quot;:&amp;quot;run.started&amp;quot;,&amp;quot;seq&amp;quot;:103}

id: 104
event: session.updated
data: {&amp;quot;session_id&amp;quot;:&amp;quot;4ed4…&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;running&amp;quot;,&amp;quot;version&amp;quot;:3,&amp;quot;head_turn&amp;quot;:{…},…,&amp;quot;kind&amp;quot;:&amp;quot;session.updated&amp;quot;,&amp;quot;seq&amp;quot;:104}

id: 105
event: calls.deferred
data: {&amp;quot;session_id&amp;quot;:&amp;quot;4ed4…&amp;quot;,&amp;quot;calls&amp;quot;:[{&amp;quot;continuation_token&amp;quot;:&amp;quot;0dd0…&amp;quot;,…}],&amp;quot;kind&amp;quot;:&amp;quot;calls.deferred&amp;quot;,&amp;quot;seq&amp;quot;:105}

id: 106
event: run.stopped
data: {&amp;quot;session_id&amp;quot;:&amp;quot;4ed4…&amp;quot;,&amp;quot;status&amp;quot;:&amp;quot;waiting_external&amp;quot;,&amp;quot;kind&amp;quot;:&amp;quot;run.stopped&amp;quot;,&amp;quot;seq&amp;quot;:106}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(The &lt;code&gt;snapshot&lt;/code&gt; frame has no &lt;code&gt;id:&lt;/code&gt;: it is a point-in-time read, not an event
in the sequence. &lt;code&gt;kind&lt;/code&gt; and &lt;code&gt;seq&lt;/code&gt; inside &lt;code&gt;data&lt;/code&gt; are additive – every field
this doc’s table names was already there.)&lt;/p&gt;
&lt;h4 id="streaming-answers"&gt;Streaming answers&lt;/h4&gt;
&lt;p&gt;With &lt;code&gt;--stream-tokens&lt;/code&gt;, the server asks the LLM for a streamed answer
(&lt;code&gt;&amp;quot;stream&amp;quot;: true&lt;/code&gt;) and forwards each piece of text as a &lt;code&gt;text.delta&lt;/code&gt; event,
before the answer is stored. Concatenating a step’s deltas gives the text of
the LLM turn that the following &lt;code&gt;session.updated&lt;/code&gt; carries. Tool calls
are not streamed: they appear in the stored turn as usual. A sub-agent that
runs as its own session streams like any other session, on its own id (its
own &lt;code&gt;text.delta&lt;/code&gt;s, not the parent’s); a still-narrowed sub-agent call
running in-tool does not (see “Sub-agents” above).&lt;/p&gt;
&lt;p&gt;The option applies to every agent of the server. It needs an endpoint that
supports streaming: OpenAI and most OpenAI-compatible APIs do. For the
&lt;code&gt;OpenAIv1&lt;/code&gt; flavor the server also asks for token usage in the last chunk
(&lt;code&gt;stream_options.include_usage&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The stream stays open across runs. It sends a &lt;code&gt;: keepalive&lt;/code&gt; comment after 15
seconds without events.&lt;/p&gt;
&lt;h4 id="reconnecting"&gt;Reconnecting&lt;/h4&gt;
&lt;p&gt;The server keeps a ring of the last 4096 events (across every session, not
per session). A reconnecting client sends &lt;code&gt;Last-Event-ID&lt;/code&gt; – set
automatically by the browser’s &lt;code&gt;EventSource&lt;/code&gt; on a dropped connection – or,
for any other client, &lt;code&gt;?after=&amp;lt;seq&amp;gt;&lt;/code&gt; naming the same thing explicitly. Two
cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The sequence number is still in the ring: the missed events replay first,
in order, with no gap and no duplicate at the point where the stream goes
live (the server takes the ring snapshot and subscribes to new events in
one atomic step). No &lt;code&gt;snapshot&lt;/code&gt; frame is sent in this case – the client
already has a consistent view and only needs what it missed.
&lt;/li&gt;
&lt;li&gt;It is older than everything still in the ring (a long disconnect, or a
server restart, which starts the sequence over): the stream falls back to
a fresh &lt;code&gt;snapshot&lt;/code&gt; followed by live events, exactly like a first
connection. There is no way to tell “missed too much” apart from “never
connected before” other than this: either way, a &lt;code&gt;snapshot&lt;/code&gt; means re-read
anything you need from it (and &lt;code&gt;GET /v1/sessions/:id&lt;/code&gt; for the full turns).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The ring is in-memory only: it does not survive a restart, and does not
replace &lt;code&gt;session_mail&lt;/code&gt;/the stored session as the durable record.&lt;/p&gt;
&lt;p&gt;Every event stream answers with an &lt;code&gt;Agents-Replay&lt;/code&gt; header saying which case
applies before any frame arrives: &lt;code&gt;live&lt;/code&gt; (no &lt;code&gt;Last-Event-ID&lt;/code&gt;/&lt;code&gt;after&lt;/code&gt; was
given), &lt;code&gt;replayed&lt;/code&gt;, or &lt;code&gt;unavailable&lt;/code&gt;. A client that must know whether it
missed events (the attached TUI’s &lt;code&gt;httpClient&lt;/code&gt;) reads it rather than
waiting for a first frame, which on a quiet stream could take a while.&lt;/p&gt;
&lt;h4 id="following-every-session"&gt;Following every session&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;GET /v1/events?scope=&amp;amp;after=&lt;/code&gt; is the same stream, server-wide instead of
per session: every event above, plus &lt;code&gt;session.created&lt;/code&gt; and
&lt;code&gt;session.deleted&lt;/code&gt;, and the same &lt;code&gt;Last-Event-ID&lt;/code&gt;/&lt;code&gt;after&lt;/code&gt; reconnect (no
&lt;code&gt;snapshot&lt;/code&gt; here – there is no single session to snapshot). &lt;code&gt;scope=owner&lt;/code&gt;
(the default when the caller has an owner) is that caller’s own sessions;
&lt;code&gt;scope=all&lt;/code&gt; is every session on the server, and needs authentication off or
the caller to be one of &lt;code&gt;--admin-owners&lt;/code&gt;, since it would otherwise let any
authenticated caller watch every other owner’s sessions. This is what a
live session list, or a dashboard across sessions, follows instead of
polling &lt;code&gt;GET /v1/sessions&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="attaching-the-tui"&gt;Attaching the TUI&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;agents-exe tui --attach&lt;/code&gt; runs the terminal UI against this server instead
of a runner of its own:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;agents-exe serve --port 8080 --socket /run/agents/agents.sock   # on the server
agents-exe tui --attach http://127.0.0.1:8080                   # over TCP
agents-exe tui --attach unix:///run/agents/agents.sock          # over the socket
agents-exe tui --attach https://agents.example --token-file ~/.agents-token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The TUI is then one more client of this API, like the chat page: it lists
agents from &lt;code&gt;GET /v1/agents&lt;/code&gt;, drives sessions through the routes above,
follows &lt;code&gt;GET /v1/events&lt;/code&gt; (&lt;code&gt;scope=all&lt;/code&gt;, or &lt;code&gt;scope=owner&lt;/code&gt; when a non-admin
token is used), and fetches &lt;code&gt;GET /v1/sessions/:id&lt;/code&gt; on each
&lt;code&gt;session.updated&lt;/code&gt;. It sees the sessions of its token’s owner (or every
session, without authentication), including ones created by other clients,
and quitting it leaves its sessions running here. Its &lt;code&gt;--params-file&lt;/code&gt;
values travel as &lt;code&gt;params&lt;/code&gt; on each create and message, as the chat page’s
do. See &lt;a href="/agents-exe/docs-tui.html#architecture"&gt;tui.md&lt;/a&gt; for what differs from the embedded
TUI.&lt;/p&gt;
&lt;h4 id="watching-with-spectate"&gt;Watching with spectate&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;agents-exe spectate --attach&lt;/code&gt; takes the same addresses and tokens, and
only reads: it lists the running sessions once (&lt;code&gt;GET /v1/sessions&lt;/code&gt;), then
follows &lt;code&gt;GET /v1/events&lt;/code&gt; and shows the session tree, the tool calls and
the model’s text live. With &lt;code&gt;--stream-tokens&lt;/code&gt; the text arrives as it is
written; without, turn by turn from &lt;code&gt;session.updated&lt;/code&gt;. See
&lt;a href="/agents-exe/docs-cli-commands.html#spectate"&gt;cli-commands.md&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;agents-exe spectate --attach unix:///run/agents/agents.sock
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3 id="api-reference"&gt;API reference&lt;/h3&gt;
&lt;p&gt;All bodies are JSON. Errors are &lt;code&gt;{&amp;quot;error&amp;quot;: &amp;quot;&amp;lt;code&amp;gt;&amp;quot;, &amp;quot;message&amp;quot;: &amp;quot;&amp;lt;text&amp;gt;&amp;quot;}&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Method and path&lt;/th&gt;&lt;th&gt;Body&lt;/th&gt;&lt;th&gt;Success&lt;/th&gt;&lt;th&gt;Errors&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 text/html&lt;/code&gt; chat page&lt;/td&gt;&lt;td&gt;404 when the page is off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /openapi.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200&lt;/code&gt; OpenAPI 3 document&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /healthz&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {ok, live_sessions, active_runs}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /mcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;JSON-RPC message or batch&lt;/td&gt;&lt;td&gt;&lt;code&gt;200&lt;/code&gt; JSON-RPC answer, or &lt;code&gt;202&lt;/code&gt;&lt;/td&gt;&lt;td&gt;see [MCP over HTTP](#mcp-over-http)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/agents&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 [{slug, description, model, system_prompt, tools, parameters, helpers, source, …}]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/agents/:slug&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200&lt;/code&gt; agent (same shape)&lt;/td&gt;&lt;td&gt;404 &lt;code&gt;unknown_agent&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;PUT /v1/agents/:slug&lt;/code&gt;&lt;/td&gt;&lt;td&gt;agent configuration&lt;/td&gt;&lt;td&gt;&lt;code&gt;201&lt;/code&gt; (new) or &lt;code&gt;200&lt;/code&gt; agent&lt;/td&gt;&lt;td&gt;403 &lt;code&gt;agent_edits_disabled&lt;/code&gt; / &lt;code&gt;forbidden&lt;/code&gt;, 400 &lt;code&gt;agent_uses_files&lt;/code&gt; / &lt;code&gt;agent_invalid_paths&lt;/code&gt; / &lt;code&gt;unknown_helper&lt;/code&gt; / &lt;code&gt;helper_cycle&lt;/code&gt; / &lt;code&gt;agent_failed_to_load&lt;/code&gt; / &lt;code&gt;bad_request&lt;/code&gt;, 409 &lt;code&gt;agent_defined_by_file&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;DELETE /v1/agents/:slug&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {deleted}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;403, 404 &lt;code&gt;unknown_agent&lt;/code&gt;, 409 &lt;code&gt;agent_defined_by_file&lt;/code&gt; / &lt;code&gt;agent_in_use&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions?wait=&amp;amp;timeout=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{agent, prompt?, media?, run?, params?, parent?, seal?, session_token?}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;201&lt;/code&gt; session (with &lt;code&gt;session_token&lt;/code&gt; once, when asked), with a &lt;code&gt;Location&lt;/code&gt; header&lt;/td&gt;&lt;td&gt;404 &lt;code&gt;unknown_agent&lt;/code&gt;, 404 &lt;code&gt;unknown_session&lt;/code&gt; (parent), 400 &lt;code&gt;bad_request&lt;/code&gt;, see [Parameters](#parameters) and [Session tokens](#session-tokens-and-sealed-sessions)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;DELETE /v1/sessions/:id/token&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;td&gt;&lt;code&gt;200&lt;/code&gt; session&lt;/td&gt;&lt;td&gt;404; revokes the session's token, also during a run&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions?agent=&amp;amp;status=&amp;amp;parent=&amp;amp;limit=&amp;amp;before=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {sessions, next_before}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;400 &lt;code&gt;bad_request&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions/:id?wait=&amp;amp;timeout=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200&lt;/code&gt; session, or &lt;code&gt;202&lt;/code&gt; when &lt;code&gt;wait&lt;/code&gt; expired with a run still active&lt;/td&gt;&lt;td&gt;404 &lt;code&gt;unknown_session&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/messages?wait=&amp;amp;timeout=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{prompt, media?, run?, params?, interrupt?}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;202&lt;/code&gt; or &lt;code&gt;200&lt;/code&gt; session&lt;/td&gt;&lt;td&gt;404, 409 &lt;code&gt;run_in_progress&lt;/code&gt;, 409 &lt;code&gt;not_accepting_messages&lt;/code&gt;, see [Parameters](#parameters)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/resume?wait=&amp;amp;timeout=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{mode?, params?}&lt;/code&gt; or no body&lt;/td&gt;&lt;td&gt;&lt;code&gt;202&lt;/code&gt; or &lt;code&gt;200&lt;/code&gt; session&lt;/td&gt;&lt;td&gt;404, 409 &lt;code&gt;run_in_progress&lt;/code&gt;, see [Parameters](#parameters)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/cancel&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200&lt;/code&gt; session metadata&lt;/td&gt;&lt;td&gt;404, 409 &lt;code&gt;no_active_run&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/cancel-attached&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200&lt;/code&gt; session metadata&lt;/td&gt;&lt;td&gt;404&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/pause&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200&lt;/code&gt; session metadata&lt;/td&gt;&lt;td&gt;404&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/mail&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{body, priority?}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;202&lt;/code&gt; mail &lt;code&gt;Receipt&lt;/code&gt;: &lt;code&gt;{id, seq, duplicate}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404, see [Mail](#mail)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions/:id/mail?unread=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {mail: [Envelope]}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/sessions/:id/fork&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{at_turn?, agent?, params?}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;201&lt;/code&gt; new session, with a &lt;code&gt;Location&lt;/code&gt; header&lt;/td&gt;&lt;td&gt;404 &lt;code&gt;unknown_session&lt;/code&gt; / &lt;code&gt;unknown_turn&lt;/code&gt; / &lt;code&gt;unknown_agent&lt;/code&gt;, see [Parameters](#parameters)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;PUT /v1/sessions/:id/params&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{params}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200&lt;/code&gt; session&lt;/td&gt;&lt;td&gt;404, 409 &lt;code&gt;run_in_progress&lt;/code&gt;, 422/403 as in [Parameters](#parameters); &lt;code&gt;message&lt;/code&gt;-scope names are &lt;code&gt;422 invalid_params&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions/:id/pending&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {calls}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/sessions/:id/events?after=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 text/event-stream&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;GET /v1/events?scope=&amp;amp;after=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 text/event-stream&lt;/code&gt;&lt;/td&gt;&lt;td&gt;403 &lt;code&gt;forbidden&lt;/code&gt; (&lt;code&gt;scope=all&lt;/code&gt; without authentication off or an admin owner)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;POST /v1/continuations/:token?wait=&amp;amp;timeout=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{result, resume?, params?}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;202&lt;/code&gt; or &lt;code&gt;200&lt;/code&gt; session&lt;/td&gt;&lt;td&gt;404 &lt;code&gt;unknown_token&lt;/code&gt;, 409 &lt;code&gt;token_already_completed&lt;/code&gt;, 409 &lt;code&gt;conflict&lt;/code&gt;, see [Parameters](#parameters)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;DELETE /v1/sessions/:id?dry_run=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;200 {sessions, continuations, dry_run}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;404, 409 &lt;code&gt;run_in_progress&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;prompt&lt;/code&gt; on create may be omitted (with no &lt;code&gt;media&lt;/code&gt; either): this stores an
idle session with no turn at all, &lt;code&gt;status: &amp;quot;ready&amp;quot;&lt;/code&gt;, ready for a later
message, mail, or &lt;code&gt;resume&lt;/code&gt; – nothing runs. A &lt;code&gt;prompt&lt;/code&gt; behaves as before.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;parent&lt;/code&gt; on create (a session id) records the new session as a child of
that one, for lineage only: it is listed through &lt;code&gt;?parent=&lt;/code&gt;, deleted with
its parent, and is never told anything by its parent or vice versa. The
caller must be able to see the parent (another owner’s answers
&lt;code&gt;404 unknown_session&lt;/code&gt;). This is what an attached TUI sends for
&lt;code&gt;createSessionAsChild&lt;/code&gt; and &lt;code&gt;spawnSession&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wait=true&lt;/code&gt; on &lt;code&gt;GET /v1/sessions/:id&lt;/code&gt; first waits (up to &lt;code&gt;timeout&lt;/code&gt; seconds,
default 120, at most 600) for the session’s active run to stop, then
answers the session with &lt;code&gt;200&lt;/code&gt;, or &lt;code&gt;202&lt;/code&gt; if a run is still active once the
time is up. Without &lt;code&gt;wait&lt;/code&gt;, it answers at once, always &lt;code&gt;200&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;at_turn&lt;/code&gt; on fork is a 0-based index into the session’s &lt;code&gt;turns&lt;/code&gt;, &lt;strong&gt;newest
first&lt;/strong&gt; (&lt;code&gt;turns[0]&lt;/code&gt; is the most recent turn): the fork keeps that turn and
every older one, dropping anything newer. Absent, the whole session is
copied. &lt;code&gt;agent&lt;/code&gt; rebinds the fork to another agent’s slug (also how to
“continue with another agent”: fork with no &lt;code&gt;at_turn&lt;/code&gt;, or &lt;code&gt;at_turn: 0&lt;/code&gt;, and
an &lt;code&gt;agent&lt;/code&gt;). &lt;code&gt;params&lt;/code&gt; on a fork are overlaid on the source’s persisted, non-secret session values and validated like any request’s; secrets are never inherited and have to be given again. &lt;code&gt;PUT /v1/sessions/:id/params&lt;/code&gt; sets session-scope values (a &lt;code&gt;null&lt;/code&gt; clears one) without starting a run, e.g. to rotate a credential or re-supply secrets after a restart. The fork gets a fresh &lt;code&gt;session_id&lt;/code&gt;, &lt;code&gt;forkedFromSessionId&lt;/code&gt; set
to the source, the source’s parent link and non-secret parameters, and
&lt;code&gt;status&lt;/code&gt; derived from the turns it kept – never the source’s own status,
and it starts no run, so it never picks up a later change to the source.&lt;/p&gt;
&lt;p&gt;Any endpoint that reads a body or a query parameter can answer
&lt;code&gt;400 bad_request&lt;/code&gt;; the table names it only where it is the usual outcome.
Other errors: &lt;code&gt;401 unauthorized&lt;/code&gt; when authentication is on (with a
&lt;code&gt;WWW-Authenticate: Bearer&lt;/code&gt; header),
&lt;code&gt;403 forbidden_origin&lt;/code&gt; when it is off (see &lt;a href="#authentication"&gt;Authentication&lt;/a&gt;),
&lt;code&gt;404 not_found&lt;/code&gt; for an unknown path, &lt;code&gt;405 method_not_allowed&lt;/code&gt;,
&lt;code&gt;413 payload_too_large&lt;/code&gt; for bodies over 32 MiB, and &lt;code&gt;500 internal_error&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Messages&lt;/strong&gt; (&lt;code&gt;prompt&lt;/code&gt;, &lt;code&gt;media&lt;/code&gt;, &lt;code&gt;interrupt&lt;/code&gt;). &lt;code&gt;media&lt;/code&gt; is a list of
&lt;code&gt;{&amp;quot;mime&amp;quot;: &amp;quot;image/png&amp;quot;, &amp;quot;base64&amp;quot;: &amp;quot;…&amp;quot;, &amp;quot;filename&amp;quot;: &amp;quot;optional&amp;quot;}&lt;/code&gt;. &lt;code&gt;interrupt&lt;/code&gt;
(default &lt;code&gt;false&lt;/code&gt;) only matters against a busy session (&lt;code&gt;status: &amp;quot;running&amp;quot;&lt;/code&gt;):
instead of being refused with &lt;code&gt;409 not_accepting_messages&lt;/code&gt;, the message is
posted as interrupt-priority mail, which detaches the session’s currently
attached tool calls (and, with the agent’s &lt;code&gt;interruptCompletions&lt;/code&gt; on,
cancels an in-flight LLM completion) and asks the model again with this
message folded in. A detached call’s result, if it still arrives, is
reported on a later run rather than lost. On an idle session &lt;code&gt;interrupt&lt;/code&gt; has
no effect: there is nothing to interrupt.&lt;/p&gt;
&lt;p&gt;Mail (a message, or any other envelope R1 folds into a turn) normally
becomes a separate user message after a round of attached tool results. For
a provider that rejects a user message directly after tool results, set the
agent’s &lt;code&gt;mailInToolResult&lt;/code&gt; (default &lt;code&gt;false&lt;/code&gt;): R1 then appends the folded
mail, with the same &lt;code&gt;[mail …]&lt;/code&gt; header, as a trailing block of the &lt;em&gt;last&lt;/em&gt;
tool result of that round instead. Only applies when the round actually had
tool calls; a plain user turn (no tool results) is unaffected, and
detached/deferred results already arrive as mail of their own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Results&lt;/strong&gt; (&lt;code&gt;result&lt;/code&gt;). A JSON string is a text result. Other forms are
&lt;code&gt;{&amp;quot;type&amp;quot;: &amp;quot;text&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;…&amp;quot;}&lt;/code&gt;, &lt;code&gt;{&amp;quot;type&amp;quot;: &amp;quot;json&amp;quot;, &amp;quot;content&amp;quot;: &amp;lt;any&amp;gt;}&lt;/code&gt;,
&lt;code&gt;{&amp;quot;type&amp;quot;: &amp;quot;media&amp;quot;, &amp;quot;mimeType&amp;quot;: &amp;quot;…&amp;quot;, &amp;quot;base64Data&amp;quot;: &amp;quot;…&amp;quot;}&lt;/code&gt;, and
&lt;code&gt;{&amp;quot;type&amp;quot;: &amp;quot;mixed&amp;quot;, &amp;quot;parts&amp;quot;: [...]}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Listing.&lt;/strong&gt; Sessions come newest first (by &lt;code&gt;updated_at&lt;/code&gt;). Filters:
&lt;code&gt;agent=&amp;lt;slug&amp;gt;&lt;/code&gt;, &lt;code&gt;status=&amp;lt;s1,s2,…&amp;gt;&lt;/code&gt;, &lt;code&gt;parent=&amp;lt;session id&amp;gt;&lt;/code&gt; (the sub-sessions
of a session; another owner’s session answers &lt;code&gt;404 unknown_session&lt;/code&gt;). &lt;code&gt;limit&lt;/code&gt; is 1 to 500 (default 50). When a page is full,
&lt;code&gt;next_before&lt;/code&gt; holds the &lt;code&gt;updated_at&lt;/code&gt; of its last session: pass it as
&lt;code&gt;before=&lt;/code&gt; to get the next page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cancelling&lt;/strong&gt; stops the active run and its background tool calls. The
session is stored with the status its turns imply, usually &lt;code&gt;ready&lt;/code&gt;. The
cancelled calls are reported to the LLM on the next run.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;cancel-attached&lt;/code&gt;&lt;/strong&gt; hard-cancels every tool call currently attached to the
session, through the async engine, &lt;em&gt;without&lt;/em&gt; stopping the run itself. A
cancelled call’s result never arrives. Contrast with posting a message with
&lt;code&gt;interrupt: true&lt;/code&gt;, which only detaches attached calls and lets them finish.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;pause&lt;/code&gt;&lt;/strong&gt; posts &lt;code&gt;Pause&lt;/code&gt; control mail: the run stops at its next iteration
and the session is stored as &lt;code&gt;status: &amp;quot;paused&amp;quot;&lt;/code&gt;. Attached calls keep running
unless the agent’s config sets &lt;code&gt;pauseCancelsCalls&lt;/code&gt; — cancel them explicitly
with &lt;code&gt;cancel-attached&lt;/code&gt; instead. &lt;code&gt;resume&lt;/code&gt; works from &lt;code&gt;paused&lt;/code&gt; regardless of
whether the pause has taken effect yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deleting&lt;/strong&gt; removes the session, all its sub-sessions, and their
continuation tokens. It is refused while a run is active on any of them or on
a parent session. &lt;code&gt;dry_run=true&lt;/code&gt; answers with what would be removed and
changes nothing.&lt;/p&gt;
&lt;h4 id="postgres"&gt;Postgres&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;--db postgresql://user:password@host:5432/agents&lt;/code&gt; stores sessions in
Postgres instead of SQLite. The server creates its tables on start
(&lt;code&gt;sessions&lt;/code&gt;, &lt;code&gt;tool_continuations&lt;/code&gt;, &lt;code&gt;agents&lt;/code&gt;, &lt;code&gt;schema_migrations&lt;/code&gt;); the
database must exist and the user must be allowed to create tables. The logs show the URL
without its user and password.&lt;/p&gt;
&lt;h5 id="several-servers-on-one-database"&gt;Several servers on one database&lt;/h5&gt;
&lt;p&gt;Several servers may share one Postgres database, and a request for a session
may go to any of them. A session’s run is on one server at a time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The server that starts a run takes a &lt;strong&gt;lease&lt;/strong&gt; on the session (the
&lt;code&gt;run_owner&lt;/code&gt; and &lt;code&gt;run_lease_until&lt;/code&gt; columns of &lt;code&gt;sessions&lt;/code&gt;) and renews it
every 10 seconds while the run lasts. The lease is given back when the run
stops. Times are the database’s, so the servers’ clocks need not agree.
&lt;/li&gt;
&lt;li&gt;While another server holds the lease, the session is busy here too. A
message is accepted as mail for the run, as it is on the server that runs
it. &lt;code&gt;resume&lt;/code&gt; and deleting answer &lt;code&gt;409 run_in_progress&lt;/code&gt;. &lt;code&gt;cancel&lt;/code&gt; asks the
owner to stop, which it does at its next step, not at once. A completed
deferred call is queued for the run. &lt;code&gt;GET /v1/sessions/:id?wait=true&lt;/code&gt;
waits for the run wherever it is.
&lt;/li&gt;
&lt;li&gt;A server that dies stops renewing. Once its lease is 30 seconds old,
another server &lt;strong&gt;takes the session over&lt;/strong&gt;: it stores the session as a
restart would (the interrupted step is lost, its background calls are
orphaned, the status is the one the turns imply) and logs
&lt;code&gt;sessions.taken_over&lt;/code&gt;. Nothing is resumed: resume the session, on any
server, to continue. Secret parameters lived in the dead server’s memory
and must be supplied again.
&lt;/li&gt;
&lt;li&gt;A server that was only cut off (from the database, or by a long pause)
and comes back after its session was taken over stops its run without
storing anything, and logs &lt;code&gt;run.lease_lost&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Servers tell each other what they write with &lt;code&gt;LISTEN&lt;/code&gt;/&lt;code&gt;NOTIFY&lt;/code&gt; (channel
&lt;code&gt;agents_sessions&lt;/code&gt;), on one extra connection per server. Mail accepted by
one server reaches the run on another at once. Each stored version of a
session is announced as &lt;code&gt;session.updated&lt;/code&gt; on every server’s event
streams, and a session that stops running as &lt;code&gt;run.stopped&lt;/code&gt;. The other
events of a run (&lt;code&gt;text.delta&lt;/code&gt;, &lt;code&gt;tool.*&lt;/code&gt;, &lt;code&gt;run.started&lt;/code&gt;, …) are only on
the streams of the server that runs it: follow a session’s events on the
server you started its run on.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All the servers must run a version with leases: an older one neither takes
nor honours them. A server started with other servers already running
recovers only the sessions no live server holds.&lt;/p&gt;
&lt;p&gt;Not shared between servers: agent files and &lt;code&gt;--set&lt;/code&gt; parameters (give every
server the same ones), and stored agents edited while the servers run (a
server loads them at startup). A &lt;code&gt;watch-session&lt;/code&gt; registration is followed
by the server that runs the watched session, if it knows the registration: a
server knows the ones made on it and the ones stored when it started.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="storing-agents"&gt;Storing agents&lt;/h3&gt;
&lt;p&gt;Besides &lt;code&gt;--agent-file&lt;/code&gt;, agents can live in the server’s database and be
created, replaced, and deleted over the API. Storing agents is off unless
&lt;code&gt;--admin-owners&lt;/code&gt; names the owners allowed to do it, which needs
&lt;code&gt;--auth-tokens&lt;/code&gt;: an agent definition can start MCP servers, which are
commands run on the server’s machine.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;curl&lt;/span&gt; &lt;span class="at"&gt;-X&lt;/span&gt; PUT localhost:8080/v1/agents/helper &lt;span class="at"&gt;-H&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;Authorization: Bearer &amp;lt;admin token&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="at"&gt;-d&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;apiKeyId&amp;quot;: &amp;quot;openai&amp;quot;, &amp;quot;flavor&amp;quot;: &amp;quot;OpenAIv1&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;modelUrl&amp;quot;: &amp;quot;https://api.openai.com/v1&amp;quot;, &amp;quot;modelName&amp;quot;: &amp;quot;gpt-4o-mini&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;announce&amp;quot;: &amp;quot;a helpful assistant&amp;quot;, &amp;quot;systemPrompt&amp;quot;: [&amp;quot;You help.&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;  &amp;quot;builtinToolboxes&amp;quot;: [], &amp;quot;mcpServers&amp;quot;: []&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt;}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The body is what goes under &lt;code&gt;contents&lt;/code&gt; in an agent file. The slug comes
from the path.
&lt;/li&gt;
&lt;li&gt;A stored agent cannot use &lt;code&gt;openApiToolboxes&lt;/code&gt;, &lt;code&gt;postgrestToolboxes&lt;/code&gt;,
&lt;code&gt;skillSources&lt;/code&gt;, or &lt;code&gt;autoEnableSkills&lt;/code&gt;, which refer to files on the server
(&lt;code&gt;400 agent_uses_files&lt;/code&gt;). Builtin toolboxes and MCP servers work, as do the
execution mode and tool-call policy. Bash tools and helpers work as
described below.
&lt;/li&gt;
&lt;li&gt;The agent is loaded before it is stored: if an MCP server fails to start,
the answer is &lt;code&gt;400 agent_failed_to_load&lt;/code&gt; and nothing is stored.
&lt;/li&gt;
&lt;li&gt;A slug used by an agent file cannot be stored (&lt;code&gt;409 agent_defined_by_file&lt;/code&gt;). If an agent file with the slug of a stored agent
appears later, the file wins, and the stored agent is skipped at startup
(logged as &lt;code&gt;agents.stored_skipped&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /v1/agents&lt;/code&gt; lists both kinds, with &lt;code&gt;source: &amp;quot;file&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;database&amp;quot;&lt;/code&gt;.
Stored agents also show &lt;code&gt;config&lt;/code&gt;, &lt;code&gt;updated_at&lt;/code&gt;, and &lt;code&gt;updated_by&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;New sessions use a replaced agent at once. Sessions already in memory keep
the version they built until they are idle long enough to be dropped
(&lt;code&gt;--live-session-ttl&lt;/code&gt;). Sessions of a deleted agent stay, but runs on them
fail with &lt;code&gt;unknown_agent&lt;/code&gt; until an agent with that slug exists again.
&lt;/li&gt;
&lt;li&gt;MCP servers started for a stored agent keep running when the agent is
replaced or deleted, until the server stops.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="bash-tools-of-a-stored-agent"&gt;Bash tools of a stored agent&lt;/h4&gt;
&lt;p&gt;The files of a stored agent’s bash tools are stored with it. Next to the
configuration’s fields, the body takes a &lt;code&gt;files&lt;/code&gt; object: contents by path.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;OpenAIv1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4o-mini&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;greets people&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;You greet.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;files&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;&amp;quot;tools/greet.sh&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;#!/bin/sh&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="st"&gt;...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;For instance, to send a configuration (&lt;code&gt;greeter.json&lt;/code&gt;, without &lt;code&gt;files&lt;/code&gt;) with
a script from disk:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;jq&lt;/span&gt; &lt;span class="at"&gt;--rawfile&lt;/span&gt; greet tools/greet.sh &lt;span class="st"&gt;&amp;#39;. + {files: {&amp;quot;tools/greet.sh&amp;quot;: $greet}}&amp;#39;&lt;/span&gt; greeter.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;curl&lt;/span&gt; &lt;span class="at"&gt;-X&lt;/span&gt; PUT localhost:8080/v1/agents/greeter &lt;span class="at"&gt;-H&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;Authorization: Bearer &amp;lt;admin token&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="at"&gt;-d&lt;/span&gt; @-&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;toolDirectory&lt;/code&gt; and the paths of &lt;code&gt;bashToolboxes&lt;/code&gt; are relative to the
directory the files are written to. Paths, of tools and of files, are
relative and without &lt;code&gt;..&lt;/code&gt; (&lt;code&gt;400 agent_invalid_paths&lt;/code&gt;); &lt;code&gt;bashToolboxes&lt;/code&gt;
entries take no &lt;code&gt;root&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;When the agent is loaded, the server writes the files to a temporary
directory of its own, makes each one executable, and loads the tools from
there. The directory goes away with that version of the agent, and with
the server. Tools run on the server’s machine, as the server’s user: this
is the reason storing agents needs an admin owner.
&lt;/li&gt;
&lt;li&gt;Files are text (UTF-8). A &lt;code&gt;PUT&lt;/code&gt; replaces the agent and all its files: send
&lt;code&gt;files&lt;/code&gt; again to keep them. &lt;code&gt;GET /v1/agents/:slug&lt;/code&gt; shows them under
&lt;code&gt;config.files&lt;/code&gt;, so that &lt;code&gt;config&lt;/code&gt; can be sent back as a body.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="helpers-of-a-stored-agent"&gt;Helpers of a stored agent&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;extraAgents&lt;/code&gt; of a stored agent name other stored agents by slug, without a
&lt;code&gt;path&lt;/code&gt;; &lt;code&gt;with&lt;/code&gt; and &lt;code&gt;narrowable&lt;/code&gt; work as in agent files.&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;greeter&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;A helper must be stored before the agent that names it (&lt;code&gt;400 unknown_helper&lt;/code&gt;). Agents from files cannot be named.
&lt;/li&gt;
&lt;li&gt;The references of stored agents cannot form a cycle, and an agent cannot
name itself (&lt;code&gt;400 helper_cycle&lt;/code&gt;). This is stricter than agent files.
&lt;/li&gt;
&lt;li&gt;Replacing a helper reloads the stored agents that reach it, so that new
sessions call the new version.
&lt;/li&gt;
&lt;li&gt;An agent that others name as a helper cannot be deleted (&lt;code&gt;409 agent_in_use&lt;/code&gt;): delete or change the agents that name it first.
&lt;/li&gt;
&lt;li&gt;At startup, a stored agent whose helpers cannot be resolved (for instance
because an agent file now has a helper’s slug) is skipped, and logged as
&lt;code&gt;agents.stored_skipped&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="authentication"&gt;Authentication&lt;/h3&gt;
&lt;p&gt;With &lt;code&gt;--auth-tokens tokens.json&lt;/code&gt;, every endpoint except &lt;code&gt;/healthz&lt;/code&gt; needs an
&lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; header, and each caller only sees their own
sessions. The file maps tokens to owners:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tokens&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;owner&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;alice&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;42f5d7b6be1957766e51c84756eb7a7c19a0e690a75d628238e2ab78f0ba9d19&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;span class="ot"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;owner&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bob&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;a-long-random-token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;sha256&lt;/code&gt; is the hex SHA-256 of the token (&lt;code&gt;printf %s TOKEN | sha256sum&lt;/code&gt;), so
the file need not hold the token itself. &lt;code&gt;token&lt;/code&gt; holds it in plain text.
Several tokens may share an owner. The file is read at startup.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A missing or unknown token answers &lt;code&gt;401 unauthorized&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;A session belongs to the caller who created it. Sub-sessions, created by
sub-agents, belong to the owner of their root session.
&lt;/li&gt;
&lt;li&gt;Another owner’s session answers &lt;code&gt;404&lt;/code&gt;, exactly as a session that does not
exist, including its continuation tokens (&lt;code&gt;404 unknown_token&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /v1/sessions&lt;/code&gt; lists the caller’s own sessions. Sub-sessions are
listed through their parent: &lt;code&gt;?parent=&amp;lt;session id&amp;gt;&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Sessions created while authentication was off have no owner, and no caller
sees them once it is on.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /v1/sessions/:id/events&lt;/code&gt; also accepts the token as an &lt;code&gt;access_token&lt;/code&gt;
query parameter, because a browser’s &lt;code&gt;EventSource&lt;/code&gt; cannot set headers. No
other endpoint does, and the request log records no query strings.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All owners share the agents of the server, and its API keys unless they
have their own (next section).&lt;/p&gt;
&lt;h4 id="api-keys-per-owner"&gt;API keys per owner&lt;/h4&gt;
&lt;p&gt;By default every owner’s sessions call the LLM with the keys in
&lt;code&gt;--api-keys&lt;/code&gt;. &lt;code&gt;--owner-api-keys OWNER=FILE&lt;/code&gt; gives one owner a keys file of
their own, in the same format; repeat it for several owners:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;agents-server&lt;/span&gt; &lt;span class="at"&gt;--agent-file&lt;/span&gt; ./weather.json &lt;span class="at"&gt;--api-keys&lt;/span&gt; ./secrets/keys.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--auth-tokens&lt;/span&gt; ./tokens.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--owner-api-keys&lt;/span&gt; alice=./secrets/alice-keys.json &lt;span class="dt"&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="at"&gt;--owner-api-keys&lt;/span&gt; bob=./secrets/bob-keys.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The agents of that owner’s sessions are built with that file: root
sessions, and the sub-sessions their sub-agents run in. An agent still
names its key by &lt;code&gt;apiKeyId&lt;/code&gt;; the id is looked up in the owner’s file.
&lt;/li&gt;
&lt;li&gt;The owner’s file replaces &lt;code&gt;--api-keys&lt;/code&gt; for that owner, it is not merged
with it. A key id it does not hold is not looked up in &lt;code&gt;--api-keys&lt;/code&gt;: the
call goes out without a key, and the provider refuses it.
&lt;/li&gt;
&lt;li&gt;Owners without an entry, and sessions without an owner, use &lt;code&gt;--api-keys&lt;/code&gt;,
as before.
&lt;/li&gt;
&lt;li&gt;The files are read at startup. A file that is missing or does not parse,
an owner listed twice, or the flag without &lt;code&gt;--auth-tokens&lt;/code&gt;, stops the
server from starting.
&lt;/li&gt;
&lt;li&gt;This covers the LLM calls only. A tool parameter whose value comes from
the keys file is still resolved from &lt;code&gt;--api-keys&lt;/code&gt; when the agent loads,
for every owner.
&lt;/li&gt;
&lt;li&gt;A sub-agent call that cannot run as a session of its own falls back to
running inside the calling tool, which does not know the owner. With
&lt;code&gt;--owner-api-keys&lt;/code&gt; in use, such a call is made without any key, rather
than with the shared ones.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="session-tokens-and-sealed-sessions"&gt;Session tokens and sealed sessions&lt;/h4&gt;
&lt;p&gt;A backend that opens a chat for an end user should not have to proxy every
message and event stream, but must not hand the browser its own token either.
Two options on &lt;code&gt;POST /v1/sessions&lt;/code&gt; (with &lt;code&gt;--auth-tokens&lt;/code&gt;) cover that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;seal&amp;quot;: true&lt;/code&gt; marks the session sealed (shown as &lt;code&gt;&amp;quot;sealed&amp;quot;: true&lt;/code&gt;). &lt;code&gt;params&lt;/code&gt; on
a message, resume or continuation is then refused with &lt;code&gt;403 forbidden_params&lt;/code&gt;
for every caller but the session’s owner, who keeps &lt;code&gt;PUT /v1/sessions/:id/params&lt;/code&gt;
to rotate values. The parameters of a sealed session are those its creator chose.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;session_token&amp;quot;: true&lt;/code&gt; adds a &lt;code&gt;session_token&lt;/code&gt; to the creation answer, once:
32 random bytes in hex, prefixed &lt;code&gt;st_&lt;/code&gt;. Only its SHA-256 digest is stored, with
the session, on either backend; reads never show it. It is refused with &lt;code&gt;400&lt;/code&gt;
without &lt;code&gt;--auth-tokens&lt;/code&gt;, where every caller has full access anyway.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Authorization: Bearer &amp;lt;session token&amp;gt;&lt;/code&gt; allows exactly, on that one session:
&lt;code&gt;GET /v1/sessions/:id&lt;/code&gt;, &lt;code&gt;GET /v1/sessions/:id/events&lt;/code&gt;, &lt;code&gt;POST /v1/sessions/:id/messages&lt;/code&gt;
(without &lt;code&gt;params&lt;/code&gt;: &lt;code&gt;403 forbidden_params&lt;/code&gt;) and &lt;code&gt;POST /v1/sessions/:id/cancel&lt;/code&gt;.
The other paths of the session answer &lt;code&gt;403 forbidden&lt;/code&gt;; every path outside it
(other sessions, the listing, agents, &lt;code&gt;/v1/events&lt;/code&gt;) answers &lt;code&gt;401&lt;/code&gt;, so a token
cannot probe for other sessions. The owner revokes a token with
&lt;code&gt;DELETE /v1/sessions/:id/token&lt;/code&gt;; it also dies with the session. A fork or a
child session does not inherit the seal or the token.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browser origins.&lt;/strong&gt; Without &lt;code&gt;--auth-tokens&lt;/code&gt;, requests carrying an &lt;code&gt;Origin&lt;/code&gt;
header that is not &lt;code&gt;localhost&lt;/code&gt;, &lt;code&gt;127.0.0.1&lt;/code&gt;, &lt;code&gt;[::1]&lt;/code&gt;, or a &lt;code&gt;--cors-origin&lt;/code&gt;
answer &lt;code&gt;403 forbidden_origin&lt;/code&gt;. This stops a web page from reaching a local
server through DNS rebinding. Clients that send no &lt;code&gt;Origin&lt;/code&gt; (curl, servers,
MCP clients) are not affected. With authentication on, origins are not
checked (a bearer token already proves the caller is authorized; there is no
cookie to leak). &lt;code&gt;/healthz&lt;/code&gt;, &lt;code&gt;/openapi.json&lt;/code&gt; and &lt;code&gt;/&lt;/code&gt; are answered before the
check, so a monitor or a documentation browser reaches them from anywhere.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-origin browser access (CORS).&lt;/strong&gt; &lt;code&gt;--cors-origin ORIGIN&lt;/code&gt; (repeatable)
lets a page served by a &lt;em&gt;different&lt;/em&gt; origin — another host, port, or scheme —
call the API and open its event stream directly, instead of proxying
through that page’s own backend. An origin must match exactly: scheme and
port are significant, host is compared case-insensitively (so
&lt;code&gt;http://app.example:5173&lt;/code&gt; and &lt;code&gt;https://app.example&lt;/code&gt; are different origins,
and each needs its own &lt;code&gt;--cors-origin&lt;/code&gt;). &lt;code&gt;--cors-origin '*'&lt;/code&gt; allows any
origin and is refused at startup together with &lt;code&gt;--auth-tokens&lt;/code&gt;, since with
tokens in play a bearer credential must not be sent to a page the operator
never named.&lt;/p&gt;
&lt;p&gt;A listed origin:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;passes the origin check above even without &lt;code&gt;--auth-tokens&lt;/code&gt; — it was opted
in explicitly, unlike an arbitrary non-loopback origin;
&lt;/li&gt;
&lt;li&gt;gets &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; (echoing the request’s own &lt;code&gt;Origin&lt;/code&gt;,
never a literal &lt;code&gt;*&lt;/code&gt;), &lt;code&gt;Vary: Origin&lt;/code&gt;, and
&lt;code&gt;Access-Control-Expose-Headers: Location&lt;/code&gt; on every response, including
errors and the event stream (&lt;code&gt;fetch&lt;/code&gt; needs &lt;code&gt;Location&lt;/code&gt; to read the
&lt;code&gt;Location&lt;/code&gt; header &lt;code&gt;POST /v1/sessions&lt;/code&gt; answers with; &lt;code&gt;EventSource&lt;/code&gt;/&lt;code&gt;fetch&lt;/code&gt;
need the others to read the response at all);
&lt;/li&gt;
&lt;li&gt;gets its &lt;code&gt;OPTIONS&lt;/code&gt; preflight requests answered with &lt;code&gt;204&lt;/code&gt; and
&lt;code&gt;Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS&lt;/code&gt;,
&lt;code&gt;Access-Control-Allow-Headers: Authorization, Content-Type, Last-Event-ID&lt;/code&gt;,
and &lt;code&gt;Access-Control-Max-Age: 600&lt;/code&gt;. Preflight is answered on any path,
before authentication and before the origin check the real request would
otherwise get — except that a non-loopback origin not on the list still
gets &lt;code&gt;403 forbidden_origin&lt;/code&gt; here too, when there is no &lt;code&gt;--auth-tokens&lt;/code&gt;,
matching what the real request would get.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;GET /v1/sessions/:id/events&lt;/code&gt; keeps working cross-origin the same way it
works same-origin: &lt;code&gt;EventSource&lt;/code&gt; cannot set the &lt;code&gt;Authorization&lt;/code&gt; header, so
with &lt;code&gt;--auth-tokens&lt;/code&gt; the token still goes as &lt;code&gt;?access_token=&lt;/code&gt; (see above);
without tokens, a listed origin needs nothing extra.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="isolating-tool-calls"&gt;Isolating tool calls&lt;/h3&gt;
&lt;p&gt;By default the server runs every tool in its own process, on its own host,
for every owner. &lt;code&gt;--isolate-tools&lt;/code&gt; sends the calls of bash tools and MCP
tools to a worker instead:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Each call is handed to&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;docker:IMAGE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;docker run --rm -i IMAGE&lt;/code&gt;, one container per call&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;process:PATH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the executable at &lt;code&gt;PATH&lt;/code&gt;, one process per call&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The worker reads one JSON envelope on stdin and writes one result envelope
on stdout:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;lt;uuid&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;toolCall&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;call_1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;function&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;function&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;bash_weather&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;arguments&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}},&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;contextSnapshot&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tecsSessionId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;…&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;tecsParams&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{}},&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="dt"&gt;&amp;quot;policy&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;runIsolated&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;spec&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;docker&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;image&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;IMAGE&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;lt;the same uuid&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;success&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;sunny&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;span class="dt"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;lt;the same uuid&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt; &lt;span class="dt"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;what went wrong&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The image, or the executable, is yours to provide: this repository ships no
worker. It has to hold whatever the tools need (the scripts of a bash
toolbox, the MCP server to start) and to find the tool from its name.&lt;/p&gt;
&lt;p&gt;What is enforced:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It applies to every agent the server builds, for every owner and for
sub-agents, and an agent’s own &lt;code&gt;toolCallPolicyConfig&lt;/code&gt; cannot turn it off.
That policy still decides whether a call is deferred or run in the
background; when the call is executed, it goes to the worker.
&lt;/li&gt;
&lt;li&gt;There is no fallback. If the worker cannot be started, exits with an
error, or answers something else than a result envelope for the call,
the call fails and its result is &lt;code&gt;isolation error: …&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;A bash or MCP tool called from another tool (a Lua script, through the
tool portal) is refused.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What is not:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Only bash tools and MCP tools are covered. Skill scripts, Lua, SQLite,
OpenAPI, PostgREST, the system and developer toolboxes, and agents called
as tools still run inside the server.
&lt;/li&gt;
&lt;li&gt;MCP servers are still started by the server when it loads an agent, to
list their tools; only the calls go to the worker.
&lt;/li&gt;
&lt;li&gt;Secret parameter values are not written into the envelope. A tool that
needs one fails in the worker.
&lt;/li&gt;
&lt;li&gt;The server sets no limit on the worker: no timeout, no network or
filesystem restriction beyond what the image and your Docker setup give.
&lt;/li&gt;
&lt;li&gt;It is off unless the flag is given, and applies to this server only:
&lt;code&gt;agents-exe run&lt;/code&gt; and the TUI’s own loop run tools in-process.
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="mcp-over-http"&gt;MCP over HTTP&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;POST /mcp&lt;/code&gt; serves the agents to MCP clients over the
&lt;a href="https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http"&gt;Streamable HTTP transport&lt;/a&gt;.
Point a client at &lt;code&gt;http://127.0.0.1:8080/mcp&lt;/code&gt;; with &lt;code&gt;--auth-tokens&lt;/code&gt;, it must
send the same bearer token as REST clients.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each root agent is one tool, &lt;code&gt;ask_&amp;lt;slug&amp;gt;&lt;/code&gt;, with a single string argument
&lt;code&gt;prompt&lt;/code&gt;. Parameters for the session that call creates can be set with
&lt;code&gt;Agents-Param-&amp;lt;name&amp;gt;&lt;/code&gt; headers or &lt;code&gt;_meta&lt;/code&gt; — see
&lt;a href="#setting-parameters-over-mcp"&gt;Setting parameters over MCP&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;A call creates a session, owned by the caller, and waits for its run (up to
120 seconds). The result is the agent’s final answer. &lt;code&gt;_meta.session_id&lt;/code&gt;
names the session, which is also visible through the REST API.
&lt;/li&gt;
&lt;li&gt;If the run stops on deferred tool calls, the result (not an error) says
so and lists the pending calls with their continuation tokens: complete
them through &lt;code&gt;POST /v1/continuations/:token&lt;/code&gt;. If the run is still going when
the wait ends, the result gives the session id to follow.
&lt;/li&gt;
&lt;li&gt;A failed run returns a result with &lt;code&gt;isError: true&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;A body that is not a JSON-RPC message, or an empty batch, answers &lt;code&gt;400&lt;/code&gt;
with a JSON-RPC error (&lt;code&gt;-32700&lt;/code&gt;, &lt;code&gt;-32600&lt;/code&gt;). An unknown method answers
&lt;code&gt;-32601&lt;/code&gt;, and an unknown tool or bad arguments &lt;code&gt;-32602&lt;/code&gt;, both inside a
&lt;code&gt;200&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Every request gets a plain JSON response. Notifications answer &lt;code&gt;202&lt;/code&gt;.
The server sends no requests or notifications of its own, so &lt;code&gt;GET /mcp&lt;/code&gt;
answers &lt;code&gt;405&lt;/code&gt;. MCP sessions (&lt;code&gt;Mcp-Session-Id&lt;/code&gt;) are not used.
&lt;/li&gt;
&lt;li&gt;Supported protocol versions: &lt;code&gt;2025-06-18&lt;/code&gt;, &lt;code&gt;2025-03-26&lt;/code&gt;, &lt;code&gt;2024-11-05&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the stdio MCP server that runs agents without storing sessions, see
&lt;a href="/agents-exe/docs-mcp.html"&gt;mcp.md&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="restarts-and-shutdown"&gt;Restarts and shutdown&lt;/h3&gt;
&lt;p&gt;On &lt;code&gt;SIGTERM&lt;/code&gt; or &lt;code&gt;SIGINT&lt;/code&gt;, the server:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;stops accepting connections;
&lt;/li&gt;
&lt;li&gt;ends event streams and answers waiting requests with the current state;
&lt;/li&gt;
&lt;li&gt;gives other open requests the grace period (&lt;code&gt;--shutdown-grace&lt;/code&gt;);
&lt;/li&gt;
&lt;li&gt;cancels active runs, storing their sessions;
&lt;/li&gt;
&lt;li&gt;closes the database.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On start, sessions left &lt;code&gt;running&lt;/code&gt; by a crash are stored with the status their
turns imply. Their interrupted step is lost, and background tool calls they
were running are reported to the LLM as orphaned on the next run. Nothing is
resumed automatically: &lt;code&gt;resume&lt;/code&gt; them.&lt;/p&gt;
&lt;p&gt;One exception is decided at startup rather than on the next run: when such a
session’s agent has a required parameter with no value left (a secret
&lt;code&gt;session&lt;/code&gt;-scope value is memory-only, so the restart lost it), its running
calls are failed right away with a message naming the parameters, the
session’s &lt;code&gt;status_detail&lt;/code&gt; reads &lt;code&gt;params_required: &amp;lt;names&amp;gt;&lt;/code&gt;, and the log
carries a &lt;code&gt;sessions.params_required&lt;/code&gt; line. A &lt;code&gt;resume&lt;/code&gt; or message without
those &lt;code&gt;params&lt;/code&gt; is refused with &lt;code&gt;422 params_required&lt;/code&gt;; one that carries them
goes on, and the LLM sees why the calls failed. Non-secret session values
are stored with the session and need no resupply.&lt;/p&gt;
&lt;p&gt;Background tool calls (&lt;code&gt;runAsync&lt;/code&gt;) live in the server process. They survive
between runs of a session, but not a restart. A session is not dropped at
the TTL while one of its background calls is still running: it is kept until
they finish. Deferred calls are the durable kind:
their tokens stay valid across restarts.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="running-as-a-service"&gt;Running as a service&lt;/h3&gt;
&lt;p&gt;Both &lt;code&gt;agents-server&lt;/code&gt; and &lt;code&gt;agents-exe serve&lt;/code&gt; are already service-ready: every
path either needs is a flag, they log JSON lines on stderr (see
&lt;a href="#logs"&gt;Logs&lt;/a&gt; below), &lt;code&gt;SIGTERM&lt;/code&gt;/&lt;code&gt;SIGINT&lt;/code&gt; trigger the graceful shutdown
described above (&lt;code&gt;--shutdown-grace&lt;/code&gt; bounds it), and &lt;code&gt;recoverOnStartup&lt;/code&gt; runs
before the first request is accepted. A &lt;code&gt;systemd&lt;/code&gt; unit only needs to point
one at the right files and restart it on crash.&lt;/p&gt;
&lt;p&gt;Ready-made units live in &lt;code&gt;bundling/systemd/&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agents-server.service&lt;/code&gt;: the system-wide unit below, for &lt;code&gt;agents-server&lt;/code&gt;.
&lt;code&gt;sudo install -Dm644 bundling/systemd/agents-server.service /etc/systemd/system/agents-server.service&lt;/code&gt;,
edit the paths, then &lt;code&gt;systemctl daemon-reload&lt;/code&gt; and &lt;code&gt;enable --now&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents-server.user.service&lt;/code&gt;: a per-user unit that also listens on
&lt;code&gt;$XDG_RUNTIME_DIR/agents-server.sock&lt;/code&gt; (&lt;code&gt;--socket&lt;/code&gt;). &lt;code&gt;install -Dm644 bundling/systemd/agents-server.user.service ~/.config/systemd/user/agents-server.service&lt;/code&gt;,
put &lt;code&gt;agent.json&lt;/code&gt; and &lt;code&gt;keys.json&lt;/code&gt; in &lt;code&gt;~/.config/agents-server/&lt;/code&gt;, and the
binary at &lt;code&gt;~/.local/bin/agents-server&lt;/code&gt;, then &lt;code&gt;systemctl --user daemon-reload&lt;/code&gt;
and &lt;code&gt;systemctl --user enable --now agents-server&lt;/code&gt;. The server creates and
owns its socket (it does not use systemd socket activation), so this is a
plain service, not a &lt;code&gt;.socket&lt;/code&gt; unit.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Create a user and directories for its state, put the agent files, API keys
and token file somewhere readable, and write a unit. This one uses
&lt;code&gt;agents-exe serve&lt;/code&gt;, so agents-exe.cfg.json in &lt;code&gt;WorkingDirectory&lt;/code&gt; can carry
the agent files instead of repeating &lt;code&gt;--agent-file&lt;/code&gt;; &lt;code&gt;agents-server&lt;/code&gt; works
the same way with &lt;code&gt;ExecStart=/usr/local/bin/agents-server&lt;/code&gt; and the agent
files always on the command line:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ini"&gt;# /etc/systemd/system/agents-server.service
[Unit]
Description=agents-server
After=network.target

[Service]
Type=simple
User=agents-server
Group=agents-server
ExecStart=/usr/local/bin/agents-exe serve \
    --agent-file /etc/agents-server/weather.json \
    --api-keys /etc/agents-server/keys.json \
    --db /var/lib/agents-server/agents.db \
    --bind 127.0.0.1 \
    --port 8080 \
    --auth-tokens /etc/agents-server/tokens.json \
    --shutdown-grace 10
Restart=on-failure
RestartSec=2
# The database directory must exist and be writable before the first start.
StateDirectory=agents-server
WorkingDirectory=/var/lib/agents-server

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;sudo&lt;/span&gt; systemctl daemon-reload&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;sudo&lt;/span&gt; systemctl enable &lt;span class="at"&gt;--now&lt;/span&gt; agents-server&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--bind 127.0.0.1&lt;/code&gt; keeps the service off the network; put a reverse proxy
(for TLS, or to publish it beyond this machine) in front of it, or add
&lt;code&gt;--cors-origin&lt;/code&gt; if a browser page on another origin on this machine needs
to reach it directly (see &lt;a href="#authentication"&gt;Authentication&lt;/a&gt;).
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--auth-tokens&lt;/code&gt; is strongly recommended for anything not strictly
loopback-only: see the warning at the top of this document.
&lt;/li&gt;
&lt;li&gt;The server writes one JSON object per line to stderr, with no other output
on stdout; under &lt;code&gt;systemd&lt;/code&gt; that means &lt;code&gt;journalctl -u agents-server -f&lt;/code&gt;
shows the log stream directly, one JSON line per entry, without extra
timestamps or framing getting in the way of &lt;code&gt;jq&lt;/code&gt;. &lt;code&gt;journalctl -u agents-server -o cat | jq .&lt;/code&gt; is a convenient way to filter it.
&lt;/li&gt;
&lt;li&gt;On &lt;code&gt;sudo systemctl stop agents-server&lt;/code&gt; (or a redeploy), &lt;code&gt;systemd&lt;/code&gt; sends
&lt;code&gt;SIGTERM&lt;/code&gt;: the server stops accepting new connections, ends event streams,
answers waiting requests with their current state, and gives other open
requests up to &lt;code&gt;--shutdown-grace&lt;/code&gt; seconds before it cancels active runs
(storing their sessions) and exits. Set &lt;code&gt;TimeoutStopSec&lt;/code&gt; in the unit at
least a few seconds above &lt;code&gt;--shutdown-grace&lt;/code&gt;, or &lt;code&gt;systemd&lt;/code&gt; may &lt;code&gt;SIGKILL&lt;/code&gt;
the process before the grace period elapses.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Restart=on-failure&lt;/code&gt; restarts the service if it exits non-zero (for
example, a database it cannot open); it does not restart on a clean
&lt;code&gt;systemctl stop&lt;/code&gt;. &lt;code&gt;recoverOnStartup&lt;/code&gt; then picks up sessions a crash left
&lt;code&gt;running&lt;/code&gt;, as described above.
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3 id="logs"&gt;Logs&lt;/h3&gt;
&lt;p&gt;The server writes one JSON object per line on stderr, with &lt;code&gt;ts&lt;/code&gt;, &lt;code&gt;kind&lt;/code&gt;,
and, when known, &lt;code&gt;session_id&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;&lt;code&gt;kind&lt;/code&gt;&lt;/th&gt;&lt;th&gt;Fields&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;server.started&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bind&lt;/code&gt;, &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;agents&lt;/code&gt;, &lt;code&gt;admin_owners&lt;/code&gt;, &lt;code&gt;database&lt;/code&gt;, &lt;code&gt;authentication&lt;/code&gt; (&lt;code&gt;bearer&lt;/code&gt; or &lt;code&gt;none&lt;/code&gt;), &lt;code&gt;ui&lt;/code&gt;, and &lt;code&gt;warning&lt;/code&gt; when authentication is off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;http.request&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;method&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;ms&lt;/code&gt; (when the response starts)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;run.started&lt;/code&gt;, &lt;code&gt;session.updated&lt;/code&gt;, &lt;code&gt;calls.deferred&lt;/code&gt;, &lt;code&gt;run.stopped&lt;/code&gt;, &lt;code&gt;session.failed&lt;/code&gt;, &lt;code&gt;tool.started&lt;/code&gt;, &lt;code&gt;tool.completed&lt;/code&gt;, &lt;code&gt;tool.progressed&lt;/code&gt;, &lt;code&gt;subcall.started&lt;/code&gt;, &lt;code&gt;subcall.completed&lt;/code&gt;, &lt;code&gt;subcall.failed&lt;/code&gt;, &lt;code&gt;session.created&lt;/code&gt;, &lt;code&gt;session.deleted&lt;/code&gt;, &lt;code&gt;hook.failed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;session_id&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;llm.request&lt;/code&gt; / &lt;code&gt;llm.response&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;, token counts&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;llm.http&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;method&lt;/code&gt;, &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sessions.recovered&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;session_ids&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sessions.params_required&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;session_id&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;: a recovered session whose running calls were failed because these required parameters are no longer bound&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agents.stored_skipped&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;slug&lt;/code&gt;, &lt;code&gt;reason&lt;/code&gt;: a stored agent hidden by an agent file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;agent_tree&lt;/code&gt;, &lt;code&gt;tool&lt;/code&gt;, &lt;code&gt;tool.portal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;event&lt;/code&gt;: what the agent loader and the tools reported&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;llm.backoff&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;attempt&lt;/code&gt;, &lt;code&gt;delay_seconds&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;server.signal&lt;/code&gt;, &lt;code&gt;server.stopping&lt;/code&gt;, &lt;code&gt;server.stopped&lt;/code&gt;, &lt;code&gt;server.failed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Prompts, LLM payloads, HTTP headers, and API keys are never logged.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="embedding-the-runner-in-your-own-program"&gt;Embedding the runner in your own program&lt;/h3&gt;
&lt;p&gt;The server is a thin layer over two library modules, which a Haskell
program can use directly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Host.withHost&lt;/code&gt; loads agent files and opens the database.
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.Host.Runner&lt;/code&gt; provides &lt;code&gt;createSession&lt;/code&gt;, &lt;code&gt;postMessage&lt;/code&gt;,
&lt;code&gt;resume&lt;/code&gt;, &lt;code&gt;completeCall&lt;/code&gt;, &lt;code&gt;cancelRun&lt;/code&gt;, &lt;code&gt;awaitRun&lt;/code&gt;, &lt;code&gt;deleteSession&lt;/code&gt;, and
&lt;code&gt;subscribe&lt;/code&gt; / &lt;code&gt;subscribeSTM&lt;/code&gt; for events.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;{-# LANGUAGE OverloadedRecordDot #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Prod.Tracer&lt;/span&gt; (silent)&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Host&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Host.Runner&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.SessionStore&lt;/span&gt; (&lt;span class="dt"&gt;SessionMeta&lt;/span&gt; (&lt;span class="op"&gt;..&lt;/span&gt;))&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;main ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;main &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; cfg &lt;span class="ot"&gt;=&lt;/span&gt; defaultHostConfig [&lt;span class="st"&gt;&amp;quot;weather.json&amp;quot;&lt;/span&gt;] &lt;span class="st"&gt;&amp;quot;keys.json&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;agents.db&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    withHost cfg silent &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;host &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="13"&gt;&lt;a href="#13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        withSessionRunner host &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;runner &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="14"&gt;&lt;a href="#14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;Right&lt;/span&gt; meta &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createSession runner &lt;span class="st"&gt;&amp;quot;weather&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;NewMessage&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Weather in Paris?&amp;quot;&lt;/span&gt; []) (&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;UntilBlocked&lt;/span&gt;)&lt;/span&gt;
&lt;span id="15"&gt;&lt;a href="#15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="dt"&gt;Right&lt;/span&gt; (stopped, _) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; awaitRun runner meta&lt;span class="op"&gt;.&lt;/span&gt;smSessionId &lt;span class="dv"&gt;120&lt;/span&gt;&lt;/span&gt;
&lt;span id="16"&gt;&lt;a href="#16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;print&lt;/span&gt; stopped&lt;span class="op"&gt;.&lt;/span&gt;smStatus&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The HTTP layer itself is in &lt;code&gt;examples/agents-server/src/AgentsServer/Api.hs&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="clients"&gt;Clients&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;System.Agents.Host.Client&lt;/code&gt; (&lt;code&gt;todos/os-as-standalone-server.md&lt;/code&gt; Phase 3a)
gives the same operations as a &lt;code&gt;RunnerClient&lt;/code&gt;: one &lt;code&gt;Command&lt;/code&gt; in, one
&lt;code&gt;Reply&lt;/code&gt; (or a &lt;code&gt;RunnerError&lt;/code&gt;) out, plus a live event feed, instead of a
bag of separate &lt;code&gt;SessionRunner&lt;/code&gt; functions. &lt;code&gt;System.Agents.Protocol&lt;/code&gt; owns
the &lt;code&gt;Command&lt;/code&gt;/&lt;code&gt;Reply&lt;/code&gt; sum types and their JSON, so a future HTTP or Unix
socket client can speak the same wire shape &lt;code&gt;inProcessClient&lt;/code&gt; already
dispatches in-process:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;RunnerClient&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;RunnerClient&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; rcCommand   ::&lt;/span&gt; &lt;span class="dt"&gt;Command&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;RunnerError&lt;/span&gt; &lt;span class="dt"&gt;Reply&lt;/span&gt;)&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; rcSubscribe ::&lt;/span&gt; &lt;span class="dt"&gt;SubscribeScope&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;EventSeq&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ReplayUnavailable&lt;/span&gt; &lt;span class="dt"&gt;Subscription&lt;/span&gt;)&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;inProcessClient ::&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;SessionRunner&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;RunnerClient&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;Maybe Text&lt;/code&gt; is the client’s own identity (an owner, or &lt;code&gt;Nothing&lt;/code&gt;),
used for &lt;code&gt;CreateSession&lt;/code&gt;, &lt;code&gt;SpawnSession&lt;/code&gt;, &lt;code&gt;SendMail&lt;/code&gt; and &lt;code&gt;ForkSession&lt;/code&gt; –
a &lt;code&gt;Command&lt;/code&gt; never carries a caller-asserted owner of its own to trust.
&lt;code&gt;System.Agents.Host.Client&lt;/code&gt; also has a typed helper per operation
(&lt;code&gt;createSession&lt;/code&gt;, &lt;code&gt;postMessage&lt;/code&gt;, &lt;code&gt;resumeSession&lt;/code&gt;, &lt;code&gt;completeCall&lt;/code&gt;,
&lt;code&gt;cancelRun&lt;/code&gt;, &lt;code&gt;cancelAttachedCalls&lt;/code&gt;, &lt;code&gt;pauseSession&lt;/code&gt;, &lt;code&gt;sendMail&lt;/code&gt;, &lt;code&gt;listMail&lt;/code&gt;,
&lt;code&gt;forkSession&lt;/code&gt;, &lt;code&gt;listSessions&lt;/code&gt;, &lt;code&gt;getSession&lt;/code&gt;, &lt;code&gt;listAgents&lt;/code&gt;, &lt;code&gt;getAgent&lt;/code&gt;,
&lt;code&gt;deleteSession&lt;/code&gt;, &lt;code&gt;awaitRun&lt;/code&gt;, &lt;code&gt;stats&lt;/code&gt;, &lt;code&gt;subscribeAll&lt;/code&gt;) that builds the
&lt;code&gt;Command&lt;/code&gt; and unwraps the expected &lt;code&gt;Reply&lt;/code&gt;, failing with &lt;code&gt;UnexpectedReply&lt;/code&gt;
(code &lt;code&gt;unexpected_reply&lt;/code&gt;) on a mismatch – which only a bug in a
&lt;code&gt;RunnerClient&lt;/code&gt; implementation can provoke, &lt;code&gt;inProcessClient&lt;/code&gt;’s dispatch
being total over every &lt;code&gt;Command&lt;/code&gt; constructor:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Host.Client&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;main ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;main &lt;span class="ot"&gt;=&lt;/span&gt; withHost cfg silent &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;host &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; withSessionRunner host &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="op"&gt;\&lt;/span&gt;runner &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; client &lt;span class="ot"&gt;=&lt;/span&gt; inProcessClient &lt;span class="dt"&gt;Nothing&lt;/span&gt; runner&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Right&lt;/span&gt; meta &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createSession client &lt;span class="st"&gt;&amp;quot;weather&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;Just&lt;/span&gt; (&lt;span class="dt"&gt;NewMessage&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Weather in Paris?&amp;quot;&lt;/span&gt; [] &lt;span class="dt"&gt;False&lt;/span&gt;)) (&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;UntilBlocked&lt;/span&gt;) &lt;span class="fu"&gt;mempty&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Right&lt;/span&gt; (stopped, _) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; awaitRun client meta&lt;span class="op"&gt;.&lt;/span&gt;smSessionId &lt;span class="dv"&gt;120&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;print&lt;/span&gt; stopped&lt;span class="op"&gt;.&lt;/span&gt;smStatus&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;System.Agents.Host.Client.Http.httpClient&lt;/code&gt; is the second implementation:
the same &lt;code&gt;RunnerClient&lt;/code&gt; over this server’s HTTP API, so the program above
runs unchanged against a server started elsewhere:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;System.Agents.Host.Client.Http&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;main ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;main &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    endpoint &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;either&lt;/span&gt; &lt;span class="fu"&gt;fail&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (parseEndpoint &lt;span class="st"&gt;&amp;quot;http://127.0.0.1:8080&amp;quot;&lt;/span&gt;)  &lt;span class="co"&gt;-- or &amp;quot;unix:///run/agents.sock&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    client &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; httpClient (defaultHttpClientConfig endpoint){hccToken &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;alice-token&amp;quot;&lt;/span&gt;}&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Right&lt;/span&gt; meta &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; createSession client &lt;span class="st"&gt;&amp;quot;weather&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;Just&lt;/span&gt; (&lt;span class="dt"&gt;NewMessage&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Weather in Paris?&amp;quot;&lt;/span&gt; [] &lt;span class="dt"&gt;False&lt;/span&gt;)) (&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;UntilBlocked&lt;/span&gt;) &lt;span class="fu"&gt;mempty&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Right&lt;/span&gt; (stopped, _) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; awaitRun client meta&lt;span class="op"&gt;.&lt;/span&gt;smSessionId &lt;span class="dv"&gt;120&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;print&lt;/span&gt; stopped&lt;span class="op"&gt;.&lt;/span&gt;smStatus&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Each &lt;code&gt;Command&lt;/code&gt; maps onto one route of the table above (&lt;code&gt;SpawnSession&lt;/code&gt; and
&lt;code&gt;createSessionAsChild&lt;/code&gt; onto &lt;code&gt;POST /v1/sessions&lt;/code&gt; with &lt;code&gt;parent&lt;/code&gt;, &lt;code&gt;AwaitRun&lt;/code&gt;
onto &lt;code&gt;GET /v1/sessions/:id?wait=true&lt;/code&gt;, &lt;code&gt;Stats&lt;/code&gt; onto &lt;code&gt;/healthz&lt;/code&gt;,
&lt;code&gt;ListSessions&lt;/code&gt; onto as many &lt;code&gt;GET /v1/sessions&lt;/code&gt; pages as its &lt;code&gt;limit&lt;/code&gt; needs).
An error answer decodes into the &lt;code&gt;RunnerError&lt;/code&gt; its code names, with the
session, token, agent or turn the command named put back; one that is not
a runner error (&lt;code&gt;unauthorized&lt;/code&gt;, &lt;code&gt;bad_request&lt;/code&gt;, …), a connection failure,
or an undecodable answer is &lt;code&gt;TransportError&lt;/code&gt; (code &lt;code&gt;transport_error&lt;/code&gt;).
&lt;code&gt;rcSubscribe&lt;/code&gt; follows &lt;code&gt;GET /v1/events&lt;/code&gt; (or one session’s stream), answers
&lt;code&gt;ReplayUnavailable&lt;/code&gt; from the &lt;code&gt;Agents-Replay&lt;/code&gt; header exactly when the
in-process runner would, and reconnects a dropped or stalled stream on its
own with &lt;code&gt;Last-Event-ID&lt;/code&gt;, never delivering an event twice. &lt;code&gt;AllSessions&lt;/code&gt;
falls back to &lt;code&gt;scope=owner&lt;/code&gt; when the server refuses &lt;code&gt;scope=all&lt;/code&gt; (a
non-admin token). The token goes in &lt;code&gt;Authorization&lt;/code&gt; on commands and in
&lt;code&gt;?access_token=&lt;/code&gt; on streams.&lt;/p&gt;
&lt;h3 id="not-yet-supported"&gt;Not yet supported&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Tool isolation by default, and for every tool kind: it is opt-in
(&lt;code&gt;--isolate-tools&lt;/code&gt;), covers bash and MCP tools only, and needs a worker
you provide. See &lt;a href="#isolating-tool-calls"&gt;Isolating tool calls&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;Issuing or rotating per-owner API keys over the API: the files are read
at startup.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;code&gt;todos/web-server-embedding.md&lt;/code&gt; for the design and the planned work.&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-agents-server.html" rel="alternate"/><summary type="text">`agents-server` runs agents as a long-lived HTTP service. Sessions live in a SQLite database rather than in files, so a web application can start conversations, follow them live, complete deferred tool calls from its own workers, and pick s</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs-MIGRATION-GUIDE.html</id><title type="text">Migration Guide</title><updated>2026-10-04T15:53:54Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;p&gt;&lt;em&gt;Generated from &lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/documentation/MIGRATION-GUIDE.md"&gt;&lt;code&gt;documentation/MIGRATION-GUIDE.md&lt;/code&gt;&lt;/a&gt;, the repository is the canonical source and may be ahead of this page.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="migration-guide"&gt;Migration Guide&lt;/h2&gt;
&lt;p&gt;The migration from Runtime-per-agent to OS-native ECS architecture is &lt;strong&gt;COMPLETE&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="status"&gt;Status&lt;/h3&gt;
&lt;p&gt;All legacy Runtime code has been removed. The system now uses OS-native structures exclusively.&lt;/p&gt;
&lt;h3 id="migration-complete"&gt;Migration Complete&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1 (Dual Mode): COMPLETE
&lt;/li&gt;
&lt;li&gt;Phase 2+ (New-Only): COMPLETE
&lt;/li&gt;
&lt;li&gt;Final Phase (Cleanup): COMPLETE
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="current-architecture"&gt;Current Architecture&lt;/h3&gt;
&lt;p&gt;The system now uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;System.Agents.OS.Core&lt;/code&gt; - ECS world and components
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.OS.Agents&lt;/code&gt; - OS-native agent management
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.Agents.AgentTree&lt;/code&gt; - OS-native agent tree loading
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;code&gt;documentation/OS-API.md&lt;/code&gt; for the complete API reference.&lt;/p&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs-MIGRATION-GUIDE.html" rel="alternate"/><summary type="text">The migration from Runtime-per-agent to OS-native ECS architecture is **COMPLETE**. ## Status All legacy Runtime code has been removed. The system now uses OS-native structures exclusively. ## Migration Complete - Phase 1 (Dual Mode): COMPL</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/comparison.html</id><title type="text">How agents-exe compares</title><updated>2026-10-03T12:00:00Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;h2 id="how-agents-exe-compares"&gt;How agents-exe compares&lt;/h2&gt;
&lt;p&gt;This page puts agents-exe next to five agent frameworks people are likely
to be choosing between: LangGraph, AutoGen, the OpenAI Agents SDK, the
Claude Agent SDK and CrewAI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read this first.&lt;/strong&gt; It is a draft. What it says about agents-exe was
checked against the code or by running it. What it says about the other
five comes only from their own documentation, read on 2026-10-03 and linked
under &lt;a href="#sources"&gt;Sources&lt;/a&gt;; none of them was installed or run for this page.
There are no benchmarks here, and no claim that one is faster, cheaper or
better than another. A cell that says “not checked” means exactly that, not
“missing”. Which frameworks belong on this page, and on which axes, is
still an open choice; corrections are welcome as
&lt;a href="https://github.com/lucasdicioccio/agents-exe/issues"&gt;issues&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="what-agents-exe-is"&gt;What agents-exe is&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A command-line program, configured with files.&lt;/strong&gt; An agent is a JSON
file: an endpoint, a model, a system prompt, tools, helper agents. There
is no Python or TypeScript API; the library underneath is Haskell.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools are programs.&lt;/strong&gt; Any executable that answers &lt;code&gt;describe&lt;/code&gt; and &lt;code&gt;run&lt;/code&gt;
is a tool, whatever language it is written in. MCP servers, OpenAPI
documents and a few builtin toolboxes (SQLite, system information, Lua)
are tools too.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Helper agents are tools as well.&lt;/strong&gt; A root agent calls a helper the way
it calls a tool, and helpers can have helpers.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One agent file, several ways to run it:&lt;/strong&gt; a one-shot command, a
terminal UI, a stdio MCP server, or an HTTP server with a chat page.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sessions are stored.&lt;/strong&gt; As JSON files for the command line, in SQLite or
PostgreSQL for the server; a session can stop on a tool call that waits
for an outside answer and be resumed later.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-hosted.&lt;/strong&gt; It talks to the model endpoint you give it; there is no
agents-exe service. Apache-2.0.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href="/agents-exe/demo.html"&gt;demo&lt;/a&gt; shows several of these at once.&lt;/p&gt;
&lt;h3 id="what-it-is-not"&gt;What it is not&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Not a library for a Python or TypeScript application: if you want to
build agents as code inside such an application, the five frameworks
below are made for that and agents-exe is not.
&lt;/li&gt;
&lt;li&gt;Not tied to one model vendor, and not a client for every vendor’s native
API either: models are reached through OpenAI-style chat-completions
endpoints (the README lists OpenAI, Mistral, Moonshot and Ollama as
working).
&lt;/li&gt;
&lt;li&gt;Not a hosted product: you run the binary and keep the database.
&lt;/li&gt;
&lt;li&gt;Not large: the commit history has a single author, and there is no
ecosystem of third-party integrations around it.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="side-by-side"&gt;Side by side&lt;/h3&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;In its own words&lt;/th&gt;&lt;th&gt;You use it from&lt;/th&gt;&lt;th&gt;State between turns and runs, as documented&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;agents-exe&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;"A handy LLM-agent tool, with a variety of calling and configuration modes"&lt;/td&gt;&lt;td&gt;the command line and JSON files; a Haskell library&lt;/td&gt;&lt;td&gt;session files; SQLite or PostgreSQL behind the server&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;LangGraph&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;"A low-level orchestration framework and runtime for building, managing, and deploying long-running, stateful agents."&lt;/td&gt;&lt;td&gt;Python; JavaScript/TypeScript&lt;/td&gt;&lt;td&gt;checkpointers: in-memory, SQLite, PostgreSQL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AutoGen&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;"A framework for building AI agents and applications."&lt;/td&gt;&lt;td&gt;Python; .NET&lt;/td&gt;&lt;td&gt;not checked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OpenAI Agents SDK&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;"agentic AI apps in a lightweight, easy-to-use package with very few abstractions"&lt;/td&gt;&lt;td&gt;Python; TypeScript&lt;/td&gt;&lt;td&gt;sessions, with SQLite, SQLAlchemy, Redis and other session stores in the documentation index&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Claude Agent SDK&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;"Build production AI agents with Claude Code as a library"&lt;/td&gt;&lt;td&gt;Python; TypeScript&lt;/td&gt;&lt;td&gt;sessions that can be resumed or forked; storage not checked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CrewAI&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;"The leading open-source framework for orchestrating autonomous AI agents and building complex workflows."&lt;/td&gt;&lt;td&gt;Python&lt;/td&gt;&lt;td&gt;Flows "persist data across steps and executions"; storage not checked&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;A few more facts from the same documentation pages, where they bear on the
choice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LangGraph&lt;/strong&gt; describes checkpointers as serving “conversation
continuity, human-in-the-loop workflows, time travel, and fault
tolerance”. That is the closest counterpart in this list to agents-exe’s
stored, resumable sessions, reached from code rather than from a
command line.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AutoGen&lt;/strong&gt; is layered: Core (“an event-driven programming framework for
building scalable multi-agent AI systems”), AgentChat on top of it, and
Studio, a web UI for prototyping without code.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenAI Agents SDK&lt;/strong&gt; names three primitives (agents, handoffs,
guardrails) and lists built-in tracing, human-in-the-loop and MCP tools.
It uses OpenAI’s Responses API by default and documents adapters for
other providers.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Claude Agent SDK&lt;/strong&gt; is “a library that runs the Claude Code binary”,
with Claude Code’s built-in tools (files, commands, web search), hooks,
subagents, MCP, permissions and sessions.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CrewAI&lt;/strong&gt; has two layers: Crews (“teams of autonomous agents”) and Flows
(“structured, event-driven workflows that manage state and control
execution”). Its repository calls it “a standalone Python framework”,
MIT-licensed.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-agents-exe-is-a-reasonable-pick"&gt;When agents-exe is a reasonable pick&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You would rather describe an agent in a file and give it shell scripts
as tools than write an application around a framework.
&lt;/li&gt;
&lt;li&gt;You want the same agent in a terminal, in an MCP client and behind HTTP
without rewriting it.
&lt;/li&gt;
&lt;li&gt;You want to keep sessions in your own SQLite file or PostgreSQL database,
and to run against a local model.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-pick-something-else"&gt;When to pick something else&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Your agents live inside a Python or TypeScript code base, or you need a
vendor’s native features (OpenAI’s tracing and voice, Claude Code’s
built-in tools and permissions).
&lt;/li&gt;
&lt;li&gt;You want a large ecosystem of integrations, tutorials and people to ask.
&lt;/li&gt;
&lt;li&gt;You need a hosted, managed runtime.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="sources"&gt;Sources&lt;/h3&gt;
&lt;p&gt;Read on 2026-10-03:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LangGraph: &lt;a href="https://docs.langchain.com/oss/python/langgraph/overview"&gt;overview&lt;/a&gt;,
&lt;a href="https://docs.langchain.com/oss/python/langgraph/persistence"&gt;persistence&lt;/a&gt;,
&lt;a href="https://docs.langchain.com/oss/javascript/langgraph/overview"&gt;JavaScript overview&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;AutoGen: &lt;a href="https://microsoft.github.io/autogen/stable/"&gt;documentation home&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;OpenAI Agents SDK: &lt;a href="https://openai.github.io/openai-agents-python/"&gt;Python documentation&lt;/a&gt;,
&lt;a href="https://openai.github.io/openai-agents-js/"&gt;TypeScript documentation&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;Claude Agent SDK: &lt;a href="https://code.claude.com/docs/en/agent-sdk/overview"&gt;overview&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;CrewAI: &lt;a href="https://docs.crewai.com/en/introduction"&gt;introduction&lt;/a&gt;,
&lt;a href="https://github.com/crewAIInc/crewAI"&gt;repository&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;agents-exe: this site, the
&lt;a href="https://github.com/lucasdicioccio/agents-exe"&gt;repository&lt;/a&gt;, and the
&lt;a href="/agents-exe/demo.html"&gt;demo&lt;/a&gt; for what was run.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/comparison.html" rel="alternate"/><summary type="text">What agents-exe is and is not, next to five other agent frameworks, from their own documentation. A draft: no benchmarks, and the choice of frameworks and axes is still open.</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/demo.html</id><title type="text">See it work: four agents on one screen</title><updated>2026-10-03T12:00:00Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;h2 id="see-it-work-four-agents-on-one-screen"&gt;See it work: four agents on one screen&lt;/h2&gt;
&lt;p&gt;One prompt, “Give me the tour.”, goes to a front-desk agent. It asks three
helper agents in the same turn; each helper runs a command-line tool of its
own and reports back; the desk writes the answer. While that happens,
&lt;code&gt;agents-exe spectate&lt;/code&gt; shows the four sessions and their tool calls live.&lt;/p&gt;
&lt;p&gt;Everything on this page was recorded on 2026-10-03 from a build of &lt;code&gt;main&lt;/code&gt;,
on a laptop, against a local model served by &lt;a href="https://ollama.com/"&gt;Ollama&lt;/a&gt;
(&lt;code&gt;gemma4:e4b&lt;/code&gt;). No hosted API and no real API key are involved, so you can
run the same thing; the agents are in
&lt;a href="https://github.com/lucasdicioccio/agents-exe/tree/main/demo-agents/repo-tour"&gt;&lt;code&gt;demo-agents/repo-tour/&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="the-screen-mid-run"&gt;The screen, mid-run&lt;/h3&gt;
&lt;p&gt;The two frames below are unedited text captures of the &lt;code&gt;spectate&lt;/code&gt; terminal
(100 columns by 24 rows), taken during one run.&lt;/p&gt;
&lt;p&gt;1 minute 46 seconds in: the historian has returned, the code counter and
the librarian are still working. Each helper is a session of its own, listed
under the session that called it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────── agents ─────────────────┐┌──────────── text: librarian (following) ────────────┐
│* repo-tour-desk  90669359  running 1m46s  ││                                                     │
│  - historian  326ce547  returned 18s      ││                                                     │
│  * code-counter  401bf8a5  running 1m07s  ││                                                     │
│  * librarian  fae942c5  running 1m07s     ││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
└───────────────────────────────────────────┘│                                                     │
┌──────────────── tool calls ───────────────┐│                                                     │
│* io_prompt_agent_code-counter  repo-tour-d││                                                     │
│* io_prompt_agent_librarian  repo-tour-desk││                                                     │
│- io_prompt_agent_historian  repo-tour-desk││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
│                                           ││                                                     │
└───────────────────────────────────────────┘└─────────────────────────────────────────────────────┘
 http://localhost:8765 | 3/4 sessions running | 2 tool calls | 27 events | up/down select, f follow,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3 minutes 49 seconds in: the three helpers have returned and the desk is
writing its answer, which streams into the right-hand pane.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────── agents ─────────────────┐┌────────── text: repo-tour-desk (following) ─────────┐
│* repo-tour-desk  90669359  running 3m49s  ││housing 66,172 lines.                                │
│  - historian  326ce547  returned 2m21s    ││*   **`test`**: Dedicated testing area with 55 files │
│  - code-counter  401bf8a5  returned 1m55s ││and 23,934 lines.                                    │
│  - librarian  fae942c5  returned 51s      ││*   **`examples`**: Includes 12 files and 5,188 lines│
│                                           ││for demonstration purposes.                          │
│                                           ││*   **`tui`**: Contains 29 files, totaling 8,234     │
│                                           ││lines.                                               │
│                                           ││*   Other areas include `agq` (6 files, 2,247 lines),│
│                                           ││`app`, `bench`, `postgres`, and `src`.               │
│                                           ││                                                     │
│                                           ││### 📜 Git History (Historian)
│                                           ││The repository has a robust development history      │
└───────────────────────────────────────────┘│spanning **722 commits**. Recent activity shows      │
┌──────────────── tool calls ───────────────┐│significant focus on improving stability and         │
│- io_prompt_agent_librarian  repo-tour-desk││capability:                                          │
│- io_prompt_agent_code-counter  repo-tour-d││*   **Key Focus:** Coordinating runs across servers  │
│- io_prompt_agent_historian  repo-tour-desk││on Postgres with a lease (2026-10-03) and adding a   │
│                                           ││read-only live dashboard called 'spectate'           │
│                                           ││(2026-10-03).                                        │
│                                           ││*   **Recent Upgrades:** The codebase has been       │
│                                           ││upgraded to                                          │
│───────────────────────────────────────────┘└─────────────────────────────────────────────────────┘
 http://localhost:8765 | 1/4 sessions running | 0 tool calls | 363 events | up/down select, f follow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(The border is broken on the line that holds an emoji, a wide character the
pane does not account for. It is left as captured.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Placeholder, not recorded yet:&lt;/strong&gt; an animated recording (asciinema or
GIF) of this run, and a screenshot of the interactive TUI
(&lt;code&gt;agents-exe tui&lt;/code&gt;), would show this better than still text frames.
Neither exists yet, and nothing on this page stands in for them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="the-agents"&gt;The agents&lt;/h3&gt;
&lt;p&gt;Four JSON files and three shell scripts:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Agent&lt;/th&gt;&lt;th&gt;File&lt;/th&gt;&lt;th&gt;Its tool&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;repo-tour-desk&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;desk.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;none of its own; three helpers under &lt;code&gt;extraAgents&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;code-counter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;code/agent.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;count_haskell&lt;/code&gt;: tracked &lt;code&gt;.hs&lt;/code&gt; files and lines, per directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;historian&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;history/agent.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;recent_commits&lt;/code&gt;: commit count and the latest non-merge commits&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;librarian&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;docs/agent.json&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;list_docs&lt;/code&gt;: the pages under &lt;code&gt;documentation/&lt;/code&gt; with their titles&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;A helper reaches the model as a function (&lt;code&gt;io_prompt_agent_&amp;lt;slug&amp;gt;&lt;/code&gt; in the
frames above), the same way a tool does; see &lt;a href="/agents-exe/docs-tools.html"&gt;tools&lt;/a&gt;. Each
tool is an executable that answers &lt;code&gt;describe&lt;/code&gt; with its interface and &lt;code&gt;run&lt;/code&gt;
with its output; see &lt;a href="/agents-exe/docs-binary-tool.html"&gt;executable tools&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="run-it-yourself"&gt;Run it yourself&lt;/h3&gt;
&lt;p&gt;You need &lt;code&gt;agents-exe&lt;/code&gt; built from the repository
(&lt;a href="/agents-exe/getting-started.html"&gt;getting started&lt;/a&gt;), Ollama running locally, and the
model (&lt;code&gt;ollama pull gemma4:e4b&lt;/code&gt;). Another model that your Ollama serves and
that supports tool calls may work if you change &lt;code&gt;modelName&lt;/code&gt; in the four JSON
files; only &lt;code&gt;gemma4:e4b&lt;/code&gt; was tried for this page. Run from the root of the
repository: the tools describe the repository in the current directory, and
the helpers’ tool directories are given relative to it.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;# one shot: the answer on stdout
agents-exe --api-keys demo-agents/repo-tour/keys.json \
  --agent-file demo-agents/repo-tour/desk.json \
  run --prompt &amp;quot;Give me the tour.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;keys.json&lt;/code&gt; holds a dummy key: Ollama does not check it, and agents-exe
looks one up for each agent’s &lt;code&gt;apiKeyId&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To watch it as above, use three terminals:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;# 1. a server, with sessions in a SQLite file
agents-exe --api-keys demo-agents/repo-tour/keys.json \
  --agent-file demo-agents/repo-tour/desk.json \
  serve --db /tmp/repo-tour.db --port 8765 --stream-tokens

# 2. the read-only dashboard
agents-exe spectate --attach http://localhost:8765

# 3. start a session
curl -s -X POST localhost:8765/v1/sessions \
  -d '{&amp;quot;agent&amp;quot;: &amp;quot;repo-tour-desk&amp;quot;, &amp;quot;prompt&amp;quot;: &amp;quot;Give me the tour.&amp;quot;}'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The server has no authentication unless you give it &lt;code&gt;--auth-tokens&lt;/code&gt;, and
binds to &lt;code&gt;127.0.0.1&lt;/code&gt; by default; see
&lt;a href="/agents-exe/docs-agents-server.html"&gt;agents-server&lt;/a&gt; before exposing it.&lt;/p&gt;
&lt;h3 id="what-the-recorded-run-did"&gt;What the recorded run did&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The desk’s first turn asked for the three helpers in one go; the server
created three child sessions, each linked to the desk’s session as its
parent.
&lt;/li&gt;
&lt;li&gt;The run took 4 minutes 15 seconds from the session’s creation to its last
update. That is the pace of an 8-billion-parameter model on a laptop, with
the three helpers sharing one Ollama. It says nothing about agents-exe
with a hosted model, which was not measured.
&lt;/li&gt;
&lt;li&gt;After the server was stopped and started again on the same database file,
&lt;code&gt;GET /v1/sessions&lt;/code&gt; still listed the four sessions with their parent links.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The desk’s answer, verbatim:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Welcome to the tour of the repository! I've gathered information from our specialists on the codebase, history, and documentation to give you a comprehensive overview.

### 💻 Codebase Structure (Code Counter)
The repository is quite large and complex, containing a total of **290 Haskell files** and approximately **109,118 lines of code**. The code is distributed across several specialized sections:
*   **`src`**: The core logic hub with 184 files, housing 66,172 lines.
*   **`test`**: Dedicated testing area with 55 files and 23,934 lines.
*   **`examples`**: Includes 12 files and 5,188 lines for demonstration purposes.
*   **`tui`**: Contains 29 files, totaling 8,234 lines.
*   Other areas include `agq` (6 files, 2,247 lines), `app`, `bench`, `postgres`, and `src`.

### 📜 Git History (Historian)
The repository has a robust development history spanning **722 commits**. Recent activity shows significant focus on improving stability and capability:
*   **Key Focus:** Coordinating runs across servers on Postgres with a lease (2026-10-03) and adding a read-only live dashboard called 'spectate' (2026-10-03).
*   **Recent Upgrades:** The codebase has been upgraded to GHC 9.10.3 and the 'topicgraph' module was updated (2026-09-28).
*   **Pattern:** There is consistent activity related to systemd units and API documentation over the past week.

### 📚 Documentation (Librarian)
The documentation is extensive and well-structured, covering the entire lifecycle of the Agents Framework. It is organized by architectural components and usage guides.
*   **Core Topics:** The docs cover system architecture, agent lifecycle (sessions, durable workflows), and tool integration. Specific guides are available for handling state (OS Model API), multi-agent interactions, and advanced workflows (SQQ agent flow/DAG).
*   **Getting Started Guide:** You should begin with `documentation/README.md` for a high-level overview.
*   **How to Use:** For integration, consult the material on `tools.md` and `binary-tool.md`. For stateful processes, refer to `durable-workflows-howto.md`.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The file and line counts, the commit count and the commit subjects match
what the three tools print. The prose around them is a small model’s: it
lists &lt;code&gt;src&lt;/code&gt; twice, and its “Pattern” line is its own reading of two commit
subjects. The mechanics shown above do not depend on the model.&lt;/p&gt;
&lt;h3 id="where-next"&gt;Where next&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-tui.html"&gt;The TUI&lt;/a&gt;, and the
&lt;a href="/agents-exe/docs-cli-commands.html"&gt;CLI reference&lt;/a&gt;, which documents &lt;code&gt;spectate&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-agents-server.html"&gt;agents-server&lt;/a&gt;: the HTTP API used in step 3,
the event stream &lt;code&gt;spectate&lt;/code&gt; follows, and sub-agents as sessions.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/comparison.html"&gt;How agents-exe compares&lt;/a&gt; with other agent frameworks.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/demo.html" rel="alternate"/><summary type="text">A root agent asks three helper agents at once, each runs its own tool, and a read-only dashboard shows all four sessions while they work. Recorded on a laptop with a local model, and reproducible from the repository.</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/docs.html</id><title type="text">Docs</title><updated>2026-09-25T12:00:00Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;h2 id="docs"&gt;Docs&lt;/h2&gt;
&lt;p&gt;These pages are generated straight from the &lt;code&gt;documentation/&lt;/code&gt; directory of the
&lt;a href="https://github.com/lucasdicioccio/agents-exe/tree/main/documentation"&gt;agents-exe repository&lt;/a&gt;:
the repository is always the canonical source, and may be ahead of what is
published here.&lt;/p&gt;
&lt;p&gt;The map below shows how the documents and the modules they describe relate,
to help you choose where to start.&lt;/p&gt;
&lt;p&gt;&lt;img src="/agents-exe/gen/images/module-docs-graph.dot.png" alt="How the guides relate to each other and to the modules they describe" /&gt;&lt;/p&gt;
&lt;h3 id="using-agents-exe"&gt;Using agents-exe&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/commands.html"&gt;&lt;strong&gt;Command reference&lt;/strong&gt;&lt;/a&gt;: the global options and every
command, from the README.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-cli-commands.html"&gt;&lt;strong&gt;CLI reference&lt;/strong&gt;&lt;/a&gt;: the same commands in
depth, with their options and examples.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-advanced-configuration.html"&gt;&lt;strong&gt;Advanced configuration&lt;/strong&gt;&lt;/a&gt;:
&lt;code&gt;agents-exe.cfg.json&lt;/code&gt;, agent directories, and per-project settings.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-tui.html"&gt;&lt;strong&gt;The TUI&lt;/strong&gt;&lt;/a&gt;: the terminal UI.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-agents-server.html"&gt;&lt;strong&gt;agents-server&lt;/strong&gt;&lt;/a&gt;: agents over HTTP, durable
sessions, event streams, the chat page, MCP over HTTP, running as a
service.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-mcp.html"&gt;&lt;strong&gt;MCP&lt;/strong&gt;&lt;/a&gt;: agents-exe as an MCP server, and MCP servers
as tool providers.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-export-import.html"&gt;&lt;strong&gt;Export and import&lt;/strong&gt;&lt;/a&gt;: moving sessions and
agents between stores.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tools-and-agents"&gt;Tools and agents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-tools.html"&gt;&lt;strong&gt;Tool system&lt;/strong&gt;&lt;/a&gt;: how tools are registered and
exposed to the model.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-binary-tool.html"&gt;&lt;strong&gt;Executable-program tools&lt;/strong&gt;&lt;/a&gt;: the
self-description protocol a program follows to become a tool.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-parameters-and-bindings.html"&gt;&lt;strong&gt;Parameters, bindings and narrowing sub-agents&lt;/strong&gt;&lt;/a&gt;:
pre-bound arguments, declared parameters, and narrowed helpers.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-internal-tool-mapping.html"&gt;&lt;strong&gt;Internal tool mapping&lt;/strong&gt;&lt;/a&gt;: the
built-in system toolbox and what each capability maps to.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-file-loader.html"&gt;&lt;strong&gt;File loader&lt;/strong&gt;&lt;/a&gt;: how agent files and
directories are discovered and loaded.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="sessions-and-workflows"&gt;Sessions and workflows&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-sessions.html"&gt;&lt;strong&gt;Session management&lt;/strong&gt;&lt;/a&gt;: turns, storage, and
resuming.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-async-tool-calls.html"&gt;&lt;strong&gt;Asynchronous tool calls&lt;/strong&gt;&lt;/a&gt;: deferred and
background calls, and how a run yields on them.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-durable-workflows-howto.html"&gt;&lt;strong&gt;Durable workflows how-to&lt;/strong&gt;&lt;/a&gt;: the
patterns for long-running, resumable work.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-ITERATIVE-WORKFLOW.html"&gt;&lt;strong&gt;Iterative development workflow&lt;/strong&gt;&lt;/a&gt;: the
build, check and run loop while writing agents.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="under-the-hood"&gt;Under the hood&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-architecture.html"&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/a&gt;: the layers and the OS model.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-OS-API.html"&gt;&lt;strong&gt;OS model API reference&lt;/strong&gt;&lt;/a&gt;: entities, components,
resources and conversations.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-MIGRATION-OS.html"&gt;&lt;strong&gt;OS model migration guide&lt;/strong&gt;&lt;/a&gt; and its
&lt;a href="/agents-exe/docs-CHANGELOG-OS-MIGRATION.html"&gt;&lt;strong&gt;changelog&lt;/strong&gt;&lt;/a&gt;: how the codebase
moved onto the OS model.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-MIGRATION-GUIDE.html"&gt;&lt;strong&gt;Migration guide&lt;/strong&gt;&lt;/a&gt;: earlier breaking
changes and how to follow them.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-sqq-flow.html"&gt;&lt;strong&gt;SQQ agent flow&lt;/strong&gt;&lt;/a&gt; and
&lt;a href="/agents-exe/docs-sqq-dag.html"&gt;&lt;strong&gt;issue dependencies as a DAG&lt;/strong&gt;&lt;/a&gt;: notes from the
issue-processing agent.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="for-people-and-agents-working-in-the-code"&gt;For people and agents working in the code&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-README.html"&gt;&lt;strong&gt;Agents, the framework overview&lt;/strong&gt;&lt;/a&gt;: the &lt;code&gt;docs/&lt;/code&gt;
directory’s own index.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-AI-CONTEXT.html"&gt;&lt;strong&gt;AI context&lt;/strong&gt;&lt;/a&gt; and
&lt;a href="/agents-exe/docs-ai-assistant-guidelines.html"&gt;&lt;strong&gt;AI assistant guidelines&lt;/strong&gt;&lt;/a&gt;: the
conventions and context an assistant should load before changing the
code.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two more documents exist only in the repository:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/lucasdicioccio/agents-exe/blob/main/CHANGELOG.md"&gt;&lt;code&gt;CHANGELOG.md&lt;/code&gt;&lt;/a&gt;:
release history.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/specs.html"&gt;&lt;code&gt;todos/&lt;/code&gt;&lt;/a&gt;: the design documents, indexed on the
&lt;a href="/agents-exe/specs.html"&gt;Specs&lt;/a&gt; page with what of each has shipped.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/docs.html" rel="alternate"/><summary type="text">The guides and references, mirrored from the repository's documentation/ directory: architecture, tools, the server, sessions, the TUI, parameters, and the migration and workflow notes.</summary></entry><entry><id>https://lucasdicioccio.github.io/agents-exe/getting-started.html</id><title type="text">Getting started with agents-exe</title><updated>2026-09-25T12:00:00Z</updated><author><name>Lucas DiCioccio</name></author><content type="html">&lt;div class="main-article"&gt;&lt;section class="main-section"&gt;&lt;h2 id="getting-started-with-agents-exe"&gt;Getting started with agents-exe&lt;/h2&gt;
&lt;p&gt;agents-exe is a command-line tool, and a Haskell library underneath it. This
page gets you from a checkout to an agent answering a prompt in each of the
modes it supports.&lt;/p&gt;
&lt;h3 id="build"&gt;Build&lt;/h3&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;git clone https://github.com/lucasdicioccio/agents-exe
cd agents-exe
cabal build
cabal install exe:agents-exe exe:agents-server    # into ~/.cabal/bin
cabal test agents-tests                           # the main test suite
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The repository is one cabal package: the &lt;code&gt;agents&lt;/code&gt; library, the &lt;code&gt;agents-exe&lt;/code&gt;
executable, &lt;code&gt;agents-server&lt;/code&gt; (the HTTP server, see
&lt;a href="/agents-exe/docs-agents-server.html"&gt;agents-server&lt;/a&gt;), &lt;code&gt;agq&lt;/code&gt; (a query tool over stored
sessions) and &lt;code&gt;durable-workflow-demo&lt;/code&gt;, which runs without any API key:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;cabal run durable-workflow-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="write-a-first-agent"&gt;Write a first agent&lt;/h3&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;agents-exe init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;walks you through writing an &lt;code&gt;agent.json&lt;/code&gt; and its tools directory. The
result looks like this:&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;my-agent&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;apiKeyId&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;flavor&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;modelUrl&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://api.openai.com/v1&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;gpt-4&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;announce&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;A helpful assistant&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;systemPrompt&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;You are a helpful assistant.&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt;]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="9"&gt;&lt;a href="#9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;toolDirectory&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;tools&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="10"&gt;&lt;a href="#10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;mcpServers&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="11"&gt;&lt;a href="#11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;extraAgents&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[]&lt;/span&gt;&lt;/span&gt;
&lt;span id="12"&gt;&lt;a href="#12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;An agent is a repeatable, parameterized LLM: an endpoint, a model, a system
prompt, a directory of command-line tools, MCP servers, and helper agents it
can prompt. Tools and helpers are both exposed to the model as functions;
when the model asks for several at once, agents-exe runs them concurrently.
&lt;a href="/agents-exe/docs-tools.html"&gt;Tools&lt;/a&gt; explains how an executable describes itself, and
&lt;a href="/agents-exe/commands.html"&gt;the command reference&lt;/a&gt; lists what &lt;code&gt;init&lt;/code&gt; and the other
commands accept.&lt;/p&gt;
&lt;p&gt;&lt;img src="/agents-exe/gen/images/agent-tree.dot.png" alt="An agent’s tree: the model calls the root agent’s tools, which are helper agents, executable tools, MCP servers, OpenAPI operations and builtin toolboxes" /&gt;&lt;/p&gt;
&lt;p&gt;Whatever the tool’s origin, the model sees a function to call; a helper
agent’s answer comes back as that function’s result, and helpers can have
tools and helpers of their own.&lt;/p&gt;
&lt;h3 id="store-an-api-key"&gt;Store an API key&lt;/h3&gt;
&lt;p&gt;Agents authenticate against their LLM endpoint with a key looked up by id in
&lt;code&gt;~/.config/agents-exe/secret-keys&lt;/code&gt; (or the file given with &lt;code&gt;--api-keys&lt;/code&gt;):&lt;/p&gt;
&lt;div class="code code--highlighted"&gt;&lt;div class="sourceCode"&gt;&lt;pre class="sourceCode"&gt;&lt;code class="sourceCode"&gt;&lt;span id="1"&gt;&lt;a href="#1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="2"&gt;&lt;a href="#2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;&amp;quot;keys&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="ot"&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id="3"&gt;&lt;a href="#3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="4"&gt;&lt;a href="#4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;openai&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id="5"&gt;&lt;a href="#5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="fu"&gt;:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="6"&gt;&lt;a href="#6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="7"&gt;&lt;a href="#7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id="8"&gt;&lt;a href="#8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; must match the agent’s &lt;code&gt;apiKeyId&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="run-it"&gt;Run it&lt;/h3&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;agents-exe check --agent-file agent.json                     # validate the agent, its tools and helpers
agents-exe run --agent-file agent.json --prompt &amp;quot;Hello!&amp;quot;     # one shot, answer on stdout
agents-exe tui --agent-file agent.json                       # the terminal UI
agents-exe mcp-server --agent-file agent.json                # a stdio MCP server exposing the agent as a tool
agents-exe serve --agent-file agent.json                     # sessions over HTTP, with a chat page
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--agent-file&lt;/code&gt; can be given several times, and is auto-discovered from
&lt;code&gt;agent.json&lt;/code&gt; when omitted; a project can also list its agents in
&lt;code&gt;agents-exe.cfg.json&lt;/code&gt; (see &lt;a href="/agents-exe/docs-advanced-configuration.html"&gt;advanced configuration&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id="where-next"&gt;Where next&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-tui.html"&gt;The TUI&lt;/a&gt;: keys, views, and how it shows tool calls and
helper agents at work.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-agents-server.html"&gt;agents-server&lt;/a&gt;: the HTTP API, durable
sessions, event streams and running it as a service.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-sessions.html"&gt;Sessions&lt;/a&gt; and
&lt;a href="/agents-exe/docs-async-tool-calls.html"&gt;asynchronous tool calls&lt;/a&gt;: what a session
stores, and how a run stops on a deferred or background call and resumes.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs-parameters-and-bindings.html"&gt;Parameters, bindings and narrowing&lt;/a&gt;:
pre-bound arguments, operator- and client-supplied parameters, and
narrowed helpers for sub-agents.
&lt;/li&gt;
&lt;li&gt;&lt;a href="/agents-exe/docs.html"&gt;Docs&lt;/a&gt;: every guide and reference, and
&lt;a href="/agents-exe/specs.html"&gt;Specs&lt;/a&gt; for the design documents.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;&lt;/div&gt;</content><link href="https://lucasdicioccio.github.io/agents-exe/getting-started.html" rel="alternate"/><summary type="text">Build the executables, write a first agent with init, store an API key, and run the agent one-shot, in the TUI, as a server and as an MCP server.</summary></entry></feed>