skip to content
$registry / workers

iii-directory

v1.2.40

Engine introspection, workers registry proxy, filesystem-backed skills, system prompts, and agent profiles, kit install and update with reviewed plans, plus function search ranked by the judge worker (falling back to local hybrid/lexical) with a conditional pre-generate hint.

worker
iiiverified
5,250 installs598 in 7d100 today
install
$iii trigger compose::add worker=iii-directory
  • macOS: arm64 · x64
  • Linux: arm64 · armv7 · x64
  • Windows: arm64 · x64

exact versions are immutable; binary and bundle artifacts are digest-pinned.

README.md

iii-directory

Workers registry HTTP proxy and filesystem-backed skills, system prompts, and agent profiles for the iii engine, plus kit install and update. Every public function sits under a single directory::* namespace, split into six surfaces (all MCP-agnostic):

Surface What clients see When to use it
Skills (directory::skills::*) Enriched listing via directory::skills::list ({ id, title, type, function_id, disable_model_invocation, description, bytes, modified_at } per row), a single-skill reader directory::skills::get { id } returning { id, title, type, function_id, disable_model_invocation, path, body, modified_at } (the full body instead of the list teaser), and directory::skills::index which renders a short per-worker overview document (one ## </code> + first paragraph + <code class="readme-inline-code">read more</code> link per <code class="readme-inline-code">type: index</code> skill). Authored by <code class="readme-inline-code">create</code>, edited by <code class="readme-inline-code">update</code>, removed by <code class="readme-inline-code">delete</code>. <code class="readme-inline-code">title</code> prefers the YAML frontmatter <code class="readme-inline-code">title:</code> (then <code class="readme-inline-code">name:</code>) over the body H1; <code class="readme-inline-code">type</code> is lifted from frontmatter <code class="readme-inline-code">type:</code> (e.g. <code class="readme-inline-code">index</code>, <code class="readme-inline-code">how-to</code>, <code class="readme-inline-code">reference</code>) and serialised as <code class="readme-inline-code">null</code> when absent. System-installed agent skills under the read-only <code class="readme-inline-code">agents_skills_folder</code> are served too (see <a href="#on-disk-layout">On-disk layout</a>).</td> <td>Orientation: "when and why to use my worker's tools"</td> </tr> <tr> <td><strong>System prompts</strong> (<code class="readme-inline-code">directory::system-prompts::*</code>)</td> <td>Identity prompts listed by <code class="readme-inline-code">list</code>, read by <code class="readme-inline-code">get</code>, authored by <code class="readme-inline-code">create</code>, edited by <code class="readme-inline-code">update</code>, and removed by <code class="readme-inline-code">delete</code>. The list response keeps its <code class="readme-inline-code">prompts</code> field name. Stored under any <code class="readme-inline-code">system-prompts/</code> path segment; <code class="readme-inline-code">create</code> writes <code class="readme-inline-code"><skills_folder>/system-prompts/<name>.md</code>.</td> <td>What the chat's system-prompt picker offers as an identity prompt (enrich or replace)</td> </tr> <tr> <td><strong>Agent Profiles</strong> (<code class="readme-inline-code">directory::agents::*</code>)</td> <td>Reusable session identities whose file body is the system prompt, with display <code class="readme-inline-code">name</code>, emoji <code class="readme-inline-code">logo</code>, preloaded <code class="readme-inline-code">skills</code> and <code class="readme-inline-code">functions</code> (bodies and contracts the harness freezes into every session's prompt), and optional <code class="readme-inline-code">model</code> + <code class="readme-inline-code">reasoning_effort</code> in required frontmatter. <code class="readme-inline-code">list</code> rows carry the display/configuration metadata and <code class="readme-inline-code">get</code> adds <code class="readme-inline-code">system_prompt</code> and <code class="readme-inline-code">unknown_skills</code>. Stored as direct <code class="readme-inline-code"><agents_folder>/<id>.md</code> files. See <a href="../docs/architecture/agent-profile-storage.md">Agent profile storage</a>.</td> <td>A named identity selected with <code class="readme-inline-code">harness::send { options: { agent } }</code></td> </tr> <tr> <td><strong>Search</strong> (<code class="readme-inline-code">directory::search_functions</code>)</td> <td>One to six external capabilities → compact function-id candidates (installed, plus registry workers under <code class="readme-inline-code">installable</code>), with a conditional pre-generate hint pointing agents at it. The response also carries <code class="readme-inline-code">skills</code> (installed how-to documents) and <code class="readme-inline-code">triggers</code> (registered bindings that already fire, schedule, or hook a function, minus ephemeral console listeners), ranked in the same mode as the functions; <code class="readme-inline-code">search_mode</code> reports the mode that actually ranked.</td> <td>"Which functions do I call for this task?"</td> </tr> <tr> <td><strong>Kits</strong> (<code class="readme-inline-code">directory::download-kit</code>, <code class="readme-inline-code">directory::kits::*</code>)</td> <td>Install, update and remove kits — agent profiles, skills and registry workers published together as <code class="readme-inline-code"><author>/<kit></code> — through plans a human reviews (ADE → Directory → Kits) before anything is written. <code class="readme-inline-code">kits.lock</code> records what is installed. See <a href="#kits">Kits</a>.</td> <td>"Install the kanban team kit", "what does 1.1.0 change?"</td> </tr> <tr> <td><strong>Registry</strong> (<code class="readme-inline-code">directory::registry::*</code>)</td> <td>HTTP proxy over <code class="readme-inline-code">api.workers.iii.dev</code> with <code class="readme-inline-code">workers::{list,info}</code>. Rows share the core <code class="readme-inline-code">name</code> / <code class="readme-inline-code">description</code> / <code class="readme-inline-code">version</code> fields with the engine's <code class="readme-inline-code">engine::workers::list</code> and add publication metadata (<code class="readme-inline-code">type</code>, <code class="readme-inline-code">config</code>, <code class="readme-inline-code">supported_targets</code>, <code class="readme-inline-code">total_downloads</code>, <code class="readme-inline-code">dependencies</code>, optional <code class="readme-inline-code">image</code>). <code class="readme-inline-code">workers::list</code> is cursor-paginated with a server-authored page size.</td> <td>"What's published in the public registry?"</td> </tr> </tbody></table> <p>Engine introspection (functions / triggers / registered triggers / workers) is served by the engine natively at <code class="readme-inline-code">engine::functions::*</code>, <code class="readme-inline-code">engine::triggers::*</code>, <code class="readme-inline-code">engine::registered-triggers::*</code>, and <code class="readme-inline-code">engine::workers::*</code>. Call the engine ids directly. One wrapper survives for callers that can only reach the <code class="readme-inline-code">directory::</code> namespace: <code class="readme-inline-code">directory::engine::functions::info</code> proxies a single function's schema (see its row below).</p> <p>This worker is where an agent's identity text LIVES. <code class="readme-inline-code">skills/system-prompts/iii-runtime.md</code> ships here and is the one copy of "how to work against a live iii engine" — <code class="readme-inline-code">claude-code</code> and <code class="readme-inline-code">pi</code> fetch it with <code class="readme-inline-code">directory::system-prompts::get name=iii-runtime</code> (plus <code class="readme-inline-code">directory::skills::index</code>) for both their headless turns and their console terminals, rather than compiling a prompt of their own. Edit that file and every agent reads the edit; no worker release involved.</p> <p>Skills and system prompts are sourced from <code class="readme-inline-code">skills_folder</code>; agent profiles use the dedicated <code class="readme-inline-code">agents_folder</code>. Writes are the <strong><code class="readme-inline-code">directory::skills::download*</code></strong> functions, which pull markdown from either the <a href="https://workers.iii.dev">workers registry</a> or a GitHub repo and route each supported family to its configured root, plus the per-kind single-file editors — <code class="readme-inline-code">directory::skills::{create,update,delete}</code>, <code class="readme-inline-code">directory::system-prompts::{create,update,delete}</code> and <code class="readme-inline-code">directory::agents::{create,update,delete}</code>. Once downloaded, files belong to the developer — edit them however you want, in the editor of your choice: a change made directly on disk fires the matching <code class="readme-inline-code">on-change</code> with <code class="readme-inline-code">op: "external"</code> (see <a href="#custom-trigger-types">Custom trigger types</a>).</p> <p><code class="readme-inline-code">directory::registry::workers::*</code> and the engine's <code class="readme-inline-code">engine::workers::*</code> share the core <code class="readme-inline-code">name</code> / <code class="readme-inline-code">description</code> / <code class="readme-inline-code">version</code> fields so a parser that touches only those keys works against either surface; the registry view also surfaces publication metadata (<code class="readme-inline-code">type</code>, <code class="readme-inline-code">config</code>, <code class="readme-inline-code">supported_targets</code>, <code class="readme-inline-code">total_downloads</code>, <code class="readme-inline-code">dependencies</code>, optional <code class="readme-inline-code">image</code>) and the engine view adds runtime / connection state.</p> <h2 id="table-of-contents" class="scroll-mt-20">Table of contents</h2> <ol> <li><a href="#install">Install</a></li> <li><a href="#configuration">Configuration</a></li> <li><a href="#quickstart-download-some-skills">Quickstart: download some skills</a></li> <li><a href="#on-disk-layout">On-disk layout</a></li> <li><a href="#skill-ids">Skill ids</a></li> <li><a href="#kits">Kits</a></li> <li><a href="#functions">Functions</a></li> <li><a href="#function-search--pre-generate-hint">Function search & pre-generate hint</a></li> <li><a href="#custom-trigger-types">Custom trigger types</a></li> <li><a href="#local-development--testing">Local development & testing</a></li> <li><a href="#migration-from-skills-v02x">Migration from skills v0.2.x</a></li> </ol> <hr> <h2 id="install" class="scroll-mt-20">Install</h2> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#59873A">iii</span><span style="color:#B56959"> trigger</span><span style="color:#B56959"> compose::add</span><span style="color:#B56959"> worker=iii-directory</span></span></code></pre><p><code class="readme-inline-code">iii trigger compose::add</code> resolves the worker and its dependencies, writes exact declarations to <code class="readme-inline-code">worker-compose.yaml</code>, and reconciles the Compose project.</p> <p>For container settings, fetch <code class="readme-inline-code">compose::schema { function_id: "compose::add" }</code> and use its <code class="readme-inline-code">workers</code> list. For example, after registering the completion wake described below:</p> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#999999">{</span></span> <span class="line"><span style="color:#99841877"> "</span><span style="color:#998418">operation_id</span><span style="color:#99841877">"</span><span style="color:#999999">:</span><span style="color:#B5695977"> "</span><span style="color:#B56959"><operation-id></span><span style="color:#B5695977">"</span><span style="color:#999999">,</span></span> <span class="line"><span style="color:#99841877"> "</span><span style="color:#998418">workers</span><span style="color:#99841877">"</span><span style="color:#999999">:</span><span style="color:#999999"> [</span></span> <span class="line"><span style="color:#B5695977"> "</span><span style="color:#B56959">state</span><span style="color:#B5695977">"</span><span style="color:#999999">,</span></span> <span class="line"><span style="color:#999999"> {</span></span> <span class="line"><span style="color:#99841877"> "</span><span style="color:#998418">worker</span><span style="color:#99841877">"</span><span style="color:#999999">:</span><span style="color:#B5695977"> "</span><span style="color:#B56959">iii-directory</span><span style="color:#B5695977">"</span><span style="color:#999999">,</span></span> <span class="line"><span style="color:#99841877"> "</span><span style="color:#998418">start_after</span><span style="color:#99841877">"</span><span style="color:#999999">:</span><span style="color:#999999"> [</span><span style="color:#B5695977">"</span><span style="color:#B56959">state</span><span style="color:#B5695977">"</span><span style="color:#999999">],</span></span> <span class="line"><span style="color:#99841877"> "</span><span style="color:#998418">config_override</span><span style="color:#99841877">"</span><span style="color:#999999">:</span><span style="color:#999999"> {</span><span style="color:#99841877"> "</span><span style="color:#998418">registry_search</span><span style="color:#99841877">"</span><span style="color:#999999">:</span><span style="color:#1E754F"> true</span><span style="color:#999999"> }</span></span> <span class="line"><span style="color:#999999"> }</span></span> <span class="line"><span style="color:#999999"> ]</span></span> <span class="line"><span style="color:#999999">}</span></span></code></pre><p>The list can mix worker names and objects. Each object accepts <code class="readme-inline-code">scripts</code>, <code class="readme-inline-code">config_name</code>, <code class="readme-inline-code">config_override</code>, <code class="readme-inline-code">working_dir</code>, <code class="readme-inline-code">environment</code>, <code class="readme-inline-code">env_file</code>, <code class="readme-inline-code">startup_timeout</code>, and package <code class="readme-inline-code">version</code> as well as <code class="readme-inline-code">worker</code> and <code class="readme-inline-code">start_after</code>. <code class="readme-inline-code">scripts.run</code> is for local workers only. Supplied maps replace the whole field; omitted settings are retained.</p> <p>The returned <code class="readme-inline-code">install.payload</code> from function search is a minimal shorthand. If the worker needs settings, replace its singular <code class="readme-inline-code">worker</code> with an object in <code class="readme-inline-code">workers</code>. Register a one-shot <code class="readme-inline-code">compose-operation</code> wake before calling <code class="readme-inline-code">compose::add</code>, use the same <code class="readme-inline-code">operation_id</code> in both calls, and wait for terminal success before using the new functions. An acceptance response does not mean the worker is ready. See the <a href="https://github.com/iii-hq/workers/blob/main/harness/README.md#adding-workers-with-container-settings">container settings example and completion flow</a> for field behavior, path resolution, and recovery.</p> <hr> <h2 id="skills" class="scroll-mt-20">Skills</h2> <p>Install the <code class="readme-inline-code">iii-directory</code> agent skill for Claude Code, Cursor, and 30+ other agents:</p> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#59873A">npx</span><span style="color:#B56959"> skills</span><span style="color:#B56959"> add</span><span style="color:#B56959"> iii-hq/workers</span><span style="color:#A65E2B"> --skill</span><span style="color:#B56959"> iii-directory</span></span></code></pre><p>Browse or install every worker skill at once:</p> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#59873A">npx</span><span style="color:#B56959"> skills</span><span style="color:#B56959"> add</span><span style="color:#B56959"> iii-hq/workers</span><span style="color:#A65E2B"> --list</span></span> <span class="line"><span style="color:#59873A">npx</span><span style="color:#B56959"> skills</span><span style="color:#B56959"> add</span><span style="color:#B56959"> iii-hq/workers</span><span style="color:#A65E2B"> --all</span></span></code></pre><hr> <h2 id="configuration" class="scroll-mt-20">Configuration</h2> <p>Runtime settings live in the <strong><code class="readme-inline-code">configuration</code> worker</strong> under id <strong><code class="readme-inline-code">iii-directory</code></strong> (the same pattern <code class="readme-inline-code">database</code> and <code class="readme-inline-code">storage</code> use). At boot the worker registers its JSON Schema, reads the live value via <code class="readme-inline-code">configuration::get</code> (the configuration worker env-expands <code class="readme-inline-code">${VAR}</code>), and binds a <code class="readme-inline-code">configuration</code> trigger so it re-fetches on change.</p> <p>Persisted values default to <code class="readme-inline-code">./data/configuration/iii-directory.yaml</code> (fs adapter). Edit that file directly, call <code class="readme-inline-code">configuration::set id=iii-directory</code>, or use the Console's global Settings modal — all three propagate without a redeploy.</p> <h3 id="fields" class="scroll-mt-20">Fields</h3> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#A0ADA0"># TOPOLOGY — changing any of these requires a worker restart.</span></span> <span class="line"><span style="color:#998418">skills_folder</span><span style="color:#999999">:</span><span style="color:#B56959"> skills</span><span style="color:#A0ADA0"> # under III_COMPOSE_DIR, or the process cwd standalone</span></span> <span class="line"><span style="color:#998418">local_skills_folder</span><span style="color:#999999">:</span><span style="color:#B56959"> skills/iii</span><span style="color:#A0ADA0"> # project-scoped overrides (whole-namespace local-wins)</span></span> <span class="line"><span style="color:#998418">agents_folder</span><span style="color:#999999">:</span><span style="color:#B56959"> agents</span><span style="color:#A0ADA0"> # direct <id>.md agent profiles</span></span> <span class="line"><span style="color:#998418">agents_skills_folder</span><span style="color:#999999">:</span><span style="color:#B56959"> .agents/skills</span><span style="color:#A0ADA0"> # READ-ONLY agent skills, with the same relative-path base</span></span> <span class="line"><span style="color:#998418">auto_download</span><span style="color:#999999">:</span><span style="color:#1E754F"> true</span><span style="color:#A0ADA0"> # subscribe to worker-add + run the boot reconcile</span></span> <span class="line"><span style="color:#A0ADA0"># function_search_model_path: ~/.cache/iii/all-MiniLM-L6-v2-<revision> # pinned Hybrid bundle; null disables it</span></span> <span class="line"><span style="color:#998418">function_search_model_download</span><span style="color:#999999">:</span><span style="color:#1E754F"> true</span><span style="color:#A0ADA0"> # download the pinned bundle at boot in Hybrid mode</span></span> <span class="line"></span> <span class="line"><span style="color:#A0ADA0"># TUNABLE — hot-reload live on `configuration:updated`.</span></span> <span class="line"><span style="color:#998418">registry_url</span><span style="color:#999999">:</span><span style="color:#B56959"> https://api.workers.iii.dev</span><span style="color:#A0ADA0"> # workers registry base URL (workers and kits)</span></span> <span class="line"><span style="color:#A0ADA0"># registry_web_url: https://workers.iii.dev # registry web app for "open in registry" links; default: registry_url without its leading `api.`</span></span> <span class="line"><span style="color:#998418">download_timeout_ms</span><span style="color:#999999">:</span><span style="color:#2F798A"> 60000</span><span style="color:#A0ADA0"> # per git-clone / HTTP request timeout (ms)</span></span> <span class="line"><span style="color:#998418">registry_cache_ttl_ms</span><span style="color:#999999">:</span><span style="color:#2F798A"> 60000</span><span style="color:#A0ADA0"> # in-process TTL for registry::workers::* responses</span></span> <span class="line"><span style="color:#998418">filter_unregistered</span><span style="color:#999999">:</span><span style="color:#1E754F"> true</span><span style="color:#A0ADA0"> # hide skills whose namespace isn't an installed worker</span></span> <span class="line"><span style="color:#998418">inject_hint</span><span style="color:#999999">:</span><span style="color:#1E754F"> false</span><span style="color:#A0ADA0"> # bind the directory::pre-generate search-hint hook (off: the harness identity prompt already teaches directory-first discovery)</span></span> <span class="line"><span style="color:#998418">hint_min_workers</span><span style="color:#999999">:</span><span style="color:#2F798A"> 2</span><span style="color:#A0ADA0"> # minimum surface width before the hint fires (0 = always)</span></span> <span class="line"><span style="color:#998418">registry_search</span><span style="color:#999999">:</span><span style="color:#1E754F"> true</span><span style="color:#A0ADA0"> # include installable registry workers in every search</span></span> <span class="line"><span style="color:#998418">function_search_mode</span><span style="color:#999999">:</span><span style="color:#B56959"> judge</span><span style="color:#A0ADA0"> # lexical | hybrid | judge (default)</span></span> <span class="line"><span style="color:#998418">function_search_judge_timeout_ms</span><span style="color:#999999">:</span><span style="color:#2F798A"> 3000</span><span style="color:#A0ADA0"> # integer 1..30000; shared judge deadline per public search</span></span> <span class="line"><span style="color:#998418">function_search_judge_min_relevance</span><span style="color:#999999">:</span><span style="color:#2F798A"> 0.5</span><span style="color:#A0ADA0"> # finite 0..1 inclusive; noul floor (initial calibration value)</span></span> <span class="line"><span style="color:#998418">function_search_judge_side_lane_min_relevance</span><span style="color:#999999">:</span><span style="color:#2F798A"> 0.3</span><span style="color:#A0ADA0"> # finite 0..1 inclusive; noul floor for the skills and triggers sections</span></span> <span class="line"><span style="color:#998418">function_search_judge_question</span><span style="color:#999999">:</span><span style="color:#B56959"> choice</span><span style="color:#A0ADA0"> # choice (default: one question per capability) | noul (one yes/no per shortlisted document) | tournament (whole catalog: compact rounds, then a final choice; no Hybrid shortlist)</span></span> <span class="line"><span style="color:#998418">function_search_judge_choice_min_probability</span><span style="color:#999999">:</span><span style="color:#2F798A"> 0.1</span><span style="color:#A0ADA0"> # finite 0..1 inclusive; with choice, the floor for all but the best document</span></span></code></pre><p>The writable <code class="readme-inline-code">skills_folder</code> and <code class="readme-inline-code">agents_folder</code> roots are created when needed.</p> <h3 id="zero-config-default-seed" class="scroll-mt-20">Zero-config default + seed</h3> <p>With no seed and no stored value the worker uses built-in defaults. Relative folder paths use <code class="readme-inline-code">III_COMPOSE_DIR</code> when set and the process current directory otherwise (<code class="readme-inline-code">skills_folder: skills</code>, <code class="readme-inline-code">agents_folder: agents</code>, <code class="readme-inline-code">registry_url: https://api.workers.iii.dev</code>). Pass <code class="readme-inline-code">--config <path></code> to supply a YAML seed: when present and no value is stored yet, its contents become <code class="readme-inline-code">initial_value</code> on <code class="readme-inline-code">configuration::register</code> (see <a href="config.yaml.example"><code class="readme-inline-code">config.yaml.example</code></a>). Engine-managed deployments inline the config under the worker entry; the engine delivers it via <code class="readme-inline-code">--config</code>.</p> <h3 id="hot-reload" class="scroll-mt-20">Hot reload</h3> <p>On <code class="readme-inline-code">configuration::set</code> (or an external edit to the persisted file), the worker re-fetches the authoritative value. Tunable changes apply in place and the registry caches are cleared so a repointed <code class="readme-inline-code">registry_url</code> takes effect immediately. Topology changes (<code class="readme-inline-code">skills_folder</code> / <code class="readme-inline-code">local_skills_folder</code> / <code class="readme-inline-code">agents_folder</code> / <code class="readme-inline-code">agents_skills_folder</code> / <code class="readme-inline-code">auto_download</code> / <code class="readme-inline-code">function_search_model_path</code> / <code class="readme-inline-code">function_search_model_download</code>) are refused with a "restart required" log; the previous configuration is kept until the worker restarts.</p> <p><code class="readme-inline-code">function_search_mode</code> and all <code class="readme-inline-code">function_search_judge_*</code> options hot-reload. Judge credentials and the model name are the <code class="readme-inline-code">judge-typesafe</code> worker's settings, not this worker's.</p> <p>The writable <code class="readme-inline-code">skills_folder</code>, <code class="readme-inline-code">local_skills_folder</code>, and <code class="readme-inline-code">agents_folder</code> are watch roots, and the watcher creates each one at boot if it is missing. Direct <code class="readme-inline-code"><id>.md</code> edits under <code class="readme-inline-code">agents_folder</code> fire <code class="readme-inline-code">directory::agents::on-change</code> with <code class="readme-inline-code">op: "external"</code>; nested files are ignored. <code class="readme-inline-code">agents_skills_folder</code> is a watch root too, but only when it already exists — the worker never creates (or writes) anything under it. Install your first agents skill while the worker is running and that root stays unwatched until the next restart: reads still serve it, since every read re-scans disk, but the live <code class="readme-inline-code">external</code> doorbell is missing until then. <code class="readme-inline-code">local_skills_folder</code> defaults to <code class="readme-inline-code">skills/iii</code> under <code class="readme-inline-code">III_COMPOSE_DIR</code>, or under the process current directory when the worker runs standalone. An empty local root shadows nothing. Because the roots are restart-required, the watch roots are fixed for the process lifetime.</p> <hr> <h2 id="quickstart-download-some-skills" class="scroll-mt-20">Quickstart: download some skills</h2> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#A0ADA0"># Pull a specific worker's directory bundle at a fixed semver from</span></span> <span class="line"><span style="color:#A0ADA0"># the registry. Files land under `<skills_folder>/agent-memory/`.</span></span> <span class="line"><span style="color:#59873A">iii</span><span style="color:#B56959"> trigger</span><span style="color:#A65E2B"> --function-id=directory::skills::download</span><span style="color:#A65E2B"> \</span></span> <span class="line"><span style="color:#A65E2B"> --payload=</span><span style="color:#B5695977">'</span><span style="color:#B56959">{"worker": "agent-memory", "version": "1.2.3"}</span><span style="color:#B5695977">'</span></span> <span class="line"></span> <span class="line"><span style="color:#A0ADA0"># Same, but always fetch whatever's tagged `latest` (also the default</span></span> <span class="line"><span style="color:#A0ADA0"># when neither version nor tag is given).</span></span> <span class="line"><span style="color:#59873A">iii</span><span style="color:#B56959"> trigger</span><span style="color:#A65E2B"> --function-id=directory::skills::download</span><span style="color:#A65E2B"> \</span></span> <span class="line"><span style="color:#A65E2B"> --payload=</span><span style="color:#B5695977">'</span><span style="color:#B56959">{"worker": "agent-memory"}</span><span style="color:#B5695977">'</span></span> <span class="line"></span> <span class="line"><span style="color:#A0ADA0"># Pull a single subfolder out of a public GitHub repo via</span></span> <span class="line"><span style="color:#A0ADA0"># `git clone --depth 1 --branch main`. Files land under</span></span> <span class="line"><span style="color:#A0ADA0"># `<skills_folder>/frontend-design/`. The `branch` field defaults to</span></span> <span class="line"><span style="color:#A0ADA0"># `main`; pass `"master"` for older repos that haven't migrated.</span></span> <span class="line"><span style="color:#59873A">iii</span><span style="color:#B56959"> trigger</span><span style="color:#A65E2B"> --function-id=directory::skills::download</span><span style="color:#A65E2B"> \</span></span> <span class="line"><span style="color:#A65E2B"> --payload=</span><span style="color:#B5695977">'</span><span style="color:#B56959">{</span></span> <span class="line"><span style="color:#B56959"> "repo": "https://github.com/anthropics/skills",</span></span> <span class="line"><span style="color:#B56959"> "skill": "frontend-design"</span></span> <span class="line"><span style="color:#B56959"> }</span><span style="color:#B5695977">'</span></span></code></pre><p>The response is <code class="readme-inline-code">{ namespace, skills_written, system_prompts_written, agents_written, agents_skipped?, source }</code>. The three <code class="readme-inline-code">*_written</code> fields list the files materialised in this run. Registry entries shaped exactly as <code class="readme-inline-code">agents/<id>.md</code> land in <code class="readme-inline-code"><agents_folder>/<id>.md</code>; repo downloads do not install agent profiles. A registry entry whose profile id an installed kit owns (<code class="readme-inline-code">kits.lock</code>) is not written — kit profiles take precedence — and is reported in <code class="readme-inline-code">agents_skipped: [{ id, owned_by }]</code>.</p> <p>A registry download (explicit or automatic) writes <code class="readme-inline-code"><skills_folder>/<worker>/.iii-skill-complete</code> with the worker, the resolved <code class="readme-inline-code">version</code> and, per agent profile it wrote, <code class="readme-inline-code">agents: { <id>: <sha256> }</code>. That is how <code class="readme-inline-code">directory::agents::list</code> attributes a profile to a worker.</p> <p>After every successful download the worker fires the <code class="readme-inline-code">directory::skills::on-change</code>, <code class="readme-inline-code">directory::system-prompts::on-change</code>, and/or <code class="readme-inline-code">directory::agents::on-change</code> trigger types so that subscribers like the <a href="https://github.com/iii-hq/workers/tree/main/mcp"><code class="readme-inline-code">mcp</code></a> worker can forward MCP <code class="readme-inline-code">notifications/list_changed</code> to their clients.</p> <hr> <h2 id="on-disk-layout" class="scroll-mt-20">On-disk layout</h2> <p>The worker uses separate roots for directory content and agent profiles:</p> <pre><code>skills_folder/ <namespace>/ # one folder per `directory::skills::download` namespace index.md # → iii://<namespace>/index contacts.md # → iii://<namespace>/contacts emails/send-email.md # → iii://<namespace>/emails/send-email system-prompts/ # ← magic marker for system prompts reviewer.md # ← identity prompt (needs YAML frontmatter) system-prompts/ # ← where system-prompts::create writes pirate.md agents_folder/ # ← where agents::create writes release-captain.md # ← agent profile (needs YAML frontmatter) frontend-design.md # ← `extends: iii` builds on the bundled base</code></pre><p>Three agent profiles ship inside the worker binary:</p> <ul> <li><code class="readme-inline-code">default</code> — shown as <strong>Default</strong> in the chat's new-session gallery: the minimal directory-first identity (the same text as the bundled <code class="readme-inline-code">iii-minimal</code> system prompt), with a composer example. New sessions in the ADE start on it.</li> <li><code class="readme-inline-code">iii</code> — the harness default identity, verbatim. <code class="readme-inline-code">hidden: true</code> keeps it out of the gallery; it stays a valid <code class="readme-inline-code">extends</code> parent and runs by id.</li> <li><code class="readme-inline-code">iii-minimal</code> — the previous id of <code class="readme-inline-code">default</code>, kept as a hidden alias (<code class="readme-inline-code">extends: default</code>, no body of its own) so existing <code class="readme-inline-code">extends: iii-minimal</code> chains, saved sessions, and explicit invocations resolve to the same identity. New profiles should use <code class="readme-inline-code">extends: default</code>.</li> </ul> <p>Each is always listed (<code class="readme-inline-code">builtin: true</code>), a local <code class="readme-inline-code">agents_folder/<id>.md</code> shadows it, <code class="readme-inline-code">update</code> on it copy-on-writes that local file, and deleting the file falls back to the bundled copy. No file is ever seeded on disk.</p> <p>An optional <code class="readme-inline-code">composer_placeholder:</code> frontmatter string is the example request the chat shows in an EMPTY composer while that profile is selected. It is presentation only — never sent, never added to the prompt — and profile-local: it does not inherit through <code class="readme-inline-code">extends</code>, so a child without its own example gets the chat's generic hint. Whitespace collapses to single spaces, blank means absent, and more than 200 characters is rejected like any other invalid frontmatter.</p> <p>An optional <code class="readme-inline-code">skills_index:</code> boolean turns off the skills index for sessions running as that profile: with <code class="readme-inline-code">skills_index: false</code> the harness starts them without the names-only <code class="readme-inline-code"><available_skills></code> block in the prompt (this is the prompt block, not the <code class="readme-inline-code">directory::skills::index</code> function). It inherits through <code class="readme-inline-code">extends</code> like <code class="readme-inline-code">model</code> — the nearest profile that sets it wins, and <code class="readme-inline-code">true</code> in a child turns the index back on. The profile's preloaded <code class="readme-inline-code">skills</code> still render, and <code class="readme-inline-code">directory::skills::get</code> stays callable when the session's policy allows it. A value that is not a YAML boolean makes the profile invalid, like <code class="readme-inline-code">hidden</code>.</p> <p>A second, READ-ONLY root — <code class="readme-inline-code">agents_skills_folder</code> (default <code class="readme-inline-code">.agents/skills</code> under the same Compose or standalone base) — serves agent skills. It is scanned <strong>shallowly</strong>: only <code class="readme-inline-code"><skill-dir>/SKILL.md</code> becomes an entry (id <code class="readme-inline-code"><skill-dir>/index</code>, displayed as <code class="readme-inline-code"><skill-dir></code>); a skill's <code class="readme-inline-code">reference/</code>, <code class="readme-inline-code">scripts/</code>, or other support payload is never listed. A missing directory is silently empty. These skills bypass <code class="readme-inline-code">filter_unregistered</code> (their namespaces are skills, not workers), stay out of <code class="readme-inline-code">directory::skills::index</code> (a per-WORKER surface), and are refused by <code class="readme-inline-code">update</code>/<code class="readme-inline-code">delete</code> — edit them with their owning tool, or copy one into <code class="readme-inline-code">skills_folder</code> on disk to fork it. Precedence is <code class="readme-inline-code">local_skills_folder</code> > <code class="readme-inline-code">skills_folder</code> > <code class="readme-inline-code">agents_skills_folder</code>, namespace-wise: a top-level namespace directory in a higher root shadows the same namespace below.</p> <p>A few rules:</p> <ul> <li><strong>Skill ids</strong> are the relative path under <code class="readme-inline-code">skills_folder</code> with <code class="readme-inline-code">.md</code> stripped. Each segment must satisfy <code class="readme-inline-code">[a-z0-9_-]{1,64}</code>.</li> <li><strong>Skill frontmatter is optional.</strong> When present, the reader recognises <code class="readme-inline-code">title:</code> (preferred title), <code class="readme-inline-code">name:</code> (title fallback), <code class="readme-inline-code">type:</code> (free-form classifier), <code class="readme-inline-code">function_id:</code> (canonical bus function id surfaced by <code class="readme-inline-code">list</code> and <code class="readme-inline-code">get</code>), <code class="readme-inline-code">description:</code> (preferred <code class="readme-inline-code">list</code> teaser), and <code class="readme-inline-code">disable-model-invocation:</code> (boolean, default <code class="readme-inline-code">false</code>, surfaced as <code class="readme-inline-code">disable_model_invocation</code> by both responses). The body H1 and first paragraph are the title and list-description fallbacks, respectively. Disabled skills remain visible to ordinary directory clients; model index consumers decide whether to filter them. Any other YAML keys are ignored.</li> <li><strong>System prompts</strong> live under any <code class="readme-inline-code">*/system-prompts/*.md</code> path, with YAML frontmatter (<code class="readme-inline-code">description</code> required, <code class="readme-inline-code">name</code> optional). A path carrying both a <code class="readme-inline-code">prompts</code> and a <code class="readme-inline-code">system-prompts</code> segment is a system prompt because <code class="readme-inline-code">system-prompts</code> is classified first. Other paths containing a <code class="readme-inline-code">prompts</code> segment are ignored by scans and downloads.</li> <li><strong>What a system prompt can do, by design.</strong> The console's chat picker can send a selected system prompt with <code class="readme-inline-code">system_prompt_strategy: "override"</code>, which replaces the harness's built-in identity prompt with that file's body verbatim. Files reach <code class="readme-inline-code">system-prompts/</code> either by local authoring or via <code class="readme-inline-code">directory::skills::download</code> from a git repo or the registry, so a downloaded bundle can supply one. This is an accepted property, not a hole: it takes a deliberate selection in the UI, the same UI already accepts arbitrary typed text, and the operator owns <code class="readme-inline-code">skills_folder</code>. Worth knowing before you point <code class="readme-inline-code">skills_folder</code> at a directory other people can write to.</li> <li><strong>Agent profiles</strong> are direct <code class="readme-inline-code"><agents_folder>/<id>.md</code> files (unrelated to the read-only <code class="readme-inline-code">agents_skills_folder</code> above, which holds external tools' <em>skills</em>). Nested profiles and the former <code class="readme-inline-code"><skills_folder>/**/agents/*.md</code> layout are ignored. Frontmatter is required and must declare a non-empty <code class="readme-inline-code">name</code> (the display name — the id is always the file stem); <code class="readme-inline-code">description</code> may be empty, <code class="readme-inline-code">logo</code> is emoji-only (≤16 bytes, no path characters), <code class="readme-inline-code">skills:</code> filters the skill index (absent/empty = every skill), and <code class="readme-inline-code">model:</code> names a model id for sessions using this profile (absent = the send decides), and optional <code class="readme-inline-code">reasoning_effort:</code> names its provider-native effort. Both are stored verbatim and resolved against the live model catalog where they are used. The body is the system prompt, verbatim, and may be empty — a profile with no prompt of its own contributes only its parent chain (if any) and its non-prompt settings. Unknown <code class="readme-inline-code">skills</code> ids are warnings surfaced by <code class="readme-inline-code">get</code>, never load failures.</li> <li><strong>Agent profiles declare preloaded functions.</strong> <code class="readme-inline-code">functions:</code> lists engine function ids (<code class="readme-inline-code">coder::tree</code>, <code class="readme-inline-code">coder::search</code>, …) the profile uses routinely. The harness resolves their contracts once, when a session starts as this profile, and freezes them into the system prompt as a <code class="readme-inline-code"><preloaded_functions></code> block (id, description, compacted request schema), so the model calls them on the first step instead of spending a <code class="readme-inline-code">directory::search_functions</code> + <code class="readme-inline-code">engine::functions::info</code> round-trip per session; everything else still goes through discovery. Ids are stored verbatim (non-empty, no whitespace; duplicates collapse, order kept); <code class="readme-inline-code">get</code> reports ids the engine does not currently know in <code class="readme-inline-code">unknown_functions</code> (a warning — the harness renders them as unavailable), <code class="readme-inline-code">list</code> carries <code class="readme-inline-code">function_count</code>. <code class="readme-inline-code">directory::agents::functions::add</code> / <code class="readme-inline-code">::remove { id, functions }</code> edit only that frontmatter field — the rest of the file stays byte-identical — and fan out <code class="readme-inline-code">on-change</code> as an update. The console's profile editor picks them from the live registry with the same keyboard-first search + Selected/Available lists as skills.</li> <li><strong>Agent profiles inherit.</strong> <code class="readme-inline-code">extends: <id></code> names one parent profile (chains allowed, at most 8 hops). The resolved system prompt served by <code class="readme-inline-code">get</code> is the parent's resolved prompt followed by a blank line and this file's body — a blank body contributes nothing, so a profile with no prompt of its own serves its parent chain unchanged; <code class="readme-inline-code">model</code> and <code class="readme-inline-code">reasoning_effort</code> fall back to the nearest ancestor that sets them when omitted, while <code class="readme-inline-code">skills</code> and <code class="readme-inline-code">functions</code> inherit ADDITIVELY (the union of the chain's lists, root first, no duplicates — a child adds to what its parents allow / preload, it cannot remove); <code class="readme-inline-code">name</code>, <code class="readme-inline-code">description</code>, <code class="readme-inline-code">logo</code>, <code class="readme-inline-code">icon</code> and <code class="readme-inline-code">color</code> are always the profile's own. A chain that does not resolve (unknown parent, loop, too deep) is reported by <code class="readme-inline-code">list</code>/<code class="readme-inline-code">get</code> as <code class="readme-inline-code">inheritance_error</code> (<code class="readme-inline-code">D415</code> text) while the profile still serves its own file (so the editor can fix it); the harness refuses to run it.</li> <li>Under a skills root, files outside <code class="readme-inline-code">prompts/</code>, <code class="readme-inline-code">system-prompts/</code>, and reserved <code class="readme-inline-code">agents/</code> segments are skills.</li> </ul> <p>The download function namespaces by source:</p> <table> <thead> <tr> <th>Source</th> <th>Destination</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">repo=URL skill=NAME branch?=main</code></td> <td><code class="readme-inline-code"><skills_folder>/<NAME>/...</code></td> </tr> <tr> <td><code class="readme-inline-code">worker=NAME version=…</code></td> <td>Skills/prompts under <code class="readme-inline-code"><skills_folder>/<NAME>/...</code>; exact <code class="readme-inline-code">agents/<id>.md</code> entries under <code class="readme-inline-code"><agents_folder>/<id>.md</code></td> </tr> <tr> <td><code class="readme-inline-code">worker=NAME tag=…</code> (default <code class="readme-inline-code">tag=latest</code>)</td> <td>Same routing as the version form</td> </tr> </tbody></table> <p>Re-pulling the same source overwrites files <strong>file-by-file</strong> — existing siblings outside the response set are preserved (so hand-edited additions survive a re-pull).</p> <hr> <h2 id="skill-ids" class="scroll-mt-20">Skill ids</h2> <p>Skills are addressed by their relative path under <code class="readme-inline-code">skills_folder</code> with <code class="readme-inline-code">.md</code> stripped — e.g. <code class="readme-inline-code"><skills_folder>/agent-memory/observe.md</code> → id <code class="readme-inline-code">"agent-memory/observe"</code>. The same string is what <code class="readme-inline-code">directory::skills::list</code> returns and what <code class="readme-inline-code">directory::skills::get</code> expects in <code class="readme-inline-code">{ "id": ... }</code>. The legacy <code class="readme-inline-code">iii://{id}</code> link form is still accepted on <code class="readme-inline-code">get</code> (the prefix is auto-stripped), but the worker no longer parses any other <code class="readme-inline-code">iii://</code> URI shape — bodies are read solely by id, and the auto-rendered tree-shaped index that previous releases served at <code class="readme-inline-code">iii://directory/skills</code> is gone. Consumers that want a tree-shaped picker iterate <code class="readme-inline-code">list</code> rows themselves and indent by <code class="readme-inline-code">id.matches('/').count()</code>.</p> <h2 id="kits" class="scroll-mt-20">Kits</h2> <p>A <strong>kit</strong> is a publishable bundle of agent profiles (<code class="readme-inline-code">agents/<id>.md</code>), skills (<code class="readme-inline-code">skills/**.md</code>) and registry workers declared by semver range, addressed as <code class="readme-inline-code"><author-handle>/<kit-name></code> and versioned in the registry (<code class="readme-inline-code">registry_url</code>, endpoints under <code class="readme-inline-code">/k</code>). Install one with</p> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#59873A">iii</span><span style="color:#B56959"> trigger</span><span style="color:#B56959"> directory::download-kit</span><span style="color:#B56959"> kit=acme/kanban-team</span><span style="color:#A0ADA0"> # latest</span></span> <span class="line"><span style="color:#59873A">iii</span><span style="color:#B56959"> trigger</span><span style="color:#B56959"> directory::download-kit</span><span style="color:#B56959"> kit=acme/kanban-team@1.3.0</span><span style="color:#A0ADA0"> # or a tag, or a range (@^1.3)</span></span></code></pre><p>Nothing is written by that call: it builds a <strong>plan</strong> and answers with it. Review the plan in the ADE (<strong>Directory → Kits</strong>) or apply it from a script with <code class="readme-inline-code">iii trigger directory::kits::apply plan_id=kp_…</code>. <code class="readme-inline-code">apply=true</code> on <code class="readme-inline-code">download-kit</code> applies at once only when the plan has no warnings, nothing blocking it and no file that needs a decision.</p> <h3 id="what-lands-where" class="scroll-mt-20">What lands where</h3> <table> <thead> <tr> <th>Kit file</th> <th>Installed at</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">agents/<id>.md</code></td> <td><code class="readme-inline-code"><agents_folder>/<id>.md</code> (flat ids, like every profile)</td> </tr> <tr> <td><code class="readme-inline-code">skills/<path>.md</code></td> <td><code class="readme-inline-code"><skills_folder>/<handle>/<kit>/<path>.md</code> — skill id <code class="readme-inline-code"><handle>/<kit>/<path></code> (<code class="readme-inline-code">SKILL.md</code> / <code class="readme-inline-code">index.md</code> → <code class="readme-inline-code">index</code>)</td> </tr> <tr> <td><code class="readme-inline-code">workers: { kanban: ^1.4 }</code></td> <td><code class="readme-inline-code">compose::add { workers: [{ worker: "kanban", version: "^1.4" }] }</code> — the compose file declares the kit's range</td> </tr> </tbody></table> <p>Kit skill namespaces have two segments. They pass <code class="readme-inline-code">filter_unregistered</code> (they are not workers), and a kit's local override is <code class="readme-inline-code"><local_skills_folder>/<handle>/<kit>/</code>, which shadows that kit only — never the author's other kits. A kit installed inside <code class="readme-inline-code">local_skills_folder</code> (the default <code class="readme-inline-code">skills/iii</code> with an author handle <code class="readme-inline-code">iii</code>) is the kit itself, not an override.</p> <h3 id="kitslock" class="scroll-mt-20"><code class="readme-inline-code">kits.lock</code></h3> <p><code class="readme-inline-code">kits.lock</code> sits next to the compose file and is meant to be committed. The compose file is <code class="readme-inline-code">III_COMPOSE_FILE</code> when Compose started this worker; otherwise it is <code class="readme-inline-code">worker-compose.yaml</code> in <code class="readme-inline-code">III_COMPOSE_DIR</code>, or in the process working directory for a standalone worker.</p> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#998418">version</span><span style="color:#999999">:</span><span style="color:#2F798A"> 1</span></span> <span class="line"><span style="color:#998418">kits</span><span style="color:#999999">:</span></span> <span class="line"><span style="color:#998418"> acme/kanban-team</span><span style="color:#999999">:</span></span> <span class="line"><span style="color:#998418"> requested</span><span style="color:#999999">:</span><span style="color:#B56959"> ^1.3.0</span><span style="color:#A0ADA0"> # a tag, a range, or ^<version> for an exact install</span></span> <span class="line"><span style="color:#998418"> version</span><span style="color:#999999">:</span><span style="color:#2F798A"> 1.3.0</span></span> <span class="line"><span style="color:#998418"> installed_at</span><span style="color:#999999">:</span><span style="color:#A65E2B"> 2026-10-08T14:02:11Z</span></span> <span class="line"><span style="color:#998418"> workers</span><span style="color:#999999">:</span></span> <span class="line"><span style="color:#998418"> kanban</span><span style="color:#999999">:</span><span style="color:#B56959"> ^1.4</span></span> <span class="line"><span style="color:#998418"> files</span><span style="color:#999999">:</span></span> <span class="line"><span style="color:#998418"> agents/product-manager.md</span><span style="color:#999999">:</span></span> <span class="line"><span style="color:#998418"> sha256</span><span style="color:#999999">:</span><span style="color:#B56959"> 4be1…</span><span style="color:#A0ADA0"> # the content the kit installed: the merge base</span></span> <span class="line"><span style="color:#998418"> agents/reviewer.md</span><span style="color:#999999">:</span></span> <span class="line"><span style="color:#998418"> sha256</span><span style="color:#999999">:</span><span style="color:#B56959"> 77c0…</span></span> <span class="line"><span style="color:#998418"> skipped</span><span style="color:#999999">:</span><span style="color:#1E754F"> true</span><span style="color:#A0ADA0"> # you kept the file that was already there</span></span> <span class="line"><span style="color:#998418"> skills/acme/kanban-team/tickets/flow.md</span><span style="color:#999999">:</span></span> <span class="line"><span style="color:#998418"> sha256</span><span style="color:#999999">:</span><span style="color:#B56959"> 9a3e…</span></span> <span class="line"><span style="color:#998418"> ignored_versions</span><span style="color:#999999">:</span><span style="color:#999999"> [</span><span style="color:#2F798A">1.4.0</span><span style="color:#999999">]</span></span></code></pre><p>Paths are install paths: <code class="readme-inline-code">agents/…</code> under <code class="readme-inline-code">agents_folder</code>, <code class="readme-inline-code">skills/…</code> under <code class="readme-inline-code">skills_folder</code>. A file's state is computed on demand — <strong>intact</strong> (on-disk sha = base), <strong>edited</strong>, <strong>missing</strong>, or <strong>skipped</strong>. Bases are fetched back from the registry (<code class="readme-inline-code">GET /blobs/<sha256></code>); no copies are kept. An exact version request installs that version and records its caret range (<code class="readme-inline-code">1.3.0</code> → <code class="readme-inline-code">^1.3.0</code>, as npm saves an exact install) so compatible releases are offered as updates; tags and ranges are recorded as given.</p> <p>Pending plans live in <code class="readme-inline-code">.iii/directory/kit-plans/<plan_id>.json</code> next to the compose file (local state, not committed) and expire after 24 hours. The last update check is cached in <code class="readme-inline-code">.iii/directory/kit-updates.json</code>.</p> <h3 id="precedence-and-collisions" class="scroll-mt-20">Precedence and collisions</h3> <p>Kit profiles take precedence over profiles workers ship, but an install or update never replaces an existing file silently. Every <code class="readme-inline-code">agents/<id>.md</code> has an owner: a kit (<code class="readme-inline-code">kits.lock</code>), a worker (its completion marker records the profiles it wrote, with their sha256), or the project itself (<code class="readme-inline-code">local</code>).</p> <table> <thead> <tr> <th>The kit writes a path that…</th> <th>Warning</th> <th>Default</th> </tr> </thead> <tbody><tr> <td>a worker's bundle wrote</td> <td><code class="readme-inline-code">agent_overwrite</code> — "came from worker kanban 0.1.18 and will be replaced"</td> <td>replace</td> </tr> <tr> <td>another kit owns</td> <td><code class="readme-inline-code">agent_overwrite_kit</code>; replacing moves the file to this kit and marks it <code class="readme-inline-code">skipped</code> in the other kit's lock</td> <td>replace</td> </tr> <tr> <td>was created in this project</td> <td><code class="readme-inline-code">agent_overwrite_local</code> (the strongest)</td> <td>replace</td> </tr> <tr> <td>a user-global profile (<code class="readme-inline-code">~/.iii/agents</code>) has</td> <td><code class="readme-inline-code">agent_shadows_global</code></td> <td>replace</td> </tr> <tr> <td>is <code class="readme-inline-code">default</code>, <code class="readme-inline-code">iii</code> or <code class="readme-inline-code">iii-minimal</code></td> <td><code class="readme-inline-code">builtin_override</code> — replaces a built-in profile project-wide</td> <td>replace</td> </tr> <tr> <td>exists under the kit's skills folder but is not in the lock</td> <td><code class="readme-inline-code">file_overwrite_local</code></td> <td>replace</td> </tr> </tbody></table> <p>Every collision can be answered <strong>keep</strong>: the kit's file is not written and the lock marks it <code class="readme-inline-code">skipped</code>; later updates respect that until it is reverted. Identical content is no collision. Worker downloads skip profiles a kit owns and report them in <code class="readme-inline-code">agents_skipped</code>. <code class="readme-inline-code">directory::agents::list</code> / <code class="readme-inline-code">get</code> carry <code class="readme-inline-code">source: { kind: kit | worker | local | global | builtin, kit?, worker?, version?, modified? }</code>.</p> <h3 id="the-plan" class="scroll-mt-20">The plan</h3> <p>The plan JSON is the contract between the functions, the Kits page and the chat cards:</p> <pre><code>{ "plan_id": "kp_…", "kind": "install | update | remove", "kit": "acme/kanban-team", "from": "1.3.0", "to": "1.4.0", "requested": "^1.3.0", "bump": "minor", "major": false, "author": { "handle": "acme", "name": "Acme", "verified": true }, "registry_url": "<registry_web_url>/kits/acme/kanban-team", "notes": "…", "workers": [ { "name": "github", "range": "^2.0", "installed": null, "action": "add", "to": "2.0.3", "type": "binary" }, { "name": "kanban", "range": "^1.6", "range_from": "^1.4", "installed": "1.5.2", "action": "update", "to": "1.6.1" } ], "files": [ { "path": "agents/reviewer.md", "source": "agents/reviewer.md", "kind": "agent", "id": "reviewer", "change": "added", "local": "occupied", "collision": { "owner": "worker", "worker": "kanban", "version": "1.6.1", "sha256": "…" }, "default": "overwrite", "options": ["overwrite", "keep"], "agent": { …frontmatter… } }, { "path": "skills/acme/kanban-team/tickets/flow.md", "kind": "skill", "change": "modified", "local": "edited", "base": "…", "theirs": "…", "ours": "…", "merge": "conflicts", "conflicts": 1, "default": null, "options": ["kit", "mine", "merged"] } ], "capabilities": { "workers_added": ["github"], "functions_added": [ … ], "models_changed": [ … ] }, "functions": [ { "id": "kanban::ticket::create", "used_by": ["planner"], "worker": "kanban", "status": "ok" } ], "warnings": [ { "code": "agent_overwrite", "path": "agents/reviewer.md", "message": "…" } ], "blocking": [ { "code": "compose_not_running", "message": "… `iii compose --up` …" } ], "counts": { "agents": 3, "skills": 12, "workers": 2, "conflicts": 1, "decisions_required": 1, … }, "created_at": "…", "expires_at": "…" }</code></pre><ul> <li><code class="readme-inline-code">change</code>: <code class="readme-inline-code">added</code>, <code class="readme-inline-code">modified</code>, <code class="readme-inline-code">removed</code>, or <code class="readme-inline-code">kept</code> (a <code class="readme-inline-code">skipped</code> file whose kit version changed). <code class="readme-inline-code">local</code>: <code class="readme-inline-code">absent</code>, <code class="readme-inline-code">intact</code>, <code class="readme-inline-code">edited</code>, <code class="readme-inline-code">missing</code>, or <code class="readme-inline-code">occupied</code> (someone else's file). File bodies are not in the plan; <code class="readme-inline-code">directory::kits::plan { plan_id, contents: true }</code> serves them.</li> <li>An update merges a file you edited with the kit's change three ways (<code class="readme-inline-code">diffy</code>): <code class="readme-inline-code">merge: clean</code> defaults to <code class="readme-inline-code">merged</code>; <code class="readme-inline-code">merge: conflicts</code> has no default and needs <code class="readme-inline-code">kit</code>, <code class="readme-inline-code">mine</code>, or <code class="readme-inline-code">merged</code> with the resolved text. Conflict markers read <code class="readme-inline-code"><<<<<<< yours</code> / <code class="readme-inline-code">||||||| installed</code> / <code class="readme-inline-code">>>>>>>> kit</code>. A file you edited that the kit did not change is not in the plan. A removed file you did not edit defaults to <code class="readme-inline-code">remove</code>; one you edited defaults to <code class="readme-inline-code">keep</code> (it becomes an ordinary local file).</li> <li>Workers: <code class="readme-inline-code">add</code> (not declared), <code class="readme-inline-code">update</code> (installed version outside the range), <code class="readme-inline-code">redeclare</code> (the compose file still declares the kit's previous range, which the installed version already satisfies), <code class="readme-inline-code">none</code>, and <code class="readme-inline-code">remove</code> for a worker the kit dropped — never removed unless named in <code class="readme-inline-code">remove_workers</code>. <code class="readme-inline-code">path://</code> workers are never touched.</li> <li>Warnings also cover <code class="readme-inline-code">local_edits_merged</code>, <code class="readme-inline-code">merge_conflict</code>, <code class="readme-inline-code">major_update</code> and, on removal, <code class="readme-inline-code">edited_file_kept</code>. Blocking: <code class="readme-inline-code">compose_not_running</code> (the plan adds or moves workers and <code class="readme-inline-code">compose::status</code> does not answer) and <code class="readme-inline-code">kit_deprecated</code>.</li> </ul> <h3 id="apply" class="scroll-mt-20">Apply</h3> <p><code class="readme-inline-code">directory::kits::apply { plan_id, decisions?, remove_workers? }</code>, one apply at a time:</p> <ol> <li><strong>Re-validate</strong>: the plan has not expired, <code class="readme-inline-code">kits.lock</code> still holds the version it was made against, and every local file it looked at is unchanged. Otherwise nothing is applied and a fresh plan comes back with <code class="readme-inline-code">status: replanned</code>.</li> <li><strong>Download</strong> <code class="readme-inline-code">GET /k/<kit>/download?version=…&ci=…</code> — counts the download (<code class="readme-inline-code">ci=true</code> when <code class="readme-inline-code">CI</code> is set) — and check every body against the sha the plan reviewed.</li> <li><strong>Workers</strong> through Compose: one <code class="readme-inline-code">compose::add</code> with <code class="readme-inline-code">{ worker, version: <range> }</code> objects for every added, moved or re-declared worker (an existing container's range is re-declared in place), then <code class="readme-inline-code">compose::remove</code> for the ticked <code class="readme-inline-code">remove_workers</code>, each followed through <code class="readme-inline-code">compose::operation</code>. A failure stops here, before any file is written.</li> <li><strong>Files</strong>, one atomic write or delete at a time, journaled in the plan so a retried apply recognises what it already wrote (the apply is idempotent).</li> <li><strong><code class="readme-inline-code">kits.lock</code></strong>, last; then the plan is deleted and <code class="readme-inline-code">on-change</code> fires.</li> </ol> <p>Workers added or moved get their own skills and profiles downloaded right after the apply (kit-owned profiles skipped), and the kit is checked for updates. Compose must be running (<code class="readme-inline-code">iii compose --up</code>): the <code class="readme-inline-code">compose::*</code> functions exist only while its daemon does.</p> <h3 id="updates" class="scroll-mt-20">Updates</h3> <p><code class="readme-inline-code">directory::kits::check-updates</code> asks <code class="readme-inline-code">POST /k/updates</code> for every installed kit (or one): the newest version satisfying <code class="readme-inline-code">requested</code>, unless it is in <code class="readme-inline-code">ignored_versions</code>. It runs 15 seconds after boot, every 6 hours, after every install or update, and on demand. <code class="readme-inline-code">directory::kits::ignore { kit, version }</code> adds a version to <code class="readme-inline-code">ignored_versions</code> (and retires a pending update plan for it); <code class="readme-inline-code">ignore: false</code> takes it back.</p> <h3 id="in-the-ade" class="scroll-mt-20">In the ADE</h3> <p>The Directory page has a <strong>Kits</strong> segment next to Skills and Agent Profiles; its badge counts plans waiting for review plus available updates.</p> <ul> <li><strong>Kits</strong> — pending reviews, an install box, and installed kits with their update state; "Check for updates".</li> <li><strong>An installed kit</strong> — Overview (README), Profiles and Skills (the files on disk, read-only, with "Edit in Directory"), Workers (as Compose has them), Files (intact / edited / missing / kept, with "View my changes" for edited ones), Remove, and a registry link.</li> <li><strong>Install review</strong> — the collisions on top (never collapsible) with replace / keep and a split diff for each, the permissions the kit asks for (workers and binaries it adds or moves, functions its profiles preload), the contents in three columns with a preview that shows frontmatter as fields and the prompt as markdown, and a button that says what will happen ("Install and replace 2 profiles"). A blocked plan shows the block instead. While it runs, the three steps (workers → files → kits.lock) report live; a failure offers "Try again".</li> <li><strong>Update review</strong> — release notes, then the changes as a pull request: new and changed profiles (a frontmatter summary, then the diff), workers and ranges, new / changed / removed skills, and the permissions the update grants. "Update" stays disabled while a conflict has no decision; "Ignore <version>" skips the version. A file you edited opens the conflict view: the kit's changes, yours, and an editable result that starts from the automatic merge.</li> <li><strong>Removal review</strong> — the files to delete (edited ones unticked) and the kit's workers (unticked, with a note when another kit uses one).</li> </ul> <p>Chat cards render <code class="readme-inline-code">download-kit</code>, <code class="readme-inline-code">plan-update</code> and <code class="readme-inline-code">remove</code> (the plan summary and "Review install", which opens this segment on the plan), <code class="readme-inline-code">apply</code> (live steps, the result, and the plan summary while a harness approval is pending), <code class="readme-inline-code">check-updates</code> and <code class="readme-inline-code">kits::list</code>.</p> <hr> <h2 id="functions" class="scroll-mt-20">Functions</h2> <p>Functions sit under <code class="readme-inline-code">directory::*</code>. All registrations are namespace-clean; this worker is intentionally agnostic to MCP and any other adapter.</p> <h3 id="directoryskills-filesystem-reader-editor" class="scroll-mt-20"><code class="readme-inline-code">directory::skills::*</code> (filesystem reader + editor)</h3> <table> <thead> <tr> <th>Function ID</th> <th>Description</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">directory::skills::download</code></td> <td>Download directory content. Flexible alias accepting either source set: <code class="readme-inline-code">{repo, skill, branch?}</code> (defaults <code class="readme-inline-code">branch=main</code>) or <code class="readme-inline-code">{worker, version?|tag?}</code> (defaults <code class="readme-inline-code">tag=latest</code>). Prefer the two explicit forms below so the source is unambiguous.</td> </tr> <tr> <td><code class="readme-inline-code">directory::skills::download_from_repo</code></td> <td>Repo-only form: <code class="readme-inline-code">{repo, skill, branch?}</code>. Copies one skill folder out of a GitHub repo; paths under <code class="readme-inline-code">prompts/</code> and <code class="readme-inline-code">agents/</code> are ignored.</td> </tr> <tr> <td><code class="readme-inline-code">directory::skills::download_from_registry</code></td> <td>Registry-only form: <code class="readme-inline-code">{worker, version?|tag?}</code>. Installs a published worker's bundle from <code class="readme-inline-code">api.workers.iii.dev</code>, routing exact <code class="readme-inline-code">agents/<id>.md</code> entries to <code class="readme-inline-code">agents_folder</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::skills::list</code></td> <td>Enriched listing of every fs-backed skill: <code class="readme-inline-code">{ id, title, type, function_id, disable_model_invocation, description, bytes, modified_at }</code> per row. <code class="readme-inline-code">title</code> prefers the YAML frontmatter <code class="readme-inline-code">title:</code> over the body H1, <code class="readme-inline-code">type</code> is lifted from frontmatter <code class="readme-inline-code">type:</code> (<code class="readme-inline-code">null</code> when absent), <code class="readme-inline-code">function_id</code> identifies the documented bus function when present, and <code class="readme-inline-code">description</code> is the frontmatter description or first body paragraph — so consumers can render a picker without a follow-up <code class="readme-inline-code">get</code> per row.</td> </tr> <tr> <td><code class="readme-inline-code">directory::skills::get</code></td> <td>Fetch one skill by id. Returns <code class="readme-inline-code">{ id, title, type, function_id, disable_model_invocation, path, body, modified_at }</code>. It shares the list row's identity, classification, function, and invocation metadata, but returns the raw markdown <code class="readme-inline-code">body</code> and absolute on-disk <code class="readme-inline-code">path</code> instead of the teaser and byte count; there is no <code class="readme-inline-code">description</code> field. The path's parent directory is the skill's base directory, where payload like <code class="readme-inline-code">scripts/</code> and <code class="readme-inline-code">reference/</code> lives, and is meaningful only to callers on this worker's machine. Accepts a bare id or the same id prefixed with <code class="readme-inline-code">iii://</code>. Pass <code class="readme-inline-code">raw: true</code> to additionally get the FULL on-disk file (frontmatter included) as <code class="readme-inline-code">raw</code> — the round-trip form <code class="readme-inline-code">update</code> takes.</td> </tr> <tr> <td><code class="readme-inline-code">directory::skills::update</code></td> <td>Overwrite one EXISTING skill file with new full-file content: <code class="readme-inline-code">{ id, content }</code> where <code class="readme-inline-code">content</code> is the edited <code class="readme-inline-code">raw</code> from <code class="readme-inline-code">get { raw: true }</code>. Validated against the read invariants (size cap, non-empty body after frontmatter); atomic write; fans out <code class="readme-inline-code">directory::skills::on-change</code> with <code class="readme-inline-code">op: "update"</code>. Never creates files (use <code class="readme-inline-code">create</code>). Refuses read-only system-installed skills under <code class="readme-inline-code">agents_skills_folder</code> (<code class="readme-inline-code">D116</code>).</td> </tr> <tr> <td><code class="readme-inline-code">directory::skills::create</code></td> <td>Create a NEW skill file at <code class="readme-inline-code"><skills_folder>/<id>.md</code> from full-file content: <code class="readme-inline-code">{ id, content }</code>. Frontmatter is optional (same rules as <code class="readme-inline-code">update</code>: size cap, non-empty body). Refuses an <code class="readme-inline-code">id</code> that already resolves in the visible set — including the <code class="readme-inline-code"><id></code> → <code class="readme-inline-code"><id>/index</code> overview alias and system-installed agents skills — or a target path that already exists on disk (<code class="readme-inline-code">D114</code>); an <code class="readme-inline-code">id</code> in a namespace reserved by a system-installed agents skill (<code class="readme-inline-code">D115</code>); and, while <code class="readme-inline-code">filter_unregistered</code> is on, an <code class="readme-inline-code">id</code> the visibility filter would immediately hide (<code class="readme-inline-code">D115</code>). Atomic write; fans out <code class="readme-inline-code">directory::skills::on-change</code> with <code class="readme-inline-code">op: "create"</code>. Returns the same shape as <code class="readme-inline-code">update</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::skills::delete</code></td> <td>Permanently remove one EXISTING skill file by <code class="readme-inline-code">{ id }</code> (same id forms as <code class="readme-inline-code">get</code>). Resolves against the same visible set as <code class="readme-inline-code">list</code>/<code class="readme-inline-code">get</code>, refuses read-only system-installed skills under <code class="readme-inline-code">agents_skills_folder</code> (<code class="readme-inline-code">D116</code>), removes the file plus any parent directories left empty (so a deleted namespace can't keep shadowing a lower-precedence root), and fans out <code class="readme-inline-code">directory::skills::on-change</code> with <code class="readme-inline-code">op: "delete"</code>. Returns <code class="readme-inline-code">{ id }</code> (the resolved on-disk id).</td> </tr> <tr> <td><code class="readme-inline-code">directory::skills::index</code></td> <td>Render one short markdown entry per installed worker (skills with frontmatter <code class="readme-inline-code">type: index</code>). Returns <code class="readme-inline-code">{ body, workers_count }</code> where <code class="readme-inline-code">body</code> is a ready-to-paste page: <code class="readme-inline-code"># Skills index</code>, then one <code class="readme-inline-code">## <worker title></code> heading + the worker's first overview paragraph + a <code class="readme-inline-code">Read iii://<ns>/index</code> pointer the agent can follow with <code class="readme-inline-code">directory::skills::get</code>. Token-light by design; use <code class="readme-inline-code">directory::skills::list</code> for per-skill rows.</td> </tr> </tbody></table> <h3 id="directorysystem-prompts-filesystem-reader-editor" class="scroll-mt-20"><code class="readme-inline-code">directory::system-prompts::*</code> (filesystem reader + editor)</h3> <table> <thead> <tr> <th>Function ID</th> <th>Description</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">directory::system-prompts::list</code></td> <td>Metadata-only listing of every fs-backed system prompt.</td> </tr> <tr> <td><code class="readme-inline-code">directory::system-prompts::get</code></td> <td>Fetch one system prompt's body + <code class="readme-inline-code">{name, description, modified_at}</code>. Plain shape, no envelope. Pass <code class="readme-inline-code">raw: true</code> to additionally get the FULL on-disk file (frontmatter included) as <code class="readme-inline-code">raw</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::system-prompts::update</code></td> <td>Overwrite one EXISTING system prompt file with new full-file content: <code class="readme-inline-code">{ name, content }</code>. The frontmatter must keep a non-empty <code class="readme-inline-code">description</code> (and a valid <code class="readme-inline-code">name</code> when declared) — the same rules the scanner enforces. Atomic write; fans out <code class="readme-inline-code">directory::system-prompts::on-change</code> with <code class="readme-inline-code">op: "update"</code>. Returns the system prompt's effective name after the write.</td> </tr> <tr> <td><code class="readme-inline-code">directory::system-prompts::create</code></td> <td>Create a NEW system prompt file at <code class="readme-inline-code"><skills_folder>/system-prompts/<name>.md</code> from full-file content: <code class="readme-inline-code">{ name, content }</code>, where <code class="readme-inline-code">content</code> is the FULL file including frontmatter. The frontmatter must carry a non-empty <code class="readme-inline-code">description</code> (and a <code class="readme-inline-code">name</code> matching the request, when declared) — the same rules <code class="readme-inline-code">update</code> enforces. Refuses a <code class="readme-inline-code">name</code> that already exists anywhere in the merged system-prompt scan, and a target path that already exists on disk even if the scanner would skip it. Atomic write; fans out <code class="readme-inline-code">directory::system-prompts::on-change</code> with <code class="readme-inline-code">op: "create"</code>. Returns <code class="readme-inline-code">{ name, description, bytes, modified_at }</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::system-prompts::delete</code></td> <td>Permanently remove one EXISTING system prompt file by <code class="readme-inline-code">{ name }</code>. Resolves against the same merged scan as <code class="readme-inline-code">list</code>/<code class="readme-inline-code">get</code>, fans out <code class="readme-inline-code">directory::system-prompts::on-change</code> with <code class="readme-inline-code">op: "delete"</code>, and returns <code class="readme-inline-code">{ name }</code>.</td> </tr> </tbody></table> <h3 id="agent-profiles-directoryagents-filesystem-reader-editor" class="scroll-mt-20">Agent Profiles — <code class="readme-inline-code">directory::agents::*</code> (filesystem reader + editor)</h3> <table> <thead> <tr> <th>Function ID</th> <th>Description</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">directory::agents::list</code></td> <td>Metadata-only listing of every agent profile — fs-backed plus the bundled <code class="readme-inline-code">default</code> / <code class="readme-inline-code">iii</code> / <code class="readme-inline-code">iii-minimal</code> profiles (<code class="readme-inline-code">builtin: true</code> until a local file shadows one): <code class="readme-inline-code">{ id, name, description, logo, skill_count, model, reasoning_effort, icon, color, extends, hidden, composer_placeholder, modified_at }</code> per row (<code class="readme-inline-code">hidden</code> and <code class="readme-inline-code">composer_placeholder</code> omitted when unset; <code class="readme-inline-code">composer_placeholder</code> never inherits), <code class="readme-inline-code">skill_count</code>/<code class="readme-inline-code">model</code>/<code class="readme-inline-code">reasoning_effort</code> resolved through <code class="readme-inline-code">extends</code> (<code class="readme-inline-code">skill_count: null</code> = every skill; <code class="readme-inline-code">model: null</code> = the send decides). A row whose chain does not resolve carries <code class="readme-inline-code">inheritance_error</code>. Every row carries <code class="readme-inline-code">source: { kind: kit | worker | local | global | builtin, kit?, worker?, version?, modified? }</code> — see <a href="#precedence-and-collisions">Precedence and collisions</a>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::agents::get</code></td> <td>Fetch one agent profile by <code class="readme-inline-code">{ id }</code>: the RESOLVED <code class="readme-inline-code">system_prompt</code> (each ancestor's body root-first, then this file's body), <code class="readme-inline-code">skills</code> + <code class="readme-inline-code">unknown_skills</code> (preloaded ids matching no visible skill — warnings), <code class="readme-inline-code">skills_index</code> (resolved through <code class="readme-inline-code">extends</code>; <code class="readme-inline-code">false</code> = sessions start without the skills index, omitted when unset), <code class="readme-inline-code">model</code> (<code class="readme-inline-code">null</code> = the send decides), provider-native <code class="readme-inline-code">reasoning_effort</code>, display <code class="readme-inline-code">icon</code>/<code class="readme-inline-code">color</code>, <code class="readme-inline-code">extends</code>, <code class="readme-inline-code">hidden</code>, the profile's own <code class="readme-inline-code">composer_placeholder</code> (omitted when unset), <code class="readme-inline-code">builtin</code>, <code class="readme-inline-code">modified_at</code>, and <code class="readme-inline-code">inheritance_error</code> when the chain does not resolve (own file served meanwhile), and the same <code class="readme-inline-code">source</code> as <code class="readme-inline-code">list</code>. Pass <code class="readme-inline-code">raw: true</code> to additionally get this profile's FULL on-disk file as <code class="readme-inline-code">raw</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::agents::update</code></td> <td>Overwrite one EXISTING agent profile file with new full-file content: <code class="readme-inline-code">{ id, content }</code>. Same rules the scanner enforces (required frontmatter with non-empty <code class="readme-inline-code">name</code>, emoji-only <code class="readme-inline-code">logo</code>; the body — the system prompt — may be empty); the id stays the file stem. Updating a bundled profile creates the local file that shadows it. Atomic write; fans out <code class="readme-inline-code">directory::agents::on-change</code> with <code class="readme-inline-code">op: "update"</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::agents::create</code></td> <td>Create a NEW agent profile at <code class="readme-inline-code"><agents_folder>/<id>.md</code> from full-file content: <code class="readme-inline-code">{ id, content }</code>. Refuses an <code class="readme-inline-code">id</code> that already exists in the configured agent-profile root, and a target path that already exists on disk even if the scanner would skip it; creating a bundled id shadows the bundled copy. Atomic write; fans out <code class="readme-inline-code">directory::agents::on-change</code> with <code class="readme-inline-code">op: "create"</code>. Returns <code class="readme-inline-code">{ id, name, description, logo, bytes, modified_at }</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::agents::delete</code></td> <td>Permanently remove one EXISTING agent profile file by <code class="readme-inline-code">{ id }</code>. Resolves against the same configured root as <code class="readme-inline-code">list</code>/<code class="readme-inline-code">get</code>, fans out <code class="readme-inline-code">directory::agents::on-change</code> with <code class="readme-inline-code">op: "delete"</code>, and returns <code class="readme-inline-code">{ id }</code>. Deleting the local shadow of a bundled profile falls back to the bundled copy; a bundled profile with no local file has nothing to delete (<code class="readme-inline-code">D414</code>). Sessions already using the profile are unaffected; profiles extending it stop resolving until fixed.</td> </tr> <tr> <td><code class="readme-inline-code">directory::agents::functions::add</code></td> <td><code class="readme-inline-code">{ id, functions: ["coder::tree", …] }</code> — append engine function ids to one EXISTING profile's OWN <code class="readme-inline-code">functions:</code> list (its <em>preloaded</em> functions: the contracts the harness pre-loads into the system prompt of every new session running as the profile). Ids already present are kept once; only that frontmatter field is rewritten (block style), every other byte of the file is untouched; writes atomically, copy-on-writes a bundled profile's shadow, fans out <code class="readme-inline-code">on-change</code> with <code class="readme-inline-code">op: "update"</code>. Returns <code class="readme-inline-code">{ id, functions, added, unchanged?, bytes, modified_at }</code> — <code class="readme-inline-code">unchanged: true</code> means nothing was written. <code class="readme-inline-code">D416</code> for a request with no valid ids (entries must be non-empty and whitespace-free).</td> </tr> <tr> <td><code class="readme-inline-code">directory::agents::functions::remove</code></td> <td><code class="readme-inline-code">{ id, functions }</code> — drop ids from one EXISTING profile's OWN <code class="readme-inline-code">functions:</code> list (absent ids are ignored; the field disappears when the list empties). Same write semantics and <code class="readme-inline-code">D416</code>; returns <code class="readme-inline-code">{ id, functions, removed, unchanged?, bytes, modified_at }</code>. Neither verb touches ids inherited through <code class="readme-inline-code">extends</code> — those stay in the resolved union and are removed on the parent that declares them.</td> </tr> </tbody></table> <h3 id="kits-directorydownload-kit-directorykits" class="scroll-mt-20">Kits — <code class="readme-inline-code">directory::download-kit</code>, <code class="readme-inline-code">directory::kits::*</code></h3> <table> <thead> <tr> <th>Function</th> <th>Description</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">directory::download-kit</code></td> <td><code class="readme-inline-code">{ kit: "<author>/<kit>[@version|tag|range]", apply? }</code> → <code class="readme-inline-code">{ status: planned | applied | up_to_date, kit, message, plan?, report? }</code>. Builds an install plan (an update plan when the kit is installed; without <code class="readme-inline-code">@…</code> an installed kit keeps its <code class="readme-inline-code">requested</code>) and stores it; writes nothing unless <code class="readme-inline-code">apply: true</code> and the plan has no warnings, blocks or pending decisions.</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::apply</code></td> <td><code class="readme-inline-code">{ plan_id, decisions?, remove_workers? }</code> → <code class="readme-inline-code">{ status: applied | replanned, report?, plan? }</code>. <code class="readme-inline-code">decisions</code> maps install paths to <code class="readme-inline-code">overwrite | keep | kit | mine | merged | remove</code> or <code class="readme-inline-code">{ choice: "merged", content }</code>; files left out take the plan's <code class="readme-inline-code">default</code>. The <code class="readme-inline-code">report</code> lists files written / merged / removed / kept, workers added / updated / removed, the steps, and the agent ids the kit now provides.</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::plan-update</code></td> <td><code class="readme-inline-code">{ kit, version? }</code> — plan an update (default target: the newest release matching <code class="readme-inline-code">requested</code>). <code class="readme-inline-code">up_to_date</code> when there is nothing newer.</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::remove</code></td> <td><code class="readme-inline-code">{ kit }</code> — plan a removal; apply it with <code class="readme-inline-code">apply</code> (<code class="readme-inline-code">remove_workers</code> to remove the kit's workers too).</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::check-updates</code></td> <td><code class="readme-inline-code">{ kit? }</code> → <code class="readme-inline-code">{ checked_at, available, kits: [{ kit, current, available, latest, major, ignored?, deprecation? }], error? }</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::list</code></td> <td>Installed kits (<code class="readme-inline-code">version</code>, <code class="readme-inline-code">requested</code>, file-state counts, workers, <code class="readme-inline-code">update</code>, pending plan ids) and pending plan summaries; <code class="readme-inline-code">attention</code> = pending plans + available updates.</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::get</code></td> <td><code class="readme-inline-code">{ kit, registry? }</code> — one installed kit with every file's state and on-disk sha, its workers as Compose has them, and with <code class="readme-inline-code">registry: true</code> the installed version's registry detail and README.</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::plan</code></td> <td><code class="readme-inline-code">{ plan_id, contents? }</code> — a pending plan, its apply progress, and with <code class="readme-inline-code">contents: true</code> the bodies it refers to (<code class="readme-inline-code">blobs</code> by sha256, <code class="readme-inline-code">ours</code> and <code class="readme-inline-code">merged</code> by install path).</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::discard</code></td> <td><code class="readme-inline-code">{ plan_id }</code> — drop a pending plan.</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::ignore</code></td> <td><code class="readme-inline-code">{ kit, version, ignore? }</code> — add a version to (or with <code class="readme-inline-code">ignore: false</code> remove it from) <code class="readme-inline-code">ignored_versions</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::diff</code></td> <td><code class="readme-inline-code">{ kit, path }</code> → <code class="readme-inline-code">{ base, local, state }</code> — what the kit installed and what is on disk, for "view my changes".</td> </tr> </tbody></table> <p>Errors: <code class="readme-inline-code">D510</code> unknown kit or version, <code class="readme-inline-code">D511</code> malformed kit ref, <code class="readme-inline-code">D512</code> expired or unknown plan, <code class="readme-inline-code">D513</code> missing or invalid decisions, <code class="readme-inline-code">D514</code> blocked plan (Compose not running, deprecated kit), <code class="readme-inline-code">D515</code> Compose operation failed, <code class="readme-inline-code">D516</code> the registry served different content than the plan reviewed, <code class="readme-inline-code">D520</code> registry unreachable.</p> <h3 id="engine-introspection-native-plus-one-wrapper" class="scroll-mt-20">Engine introspection (native, plus one wrapper)</h3> <p>Engine introspection is served natively; call these ids directly — every one takes the same filters (<code class="readme-inline-code">prefix</code>, <code class="readme-inline-code">search</code>, <code class="readme-inline-code">worker</code>, <code class="readme-inline-code">include_internal</code> where applicable). One wrapper is kept for callers whose policy only admits the <code class="readme-inline-code">directory::</code> namespace:</p> <table> <thead> <tr> <th>Function ID</th> <th>Description</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">directory::engine::functions::info</code></td> <td>Thin proxy to <code class="readme-inline-code">engine::functions::info</code> for a single <code class="readme-inline-code">function_id</code>: request/response schemas, metadata, and registered triggers. The one <code class="readme-inline-code">directory::engine::*</code> helper that still exists — reach for it only when you cannot call <code class="readme-inline-code">engine::*</code> directly.</td> </tr> </tbody></table> <p>The native ids:</p> <table> <thead> <tr> <th>Function ID</th> <th>Description</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">engine::functions::list</code></td> <td>List functions registered with the engine.</td> </tr> <tr> <td><code class="readme-inline-code">engine::functions::info</code></td> <td>Single-function detail: schemas, owning worker.</td> </tr> <tr> <td><code class="readme-inline-code">engine::triggers::list</code></td> <td>List trigger TYPES (the providers, e.g. <code class="readme-inline-code">http</code>, <code class="readme-inline-code">cron</code>).</td> </tr> <tr> <td><code class="readme-inline-code">engine::triggers::info</code></td> <td>Single trigger-type detail: configuration schema, return schema.</td> </tr> <tr> <td><code class="readme-inline-code">engine::registered-triggers::list</code></td> <td>List trigger INSTANCES (subscriber rows).</td> </tr> <tr> <td><code class="readme-inline-code">engine::registered-triggers::info</code></td> <td>Single registered-trigger detail.</td> </tr> <tr> <td><code class="readme-inline-code">engine::workers::list</code></td> <td>List workers with an open engine WS connection. Daemon-managed providers (<code class="readme-inline-code">http</code>, <code class="readme-inline-code">cron</code>, <code class="readme-inline-code">state</code>) won't appear — call <code class="readme-inline-code">worker::list</code> from the supervisor to see those.</td> </tr> <tr> <td><code class="readme-inline-code">engine::workers::info</code></td> <td>One worker's detail by <code class="readme-inline-code">name</code>.</td> </tr> </tbody></table> <h3 id="directoryregistry-workers-registry-http-proxy" class="scroll-mt-20"><code class="readme-inline-code">directory::registry::*</code> (workers registry HTTP proxy)</h3> <table> <thead> <tr> <th>Function ID</th> <th>Description</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">directory::registry::workers::list</code></td> <td>Browse / search published workers in <code class="readme-inline-code">api.workers.iii.dev</code>. Optional free-text <code class="readme-inline-code">search</code> (matched fuzzy by <code class="readme-inline-code">pg_trgm</code>) and opaque <code class="readme-inline-code">cursor</code> for pagination; page size is server-authored. Response is <code class="readme-inline-code">{ workers: [...], pagination: { next_cursor, has_more, page_size } }</code>. Shares the core <code class="readme-inline-code">name</code> / <code class="readme-inline-code">description</code> / <code class="readme-inline-code">version</code> fields with the engine's <code class="readme-inline-code">engine::workers::list</code>.</td> </tr> <tr> <td><code class="readme-inline-code">directory::registry::workers::info</code></td> <td>Pre-install card for one worker. Fans out two parallel registry calls — <code class="readme-inline-code">GET /w/{slug}</code> for the worker envelope (publication metadata + readme + functions + triggers) and <code class="readme-inline-code">GET /w/{slug}/skills</code> for the skills tree — and merges them into <code class="readme-inline-code">{ worker, api_reference, skills_tree, readme? }</code>. The card keeps public function/trigger names and descriptions only: request/response schemas, metadata, internal and search-excluded functions are dropped (browser's schemas alone ran 65 KB; the contract is <code class="readme-inline-code">engine::functions::info</code> after installing), and <code class="readme-inline-code">readme</code> (10–25 KB) is included only with <code class="readme-inline-code">readme: true</code>. The full record stays cached in-process for <code class="readme-inline-code">directory::search_functions</code>. Input still accepts <code class="readme-inline-code">version:</code> (semver) or <code class="readme-inline-code">tag:</code> (e.g. <code class="readme-inline-code">latest</code>); both go on the wire as <code class="readme-inline-code">?version=…</code>.</td> </tr> </tbody></table> <p>Both <code class="readme-inline-code">directory::registry::*</code> responses are cached in-process for <code class="readme-inline-code">registry_cache_ttl_ms</code> (default 60s).</p> <p>There is <strong>no</strong> <code class="readme-inline-code">directory::skills::register</code> — see <a href="#migration-from-skills-v02x">Migration</a> below.</p> <hr> <h2 id="function-search-pre-generate-hint" class="scroll-mt-20">Function search & pre-generate hint</h2> <p>One-shot function search over the live engine catalog. <code class="readme-inline-code">judge</code> (the default) ranks through the optional <code class="readme-inline-code">judge</code> worker when it is registered and answers, and otherwise behaves as <code class="readme-inline-code">hybrid</code> (BM25 fused with the local MiniLM model, reranked); <code class="readme-inline-code">lexical</code> is BM25 only. Absorbed from the former <code class="readme-inline-code">discovery</code> worker, it returns only compact <code class="readme-inline-code">{ function_id, description }</code> candidates, grouped by worker in rank order. The model chooses the candidates it needs, then fetches their contracts in one <code class="readme-inline-code">engine::functions::info { function_ids: [...] }</code> call instead of walking the catalog with <code class="readme-inline-code">engine::functions::list</code>.</p> <table> <thead> <tr> <th>Function</th> <th>Kind</th> <th>What it does</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">directory::search_functions</code></td> <td>public</td> <td><code class="readme-inline-code">{ capabilities }</code> → <code class="readme-inline-code">{ guidance, workers[], installable[]?, skills[]?, triggers[]?, search_mode, latency_ms }</code>: rank with the configured mode over the live engine catalog in batches of six capabilities (12 candidates per batch across at most max(6, 2 × capabilities) workers, up to 3 batches) plus matching NOT-installed registry workers under <code class="readme-inline-code">installable</code>. <code class="readme-inline-code">capabilities</code> is a required list of non-empty unmet external capability searches (one to six is the norm); entries past the 18th are not searched and are named in <code class="readme-inline-code">guidance</code>. Requests to summarize provided text/content are ignored.</td> </tr> <tr> <td><code class="readme-inline-code">directory::pre-generate</code></td> <td>internal hook</td> <td>Injects the conditional search hint into a harness generation (at most once per turn).</td> </tr> <tr> <td><code class="readme-inline-code">directory::on-functions-change</code></td> <td>internal</td> <td>Refreshes the search catalog on the engine's functions-available push.</td> </tr> <tr> <td><code class="readme-inline-code">directory::hint-preview</code></td> <td>internal</td> <td>The exact hint text per exposure mode, for the configuration UI.</td> </tr> </tbody></table> <p>Lexical/Hybrid ranking pipeline:</p> <ol> <li><strong>Corpus</strong>: the live engine catalog (boot snapshot + push refresh), slimmed to name + first description sentence + argument names. <code class="readme-inline-code">engine::</code> ids, functions published with <code class="readme-inline-code">metadata.internal</code>, and the search itself never participate — the worker's own public <code class="readme-inline-code">directory::*</code> functions are searchable like any other capability.</li> <li><strong>Scoring</strong>: Okapi BM25 (k1 1.2, b 0.75) with the function name indexed at 3× weight, camelCase segmentation (<code class="readme-inline-code">presignUrl</code> → presign + url), a 22-word grammatical stoplist, conservative plural folding, JSON-key stripping from capability text, and a two-distinct-terms minimum match.</li> <li><strong>Capability queries</strong>: each <code class="readme-inline-code">capabilities</code> entry is ranked independently against its own leader and is authoritative. Include every currently unmet external capability once in the same call. Write every capability in English, translating non-English requests while preserving proper names, URLs, and function ids. Requests to summarize provided text or content are ignored. Results merge round-robin so every capability gets a candidate before any gets a rider.</li> <li><strong>Pruning</strong>: coverage-aware function floor (≥50% of the leader AND full term coverage or ≥85% score) drops same-worker family riders; a namespace-level floor (40% of the leader) drops trailing workers.</li> <li><strong>Registry search</strong> (<code class="readme-inline-code">registry_search</code>, default on): every call also consults the private workers registry in-process with the same capability queries plus informative-term retries (all concurrent; every listed worker is a candidate — the registry is team-authored). Candidates merge round-robin across search variants; their API references are pooled and ranked per capability with the configured mode. Hybrid fuses BM25 with the MiniLM dense lane (same 0.30 admission floor as the installed catalog), so a capability sharing no vocabulary with a contract ("retrieve web news articles" → <code class="readme-inline-code">web::fetch</code>) still surfaces. Returns up to 2 workers / 6 candidates per batch of six capabilities (so up to 6 workers / 18 candidates across three batches; a worker two batches both surface keeps one entry with its functions merged) that WOULD match if installed, with <code class="readme-inline-code">compose::add</code> guidance.</li> <li><strong>Session memory</strong> (keyed by caller-supplied OTel baggage, fail-open): repeat queries omit candidates already delivered.</li> </ol> <h3 id="judge-mode" class="scroll-mt-20">Judge mode</h3> <p>Function relevance is judged by the <a href="../judge"><code class="readme-inline-code">judge</code></a> worker (<code class="readme-inline-code">judge::evaluate</code>), which forwards to its configured provider (<a href="../judge-typesafe"><code class="readme-inline-code">judge-typesafe</code></a> by default). Both are optional: this worker does not declare them as dependencies, because Compose turns a dependency into a <code class="readme-inline-code">start_after</code> edge and stops the directory whenever the judge exits. The Harness and dev-template stacks do not run them. Install the hub with <code class="readme-inline-code">iii trigger compose::add worker=judge</code> (it brings <code class="readme-inline-code">judge-typesafe</code>) and set the TypeSafe key and model in the <strong>judge-typesafe</strong> settings. This worker holds no credentials.</p> <p><code class="readme-inline-code">judge</code> is the default mode for new installs. It ranks through the judge only while <code class="readme-inline-code">judge::evaluate</code> is in the live function catalog and answers. <strong>Whenever the judge is unavailable the search uses Hybrid</strong> (then Lexical if the local model is not ready), for functions, installable workers, skills and triggers alike:</p> <ul> <li><code class="readme-inline-code">judge::evaluate</code> is not registered: no call is made at all.</li> <li>the hub has no provider (<code class="readme-inline-code">provider_unavailable</code>), or the provider has no API key (<code class="readme-inline-code">missing_key</code>): logged once at info.</li> <li>a provider error, transport failure or invalid reply: logged once as a warning.</li> <li>the judge deadline runs out: that lane alone uses Hybrid.</li> </ul> <p>After an unavailable or failing judge (the second and third cases), every search skips it for 30 seconds and uses Hybrid, so a missing key costs one fast round trip per 30 s rather than one per search. A key added to judge-typesafe, or a judge that comes back, is used within 30 seconds. A missed deadline does not pause the judge.</p> <p>An install that already stored <code class="readme-inline-code">function_search_mode: hybrid</code> keeps it: the stored configuration wins over the new default. Set <code class="readme-inline-code">judge</code> with <code class="readme-inline-code">configuration::set</code> (or the console form) to opt in.</p> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#998418">function_search_mode</span><span style="color:#999999">:</span><span style="color:#B56959"> judge</span></span> <span class="line"><span style="color:#998418">function_search_judge_timeout_ms</span><span style="color:#999999">:</span><span style="color:#2F798A"> 3000</span></span> <span class="line"><span style="color:#998418">function_search_judge_min_relevance</span><span style="color:#999999">:</span><span style="color:#2F798A"> 0.5</span></span> <span class="line"><span style="color:#998418">function_search_judge_side_lane_min_relevance</span><span style="color:#999999">:</span><span style="color:#2F798A"> 0.3</span></span> <span class="line"><span style="color:#998418">function_search_judge_question</span><span style="color:#999999">:</span><span style="color:#B56959"> choice</span></span> <span class="line"><span style="color:#998418">function_search_judge_choice_min_probability</span><span style="color:#999999">:</span><span style="color:#2F798A"> 0.1</span></span></code></pre><p>These fields apply without a restart. The timeout is an integer from 1 to 30000 ms and relevance a finite number from 0 to 1 inclusive. YAML seeds and JSON configuration updates use the same validation. The relevance floors were calibrated against <code class="readme-inline-code">jev-1.13.0</code>; judge-typesafe defaults to the <code class="readme-inline-code">jev-latest</code> alias, so pin its model if you rely on the floors.</p> <p>The judge scores a shortlist per capability, not the whole catalog. A corpus of at most 16 documents goes whole, so the judge still finds functions whose wording shares nothing with the capability. A larger one is cut to the top 16 of raw BM25 fused with the raw MiniLM ranking (when the index is ready). Each capability is one evaluation, and all capabilities of a lane (functions, registry pool, skills or triggers) travel in one <code class="readme-inline-code">judge::evaluate</code> call, so the provider answers them together with one model, and cancels the rest when one fails. Requests carry normalized capabilities, function IDs, short descriptions and parameter names; no conversation history or argument values. Exact eligible IDs, internal-function exclusions, session deduplication and result limits stay local.</p> <p><code class="readme-inline-code">function_search_judge_question</code> sets how each capability's shortlist is asked. <code class="readme-inline-code">choice</code> (the default) asks one multiple-choice question per capability whose options are the shortlisted documents: 16× fewer questions, and the documents compete. The best document is always kept and every other needs <code class="readme-inline-code">function_search_judge_choice_min_probability</code> (the relevance floors do not apply). <code class="readme-inline-code">noul</code> asks one yes/no question per document and admits each by the relevance floors. Local judges need <code class="readme-inline-code">choice</code> to fit the deadline: judge-semif answers a capability in about 0.3 s on a GPU, where the Noul shortlist of every lane takes it past 30 s. On 22 English capabilities over the 16-document shortlist, <code class="readme-inline-code">choice</code> with 0.1 kept a correct function in every search for both <code class="readme-inline-code">jev-1.13.0</code> (precision 0.98, 1.2 functions per capability) and judge-semif (precision 0.87, 1.5 functions). Providers register their <code class="readme-inline-code">judge-<provider>::*</code> functions as internal, so search results show only the hub's <code class="readme-inline-code">judge::*</code>.</p> <p>With <code class="readme-inline-code">choice</code>, a judge whose models advertise a context window under 4096 tokens (<code class="readme-inline-code">context_window</code> in <code class="readme-inline-code">judge::models::list</code>, re-read when the judge hub's configuration changes and at least once a minute) gets compact options instead of the full description objects: each option is keyed by the function id and reads the first eight words of its description, and the state names the capability plainly (<code class="readme-inline-code">{"capability": …}</code>). laya (512 tokens) shares about 190 of them among the sixteen options, so the objects cut the function ids themselves: live, it found the expected function in 13/22 searches with objects and 17/22 compact. SemIf (16384) and judges that advertise no window keep the objects.</p> <p><code class="readme-inline-code">tournament</code> skips the Hybrid shortlist, following TypeSafe's skill-suggestion pattern (skim everything cheaply, then read the few in detail). The whole function catalog, sorted by id, is skimmed in rounds of compact Choices (the function id and the first eight words of its description) over groups of up to 128, or 16 for a judge that advertises a context window under 4096 tokens, and never more than the judge's advertised <code class="readme-inline-code">max_options</code> (SemIf: 16); each group's three best go on (only the winner, for a small-window judge, whose final Choice degrades with more options) until 16 or fewer remain, and those get one final Choice with their full descriptions, admitted like <code class="readme-inline-code">choice</code>. A 260-function catalog takes one round of three groups, then the final Choice over nine. It needs no local semantic model. Live through <code class="readme-inline-code">directory::search_functions</code> over 22 English capabilities (RX 6900 XT), hit / top-1 / precision and median search time: JEV 22 / 22 / 1.00 at 2.2 s, SemIf 22 / 22 / 0.90 at 6.1 s, decider 22 / 21 / 0.88 at 3.7 s, laya 20 / 19 / 0.80 at 2.2 s; the former winner-only rounds of 16 gave JEV 22 / 22 / 0.98, decider 21 / 21 / 0.81 at 9.1 s, and timed SemIf out at 10 s. The installed functions and the registry pools play it; skills and triggers keep their shortlists. With <code class="readme-inline-code">choice</code> (the default), a judge that advertises a context window under 4096 tokens gets a tournament automatically; SemIf and hosted judges keep <code class="readme-inline-code">choice</code>.</p> <p><code class="readme-inline-code">function_search_model_path: null</code> is valid in judge mode and makes the Hybrid fallback BM25-only, without the local-model warning. With a configured path, the worker keeps an installed MiniLM bundle and its catalog index current, downloads a missing bundle at boot like Hybrid does, and uses the index both for the shortlist and for the fallback.</p> <p>Registry discovery still starts with the registry API's lexical search. The judge evaluates a shortlist of the returned contract pool and <strong>cannot recover workers that upstream search did not return</strong>. Installable results remain suggestions until installation.</p> <p>Every response carries <code class="readme-inline-code">search_mode</code> — the mode that actually ranked the results (<code class="readme-inline-code">judge</code>, <code class="readme-inline-code">hybrid</code> or <code class="readme-inline-code">lexical</code>), which can be lower than the configured mode when the judge was unavailable or paused, or the local model is not loaded yet. The console's search card shows it as the card's badge. A search whose lanes partly fell back reports the highest tier any lane reached.</p> <p>Every mode also ranks the installed skill documents (the rows <code class="readme-inline-code">directory::skills::list</code> serves, minus <code class="readme-inline-code">disable_model_invocation</code> ones) against the same capabilities and lists the matches under <code class="readme-inline-code">skills</code> as <code class="readme-inline-code">{ id, title, description }</code>, at most six per call round-robin across the capabilities, with a guidance note to read them through <code class="readme-inline-code">directory::skills::get { id }</code>. Each skill's id and a trimmed <code class="readme-inline-code">title: description</code> (300 bytes) form the document. The judge judges them with a how-to question under the same deadline as the functions; Lexical ranks them with BM25 and Hybrid fuses in the dense lane, the same ad-hoc document ranking the <code class="readme-inline-code">installable</code> section uses, and that local ranking also serves whenever the judge fails. "Installed" is read off the live function catalog: a worker with no registered functions contributes no skills. The registered-trigger section (under <code class="readme-inline-code">triggers</code>) is ranked the same way in every mode.</p> <p>A valid response with no functions at or above the relevance threshold stays empty. Judge failures instead trigger <strong>Judge → Hybrid → Lexical</strong> fallback. Hybrid uses the existing local ranking policy; if the model is disabled, missing, not yet indexed for the current catalog, or fails, Lexical serves the results. A registry HTTP failure still omits the installable section.</p> <p>The judge deadline is shared by every judge call of one public search. Capability batches run concurrently, and each batch's registry lookup runs in parallel with its installed-function judge call; the registry judge call then gets what is left of the deadline and, if nothing is, the pool is ranked locally. Local Hybrid fallback runs outside the budget. Evaluations are split at local byte limits (48 KiB per evaluation, 16 KiB for state plus the largest question); these guards are not token counts. Retries are the provider's policy (judge-typesafe retries 408/429/5xx within the deadline); the 30-second pause keeps a failing provider from being retried on every search. The hub's returned usage (<code class="readme-inline-code">stats</code>) is logged per lane at debug level.</p> <p>Switch to <code class="readme-inline-code">lexical</code> at any time to use BM25 only. Switching from <code class="readme-inline-code">lexical</code> to <code class="readme-inline-code">hybrid</code> or <code class="readme-inline-code">judge</code> prepares the local index from the current catalog. If the MiniLM bundle is missing, both use lexical fallback; the boot-time download and changes to the local model path require a worker restart.</p> <p><strong>Upgrading from the in-worker <code class="readme-inline-code">jev</code> mode:</strong> the stored value <code class="readme-inline-code">function_search_mode: jev</code> no longer parses, and the worker refuses to boot on it. While the old worker still runs, its schema only accepts <code class="readme-inline-code">lexical</code>/<code class="readme-inline-code">hybrid</code>/<code class="readme-inline-code">jev</code>, so before upgrading set the mode to <code class="readme-inline-code">hybrid</code> (or remove the key) with <code class="readme-inline-code">configuration::set</code>, then set <code class="readme-inline-code">judge</code> once the new worker is up. The removed keys <code class="readme-inline-code">function_search_jev_api_key</code> and <code class="readme-inline-code">function_search_jev_model</code> are ignored, and the console form drops every <code class="readme-inline-code">function_search_jev_*</code> key on its next save; the remaining settings are read under their <code class="readme-inline-code">function_search_judge_*</code> names only.</p> <h3 id="pre-generate-hint" class="scroll-mt-20">Pre-generate hint</h3> <p>The pre-generate hook appends one <code class="readme-inline-code"><discovery_assist></code> block pointing the model at <code class="readme-inline-code">search_functions</code>, telling it to derive capabilities from the goal and current execution state and to batch selected ids through <code class="readme-inline-code">engine::functions::info</code> — at most once per turn, and only when every gate clears: the function is callable in the surface, no search result is in the current task window yet, the surface spans at least <code class="readme-inline-code">hint_min_workers</code> distinct workers, the current task (from the latest user message) has no real function results yet, and it does not already name a callable function id. Measured on 26 pre-existing e2e scenarios: an unconditional hint <em>induces</em> redundant discovery on guided tasks (up to +110% tokens). The hook ships OFF by default (<code class="readme-inline-code">inject_hint: false</code>): the harness identity prompt already teaches <code class="readme-inline-code">directory::search_functions</code> as the default discovery path, so the hint is for deployments running a custom identity prompt without that doctrine. The hook's transcript annotations (<code class="readme-inline-code">origin.directory</code>) carry only coarse outcome/reason and counts.</p> <p>Knobs (<code class="readme-inline-code">inject_hint</code>, <code class="readme-inline-code">hint_min_workers</code>, <code class="readme-inline-code">registry_search</code>) live in the <code class="readme-inline-code">iii-directory</code> configuration entry and hot-apply — see Configuration.</p> <h2 id="custom-trigger-types" class="scroll-mt-20">Custom trigger types</h2> <table> <thead> <tr> <th>Trigger type</th> <th>Fires when</th> <th>Payload to subscribers</th> </tr> </thead> <tbody><tr> <td><code class="readme-inline-code">directory::skills::on-change</code></td> <td>After a <code class="readme-inline-code">directory::skills::download</code> that wrote at least one skill markdown file, a <code class="readme-inline-code">directory::skills::update</code>, <code class="readme-inline-code">create</code>, or <code class="readme-inline-code">delete</code>, or external (file pasted/edited/deleted directly on disk — including under <code class="readme-inline-code">agents_skills_folder</code>)</td> <td>download: <code class="readme-inline-code">{ "op": "download", "namespace": "<ns>", "source": "repo" | "registry" }</code>; update/create/delete: <code class="readme-inline-code">{ "op": "<operation>", "namespace": "<ns>", "id": "<id>" }</code>; external (file pasted/edited/deleted directly on disk): <code class="readme-inline-code">{ "op": "external" }</code></td> </tr> <tr> <td><code class="readme-inline-code">directory::system-prompts::on-change</code></td> <td>After a <code class="readme-inline-code">directory::skills::download</code> that wrote at least one system prompt markdown file, a <code class="readme-inline-code">directory::system-prompts::update</code>, <code class="readme-inline-code">create</code>, <code class="readme-inline-code">delete</code>, or external file change</td> <td>download: <code class="readme-inline-code">{ "op": "download", "namespace": "<ns>", "source": "repo" | "registry" }</code>; update/create/delete: <code class="readme-inline-code">{ "op": "<operation>", "name": "<name>" }</code>; external: <code class="readme-inline-code">{ "op": "external" }</code></td> </tr> <tr> <td><code class="readme-inline-code">directory::agents::on-change</code></td> <td>After a <code class="readme-inline-code">directory::skills::download</code> that wrote at least one agent profile, a <code class="readme-inline-code">directory::agents::update</code>, <code class="readme-inline-code">create</code>, <code class="readme-inline-code">delete</code>, or external file change</td> <td>download: <code class="readme-inline-code">{ "op": "download", "namespace": "<ns>", "source": "repo" | "registry" }</code>; update/create/delete: <code class="readme-inline-code">{ "op": "<operation>", "name": "<id>" }</code>; external: <code class="readme-inline-code">{ "op": "external" }</code></td> </tr> <tr> <td><code class="readme-inline-code">directory::kits::on-change</code></td> <td>A kit plan is created or discarded, an apply makes progress or lands, or an update check changes the set of available updates (also fires the skills / agents on-change when an apply wrote those files)</td> <td><code class="readme-inline-code">{ "op": "plan", "kit", "plan_id", "kind" }</code>, <code class="readme-inline-code">{ "op": "discard", "kit", "plan_id" }</code>, <code class="readme-inline-code">{ "op": "progress", "plan_id", "kit", "steps": [{ id, label, state, detail? }], "error"? }</code>, <code class="readme-inline-code">{ "op": "apply", "kit", "plan_id", "kind" }</code>, <code class="readme-inline-code">{ "op": "updates", "kit"? }</code></td> </tr> </tbody></table> <p>Dispatches are fire-and-forget (Void), so the write path doesn't block on downstream latency.</p> <p>The <code class="readme-inline-code">external</code> op comes from a filesystem watch over <code class="readme-inline-code">skills_folder</code>, <code class="readme-inline-code">local_skills_folder</code>, and (when it already exists) the read-only <code class="readme-inline-code">agents_skills_folder</code>. It is a doorbell, not a ledger: every read re-scans disk, so a missed event costs a stale open view until the next call, never data. A burst coalesces into one event per kind, and this worker's own writes are suppressed — a <code class="readme-inline-code">create</code> or <code class="readme-inline-code">update</code> sends its precise op and never an extra <code class="readme-inline-code">external</code>.</p> <p><strong>Loop hazard for subscribers.</strong> Suppression covers writes made <em>through this worker</em>. A subscriber that reacts to <code class="readme-inline-code">{ "op": "external" }</code> by writing <code class="readme-inline-code">.md</code> files under <code class="readme-inline-code">skills_folder</code> by some other route — a shell or coder worker, a script — is not suppressed and will re-trigger itself. Either write through <code class="readme-inline-code">directory::*::update</code> / <code class="readme-inline-code">create</code>, or make the reaction idempotent and gated.</p> <hr> <h2 id="local-development-testing" class="scroll-mt-20">Local development & testing</h2> <h3 id="run-from-source" class="scroll-mt-20">Run from source</h3> <p>On targets with a pinned static ONNX Runtime (Linux glibc x86_64/aarch64, Apple Silicon macOS, Windows MSVC) every build links it and MiniLM retrieval and reranking are compiled in. With no <code class="readme-inline-code">ORT_LIB_PATH</code>, <code class="readme-inline-code">ort-sys</code> downloads the runtime for the build target at build time (SHA-256-verified). For offline or cached x86_64 Linux builds, provision it once and export the path it prints:</p> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#AB5959">export</span><span style="color:#B07D48"> ORT_LIB_PATH</span><span style="color:#999999">=</span><span style="color:#B5695977">"</span><span style="color:#999999">$(</span><span style="color:#59873A">scripts/provision-onnxruntime.sh</span><span style="color:#999999">)</span><span style="color:#B5695977">"</span><span style="color:#A0ADA0"> # idempotent, SHA-256 verified</span></span> <span class="line"><span style="color:#AB5959">export</span><span style="color:#B07D48"> ORT_PREFER_DYNAMIC_LINK</span><span style="color:#999999">=</span><span style="color:#2F798A">0</span></span></code></pre><p>Other targets (musl, armv7, Intel macOS) build the BM25-only worker and need nothing extra.</p> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#A0ADA0"># --config is an optional YAML seed (see config.yaml.example); omit it to</span></span> <span class="line"><span style="color:#A0ADA0"># rely on the value stored in the `configuration` worker (or built-in defaults).</span></span> <span class="line"><span style="color:#59873A">cargo</span><span style="color:#B56959"> run</span><span style="color:#A65E2B"> --release</span><span style="color:#A65E2B"> --</span><span style="color:#A65E2B"> --url</span><span style="color:#B56959"> ws://127.0.0.1:49134</span><span style="color:#A65E2B"> --config</span><span style="color:#B56959"> ./config.yaml.example</span></span></code></pre><h3 id="tests" class="scroll-mt-20">Tests</h3> <pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span style="color:#A0ADA0"># Fast, offline — exercises the pure helpers (markdown / id validators</span></span> <span class="line"><span style="color:#A0ADA0"># / fs source) without needing an iii engine.</span></span> <span class="line"><span style="color:#59873A">cargo</span><span style="color:#B56959"> test</span><span style="color:#A65E2B"> --lib</span></span> <span class="line"></span> <span class="line"><span style="color:#A0ADA0"># Full BDD suite — requires an iii engine on ws://127.0.0.1:49134</span></span> <span class="line"><span style="color:#A0ADA0"># (or III_ENGINE_WS_URL). The git-backed download scenarios spin up</span></span> <span class="line"><span style="color:#A0ADA0"># a local fixture repo via `git init`; the registry-backed scenarios</span></span> <span class="line"><span style="color:#A0ADA0"># point a wiremock server at the worker's `registry_url` config.</span></span> <span class="line"><span style="color:#59873A">cargo</span><span style="color:#B56959"> test</span></span> <span class="line"></span> <span class="line"><span style="color:#A0ADA0"># One feature group at a time. Available tags:</span></span> <span class="line"><span style="color:#A0ADA0"># @engine @read @download @download_repo @download_registry</span></span> <span class="line"><span style="color:#59873A">cargo</span><span style="color:#B56959"> test</span><span style="color:#A65E2B"> --test</span><span style="color:#B56959"> bdd</span><span style="color:#A65E2B"> --</span><span style="color:#A65E2B"> --tags</span><span style="color:#B56959"> @download</span></span></code></pre><p>The BDD harness lives under <a href="tests/">tests/</a>. Feature files mirror the modules in <a href="src/functions/">src/functions/</a>. Step definitions under <a href="tests/steps/">tests/steps/</a> drive each feature through the same <code class="readme-inline-code">iii.trigger</code> path the production binary uses.</p> </div></div></section></div><aside class="flex flex-col gap-y-4 @4xl:sticky @4xl:top-4 @4xl:self-start @4xl:max-h-[calc(100dvh-2rem)] @4xl:overflow-y-auto"><div class="border border-rule bg-bg"><div class="bg-panel px-3.5 py-2.5 border-b border-rule"><span class="font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-ink-faint">details</span></div><div class="p-4 flex flex-col gap-y-2.5"><div class="flex items-baseline justify-between font-mono text-[13px] gap-x-3"><span class="text-ink-faint shrink-0 uppercase tracking-[0.06em] text-[11px]">version</span><span class="text-ink truncate text-right lowercase tabular-nums">v1.2.40</span></div><div class="flex items-baseline justify-between font-mono text-[13px] gap-x-3"><span class="text-ink-faint shrink-0 uppercase tracking-[0.06em] text-[11px]">type</span><span class="text-ink truncate text-right lowercase ">binary</span></div><div class="flex items-baseline justify-between font-mono text-[13px] gap-x-3"><span class="text-ink-faint shrink-0 uppercase tracking-[0.06em] text-[11px]">license</span><span class="text-ink truncate text-right ">Apache-2.0</span></div><div class="flex items-baseline justify-between font-mono text-[13px] gap-x-3 min-w-0"><span class="text-ink-faint shrink-0 uppercase tracking-[0.06em] text-[11px]">repo</span><a href="https://github.com/iii-hq/workers" target="_blank" rel="noreferrer" class="inline-flex items-center gap-x-1 font-mono text-[13px] text-ink lowercase hover:text-accent transition-colors min-w-0 text-right justify-end"><span class="truncate">iii-hq/workers</span><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-external-link size-3 shrink-0" aria-hidden="true"><path d="M15 3h6v6"></path><path d="M10 14 21 3"></path><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path></svg></a></div></div></div><section id="used-in-kits" class="border border-rule bg-bg scroll-mt-20" aria-labelledby="used-in-kits-title"><div class="flex items-baseline justify-between bg-panel px-3.5 py-2.5 border-b border-rule"><span id="used-in-kits-title" class="font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-ink-faint">used in <!-- -->1<!-- --> <!-- -->kit</span></div><ul class="divide-y divide-rule-2"><li><a class="group flex items-start gap-x-2.5 px-3.5 py-2.5 hover:bg-panel transition-colors" href="/kits/iii/deepwork"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false" class="size-4 shrink-0 text-type-kit mt-0.5" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linejoin="miter" stroke-linecap="square"><path d="M2 5h2.9a1.9 1.9 0 1 1 3.2 0H11v2.9a1.9 1.9 0 1 1 0 3.2V14H8.1a1.6 1.6 0 0 0-3.2 0H2Z"></path></svg><span class="min-w-0 flex flex-col"><span class="font-mono text-[13px] text-ink truncate group-hover:underline underline-offset-4"><span class="text-ink-faint">iii<!-- -->/</span>deepwork</span><span class="font-mono text-[11px] uppercase tracking-[0.06em] text-ink-ghost tabular-nums">v<!-- -->0.2.1<!-- --> · <!-- -->6<!-- --> <!-- -->profiles</span></span></a></li></ul></section><div class="border border-rule bg-bg"><div class="bg-panel px-3.5 py-2.5 border-b border-rule"><span class="font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-ink-faint">api</span></div><div class="p-4 flex flex-col gap-y-4"><div class="flex flex-col gap-y-1.5"><div class="flex items-baseline justify-between"><span class="font-mono text-[10px] uppercase tracking-[0.18em] text-ink-ghost">functions</span><span class="font-mono text-[10px] text-ink-ghost tabular-nums">42</span></div><ul class="flex flex-col"><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::__on_worker_added">directory::__on_worker_added</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::agents::create">directory::agents::create</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::agents::delete">directory::agents::delete</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::agents::functions::add">directory::agents::functions::add</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::agents::functions::remove">directory::agents::functions::remove</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::agents::get">directory::agents::get</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::agents::list">directory::agents::list</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::agents::update">directory::agents::update</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::download-kit">directory::download-kit</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::engine::functions::info">directory::engine::functions::info</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::hint-preview">directory::hint-preview</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::apply">directory::kits::apply</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::check-updates">directory::kits::check-updates</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::diff">directory::kits::diff</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::discard">directory::kits::discard</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::get">directory::kits::get</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::ignore">directory::kits::ignore</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::list">directory::kits::list</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::plan">directory::kits::plan</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::plan-update">directory::kits::plan-update</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::kits::remove">directory::kits::remove</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::on-config-change">directory::on-config-change</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::on-functions-change">directory::on-functions-change</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::pre-generate">directory::pre-generate</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::registry::workers::info">directory::registry::workers::info</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::registry::workers::list">directory::registry::workers::list</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::search_functions">directory::search_functions</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::skills::create">directory::skills::create</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::skills::delete">directory::skills::delete</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::skills::download">directory::skills::download</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::skills::download_from_registry">directory::skills::download_from_registry</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::skills::download_from_repo">directory::skills::download_from_repo</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::skills::get">directory::skills::get</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::skills::index">directory::skills::index</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::skills::list">directory::skills::list</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::skills::update">directory::skills::update</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::system-prompts::create">directory::system-prompts::create</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::system-prompts::delete">directory::system-prompts::delete</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::system-prompts::get">directory::system-prompts::get</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::system-prompts::list">directory::system-prompts::list</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-directory::system-prompts::update">directory::system-prompts::update</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#fn-iii-directory::ui-content">iii-directory::ui-content</a></li></ul></div><div class="flex flex-col gap-y-1.5"><div class="flex items-baseline justify-between"><span class="font-mono text-[10px] uppercase tracking-[0.18em] text-ink-ghost">triggers</span><span class="font-mono text-[10px] text-ink-ghost tabular-nums">4</span></div><ul class="flex flex-col"><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#trigger-directory::agents::on-change">directory::agents::on-change</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#trigger-directory::kits::on-change">directory::kits::on-change</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#trigger-directory::skills::on-change">directory::skills::on-change</a></li><li><a class="block font-mono text-[12.5px] truncate py-0.5 transition-colors text-ink hover:text-accent" href="/workers/iii-directory?tab=api#trigger-directory::system-prompts::on-change">directory::system-prompts::on-change</a></li></ul></div></div></div><div class="border border-rule bg-bg"><div class="bg-panel px-3.5 py-2.5 border-b border-rule"><span class="font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-ink-faint">author</span></div><div class="p-4 flex flex-col gap-y-2.5"><div class="flex items-center gap-x-2 font-mono text-[13px]"><img src="https://iii.dev/docs/_mintlify/favicons/motiadev/AFkVbz_UcSL_5jsm/_generated/favicon/apple-touch-icon.png" alt="" class="size-5 object-cover"/><span class="text-ink lowercase">iii</span><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-check size-3.5 text-accent" aria-hidden="true"><path d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z"></path><path d="m9 12 2 2 4-4"></path></svg></div></div></div></aside></div></div></div><!--$--><!--/$--></main><footer class="border-t border-rule bg-bg"><div class="flex items-center justify-between flex-wrap gap-x-6 gap-y-3 px-9 py-4.5"><div class="inline-flex items-center gap-x-4"><a aria-label="iii worker — registry home" class="inline-flex items-center gap-x-2 text-ink" href="/"><svg viewBox="0 0 1075.74 1075.69" aria-hidden="true" focusable="false" class="size-[14px]" fill="currentColor"><rect x="0" y="0.05" width="268.94" height="268.94"></rect><rect x="403.4" y="0.05" width="268.94" height="268.94"></rect><rect x="806.81" y="0.05" width="268.94" height="268.94"></rect><rect x="0" y="403.45" width="268.94" height="672.24"></rect><rect x="403.4" y="403.45" width="268.94" height="672.24"></rect><rect x="806.81" y="403.45" width="268.94" height="672.24"></rect></svg><span class="font-mono text-[13px] font-medium tracking-[-0.02em] lowercase">iii / worker</span></a><a href="https://github.com/iii-hq/iii" target="_blank" rel="noopener noreferrer" aria-label="iii-hq/iii on GitHub — 18,845 stars" class="inline-flex shrink-0 items-center gap-x-2 border border-rule px-2.5 py-1 font-mono text-[13px] text-ink-faint transition-colors hover:text-ink sm:hidden"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false" class="size-3.5 shrink-0" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"></path></svg><span class="hidden sm:inline lowercase">stars</span><span class="tabular-nums text-ink" aria-hidden="true">18.8k</span></a></div><nav aria-label="footer" class="flex items-center flex-wrap gap-x-6 gap-y-2"><a href="https://iii.dev" target="_blank" rel="noreferrer" class="inline-flex items-center gap-x-1 font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors">iii.dev<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-external-link size-3 shrink-0" aria-hidden="true"><path d="M15 3h6v6"></path><path d="M10 14 21 3"></path><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path></svg></a><a href="https://iii.dev/docs" target="_blank" rel="noreferrer" class="inline-flex items-center gap-x-1 font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors">docs<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-external-link size-3 shrink-0" aria-hidden="true"><path d="M15 3h6v6"></path><path d="M10 14 21 3"></path><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path></svg></a><a class="font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors" href="/collections">collections</a><a class="font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors" href="/leaderboard">leaderboard</a><a class="font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors" href="/publish">publish</a><a class="font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors" href="/badge-preview">badge preview</a><a href="https://discord.gg/iiidev" target="_blank" rel="noreferrer" class="inline-flex items-center gap-x-1 font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors">discord<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-external-link size-3 shrink-0" aria-hidden="true"><path d="M15 3h6v6"></path><path d="M10 14 21 3"></path><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path></svg></a><a href="https://github.com/iii-hq/iii" target="_blank" rel="noreferrer" class="inline-flex items-center gap-x-1 font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors">github<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-external-link size-3 shrink-0" aria-hidden="true"><path d="M15 3h6v6"></path><path d="M10 14 21 3"></path><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path></svg></a></nav></div></footer></div></div><script src="/_next/static/chunks/0b_t-9oq5.7ee.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n3:I[20685,[\"/_next/static/chunks/0wcm0wpln.-h..js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0c0r_-py6v_70.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"SiteHeader\"]\n5:I[90280,[\"/_next/static/chunks/04ylibgf-0e6d.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0.vqct1a~k736.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"default\"]\n6:I[69616,[\"/_next/static/chunks/04ylibgf-0e6d.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0.vqct1a~k736.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"default\"]\n7:I[46610,[\"/_next/static/chunks/0wcm0wpln.-h..js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0c0r_-py6v_70.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0-3vzlyvl.dxh.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"\"]\ne:I[50609,[\"/_next/static/chunks/0wcm0wpln.-h..js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0c0r_-py6v_70.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/02eqejg_b4k2y.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"default\"]\n11:I[41074,[\"/_next/static/chunks/0wcm0wpln.-h..js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0c0r_-py6v_70.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0-3vzlyvl.dxh.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"default\"]\n13:I[51557,[\"/_next/static/chunks/04ylibgf-0e6d.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0.vqct1a~k736.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"OutletBoundary\"]\n14:\"$Sreact.suspense\"\n17:I[51557,[\"/_next/static/chunks/04ylibgf-0e6d.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0.vqct1a~k736.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"ViewportBoundary\"]\n19:I[51557,[\"/_next/static/chunks/04ylibgf-0e6d.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0.vqct1a~k736.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"MetadataBoundary\"]\n:HL[\"/_next/static/chunks/05q2cs4d4qqrk.css?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"style\"]\n:HL[\"/_next/static/media/387ee14c0e0fe675-s.p.16njqniuj6huf.woff2?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n2:[\"$\",\"iframe\",null,{\"src\":\"https://www.googletagmanager.com/ns.html?id=GTM-N8DCTFB8\",\"height\":\"0\",\"width\":\"0\",\"style\":{\"display\":\"none\",\"visibility\":\"hidden\"},\"title\":\"Google Tag Manager\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"workers\",\"iii-directory?version=1.2.40\"],\"q\":\"?version=1.2.40\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"workers\",{\"children\":[[\"slug\",\"iii-directory\",\"d\",null],{\"children\":[\"__PAGE__?{\\\"version\\\":\\\"1.2.40\\\"}\",{}]}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/05q2cs4d4qqrk.css?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0wcm0wpln.-h..js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0c0r_-py6v_70.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"chivo_mono_90504305-module__244I6q__variable antialiased\",\"data-theme\":\"light\",\"suppressHydrationWarning\":true,\"children\":[\"$\",\"body\",null,{\"className\":\"bg-bg text-ink font-sans min-h-full flex flex-col\",\"children\":[[[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"\\n try {\\n var stored = localStorage.getItem('iii-theme');\\n if (stored === 'dark' || stored === 'light') {\\n document.documentElement.dataset.theme = stored;\\n } else {\\n document.documentElement.dataset.theme = 'light';\\n }\\n } catch (_) {\\n document.documentElement.dataset.theme = 'light';\\n }\\n\"}}],[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"\\n (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':\\n new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],\\n j=d.createElement(s),dl=l!='dataLayer'?'\u0026l='+l:'';j.async=true;j.src=\\n 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);\\n })(window,document,'script','dataLayer','GTM-N8DCTFB8');\\n\"}}]],[\"$\",\"noscript\",null,{\"children\":\"$2\"}],[\"$\",\"div\",null,{\"className\":\"mx-auto w-full max-w-[1200px] @container border-x border-rule min-h-screen bg-bg flex flex-col\",\"children\":[[\"$\",\"a\",null,{\"href\":\"#main-content\",\"className\":\"sr-only focus:not-sr-only focus:absolute focus:left-4 focus:top-4 focus:z-50 focus:bg-ink focus:text-bg focus:px-3 focus:py-2 focus:font-mono focus:text-[13px] lowercase\",\"children\":\"skip to content\"}],[\"$\",\"$L3\",null,{\"githubStars\":\"$L4\"}],[\"$\",\"div\",null,{\"className\":\"flex-1 overflow-x-clip flex flex-col\",\"children\":[[\"$\",\"main\",null,{\"id\":\"main-content\",\"className\":\"flex-1\",\"tabIndex\":-1,\"children\":[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"div\",null,{\"className\":\"page-transition\",\"children\":[\"$\",\"div\",null,{\"className\":\"flex items-end justify-between flex-wrap gap-x-6 gap-y-4 px-9 py-12\",\"children\":[[\"$\",\"div\",null,{\"className\":\"min-w-0\",\"children\":[[\"$\",\"div\",null,{\"className\":\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-faint mb-3\",\"children\":[\"$\",\"span\",null,{\"className\":\"font-mono text-accent\",\"children\":[\"$$\",[\"$\",\"span\",null,{\"className\":\"text-ink ml-2\",\"children\":\"error\"}]]}]}],[\"$\",\"div\",null,{\"className\":\"flex items-baseline flex-wrap gap-x-3 gap-y-1\",\"children\":[[\"$\",\"h1\",null,{\"className\":\"font-mono text-[28px] font-medium tracking-[-0.01em] text-ink lowercase\",\"children\":[\"$\",\"span\",null,{\"className\":\"inline-flex items-baseline gap-x-2 tabular-nums\",\"children\":[\"404\",[\"$\",\"span\",null,{\"aria-hidden\":true,\"className\":\"blink inline-block w-[6px] h-[13px] bg-ink align-middle translate-y-[1px]\"}]]}]}],\"$undefined\",null]}],[\"$\",\"p\",null,{\"className\":\"mt-3 font-mono text-[14px] leading-[1.7] text-ink-faint max-w-[60ch] lowercase\",\"children\":\"that worker is not in the registry. it may have been renamed or never published.\"}]]}],[\"$\",\"div\",null,{\"className\":\"flex items-center gap-x-3\",\"children\":[\"$\",\"$L7\",null,{\"href\":\"/\",\"className\":\"inline-flex items-center justify-center gap-x-2 whitespace-nowrap font-mono lowercase rounded-none transition-[background-color,color,border-color,transform] duration-150 ease-out focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent disabled:pointer-events-none disabled:opacity-40 select-none active:scale-[0.97] motion-reduce:active:scale-100 bg-ink text-bg border border-ink hover:bg-bg hover:text-ink h-9 px-5 text-[13px]\",\"children\":\"back to registry\"}]}]]}]}],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}],\"$L8\"]}]]}]]}]}]]}],{\"children\":[\"$L9\",{\"children\":[\"$La\",{\"children\":[\"$Lb\",{},null,false,null]},null,false,\"$@c\"]},null,false,\"$@c\"]},null,false,null],\"$Ld\",false]],\"m\":\"$undefined\",\"G\":[\"$e\",[\"$Lf\"]],\"S\":false,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"8:[\"$\",\"footer\",null,{\"className\":\"border-t border-rule bg-bg\",\"children\":[\"$\",\"div\",null,{\"className\":\"flex items-center justify-between flex-wrap gap-x-6 gap-y-3 px-9 py-4.5\",\"children\":[[\"$\",\"div\",null,{\"className\":\"inline-flex items-center gap-x-4\",\"children\":[[\"$\",\"$L7\",null,{\"href\":\"/\",\"aria-label\":\"iii worker — registry home\",\"className\":\"inline-flex items-center gap-x-2 text-ink\",\"children\":[[\"$\",\"svg\",null,{\"viewBox\":\"0 0 1075.74 1075.69\",\"aria-hidden\":\"true\",\"focusable\":\"false\",\"className\":\"size-[14px]\",\"fill\":\"currentColor\",\"children\":[[\"$\",\"rect\",null,{\"x\":\"0\",\"y\":\"0.05\",\"width\":\"268.94\",\"height\":\"268.94\"}],[\"$\",\"rect\",null,{\"x\":\"403.4\",\"y\":\"0.05\",\"width\":\"268.94\",\"height\":\"268.94\"}],[\"$\",\"rect\",null,{\"x\":\"806.81\",\"y\":\"0.05\",\"width\":\"268.94\",\"height\":\"268.94\"}],[\"$\",\"rect\",null,{\"x\":\"0\",\"y\":\"403.45\",\"width\":\"268.94\",\"height\":\"672.24\"}],[\"$\",\"rect\",null,{\"x\":\"403.4\",\"y\":\"403.45\",\"width\":\"268.94\",\"height\":\"672.24\"}],[\"$\",\"rect\",null,{\"x\":\"806.81\",\"y\":\"403.45\",\"width\":\"268.94\",\"height\":\"672.24\"}]]}],[\"$\",\"span\",null,{\"className\":\"font-mono text-[13px] font-medium tracking-[-0.02em] lowercase\",\"children\":\"iii / worker\"}]]}],\"$L10\"]}],[\"$\",\"nav\",null,{\"aria-label\":\"footer\",\"className\":\"flex items-center flex-wrap gap-x-6 gap-y-2\",\"children\":[[\"$\",\"a\",\"https://iii.dev\",{\"href\":\"https://iii.dev\",\"target\":\"_blank\",\"rel\":\"noreferrer\",\"className\":\"inline-flex items-center gap-x-1 font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors\",\"children\":[\"iii.dev\",[\"$\",\"$L11\",null,{\"ref\":\"$undefined\",\"iconNode\":[[\"path\",{\"d\":\"M15 3h6v6\",\"key\":\"1q9fwt\"}],[\"path\",{\"d\":\"M10 14 21 3\",\"key\":\"gplh6r\"}],[\"path\",{\"d\":\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\",\"key\":\"a6xqqp\"}]],\"className\":\"lucide-external-link size-3 shrink-0\",\"aria-hidden\":true}]]}],[\"$\",\"a\",\"https://iii.dev/docs\",{\"href\":\"https://iii.dev/docs\",\"target\":\"_blank\",\"rel\":\"noreferrer\",\"className\":\"inline-flex items-center gap-x-1 font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors\",\"children\":[\"docs\",[\"$\",\"$L11\",null,{\"ref\":\"$undefined\",\"iconNode\":\"$8:props:children:props:children:1:props:children:0:props:children:1:props:iconNode\",\"className\":\"lucide-external-link size-3 shrink-0\",\"aria-hidden\":true}]]}],[\"$\",\"$L7\",\"/collections\",{\"href\":\"/collections\",\"className\":\"font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors\",\"children\":\"collections\"}],[\"$\",\"$L7\",\"/leaderboard\",{\"href\":\"/leaderboard\",\"className\":\"font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors\",\"children\":\"leaderboard\"}],[\"$\",\"$L7\",\"/publish\",{\"href\":\"/publish\",\"className\":\"font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors\",\"children\":\"publish\"}],[\"$\",\"$L7\",\"/badge-preview\",{\"href\":\"/badge-preview\",\"className\":\"font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors\",\"children\":\"badge preview\"}],[\"$\",\"a\",\"https://discord.gg/iiidev\",{\"href\":\"https://discord.gg/iiidev\",\"target\":\"_blank\",\"rel\":\"noreferrer\",\"className\":\"inline-flex items-center gap-x-1 font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors\",\"children\":[\"discord\",[\"$\",\"$L11\",null,{\"ref\":\"$undefined\",\"iconNode\":\"$8:props:children:props:children:1:props:children:0:props:children:1:props:iconNode\",\"className\":\"lucide-external-link size-3 shrink-0\",\"aria-hidden\":true}]]}],[\"$\",\"a\",\"https://github.com/iii-hq/iii\",{\"href\":\"https://github.com/iii-hq/iii\",\"target\":\"_blank\",\"rel\":\"noreferrer\",\"className\":\"inline-flex items-center gap-x-1 font-mono text-[13px] text-ink-faint hover:text-ink lowercase transition-colors\",\"children\":[\"github\",[\"$\",\"$L11\",null,{\"ref\":\"$undefined\",\"iconNode\":\"$8:props:children:props:children:1:props:children:0:props:children:1:props:iconNode\",\"className\":\"lucide-external-link size-3 shrink-0\",\"aria-hidden\":true}]]}]]}]]}]}]\n"])</script><script>self.__next_f.push([1,"9:[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]\na:[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]\nb:[\"$\",\"$1\",\"c\",{\"children\":[\"$L12\",[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0-3vzlyvl.dxh.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L13\",null,{\"children\":[\"$\",\"$14\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@15\"}]}]]}]\n16:[]\nc:\"$W16\"\nd:[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L17\",null,{\"children\":\"$L18\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L19\",null,{\"children\":[\"$\",\"$14\",null,{\"name\":\"Next.Metadata\",\"children\":\"$L1a\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}]\nf:[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/05q2cs4d4qqrk.css?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]\n18:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"4:[\"$\",\"a\",null,{\"href\":\"https://github.com/iii-hq/iii\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"aria-label\":\"iii-hq/iii on GitHub — 18,845 stars\",\"className\":\"shrink-0 items-center gap-x-2 border border-rule px-2.5 py-1 font-mono text-[13px] text-ink-faint transition-colors hover:text-ink hidden sm:inline-flex\",\"children\":[[\"$\",\"svg\",null,{\"viewBox\":\"0 0 16 16\",\"aria-hidden\":\"true\",\"focusable\":\"false\",\"className\":\"size-3.5 shrink-0\",\"fill\":\"currentColor\",\"children\":[\"$\",\"path\",null,{\"d\":\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z\"}]}],[\"$\",\"span\",null,{\"className\":\"hidden sm:inline lowercase\",\"children\":\"stars\"}],[\"$\",\"span\",null,{\"className\":\"tabular-nums text-ink\",\"aria-hidden\":true,\"children\":\"18.8k\"}]]}]\n10:[\"$\",\"a\",null,{\"href\":\"https://github.com/iii-hq/iii\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"aria-label\":\"iii-hq/iii on GitHub — 18,845 stars\",\"className\":\"inline-flex shrink-0 items-center gap-x-2 border border-rule px-2.5 py-1 font-mono text-[13px] text-ink-faint transition-colors hover:text-ink sm:hidden\",\"children\":[[\"$\",\"svg\",null,{\"viewBox\":\"0 0 16 16\",\"aria-hidden\":\"true\",\"focusable\":\"false\",\"className\":\"size-3.5 shrink-0\",\"fill\":\"currentColor\",\"children\":[\"$\",\"path\",null,{\"d\":\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z\"}]}],[\"$\",\"span\",null,{\"className\":\"hidden sm:inline lowercase\",\"children\":\"stars\"}],[\"$\",\"span\",null,{\"className\":\"tabular-nums text-ink\",\"aria-hidden\":true,\"children\":\"18.8k\"}]]}]\n"])</script><script>self.__next_f.push([1,"1b:I[18418,[\"/_next/static/chunks/04ylibgf-0e6d.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0.vqct1a~k736.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"IconMark\"]\n15:null\n"])</script><script>self.__next_f.push([1,"1a:[[\"$\",\"title\",\"0\",{\"children\":\"iii-directory - iii worker\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Engine introspection, workers registry proxy, filesystem-backed skills, system prompts, and agent profiles, kit install and update with reviewed plans, plus function search ranked by the judge worker (falling back to local hybrid/lexical) with a conditional pre-generate hint.\"}],[\"$\",\"meta\",\"2\",{\"name\":\"robots\",\"content\":\"index, follow\"}],[\"$\",\"link\",\"3\",{\"rel\":\"canonical\",\"href\":\"https://workers.iii.dev/workers/iii-directory\"}],[\"$\",\"meta\",\"4\",{\"property\":\"og:title\",\"content\":\"iii-directory - iii worker\"}],[\"$\",\"meta\",\"5\",{\"property\":\"og:description\",\"content\":\"Engine introspection, workers registry proxy, filesystem-backed skills, system prompts, and agent profiles, kit install and update with reviewed plans, plus function search ranked by the judge worker (falling back to local hybrid/lexical) with a conditional pre-generate hint.\"}],[\"$\",\"meta\",\"6\",{\"property\":\"og:url\",\"content\":\"https://workers.iii.dev/workers/iii-directory\"}],[\"$\",\"meta\",\"7\",{\"property\":\"og:image\",\"content\":\"https://workers.iii.dev/workers/iii-directory/opengraph-image?bced171a25d0f70f\"}],[\"$\",\"meta\",\"8\",{\"property\":\"og:image:type\",\"content\":\"image/png\"}],[\"$\",\"meta\",\"9\",{\"property\":\"og:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"10\",{\"property\":\"og:image:height\",\"content\":\"630\"}],[\"$\",\"meta\",\"11\",{\"property\":\"og:image:alt\",\"content\":\"iii worker\"}],[\"$\",\"meta\",\"12\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],[\"$\",\"meta\",\"13\",{\"name\":\"twitter:title\",\"content\":\"iii-directory - iii worker\"}],[\"$\",\"meta\",\"14\",{\"name\":\"twitter:description\",\"content\":\"Engine introspection, workers registry proxy, filesystem-backed skills, system prompts, and agent profiles, kit install and update with reviewed plans, plus function search ranked by the judge worker (falling back to local hybrid/lexical) with a conditional pre-generate hint.\"}],[\"$\",\"meta\",\"15\",{\"name\":\"twitter:image\",\"content\":\"https://workers.iii.dev/workers/iii-directory/opengraph-image?bced171a25d0f70f\"}],[\"$\",\"meta\",\"16\",{\"name\":\"twitter:image:alt\",\"content\":\"iii worker\"}],[\"$\",\"meta\",\"17\",{\"name\":\"twitter:image:type\",\"content\":\"image/png\"}],[\"$\",\"meta\",\"18\",{\"name\":\"twitter:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"19\",{\"name\":\"twitter:image:height\",\"content\":\"630\"}],[\"$\",\"link\",\"20\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0n6vou73am7b3.ico\",\"sizes\":\"48x48\",\"type\":\"image/x-icon\"}],[\"$\",\"$L1b\",\"21\",{}]]\n"])</script><script>self.__next_f.push([1,":HL[\"https://iii.dev/docs/_mintlify/favicons/motiadev/AFkVbz_UcSL_5jsm/_generated/favicon/apple-touch-icon.png\",\"image\"]\n"])</script><script>self.__next_f.push([1,"12:[\"$\",\"div\",null,{\"className\":\"page-transition\",\"children\":[[\"$\",\"script\",null,{\"type\":\"application/ld+json\",\"dangerouslySetInnerHTML\":{\"__html\":\"{\\\"@context\\\":\\\"https://schema.org\\\",\\\"@type\\\":\\\"SoftwareApplication\\\",\\\"name\\\":\\\"iii-directory\\\",\\\"description\\\":\\\"Engine introspection, workers registry proxy, filesystem-backed skills, system prompts, and agent profiles, kit install and update with reviewed plans, plus function search ranked by the judge worker (falling back to local hybrid/lexical) with a conditional pre-generate hint.\\\",\\\"applicationCategory\\\":\\\"DeveloperApplication\\\",\\\"softwareVersion\\\":\\\"1.2.40\\\",\\\"url\\\":\\\"https://workers.iii.dev/workers/iii-directory\\\",\\\"license\\\":\\\"Apache-2.0\\\",\\\"codeRepository\\\":\\\"https://github.com/iii-hq/workers\\\",\\\"author\\\":{\\\"@type\\\":\\\"Person\\\",\\\"name\\\":\\\"iii\\\"}}\"}}],[\"$\",\"div\",null,{\"className\":\"flex items-end justify-between flex-wrap gap-x-6 gap-y-4 px-9 py-12\",\"children\":[[\"$\",\"div\",null,{\"className\":\"min-w-0\",\"children\":[[\"$\",\"div\",null,{\"className\":\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-faint mb-3\",\"children\":[\"$\",\"span\",null,{\"className\":\"font-mono text-accent\",\"children\":[\"$$\",[\"$\",\"span\",null,{\"className\":\"text-ink ml-2\",\"children\":\"registry / workers\"}]]}]}],[\"$\",\"div\",null,{\"className\":\"flex items-baseline flex-wrap gap-x-3 gap-y-1\",\"children\":[[\"$\",\"h1\",null,{\"className\":\"font-mono text-[28px] font-medium tracking-[-0.01em] text-ink lowercase\",\"children\":\"iii-directory\"}],\"$undefined\",[\"$\",\"span\",null,{\"className\":\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-ghost tabular-nums\",\"children\":\"v1.2.40\"}]]}],[\"$\",\"p\",null,{\"className\":\"mt-3 font-mono text-[14px] leading-[1.7] text-ink-faint max-w-[60ch] lowercase\",\"children\":\"Engine introspection, workers registry proxy, filesystem-backed skills, system prompts, and agent profiles, kit install and update with reviewed plans, plus function search ranked by the judge worker (falling back to local hybrid/lexical) with a conditional pre-generate hint.\"}]]}],null]}],[\"$\",\"div\",null,{\"className\":\"px-9 pb-8 flex flex-col gap-y-6\",\"children\":[null,null,[\"$\",\"div\",null,{\"className\":\"flex flex-col gap-y-5 border border-rule bg-bg p-5 @2xl:p-6\",\"children\":[[\"$\",\"div\",null,{\"className\":\"flex flex-wrap items-center gap-x-4 gap-y-2\",\"children\":[[\"$\",\"span\",null,{\"data-type-mark\":\"worker\",\"className\":\"inline-flex items-center gap-x-1.5 shrink-0\",\"children\":[[\"$\",\"svg\",null,{\"viewBox\":\"0 0 16 16\",\"aria-hidden\":\"true\",\"focusable\":\"false\",\"className\":\"size-4 shrink-0 text-type-worker\",\"fill\":\"none\",\"stroke\":\"currentColor\",\"strokeWidth\":1.25,\"strokeLinejoin\":\"miter\",\"strokeLinecap\":\"square\",\"children\":[[\"$\",\"path\",null,{\"d\":\"M8 1.6 13.6 4.8v6.4L8 14.4 2.4 11.2V4.8Z\"}],null,null]}],[\"$\",\"span\",null,{\"className\":\"font-mono text-[11px] font-medium uppercase leading-none tracking-[0.06em] text-ink-faint\",\"children\":\"worker\"}]]}],[\"$\",\"div\",null,{\"className\":\"flex items-center gap-x-2 font-mono text-[13px]\",\"children\":[[\"$\",\"img\",null,{\"src\":\"https://iii.dev/docs/_mintlify/favicons/motiadev/AFkVbz_UcSL_5jsm/_generated/favicon/apple-touch-icon.png\",\"alt\":\"\",\"className\":\"size-5 object-cover\"}],[\"$\",\"span\",null,{\"className\":\"text-ink lowercase\",\"children\":\"iii\"}],[\"$\",\"span\",null,{\"className\":\"inline-flex items-center gap-x-1 text-ink-faint\",\"children\":[[\"$\",\"$L11\",null,{\"ref\":\"$undefined\",\"iconNode\":[[\"path\",{\"d\":\"M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z\",\"key\":\"3c2336\"}],[\"path\",{\"d\":\"m9 12 2 2 4-4\",\"key\":\"dzmm74\"}]],\"className\":\"lucide-badge-check size-3.5 text-accent\",\"aria-hidden\":true}],[\"$\",\"span\",null,{\"className\":\"text-[11px] uppercase tracking-[0.06em]\",\"children\":\"verified\"}]]}]]}],[\"$\",\"span\",null,{\"className\":\"flex flex-wrap items-center gap-x-3 gap-y-1 font-mono text-[12px] text-ink-ghost tabular-nums\",\"children\":[[\"$\",\"span\",null,{\"children\":[[\"$\",\"span\",null,{\"className\":\"text-ink\",\"children\":\"5,250\"}],\" installs\"]}],\"$L1c\",\"$L1d\"]}]]}],\"$L1e\",\"$L1f\",\"$L20\"]}],false,false]}],\"$L21\"]}]\n"])</script><script>self.__next_f.push([1,"22:I[15957,[\"/_next/static/chunks/0wcm0wpln.-h..js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0c0r_-py6v_70.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0-3vzlyvl.dxh.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"InstallCommand\"]\n23:I[33516,[\"/_next/static/chunks/0wcm0wpln.-h..js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0c0r_-py6v_70.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0-3vzlyvl.dxh.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"Image\"]\n2a:I[84938,[\"/_next/static/chunks/0wcm0wpln.-h..js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0c0r_-py6v_70.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0-3vzlyvl.dxh.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"PageTabs\"]\n1c:[[\"$\",\"span\",null,{\"aria-hidden\":true,\"className\":\"text-rule\",\"children\":\"/\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"span\",null,{\"className\":\"text-ink\",\"children\":\"598\"}],\" in 7d\"]}]]\n1d:[[\"$\",\"span\",null,{\"aria-hidden\":true,\"className\":\"text-rule\",\"children\":\"/\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"span\",null,{\"className\":\"text-ink\",\"children\":\"100\"}],\" \",\"today\"]}]]\n1e:[\"$\",\"$L22\",null,{\"workerName\":\"iii-directory\",\"version\":\"latest\",\"kind\":\"worker\"}]\n"])</script><script>self.__next_f.push([1,"1f:[\"$\",\"div\",null,{\"className\":\"flex flex-col gap-y-3\",\"children\":[[\"$\",\"div\",null,{\"className\":\"flex flex-wrap items-center gap-2 font-mono text-[12px] lowercase\",\"children\":[[\"$\",\"span\",null,{\"className\":\"border border-rule px-2 py-1 text-ink\",\"children\":\"binary\"}],[\"$\",\"span\",null,{\"className\":\"border border-rule px-2 py-1 text-ink normal-case\",\"children\":[\"license: \",\"Apache-2.0\"]}],[[\"$\",\"$L7\",\"agents\",{\"href\":\"/search?tag=agents\",\"className\":\"border border-rule-2 px-2 py-1 text-ink-faint hover:text-ink hover:border-rule transition-colors\",\"children\":\"agents\"}],[\"$\",\"$L7\",\"directory\",{\"href\":\"/search?tag=directory\",\"className\":\"border border-rule-2 px-2 py-1 text-ink-faint hover:text-ink hover:border-rule transition-colors\",\"children\":\"directory\"}],[\"$\",\"$L7\",\"functions\",{\"href\":\"/search?tag=functions\",\"className\":\"border border-rule-2 px-2 py-1 text-ink-faint hover:text-ink hover:border-rule transition-colors\",\"children\":\"functions\"}],[\"$\",\"$L7\",\"introspect\",{\"href\":\"/search?tag=introspect\",\"className\":\"border border-rule-2 px-2 py-1 text-ink-faint hover:text-ink hover:border-rule transition-colors\",\"children\":\"introspect\"}],[\"$\",\"$L7\",\"kits\",{\"href\":\"/search?tag=kits\",\"className\":\"border border-rule-2 px-2 py-1 text-ink-faint hover:text-ink hover:border-rule transition-colors\",\"children\":\"kits\"}],[\"$\",\"$L7\",\"registry\",{\"href\":\"/search?tag=registry\",\"className\":\"border border-rule-2 px-2 py-1 text-ink-faint hover:text-ink hover:border-rule transition-colors\",\"children\":\"registry\"}],[\"$\",\"$L7\",\"search\",{\"href\":\"/search?tag=search\",\"className\":\"border border-rule-2 px-2 py-1 text-ink-faint hover:text-ink hover:border-rule transition-colors\",\"children\":\"search\"}],[\"$\",\"$L7\",\"skills\",{\"href\":\"/search?tag=skills\",\"className\":\"border border-rule-2 px-2 py-1 text-ink-faint hover:text-ink hover:border-rule transition-colors\",\"children\":\"skills\"}]]]}],[\"$\",\"ul\",null,{\"aria-label\":\"Supported platforms\",\"className\":\"flex flex-wrap items-center font-mono text-[12px] gap-x-2 gap-y-1.5 \",\"children\":[[\"$\",\"li\",\"apple\",{\"title\":\"macOS: arm64, x64\",\"className\":\"inline-flex items-center border border-rule bg-bg gap-x-2 px-2 py-1\",\"children\":[[\"$\",\"$L23\",null,{\"src\":\"/icons/apple_dark.svg\",\"alt\":\"\",\"aria-hidden\":true,\"width\":209,\"height\":256,\"className\":\"shrink-0 [filter:brightness(0)] dark:[filter:brightness(0)_invert(1)] h-4 w-auto\"}],[\"$\",\"span\",null,{\"className\":\"sr-only\",\"children\":[\"macOS\",\": \"]}],[\"$\",\"span\",null,{\"className\":\"text-ink tabular-nums\",\"children\":\"arm64 · x64\"}]]}],[\"$\",\"li\",\"linux\",{\"title\":\"Linux: arm64, armv7, x64\",\"className\":\"inline-flex items-center border border-rule bg-bg gap-x-2 px-2 py-1\",\"children\":[[\"$\",\"$L23\",null,{\"src\":\"/icons/linux.svg\",\"alt\":\"\",\"aria-hidden\":true,\"width\":256,\"height\":295,\"className\":\"shrink-0 [filter:brightness(0)] dark:[filter:brightness(0)_invert(1)] h-4 w-auto\"}],[\"$\",\"span\",null,{\"className\":\"sr-only\",\"children\":[\"Linux\",\": \"]}],[\"$\",\"span\",null,{\"className\":\"text-ink tabular-nums\",\"children\":\"arm64 · armv7 · x64\"}]]}],[\"$\",\"li\",\"windows\",{\"title\":\"Windows: arm64, x64\",\"className\":\"inline-flex items-center border border-rule bg-bg gap-x-2 px-2 py-1\",\"children\":[[\"$\",\"$L23\",null,{\"src\":\"/icons/windows.svg\",\"alt\":\"\",\"aria-hidden\":true,\"width\":88,\"height\":88,\"className\":\"shrink-0 [filter:brightness(0)] dark:[filter:brightness(0)_invert(1)] h-4 w-auto\"}],[\"$\",\"span\",null,{\"className\":\"sr-only\",\"children\":[\"Windows\",\": \"]}],[\"$\",\"span\",null,{\"className\":\"text-ink tabular-nums\",\"children\":\"arm64 · x64\"}]]}]]}],[\"$\",\"div\",null,{\"className\":\"flex flex-wrap gap-x-4 gap-y-2 font-mono text-[12px]\",\"children\":[[[\"$\",\"$L7\",null,{\"href\":\"/workers/iii-directory?tab=api\",\"className\":\"inline-flex items-baseline gap-x-1.5 text-ink-faint hover:text-ink transition-colors\",\"children\":[[\"$\",\"span\",null,{\"className\":\"tabular-nums text-ink\",\"children\":\"42\"}],[\"$\",\"span\",null,{\"className\":\"uppercase tracking-[0.06em] text-[11px]\",\"children\":\"functions\"}]]}],[\"$\",\"$L7\",null,{\"href\":\"/workers/iii-directory?tab=api\",\"className\":\"inline-flex items-baseline gap-x-1.5 text-ink-faint hover:text-ink transition-colors\",\"children\":[\"$L24\",\"$L25\"]}]],\"$L26\",\"$L27\",\"$L28\",\"$L29\"]}]]}]\n"])</script><script>self.__next_f.push([1,"20:[\"$\",\"div\",null,{\"className\":\"flex flex-col @2xl:flex-row @2xl:items-center gap-3 border-t border-rule-2 pt-4\",\"children\":[[\"$\",\"div\",null,{\"className\":\"flex items-center gap-x-2 min-w-0 font-mono text-[13px]\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-[11px] uppercase tracking-[0.06em] text-ink-faint shrink-0\",\"children\":\"repo\"}],[\"$\",\"a\",null,{\"href\":\"https://github.com/iii-hq/workers\",\"target\":\"_blank\",\"rel\":\"noreferrer\",\"className\":\"inline-flex items-center gap-x-1 font-mono text-[13px] text-ink lowercase hover:text-accent transition-colors min-w-0\",\"children\":[[\"$\",\"span\",null,{\"className\":\"truncate\",\"children\":\"iii-hq/workers\"}],[\"$\",\"$L11\",null,{\"ref\":\"$undefined\",\"iconNode\":\"$8:props:children:props:children:1:props:children:0:props:children:1:props:iconNode\",\"className\":\"lucide-external-link size-3 shrink-0\",\"aria-hidden\":true}]]}]]}],[\"$\",\"p\",null,{\"className\":\"font-mono text-[12px] leading-[1.5] text-ink-faint @2xl:ml-auto @2xl:max-w-[42ch] @2xl:text-right\",\"children\":\"exact versions are immutable; binary and bundle artifacts are digest-pinned.\"}]]}]\n"])</script><script>self.__next_f.push([1,"21:[\"$\",\"div\",null,{\"className\":\"px-9 pb-12 flex flex-col gap-y-6\",\"children\":[\"$\",\"div\",null,{\"className\":\"grid grid-cols-1 @4xl:grid-cols-[1fr_280px] gap-x-8 gap-y-8\",\"children\":[[\"$\",\"div\",null,{\"className\":\"min-w-0 flex flex-col gap-y-6\",\"children\":[[\"$\",\"$L2a\",null,{\"slug\":\"iii-directory\",\"activeTab\":\"readme\",\"version\":\"latest\",\"basePath\":\"/workers\",\"tabs\":\"$undefined\"}],[null,[\"$\",\"section\",null,{\"children\":[[\"$\",\"div\",null,{\"className\":\"flex items-center justify-between mb-3\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-[12px] font-medium uppercase tracking-[0.18em] text-ink-faint\",\"children\":\"readme\"}],[\"$\",\"a\",null,{\"href\":\"https://api.workers.iii.dev/w/iii-directory/readme\",\"target\":\"_blank\",\"rel\":\"noreferrer\",\"className\":\"inline-flex items-center gap-x-1.5 font-mono text-[11px] uppercase tracking-[0.06em] text-ink-faint hover:text-accent transition-colors\",\"children\":[[\"$\",\"span\",null,{\"children\":\"open as markdown\"}],[\"$\",\"$L11\",null,{\"ref\":\"$undefined\",\"iconNode\":\"$8:props:children:props:children:1:props:children:0:props:children:1:props:iconNode\",\"className\":\"lucide-external-link w-3 h-3\",\"aria-hidden\":true}]]}]]}],\"$L2b\"]}]],false,false,false,false,false,false]}],[\"$\",\"aside\",null,{\"className\":\"flex flex-col gap-y-4 @4xl:sticky @4xl:top-4 @4xl:self-start @4xl:max-h-[calc(100dvh-2rem)] @4xl:overflow-y-auto\",\"children\":[[\"$\",\"div\",null,{\"className\":\"border border-rule bg-bg\",\"children\":[[\"$\",\"div\",null,{\"className\":\"bg-panel px-3.5 py-2.5 border-b border-rule\",\"children\":[\"$\",\"span\",null,{\"className\":\"font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-ink-faint\",\"children\":\"details\"}]}],[\"$\",\"div\",null,{\"className\":\"p-4 flex flex-col gap-y-2.5\",\"children\":[[\"$\",\"div\",null,{\"className\":\"flex items-baseline justify-between font-mono text-[13px] gap-x-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-ink-faint shrink-0 uppercase tracking-[0.06em] text-[11px]\",\"children\":\"version\"}],[\"$\",\"span\",null,{\"className\":\"text-ink truncate text-right lowercase tabular-nums\",\"children\":\"v1.2.40\"}]]}],[\"$\",\"div\",null,{\"className\":\"flex items-baseline justify-between font-mono text-[13px] gap-x-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-ink-faint shrink-0 uppercase tracking-[0.06em] text-[11px]\",\"children\":\"type\"}],[\"$\",\"span\",null,{\"className\":\"text-ink truncate text-right lowercase \",\"children\":\"binary\"}]]}],[\"$\",\"div\",null,{\"className\":\"flex items-baseline justify-between font-mono text-[13px] gap-x-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-ink-faint shrink-0 uppercase tracking-[0.06em] text-[11px]\",\"children\":\"license\"}],[\"$\",\"span\",null,{\"className\":\"text-ink truncate text-right \",\"children\":\"Apache-2.0\"}]]}],null,[\"$\",\"div\",null,{\"className\":\"flex items-baseline justify-between font-mono text-[13px] gap-x-3 min-w-0\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-ink-faint shrink-0 uppercase tracking-[0.06em] text-[11px]\",\"children\":\"repo\"}],[\"$\",\"a\",null,{\"href\":\"https://github.com/iii-hq/workers\",\"target\":\"_blank\",\"rel\":\"noreferrer\",\"className\":\"inline-flex items-center gap-x-1 font-mono text-[13px] text-ink lowercase hover:text-accent transition-colors min-w-0 text-right justify-end\",\"children\":[[\"$\",\"span\",null,{\"className\":\"truncate\",\"children\":\"iii-hq/workers\"}],[\"$\",\"$L11\",null,{\"ref\":\"$undefined\",\"iconNode\":\"$8:props:children:props:children:1:props:children:0:props:children:1:props:iconNode\",\"className\":\"lucide-external-link size-3 shrink-0\",\"aria-hidden\":true}]]}]]}],\"$undefined\"]}]]}],[\"$\",\"section\",null,{\"id\":\"used-in-kits\",\"className\":\"border border-rule bg-bg scroll-mt-20\",\"aria-labelledby\":\"used-in-kits-title\",\"children\":[[\"$\",\"div\",null,{\"className\":\"flex items-baseline justify-between bg-panel px-3.5 py-2.5 border-b border-rule\",\"children\":[\"$\",\"span\",null,{\"id\":\"used-in-kits-title\",\"className\":\"font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-ink-faint\",\"children\":[\"used in \",1,\" \",\"kit\"]}]}],[\"$\",\"ul\",null,{\"className\":\"divide-y divide-rule-2\",\"children\":[[\"$\",\"li\",\"iii/deepwork\",{\"children\":[\"$\",\"$L7\",null,{\"href\":\"/kits/iii/deepwork\",\"className\":\"group flex items-start gap-x-2.5 px-3.5 py-2.5 hover:bg-panel transition-colors\",\"children\":[[\"$\",\"svg\",null,{\"viewBox\":\"0 0 16 16\",\"aria-hidden\":\"true\",\"focusable\":\"false\",\"className\":\"size-4 shrink-0 text-type-kit mt-0.5\",\"fill\":\"none\",\"stroke\":\"currentColor\",\"strokeWidth\":1.25,\"strokeLinejoin\":\"miter\",\"strokeLinecap\":\"square\",\"children\":[null,\"$L2c\",null]}],\"$L2d\"]}]}]]}]]}],\"$L2e\",\"$L2f\"]}]]}]}]\n"])</script><script>self.__next_f.push([1,"30:I[42794,[\"/_next/static/chunks/0wcm0wpln.-h..js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0c0r_-py6v_70.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\",\"/_next/static/chunks/0-3vzlyvl.dxh.js?dpl=dpl_Aek62oZSuVbHEfXvLZ3d1fURYNU1\"],\"SummaryList\"]\n24:[\"$\",\"span\",null,{\"className\":\"tabular-nums text-ink\",\"children\":\"4\"}]\n25:[\"$\",\"span\",null,{\"className\":\"uppercase tracking-[0.06em] text-[11px]\",\"children\":\"triggers\"}]\n26:[\"$\",\"$L7\",null,{\"href\":\"/workers/iii-directory?tab=skills\",\"className\":\"inline-flex items-baseline gap-x-1.5 text-ink-faint hover:text-ink transition-colors\",\"children\":[[\"$\",\"span\",null,{\"className\":\"tabular-nums text-ink\",\"children\":\"5\"}],[\"$\",\"span\",null,{\"className\":\"uppercase tracking-[0.06em] text-[11px]\",\"children\":\"skills\"}]]}]\n27:[\"$\",\"$L7\",null,{\"href\":\"/workers/iii-directory?tab=deps\",\"className\":\"inline-flex items-baseline gap-x-1.5 text-ink-faint hover:text-ink transition-colors\",\"children\":[[\"$\",\"span\",null,{\"className\":\"tabular-nums text-ink\",\"children\":\"1\"}],[\"$\",\"span\",null,{\"className\":\"uppercase tracking-[0.06em] text-[11px]\",\"children\":\"deps\"}]]}]\n28:[\"$\",\"$L7\",null,{\"href\":\"/workers/iii-directory?tab=versions\",\"className\":\"inline-flex items-baseline gap-x-1.5 text-ink-faint hover:text-ink transition-colors\",\"children\":[[\"$\",\"span\",null,{\"className\":\"tabular-nums text-ink\",\"children\":\"v1.2.40\"}],[\"$\",\"span\",null,{\"className\":\"uppercase tracking-[0.06em] text-[11px]\",\"children\":\"version\"}]]}]\n29:[\"$\",\"$L7\",null,{\"href\":\"#used-in-kits\",\"className\":\"inline-flex items-baseline gap-x-1.5 text-ink-faint hover:text-ink transition-colors\",\"children\":[[\"$\",\"span\",null,{\"className\":\"tabular-nums text-ink\",\"children\":\"1\"}],[\"$\",\"span\",null,{\"className\":\"uppercase tracking-[0.06em] text-[11px]\",\"children\":\"kit\"}]]}]\n2c:[\"$\",\"path\",null,{\"d\":\"M2 5h2.9a1.9 1.9 0 1 1 3.2 0H11v2.9a1.9 1.9 0 1 1 0 3.2V14H8.1a1.6 1.6 0 0 0-3.2 0H2Z\"}]\n2d:[\"$\",\"span\",null,{\"className\":\"min-w-0 flex flex-col\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono text-[13px] text-ink truncate group-hover:underline underline-offset-4\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-ink-faint\",\"children\":[\"iii\",\"/\"]}],\"deepwork\"]}],[\"$\",\"span\",null,{\"className\":\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-ghost tabular-nums\",\"children\":[\"v\",\"0.2.1\",\" · \",6,\" \",\"profiles\"]}]]}]\n"])</script><script>self.__next_f.push([1,"2e:[\"$\",\"div\",null,{\"className\":\"border border-rule bg-bg\",\"children\":[[\"$\",\"div\",null,{\"className\":\"bg-panel px-3.5 py-2.5 border-b border-rule\",\"children\":[\"$\",\"span\",null,{\"className\":\"font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-ink-faint\",\"children\":\"api\"}]}],[\"$\",\"$L30\",null,{\"slug\":\"iii-directory\",\"version\":\"latest\",\"functions\":[{\"name\":\"directory::__on_worker_added\",\"anchor\":\"fn-directory::__on_worker_added\"},{\"name\":\"directory::agents::create\",\"anchor\":\"fn-directory::agents::create\"},{\"name\":\"directory::agents::delete\",\"anchor\":\"fn-directory::agents::delete\"},{\"name\":\"directory::agents::functions::add\",\"anchor\":\"fn-directory::agents::functions::add\"},{\"name\":\"directory::agents::functions::remove\",\"anchor\":\"fn-directory::agents::functions::remove\"},{\"name\":\"directory::agents::get\",\"anchor\":\"fn-directory::agents::get\"},{\"name\":\"directory::agents::list\",\"anchor\":\"fn-directory::agents::list\"},{\"name\":\"directory::agents::update\",\"anchor\":\"fn-directory::agents::update\"},{\"name\":\"directory::download-kit\",\"anchor\":\"fn-directory::download-kit\"},{\"name\":\"directory::engine::functions::info\",\"anchor\":\"fn-directory::engine::functions::info\"},{\"name\":\"directory::hint-preview\",\"anchor\":\"fn-directory::hint-preview\"},{\"name\":\"directory::kits::apply\",\"anchor\":\"fn-directory::kits::apply\"},{\"name\":\"directory::kits::check-updates\",\"anchor\":\"fn-directory::kits::check-updates\"},{\"name\":\"directory::kits::diff\",\"anchor\":\"fn-directory::kits::diff\"},{\"name\":\"directory::kits::discard\",\"anchor\":\"fn-directory::kits::discard\"},{\"name\":\"directory::kits::get\",\"anchor\":\"fn-directory::kits::get\"},{\"name\":\"directory::kits::ignore\",\"anchor\":\"fn-directory::kits::ignore\"},{\"name\":\"directory::kits::list\",\"anchor\":\"fn-directory::kits::list\"},{\"name\":\"directory::kits::plan\",\"anchor\":\"fn-directory::kits::plan\"},{\"name\":\"directory::kits::plan-update\",\"anchor\":\"fn-directory::kits::plan-update\"},{\"name\":\"directory::kits::remove\",\"anchor\":\"fn-directory::kits::remove\"},{\"name\":\"directory::on-config-change\",\"anchor\":\"fn-directory::on-config-change\"},{\"name\":\"directory::on-functions-change\",\"anchor\":\"fn-directory::on-functions-change\"},{\"name\":\"directory::pre-generate\",\"anchor\":\"fn-directory::pre-generate\"},{\"name\":\"directory::registry::workers::info\",\"anchor\":\"fn-directory::registry::workers::info\"},{\"name\":\"directory::registry::workers::list\",\"anchor\":\"fn-directory::registry::workers::list\"},{\"name\":\"directory::search_functions\",\"anchor\":\"fn-directory::search_functions\"},{\"name\":\"directory::skills::create\",\"anchor\":\"fn-directory::skills::create\"},{\"name\":\"directory::skills::delete\",\"anchor\":\"fn-directory::skills::delete\"},{\"name\":\"directory::skills::download\",\"anchor\":\"fn-directory::skills::download\"},{\"name\":\"directory::skills::download_from_registry\",\"anchor\":\"fn-directory::skills::download_from_registry\"},{\"name\":\"directory::skills::download_from_repo\",\"anchor\":\"fn-directory::skills::download_from_repo\"},{\"name\":\"directory::skills::get\",\"anchor\":\"fn-directory::skills::get\"},{\"name\":\"directory::skills::index\",\"anchor\":\"fn-directory::skills::index\"},{\"name\":\"directory::skills::list\",\"anchor\":\"fn-directory::skills::list\"},{\"name\":\"directory::skills::update\",\"anchor\":\"fn-directory::skills::update\"},{\"name\":\"directory::system-prompts::create\",\"anchor\":\"fn-directory::system-prompts::create\"},{\"name\":\"directory::system-prompts::delete\",\"anchor\":\"fn-directory::system-prompts::delete\"},{\"name\":\"directory::system-prompts::get\",\"anchor\":\"fn-directory::system-prompts::get\"},{\"name\":\"directory::system-prompts::list\",\"anchor\":\"fn-directory::system-prompts::list\"},{\"name\":\"directory::system-prompts::update\",\"anchor\":\"fn-directory::system-prompts::update\"},{\"name\":\"iii-directory::ui-content\",\"anchor\":\"fn-iii-directory::ui-content\"}],\"triggers\":[{\"name\":\"directory::agents::on-change\",\"anchor\":\"trigger-directory::agents::on-change\"},{\"name\":\"directory::kits::on-change\",\"anchor\":\"trigger-directory::kits::on-change\"},{\"name\":\"directory::skills::on-change\",\"anchor\":\"trigger-directory::skills::on-change\"},{\"name\":\"directory::system-prompts::on-change\",\"anchor\":\"trigger-directory::system-prompts::on-change\"}]}]]}]\n"])</script><script>self.__next_f.push([1,"2f:[\"$\",\"div\",null,{\"className\":\"border border-rule bg-bg\",\"children\":[[\"$\",\"div\",null,{\"className\":\"bg-panel px-3.5 py-2.5 border-b border-rule\",\"children\":[\"$\",\"span\",null,{\"className\":\"font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-ink-faint\",\"children\":\"author\"}]}],[\"$\",\"div\",null,{\"className\":\"p-4 flex flex-col gap-y-2.5\",\"children\":[\"$\",\"div\",null,{\"className\":\"flex items-center gap-x-2 font-mono text-[13px]\",\"children\":[[\"$\",\"img\",null,{\"src\":\"https://iii.dev/docs/_mintlify/favicons/motiadev/AFkVbz_UcSL_5jsm/_generated/favicon/apple-touch-icon.png\",\"alt\":\"\",\"className\":\"size-5 object-cover\"}],[\"$\",\"span\",null,{\"className\":\"text-ink lowercase\",\"children\":\"iii\"}],[\"$\",\"$L11\",null,{\"ref\":\"$undefined\",\"iconNode\":\"$12:props:children:2:props:children:2:props:children:0:props:children:1:props:children:2:props:children:0:props:iconNode\",\"className\":\"lucide-badge-check size-3.5 text-accent\"}]]}]}]]}]\n31:T1f98a,"])</script><script>self.__next_f.push([1,"\u003ch1 id=\"iii-directory\" class=\"scroll-mt-20\"\u003eiii-directory\u003c/h1\u003e\n\u003cp\u003eWorkers registry HTTP proxy and filesystem-backed skills, system prompts,\nand agent profiles for the \u003ca href=\"https://github.com/iii-hq/iii\"\u003eiii engine\u003c/a\u003e, plus\nkit install and update. Every public function sits under a single\n\u003ccode class=\"readme-inline-code\"\u003edirectory::*\u003c/code\u003e namespace, split into six surfaces (all MCP-agnostic):\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eSurface\u003c/th\u003e\n\u003cth\u003eWhat clients see\u003c/th\u003e\n\u003cth\u003eWhen to use it\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eSkills\u003c/strong\u003e (\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::*\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003eEnriched listing via \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::list\u003c/code\u003e (\u003ccode class=\"readme-inline-code\"\u003e{ id, title, type, function_id, disable_model_invocation, description, bytes, modified_at }\u003c/code\u003e per row), a single-skill reader \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::get { id }\u003c/code\u003e returning \u003ccode class=\"readme-inline-code\"\u003e{ id, title, type, function_id, disable_model_invocation, path, body, modified_at }\u003c/code\u003e (the full body instead of the list teaser), and \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::index\u003c/code\u003e which renders a short per-worker overview document (one \u003ccode class=\"readme-inline-code\"\u003e## \u003ctitle\u003e\u003c/code\u003e + first paragraph + \u003ccode class=\"readme-inline-code\"\u003eread more\u003c/code\u003e link per \u003ccode class=\"readme-inline-code\"\u003etype: index\u003c/code\u003e skill). Authored by \u003ccode class=\"readme-inline-code\"\u003ecreate\u003c/code\u003e, edited by \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e, removed by \u003ccode class=\"readme-inline-code\"\u003edelete\u003c/code\u003e. \u003ccode class=\"readme-inline-code\"\u003etitle\u003c/code\u003e prefers the YAML frontmatter \u003ccode class=\"readme-inline-code\"\u003etitle:\u003c/code\u003e (then \u003ccode class=\"readme-inline-code\"\u003ename:\u003c/code\u003e) over the body H1; \u003ccode class=\"readme-inline-code\"\u003etype\u003c/code\u003e is lifted from frontmatter \u003ccode class=\"readme-inline-code\"\u003etype:\u003c/code\u003e (e.g. \u003ccode class=\"readme-inline-code\"\u003eindex\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ehow-to\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ereference\u003c/code\u003e) and serialised as \u003ccode class=\"readme-inline-code\"\u003enull\u003c/code\u003e when absent. System-installed agent skills under the read-only \u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e are served too (see \u003ca href=\"#on-disk-layout\"\u003eOn-disk layout\u003c/a\u003e).\u003c/td\u003e\n\u003ctd\u003eOrientation: \u0026quot;when and why to use my worker\u0026#39;s tools\u0026quot;\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eSystem prompts\u003c/strong\u003e (\u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::*\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003eIdentity prompts listed by \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e, read by \u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e, authored by \u003ccode class=\"readme-inline-code\"\u003ecreate\u003c/code\u003e, edited by \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e, and removed by \u003ccode class=\"readme-inline-code\"\u003edelete\u003c/code\u003e. The list response keeps its \u003ccode class=\"readme-inline-code\"\u003eprompts\u003c/code\u003e field name. Stored under any \u003ccode class=\"readme-inline-code\"\u003esystem-prompts/\u003c/code\u003e path segment; \u003ccode class=\"readme-inline-code\"\u003ecreate\u003c/code\u003e writes \u003ccode class=\"readme-inline-code\"\u003e\u003cskills_folder\u003e/system-prompts/\u003cname\u003e.md\u003c/code\u003e.\u003c/td\u003e\n\u003ctd\u003eWhat the chat\u0026#39;s system-prompt picker offers as an identity prompt (enrich or replace)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eAgent Profiles\u003c/strong\u003e (\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::*\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003eReusable session identities whose file body is the system prompt, with display \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e, emoji \u003ccode class=\"readme-inline-code\"\u003elogo\u003c/code\u003e, preloaded \u003ccode class=\"readme-inline-code\"\u003eskills\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003efunctions\u003c/code\u003e (bodies and contracts the harness freezes into every session\u0026#39;s prompt), and optional \u003ccode class=\"readme-inline-code\"\u003emodel\u003c/code\u003e + \u003ccode class=\"readme-inline-code\"\u003ereasoning_effort\u003c/code\u003e in required frontmatter. \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e rows carry the display/configuration metadata and \u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e adds \u003ccode class=\"readme-inline-code\"\u003esystem_prompt\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003eunknown_skills\u003c/code\u003e. Stored as direct \u003ccode class=\"readme-inline-code\"\u003e\u003cagents_folder\u003e/\u003cid\u003e.md\u003c/code\u003e files. See \u003ca href=\"../docs/architecture/agent-profile-storage.md\"\u003eAgent profile storage\u003c/a\u003e.\u003c/td\u003e\n\u003ctd\u003eA named identity selected with \u003ccode class=\"readme-inline-code\"\u003eharness::send { options: { agent } }\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eSearch\u003c/strong\u003e (\u003ccode class=\"readme-inline-code\"\u003edirectory::search_functions\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003eOne to six external capabilities → compact function-id candidates (installed, plus registry workers under \u003ccode class=\"readme-inline-code\"\u003einstallable\u003c/code\u003e), with a conditional pre-generate hint pointing agents at it. The response also carries \u003ccode class=\"readme-inline-code\"\u003eskills\u003c/code\u003e (installed how-to documents) and \u003ccode class=\"readme-inline-code\"\u003etriggers\u003c/code\u003e (registered bindings that already fire, schedule, or hook a function, minus ephemeral console listeners), ranked in the same mode as the functions; \u003ccode class=\"readme-inline-code\"\u003esearch_mode\u003c/code\u003e reports the mode that actually ranked.\u003c/td\u003e\n\u003ctd\u003e\u0026quot;Which functions do I call for this task?\u0026quot;\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eKits\u003c/strong\u003e (\u003ccode class=\"readme-inline-code\"\u003edirectory::download-kit\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003edirectory::kits::*\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003eInstall, update and remove kits — agent profiles, skills and registry workers published together as \u003ccode class=\"readme-inline-code\"\u003e\u003cauthor\u003e/\u003ckit\u003e\u003c/code\u003e — through plans a human reviews (ADE → Directory → Kits) before anything is written. \u003ccode class=\"readme-inline-code\"\u003ekits.lock\u003c/code\u003e records what is installed. See \u003ca href=\"#kits\"\u003eKits\u003c/a\u003e.\u003c/td\u003e\n\u003ctd\u003e\u0026quot;Install the kanban team kit\u0026quot;, \u0026quot;what does 1.1.0 change?\u0026quot;\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eRegistry\u003c/strong\u003e (\u003ccode class=\"readme-inline-code\"\u003edirectory::registry::*\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003eHTTP proxy over \u003ccode class=\"readme-inline-code\"\u003eapi.workers.iii.dev\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eworkers::{list,info}\u003c/code\u003e. Rows share the core \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003eversion\u003c/code\u003e fields with the engine\u0026#39;s \u003ccode class=\"readme-inline-code\"\u003eengine::workers::list\u003c/code\u003e and add publication metadata (\u003ccode class=\"readme-inline-code\"\u003etype\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003econfig\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003esupported_targets\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003etotal_downloads\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003edependencies\u003c/code\u003e, optional \u003ccode class=\"readme-inline-code\"\u003eimage\u003c/code\u003e). \u003ccode class=\"readme-inline-code\"\u003eworkers::list\u003c/code\u003e is cursor-paginated with a server-authored page size.\u003c/td\u003e\n\u003ctd\u003e\u0026quot;What\u0026#39;s published in the public registry?\u0026quot;\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eEngine introspection (functions / triggers / registered triggers /\nworkers) is served by the engine natively at\n\u003ccode class=\"readme-inline-code\"\u003eengine::functions::*\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eengine::triggers::*\u003c/code\u003e,\n\u003ccode class=\"readme-inline-code\"\u003eengine::registered-triggers::*\u003c/code\u003e, and \u003ccode class=\"readme-inline-code\"\u003eengine::workers::*\u003c/code\u003e. Call the\nengine ids directly. One wrapper survives for callers that can only\nreach the \u003ccode class=\"readme-inline-code\"\u003edirectory::\u003c/code\u003e namespace: \u003ccode class=\"readme-inline-code\"\u003edirectory::engine::functions::info\u003c/code\u003e\nproxies a single function\u0026#39;s schema (see its row below).\u003c/p\u003e\n\u003cp\u003eThis worker is where an agent\u0026#39;s identity text LIVES. \u003ccode class=\"readme-inline-code\"\u003eskills/system-prompts/iii-runtime.md\u003c/code\u003e\nships here and is the one copy of \u0026quot;how to work against a live iii engine\u0026quot; —\n\u003ccode class=\"readme-inline-code\"\u003eclaude-code\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003epi\u003c/code\u003e fetch it with \u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::get name=iii-runtime\u003c/code\u003e (plus \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::index\u003c/code\u003e) for both their headless\nturns and their console terminals, rather than compiling a prompt of their own.\nEdit that file and every agent reads the edit; no worker release involved.\u003c/p\u003e\n\u003cp\u003eSkills and system prompts are sourced from \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e; agent profiles\nuse the dedicated \u003ccode class=\"readme-inline-code\"\u003eagents_folder\u003c/code\u003e. Writes are the\n\u003cstrong\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::download*\u003c/code\u003e\u003c/strong\u003e functions, which pull markdown from either\nthe \u003ca href=\"https://workers.iii.dev\"\u003eworkers registry\u003c/a\u003e or a GitHub repo and route each\nsupported family to its configured root, plus the\nper-kind single-file editors — \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::{create,update,delete}\u003c/code\u003e,\n\u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::{create,update,delete}\u003c/code\u003e and\n\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::{create,update,delete}\u003c/code\u003e. Once downloaded, files\nbelong to the developer — edit them however you want, in the editor of\nyour choice: a change made directly on disk fires the matching\n\u003ccode class=\"readme-inline-code\"\u003eon-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"external\"\u003c/code\u003e (see \u003ca href=\"#custom-trigger-types\"\u003eCustom trigger\ntypes\u003c/a\u003e).\u003c/p\u003e\n\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::registry::workers::*\u003c/code\u003e and the engine\u0026#39;s \u003ccode class=\"readme-inline-code\"\u003eengine::workers::*\u003c/code\u003e\nshare the core \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003eversion\u003c/code\u003e fields so a parser\nthat touches only those keys works against either surface; the\nregistry view also surfaces publication metadata (\u003ccode class=\"readme-inline-code\"\u003etype\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003econfig\u003c/code\u003e,\n\u003ccode class=\"readme-inline-code\"\u003esupported_targets\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003etotal_downloads\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003edependencies\u003c/code\u003e, optional\n\u003ccode class=\"readme-inline-code\"\u003eimage\u003c/code\u003e) and the engine view adds runtime / connection state.\u003c/p\u003e\n\u003ch2 id=\"table-of-contents\" class=\"scroll-mt-20\"\u003eTable of contents\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"#install\"\u003eInstall\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#configuration\"\u003eConfiguration\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#quickstart-download-some-skills\"\u003eQuickstart: download some skills\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#on-disk-layout\"\u003eOn-disk layout\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#skill-ids\"\u003eSkill ids\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#kits\"\u003eKits\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#functions\"\u003eFunctions\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#function-search--pre-generate-hint\"\u003eFunction search \u0026amp; pre-generate hint\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#custom-trigger-types\"\u003eCustom trigger types\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#local-development--testing\"\u003eLocal development \u0026amp; testing\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#migration-from-skills-v02x\"\u003eMigration from skills v0.2.x\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"install\" class=\"scroll-mt-20\"\u003eInstall\u003c/h2\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003eiii\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e trigger\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e compose::add\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e worker=iii-directory\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003eiii trigger compose::add\u003c/code\u003e resolves the worker and its dependencies, writes\nexact declarations to \u003ccode class=\"readme-inline-code\"\u003eworker-compose.yaml\u003c/code\u003e, and reconciles the Compose project.\u003c/p\u003e\n\u003cp\u003eFor container settings, fetch \u003ccode class=\"readme-inline-code\"\u003ecompose::schema { function_id: \"compose::add\" }\u003c/code\u003e and use\nits \u003ccode class=\"readme-inline-code\"\u003eworkers\u003c/code\u003e list. For example, after registering the completion wake described below:\u003c/p\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#999999\"\u003e{\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#99841877\"\u003e \"\u003c/span\u003e\u003cspan style=\"color:#998418\"\u003eoperation_id\u003c/span\u003e\u003cspan style=\"color:#99841877\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e \"\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e\u0026#x3C;operation-id\u003e\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e,\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#99841877\"\u003e \"\u003c/span\u003e\u003cspan style=\"color:#998418\"\u003eworkers\u003c/span\u003e\u003cspan style=\"color:#99841877\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e [\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#B5695977\"\u003e \"\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003estate\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e,\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#999999\"\u003e {\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#99841877\"\u003e \"\u003c/span\u003e\u003cspan style=\"color:#998418\"\u003eworker\u003c/span\u003e\u003cspan style=\"color:#99841877\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e \"\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003eiii-directory\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e,\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#99841877\"\u003e \"\u003c/span\u003e\u003cspan style=\"color:#998418\"\u003estart_after\u003c/span\u003e\u003cspan style=\"color:#99841877\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e [\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003estate\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e],\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#99841877\"\u003e \"\u003c/span\u003e\u003cspan style=\"color:#998418\"\u003econfig_override\u003c/span\u003e\u003cspan style=\"color:#99841877\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e {\u003c/span\u003e\u003cspan style=\"color:#99841877\"\u003e \"\u003c/span\u003e\u003cspan style=\"color:#998418\"\u003eregistry_search\u003c/span\u003e\u003cspan style=\"color:#99841877\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#1E754F\"\u003e true\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e }\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#999999\"\u003e }\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#999999\"\u003e ]\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#999999\"\u003e}\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe list can mix worker names and objects. Each object accepts \u003ccode class=\"readme-inline-code\"\u003escripts\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003econfig_name\u003c/code\u003e,\n\u003ccode class=\"readme-inline-code\"\u003econfig_override\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eworking_dir\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eenvironment\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eenv_file\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003estartup_timeout\u003c/code\u003e, and\npackage \u003ccode class=\"readme-inline-code\"\u003eversion\u003c/code\u003e as well as \u003ccode class=\"readme-inline-code\"\u003eworker\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003estart_after\u003c/code\u003e. \u003ccode class=\"readme-inline-code\"\u003escripts.run\u003c/code\u003e is for local\nworkers only. Supplied maps replace the whole field; omitted settings are retained.\u003c/p\u003e\n\u003cp\u003eThe returned \u003ccode class=\"readme-inline-code\"\u003einstall.payload\u003c/code\u003e from function search is a minimal shorthand. If the worker\nneeds settings, replace its singular \u003ccode class=\"readme-inline-code\"\u003eworker\u003c/code\u003e with an object in \u003ccode class=\"readme-inline-code\"\u003eworkers\u003c/code\u003e.\nRegister a one-shot \u003ccode class=\"readme-inline-code\"\u003ecompose-operation\u003c/code\u003e wake before calling \u003ccode class=\"readme-inline-code\"\u003ecompose::add\u003c/code\u003e, use the same\n\u003ccode class=\"readme-inline-code\"\u003eoperation_id\u003c/code\u003e in both calls, and wait for terminal success before using the new functions.\nAn acceptance response does not mean the worker is ready. See the\n\u003ca href=\"https://github.com/iii-hq/workers/blob/main/harness/README.md#adding-workers-with-container-settings\"\u003econtainer settings example and completion flow\u003c/a\u003e\nfor field behavior, path resolution, and recovery.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"skills\" class=\"scroll-mt-20\"\u003eSkills\u003c/h2\u003e\n\u003cp\u003eInstall the \u003ccode class=\"readme-inline-code\"\u003eiii-directory\u003c/code\u003e agent skill for Claude Code, Cursor, and 30+ other agents:\u003c/p\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003enpx\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e skills\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e add\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e iii-hq/workers\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --skill\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e iii-directory\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eBrowse or install every worker skill at once:\u003c/p\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003enpx\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e skills\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e add\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e iii-hq/workers\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --list\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003enpx\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e skills\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e add\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e iii-hq/workers\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --all\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003chr\u003e\n\u003ch2 id=\"configuration\" class=\"scroll-mt-20\"\u003eConfiguration\u003c/h2\u003e\n\u003cp\u003eRuntime settings live in the \u003cstrong\u003e\u003ccode class=\"readme-inline-code\"\u003econfiguration\u003c/code\u003e worker\u003c/strong\u003e under id\n\u003cstrong\u003e\u003ccode class=\"readme-inline-code\"\u003eiii-directory\u003c/code\u003e\u003c/strong\u003e (the same pattern \u003ccode class=\"readme-inline-code\"\u003edatabase\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003estorage\u003c/code\u003e use). At boot\nthe worker registers its JSON Schema, reads the live value via\n\u003ccode class=\"readme-inline-code\"\u003econfiguration::get\u003c/code\u003e (the configuration worker env-expands \u003ccode class=\"readme-inline-code\"\u003e${VAR}\u003c/code\u003e), and binds\na \u003ccode class=\"readme-inline-code\"\u003econfiguration\u003c/code\u003e trigger so it re-fetches on change.\u003c/p\u003e\n\u003cp\u003ePersisted values default to \u003ccode class=\"readme-inline-code\"\u003e./data/configuration/iii-directory.yaml\u003c/code\u003e (fs\nadapter). Edit that file directly, call \u003ccode class=\"readme-inline-code\"\u003econfiguration::set id=iii-directory\u003c/code\u003e,\nor use the Console\u0026#39;s global Settings modal — all three propagate without a redeploy.\u003c/p\u003e\n\u003ch3 id=\"fields\" class=\"scroll-mt-20\"\u003eFields\u003c/h3\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# TOPOLOGY — changing any of these requires a worker restart.\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003eskills_folder\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e skills\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # under III_COMPOSE_DIR, or the process cwd standalone\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003elocal_skills_folder\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e skills/iii\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # project-scoped overrides (whole-namespace local-wins)\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003eagents_folder\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e agents\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # direct \u0026#x3C;id\u003e.md agent profiles\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003eagents_skills_folder\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e .agents/skills\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # READ-ONLY agent skills, with the same relative-path base\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003eauto_download\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#1E754F\"\u003e true\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # subscribe to worker-add + run the boot reconcile\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# function_search_model_path: ~/.cache/iii/all-MiniLM-L6-v2-\u0026#x3C;revision\u003e # pinned Hybrid bundle; null disables it\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_model_download\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#1E754F\"\u003e true\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # download the pinned bundle at boot in Hybrid mode\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# TUNABLE — hot-reload live on `configuration:updated`.\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003eregistry_url\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e https://api.workers.iii.dev\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # workers registry base URL (workers and kits)\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# registry_web_url: https://workers.iii.dev # registry web app for \"open in registry\" links; default: registry_url without its leading `api.`\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003edownload_timeout_ms\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 60000\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # per git-clone / HTTP request timeout (ms)\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003eregistry_cache_ttl_ms\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 60000\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # in-process TTL for registry::workers::* responses\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efilter_unregistered\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#1E754F\"\u003e true\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # hide skills whose namespace isn't an installed worker\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003einject_hint\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#1E754F\"\u003e false\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # bind the directory::pre-generate search-hint hook (off: the harness identity prompt already teaches directory-first discovery)\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003ehint_min_workers\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 2\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # minimum surface width before the hint fires (0 = always)\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003eregistry_search\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#1E754F\"\u003e true\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # include installable registry workers in every search\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_mode\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e judge\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # lexical | hybrid | judge (default)\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_timeout_ms\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 3000\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # integer 1..30000; shared judge deadline per public search\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_min_relevance\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 0.5\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # finite 0..1 inclusive; noul floor (initial calibration value)\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_side_lane_min_relevance\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 0.3\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # finite 0..1 inclusive; noul floor for the skills and triggers sections\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_question\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e choice\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # choice (default: one question per capability) | noul (one yes/no per shortlisted document) | tournament (whole catalog: compact rounds, then a final choice; no Hybrid shortlist)\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_choice_min_probability\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 0.1\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # finite 0..1 inclusive; with choice, the floor for all but the best document\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe writable \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003eagents_folder\u003c/code\u003e roots are created when needed.\u003c/p\u003e\n\u003ch3 id=\"zero-config-default-seed\" class=\"scroll-mt-20\"\u003eZero-config default + seed\u003c/h3\u003e\n\u003cp\u003eWith no seed and no stored value the worker uses built-in defaults. Relative\nfolder paths use \u003ccode class=\"readme-inline-code\"\u003eIII_COMPOSE_DIR\u003c/code\u003e when set and the process current directory\notherwise (\u003ccode class=\"readme-inline-code\"\u003eskills_folder: skills\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eagents_folder: agents\u003c/code\u003e,\n\u003ccode class=\"readme-inline-code\"\u003eregistry_url: https://api.workers.iii.dev\u003c/code\u003e).\nPass \u003ccode class=\"readme-inline-code\"\u003e--config \u003cpath\u003e\u003c/code\u003e to supply a YAML seed: when present and no value is\nstored yet, its contents become \u003ccode class=\"readme-inline-code\"\u003einitial_value\u003c/code\u003e on \u003ccode class=\"readme-inline-code\"\u003econfiguration::register\u003c/code\u003e\n(see \u003ca href=\"config.yaml.example\"\u003e\u003ccode class=\"readme-inline-code\"\u003econfig.yaml.example\u003c/code\u003e\u003c/a\u003e). Engine-managed deployments\ninline the config under the worker entry; the engine delivers it via \u003ccode class=\"readme-inline-code\"\u003e--config\u003c/code\u003e.\u003c/p\u003e\n\u003ch3 id=\"hot-reload\" class=\"scroll-mt-20\"\u003eHot reload\u003c/h3\u003e\n\u003cp\u003eOn \u003ccode class=\"readme-inline-code\"\u003econfiguration::set\u003c/code\u003e (or an external edit to the persisted file), the worker\nre-fetches the authoritative value. Tunable changes apply in place and the\nregistry caches are cleared so a repointed \u003ccode class=\"readme-inline-code\"\u003eregistry_url\u003c/code\u003e takes effect\nimmediately. Topology changes (\u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003elocal_skills_folder\u003c/code\u003e /\n\u003ccode class=\"readme-inline-code\"\u003eagents_folder\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003eauto_download\u003c/code\u003e /\n\u003ccode class=\"readme-inline-code\"\u003efunction_search_model_path\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003efunction_search_model_download\u003c/code\u003e) are refused with a \u0026quot;restart\nrequired\u0026quot; log; the previous configuration is kept until the worker restarts.\u003c/p\u003e\n\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003efunction_search_mode\u003c/code\u003e and all \u003ccode class=\"readme-inline-code\"\u003efunction_search_judge_*\u003c/code\u003e options hot-reload.\nJudge credentials and the model name are the \u003ccode class=\"readme-inline-code\"\u003ejudge-typesafe\u003c/code\u003e worker\u0026#39;s\nsettings, not this worker\u0026#39;s.\u003c/p\u003e\n\u003cp\u003eThe writable \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003elocal_skills_folder\u003c/code\u003e, and \u003ccode class=\"readme-inline-code\"\u003eagents_folder\u003c/code\u003e are\nwatch roots, and the watcher creates each one at boot if it is missing.\nDirect \u003ccode class=\"readme-inline-code\"\u003e\u003cid\u003e.md\u003c/code\u003e edits under \u003ccode class=\"readme-inline-code\"\u003eagents_folder\u003c/code\u003e fire\n\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"external\"\u003c/code\u003e; nested files are ignored.\n\u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e is a watch root too,\nbut only when it already exists — the worker never creates (or writes)\nanything under it. Install your first agents skill while the worker is\nrunning and that root stays unwatched until the next restart: reads still\nserve it, since every read re-scans disk, but the live \u003ccode class=\"readme-inline-code\"\u003eexternal\u003c/code\u003e doorbell\nis missing until then. \u003ccode class=\"readme-inline-code\"\u003elocal_skills_folder\u003c/code\u003e defaults to \u003ccode class=\"readme-inline-code\"\u003eskills/iii\u003c/code\u003e under\n\u003ccode class=\"readme-inline-code\"\u003eIII_COMPOSE_DIR\u003c/code\u003e, or under the process current directory when the worker runs\nstandalone. An empty local root shadows nothing. Because the roots are\nrestart-required, the watch\nroots are fixed for the process lifetime.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"quickstart-download-some-skills\" class=\"scroll-mt-20\"\u003eQuickstart: download some skills\u003c/h2\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# Pull a specific worker's directory bundle at a fixed semver from\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# the registry. Files land under `\u0026#x3C;skills_folder\u003e/agent-memory/`.\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003eiii\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e trigger\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --function-id=directory::skills::download\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e \\\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A65E2B\"\u003e --payload=\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e'\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e{\"worker\": \"agent-memory\", \"version\": \"1.2.3\"}\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e'\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# Same, but always fetch whatever's tagged `latest` (also the default\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# when neither version nor tag is given).\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003eiii\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e trigger\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --function-id=directory::skills::download\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e \\\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A65E2B\"\u003e --payload=\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e'\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e{\"worker\": \"agent-memory\"}\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e'\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# Pull a single subfolder out of a public GitHub repo via\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# `git clone --depth 1 --branch main`. Files land under\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# `\u0026#x3C;skills_folder\u003e/frontend-design/`. The `branch` field defaults to\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# `main`; pass `\"master\"` for older repos that haven't migrated.\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003eiii\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e trigger\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --function-id=directory::skills::download\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e \\\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A65E2B\"\u003e --payload=\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e'\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e{\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#B56959\"\u003e \"repo\": \"https://github.com/anthropics/skills\",\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#B56959\"\u003e \"skill\": \"frontend-design\"\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#B56959\"\u003e }\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe response is\n\u003ccode class=\"readme-inline-code\"\u003e{ namespace, skills_written, system_prompts_written, agents_written, agents_skipped?, source }\u003c/code\u003e.\nThe three \u003ccode class=\"readme-inline-code\"\u003e*_written\u003c/code\u003e fields list the files materialised in this run.\nRegistry entries shaped exactly as \u003ccode class=\"readme-inline-code\"\u003eagents/\u003cid\u003e.md\u003c/code\u003e land in\n\u003ccode class=\"readme-inline-code\"\u003e\u003cagents_folder\u003e/\u003cid\u003e.md\u003c/code\u003e; repo downloads do not install agent profiles.\nA registry entry whose profile id an installed kit owns (\u003ccode class=\"readme-inline-code\"\u003ekits.lock\u003c/code\u003e) is not\nwritten — kit profiles take precedence — and is reported in\n\u003ccode class=\"readme-inline-code\"\u003eagents_skipped: [{ id, owned_by }]\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eA registry download (explicit or automatic) writes\n\u003ccode class=\"readme-inline-code\"\u003e\u003cskills_folder\u003e/\u003cworker\u003e/.iii-skill-complete\u003c/code\u003e with the worker, the resolved\n\u003ccode class=\"readme-inline-code\"\u003eversion\u003c/code\u003e and, per agent profile it wrote, \u003ccode class=\"readme-inline-code\"\u003eagents: { \u003cid\u003e: \u003csha256\u003e }\u003c/code\u003e. That\nis how \u003ccode class=\"readme-inline-code\"\u003edirectory::agents::list\u003c/code\u003e attributes a profile to a worker.\u003c/p\u003e\n\u003cp\u003eAfter every successful download the worker fires the\n\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::on-change\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::on-change\u003c/code\u003e,\nand/or \u003ccode class=\"readme-inline-code\"\u003edirectory::agents::on-change\u003c/code\u003e trigger types so that\nsubscribers like the \u003ca href=\"https://github.com/iii-hq/workers/tree/main/mcp\"\u003e\u003ccode class=\"readme-inline-code\"\u003emcp\u003c/code\u003e\u003c/a\u003e worker can\nforward MCP \u003ccode class=\"readme-inline-code\"\u003enotifications/list_changed\u003c/code\u003e to their clients.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"on-disk-layout\" class=\"scroll-mt-20\"\u003eOn-disk layout\u003c/h2\u003e\n\u003cp\u003eThe worker uses separate roots for directory content and agent profiles:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eskills_folder/\n \u0026lt;namespace\u0026gt;/ # one folder per `directory::skills::download` namespace\n index.md # → iii://\u0026lt;namespace\u0026gt;/index\n contacts.md # → iii://\u0026lt;namespace\u0026gt;/contacts\n emails/send-email.md # → iii://\u0026lt;namespace\u0026gt;/emails/send-email\n system-prompts/ # ← magic marker for system prompts\n reviewer.md # ← identity prompt (needs YAML frontmatter)\n system-prompts/ # ← where system-prompts::create writes\n pirate.md\n\nagents_folder/ # ← where agents::create writes\n release-captain.md # ← agent profile (needs YAML frontmatter)\n frontend-design.md # ← `extends: iii` builds on the bundled base\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThree agent profiles ship inside the worker binary:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode class=\"readme-inline-code\"\u003edefault\u003c/code\u003e — shown as \u003cstrong\u003eDefault\u003c/strong\u003e in the chat\u0026#39;s new-session gallery: the\nminimal directory-first identity (the same text as the bundled\n\u003ccode class=\"readme-inline-code\"\u003eiii-minimal\u003c/code\u003e system prompt), with a composer example. New sessions in the\nADE start on it.\u003c/li\u003e\n\u003cli\u003e\u003ccode class=\"readme-inline-code\"\u003eiii\u003c/code\u003e — the harness default identity, verbatim. \u003ccode class=\"readme-inline-code\"\u003ehidden: true\u003c/code\u003e keeps it\nout of the gallery; it stays a valid \u003ccode class=\"readme-inline-code\"\u003eextends\u003c/code\u003e parent and runs by id.\u003c/li\u003e\n\u003cli\u003e\u003ccode class=\"readme-inline-code\"\u003eiii-minimal\u003c/code\u003e — the previous id of \u003ccode class=\"readme-inline-code\"\u003edefault\u003c/code\u003e, kept as a hidden alias\n(\u003ccode class=\"readme-inline-code\"\u003eextends: default\u003c/code\u003e, no body of its own) so existing \u003ccode class=\"readme-inline-code\"\u003eextends: iii-minimal\u003c/code\u003e chains, saved sessions, and explicit invocations resolve to\nthe same identity. New profiles should use \u003ccode class=\"readme-inline-code\"\u003eextends: default\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eEach is always listed (\u003ccode class=\"readme-inline-code\"\u003ebuiltin: true\u003c/code\u003e), a local \u003ccode class=\"readme-inline-code\"\u003eagents_folder/\u003cid\u003e.md\u003c/code\u003e\nshadows it, \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e on it copy-on-writes that local file, and deleting the\nfile falls back to the bundled copy. No file is ever seeded on disk.\u003c/p\u003e\n\u003cp\u003eAn optional \u003ccode class=\"readme-inline-code\"\u003ecomposer_placeholder:\u003c/code\u003e frontmatter string is the example request\nthe chat shows in an EMPTY composer while that profile is selected. It is\npresentation only — never sent, never added to the prompt — and\nprofile-local: it does not inherit through \u003ccode class=\"readme-inline-code\"\u003eextends\u003c/code\u003e, so a child without its\nown example gets the chat\u0026#39;s generic hint. Whitespace collapses to single\nspaces, blank means absent, and more than 200 characters is rejected like any\nother invalid frontmatter.\u003c/p\u003e\n\u003cp\u003eAn optional \u003ccode class=\"readme-inline-code\"\u003eskills_index:\u003c/code\u003e boolean turns off the skills index for sessions\nrunning as that profile: with \u003ccode class=\"readme-inline-code\"\u003eskills_index: false\u003c/code\u003e the harness starts them\nwithout the names-only \u003ccode class=\"readme-inline-code\"\u003e\u003cavailable_skills\u003e\u003c/code\u003e block in the prompt (this is the\nprompt block, not the \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::index\u003c/code\u003e function). It inherits\nthrough \u003ccode class=\"readme-inline-code\"\u003eextends\u003c/code\u003e like \u003ccode class=\"readme-inline-code\"\u003emodel\u003c/code\u003e — the nearest profile that sets it wins, and\n\u003ccode class=\"readme-inline-code\"\u003etrue\u003c/code\u003e in a child turns the index back on. The profile\u0026#39;s preloaded \u003ccode class=\"readme-inline-code\"\u003eskills\u003c/code\u003e\nstill render, and \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::get\u003c/code\u003e stays callable when the session\u0026#39;s\npolicy allows it. A value that is not a YAML boolean makes the profile\ninvalid, like \u003ccode class=\"readme-inline-code\"\u003ehidden\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eA second, READ-ONLY root — \u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e (default \u003ccode class=\"readme-inline-code\"\u003e.agents/skills\u003c/code\u003e\nunder the same Compose or standalone base) — serves agent skills. It is\nscanned \u003cstrong\u003eshallowly\u003c/strong\u003e: only \u003ccode class=\"readme-inline-code\"\u003e\u003cskill-dir\u003e/SKILL.md\u003c/code\u003e becomes an entry\n(id \u003ccode class=\"readme-inline-code\"\u003e\u003cskill-dir\u003e/index\u003c/code\u003e, displayed as \u003ccode class=\"readme-inline-code\"\u003e\u003cskill-dir\u003e\u003c/code\u003e); a skill\u0026#39;s\n\u003ccode class=\"readme-inline-code\"\u003ereference/\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003escripts/\u003c/code\u003e, or other support payload is never listed. A\nmissing directory is silently empty. These skills bypass\n\u003ccode class=\"readme-inline-code\"\u003efilter_unregistered\u003c/code\u003e (their namespaces are skills, not workers), stay\nout of \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::index\u003c/code\u003e (a per-WORKER surface), and are\nrefused by \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003edelete\u003c/code\u003e — edit them with their owning tool, or\ncopy one into \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e on disk to fork it. Precedence is\n\u003ccode class=\"readme-inline-code\"\u003elocal_skills_folder\u003c/code\u003e \u0026gt; \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e \u0026gt; \u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e,\nnamespace-wise: a top-level namespace directory in a higher root\nshadows the same namespace below.\u003c/p\u003e\n\u003cp\u003eA few rules:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eSkill ids\u003c/strong\u003e are the relative path under \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003e.md\u003c/code\u003e\nstripped. Each segment must satisfy \u003ccode class=\"readme-inline-code\"\u003e[a-z0-9_-]{1,64}\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSkill frontmatter is optional.\u003c/strong\u003e When present, the reader recognises\n\u003ccode class=\"readme-inline-code\"\u003etitle:\u003c/code\u003e (preferred title), \u003ccode class=\"readme-inline-code\"\u003ename:\u003c/code\u003e (title fallback), \u003ccode class=\"readme-inline-code\"\u003etype:\u003c/code\u003e (free-form\nclassifier), \u003ccode class=\"readme-inline-code\"\u003efunction_id:\u003c/code\u003e (canonical bus function id surfaced by \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e\nand \u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e), \u003ccode class=\"readme-inline-code\"\u003edescription:\u003c/code\u003e (preferred \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e teaser), and\n\u003ccode class=\"readme-inline-code\"\u003edisable-model-invocation:\u003c/code\u003e (boolean, default \u003ccode class=\"readme-inline-code\"\u003efalse\u003c/code\u003e, surfaced as\n\u003ccode class=\"readme-inline-code\"\u003edisable_model_invocation\u003c/code\u003e by both responses). The body H1 and first\nparagraph are the title and list-description fallbacks, respectively.\nDisabled skills remain visible to ordinary directory clients; model\nindex consumers decide whether to filter them. Any other YAML keys are ignored.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSystem prompts\u003c/strong\u003e live under any \u003ccode class=\"readme-inline-code\"\u003e*/system-prompts/*.md\u003c/code\u003e path, with\nYAML frontmatter (\u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e required, \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e optional). A path carrying\nboth a \u003ccode class=\"readme-inline-code\"\u003eprompts\u003c/code\u003e and a \u003ccode class=\"readme-inline-code\"\u003esystem-prompts\u003c/code\u003e segment is a system prompt because\n\u003ccode class=\"readme-inline-code\"\u003esystem-prompts\u003c/code\u003e is classified first. Other paths containing a \u003ccode class=\"readme-inline-code\"\u003eprompts\u003c/code\u003e\nsegment are ignored by scans and downloads.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eWhat a system prompt can do, by design.\u003c/strong\u003e The console\u0026#39;s chat picker\ncan send a selected system prompt with\n\u003ccode class=\"readme-inline-code\"\u003esystem_prompt_strategy: \"override\"\u003c/code\u003e, which replaces the harness\u0026#39;s\nbuilt-in identity prompt with that file\u0026#39;s body verbatim. Files reach\n\u003ccode class=\"readme-inline-code\"\u003esystem-prompts/\u003c/code\u003e either by local authoring or via\n\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::download\u003c/code\u003e from a git repo or the registry, so a\ndownloaded bundle can supply one. This is an accepted property, not a\nhole: it takes a deliberate selection in the UI, the same UI already\naccepts arbitrary typed text, and the operator owns \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e.\nWorth knowing before you point \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e at a directory other\npeople can write to.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAgent profiles\u003c/strong\u003e are direct \u003ccode class=\"readme-inline-code\"\u003e\u003cagents_folder\u003e/\u003cid\u003e.md\u003c/code\u003e files (unrelated to\nthe read-only \u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e above, which holds external tools\u0026#39;\n\u003cem\u003eskills\u003c/em\u003e). Nested profiles and the former\n\u003ccode class=\"readme-inline-code\"\u003e\u003cskills_folder\u003e/**/agents/*.md\u003c/code\u003e layout are ignored. Frontmatter is required\nand must declare a non-empty \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e\n(the display name — the id is always the file stem); \u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e may\nbe empty, \u003ccode class=\"readme-inline-code\"\u003elogo\u003c/code\u003e is emoji-only (≤16 bytes, no path characters),\n\u003ccode class=\"readme-inline-code\"\u003eskills:\u003c/code\u003e filters the skill index (absent/empty = every skill), and\n\u003ccode class=\"readme-inline-code\"\u003emodel:\u003c/code\u003e names a model id for sessions using this profile (absent = the\nsend decides), and optional \u003ccode class=\"readme-inline-code\"\u003ereasoning_effort:\u003c/code\u003e names its provider-native\neffort. Both are stored verbatim and resolved against the live model\ncatalog where they are used. The body is the\nsystem prompt, verbatim, and may be empty — a profile with no prompt of\nits own contributes only its parent chain (if any) and its non-prompt\nsettings. Unknown \u003ccode class=\"readme-inline-code\"\u003eskills\u003c/code\u003e ids are\nwarnings surfaced by \u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e, never load failures.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAgent profiles declare preloaded functions.\u003c/strong\u003e \u003ccode class=\"readme-inline-code\"\u003efunctions:\u003c/code\u003e lists engine\nfunction ids (\u003ccode class=\"readme-inline-code\"\u003ecoder::tree\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ecoder::search\u003c/code\u003e, …) the profile uses\nroutinely. The harness resolves their contracts once, when a session\nstarts as this profile, and freezes them into the system prompt as a\n\u003ccode class=\"readme-inline-code\"\u003e\u003cpreloaded_functions\u003e\u003c/code\u003e block (id, description, compacted request schema), so\nthe model calls them on the first step instead of spending a\n\u003ccode class=\"readme-inline-code\"\u003edirectory::search_functions\u003c/code\u003e + \u003ccode class=\"readme-inline-code\"\u003eengine::functions::info\u003c/code\u003e round-trip per\nsession; everything else still goes through discovery. Ids are stored\nverbatim (non-empty, no whitespace; duplicates collapse, order kept);\n\u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e reports ids the engine does not currently know in\n\u003ccode class=\"readme-inline-code\"\u003eunknown_functions\u003c/code\u003e (a warning — the harness renders them as unavailable),\n\u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e carries \u003ccode class=\"readme-inline-code\"\u003efunction_count\u003c/code\u003e. \u003ccode class=\"readme-inline-code\"\u003edirectory::agents::functions::add\u003c/code\u003e /\n\u003ccode class=\"readme-inline-code\"\u003e::remove { id, functions }\u003c/code\u003e edit only that frontmatter field — the rest\nof the file stays byte-identical — and fan out \u003ccode class=\"readme-inline-code\"\u003eon-change\u003c/code\u003e as an update.\nThe console\u0026#39;s profile editor picks them from the live registry with the\nsame keyboard-first search + Selected/Available lists as skills.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAgent profiles inherit.\u003c/strong\u003e \u003ccode class=\"readme-inline-code\"\u003eextends: \u003cid\u003e\u003c/code\u003e names one parent profile\n(chains allowed, at most 8 hops). The resolved system prompt served by\n\u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e is the parent\u0026#39;s resolved prompt followed by a blank line and this\nfile\u0026#39;s body — a blank body contributes nothing, so a profile with no\nprompt of its own serves its parent chain unchanged; \u003ccode class=\"readme-inline-code\"\u003emodel\u003c/code\u003e and\n\u003ccode class=\"readme-inline-code\"\u003ereasoning_effort\u003c/code\u003e fall back to the nearest ancestor that sets them when\nomitted, while \u003ccode class=\"readme-inline-code\"\u003eskills\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003efunctions\u003c/code\u003e inherit ADDITIVELY (the union of\nthe chain\u0026#39;s lists, root first, no duplicates — a child adds to what its\nparents allow / preload, it cannot remove); \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003elogo\u003c/code\u003e,\n\u003ccode class=\"readme-inline-code\"\u003eicon\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003ecolor\u003c/code\u003e are always the profile\u0026#39;s own. A chain that does not resolve\n(unknown parent, loop, too deep) is reported by \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e as\n\u003ccode class=\"readme-inline-code\"\u003einheritance_error\u003c/code\u003e (\u003ccode class=\"readme-inline-code\"\u003eD415\u003c/code\u003e text) while the profile still serves its own\nfile (so the editor can fix it); the harness refuses to run it.\u003c/li\u003e\n\u003cli\u003eUnder a skills root, files outside \u003ccode class=\"readme-inline-code\"\u003eprompts/\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003esystem-prompts/\u003c/code\u003e, and\nreserved \u003ccode class=\"readme-inline-code\"\u003eagents/\u003c/code\u003e segments are skills.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe download function namespaces by source:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eSource\u003c/th\u003e\n\u003cth\u003eDestination\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003erepo=URL skill=NAME branch?=main\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e\u003cskills_folder\u003e/\u003cNAME\u003e/...\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eworker=NAME version=…\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eSkills/prompts under \u003ccode class=\"readme-inline-code\"\u003e\u003cskills_folder\u003e/\u003cNAME\u003e/...\u003c/code\u003e; exact \u003ccode class=\"readme-inline-code\"\u003eagents/\u003cid\u003e.md\u003c/code\u003e entries under \u003ccode class=\"readme-inline-code\"\u003e\u003cagents_folder\u003e/\u003cid\u003e.md\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eworker=NAME tag=…\u003c/code\u003e (default \u003ccode class=\"readme-inline-code\"\u003etag=latest\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003eSame routing as the version form\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eRe-pulling the same source overwrites files \u003cstrong\u003efile-by-file\u003c/strong\u003e —\nexisting siblings outside the response set are preserved (so\nhand-edited additions survive a re-pull).\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"skill-ids\" class=\"scroll-mt-20\"\u003eSkill ids\u003c/h2\u003e\n\u003cp\u003eSkills are addressed by their relative path under \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e with\n\u003ccode class=\"readme-inline-code\"\u003e.md\u003c/code\u003e stripped — e.g. \u003ccode class=\"readme-inline-code\"\u003e\u003cskills_folder\u003e/agent-memory/observe.md\u003c/code\u003e →\nid \u003ccode class=\"readme-inline-code\"\u003e\"agent-memory/observe\"\u003c/code\u003e. The same string is what\n\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::list\u003c/code\u003e returns and what \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::get\u003c/code\u003e\nexpects in \u003ccode class=\"readme-inline-code\"\u003e{ \"id\": ... }\u003c/code\u003e. The legacy \u003ccode class=\"readme-inline-code\"\u003eiii://{id}\u003c/code\u003e link form is still\naccepted on \u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e (the prefix is auto-stripped), but the worker no\nlonger parses any other \u003ccode class=\"readme-inline-code\"\u003eiii://\u003c/code\u003e URI shape — bodies are read solely by\nid, and the auto-rendered tree-shaped index that previous releases\nserved at \u003ccode class=\"readme-inline-code\"\u003eiii://directory/skills\u003c/code\u003e is gone. Consumers that want a\ntree-shaped picker iterate \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e rows themselves and indent by\n\u003ccode class=\"readme-inline-code\"\u003eid.matches('/').count()\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"kits\" class=\"scroll-mt-20\"\u003eKits\u003c/h2\u003e\n\u003cp\u003eA \u003cstrong\u003ekit\u003c/strong\u003e is a publishable bundle of agent profiles (\u003ccode class=\"readme-inline-code\"\u003eagents/\u003cid\u003e.md\u003c/code\u003e), skills\n(\u003ccode class=\"readme-inline-code\"\u003eskills/**.md\u003c/code\u003e) and registry workers declared by semver range, addressed as\n\u003ccode class=\"readme-inline-code\"\u003e\u003cauthor-handle\u003e/\u003ckit-name\u003e\u003c/code\u003e and versioned in the registry\n(\u003ccode class=\"readme-inline-code\"\u003eregistry_url\u003c/code\u003e, endpoints under \u003ccode class=\"readme-inline-code\"\u003e/k\u003c/code\u003e). Install one with\u003c/p\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003eiii\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e trigger\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e directory::download-kit\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e kit=acme/kanban-team\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # latest\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003eiii\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e trigger\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e directory::download-kit\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e kit=acme/kanban-team@1.3.0\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # or a tag, or a range (@^1.3)\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eNothing is written by that call: it builds a \u003cstrong\u003eplan\u003c/strong\u003e and answers with it.\nReview the plan in the ADE (\u003cstrong\u003eDirectory → Kits\u003c/strong\u003e) or apply it from a script\nwith \u003ccode class=\"readme-inline-code\"\u003eiii trigger directory::kits::apply plan_id=kp_…\u003c/code\u003e. \u003ccode class=\"readme-inline-code\"\u003eapply=true\u003c/code\u003e on\n\u003ccode class=\"readme-inline-code\"\u003edownload-kit\u003c/code\u003e applies at once only when the plan has no warnings, nothing\nblocking it and no file that needs a decision.\u003c/p\u003e\n\u003ch3 id=\"what-lands-where\" class=\"scroll-mt-20\"\u003eWhat lands where\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eKit file\u003c/th\u003e\n\u003cth\u003eInstalled at\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eagents/\u003cid\u003e.md\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e\u003cagents_folder\u003e/\u003cid\u003e.md\u003c/code\u003e (flat ids, like every profile)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eskills/\u003cpath\u003e.md\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e\u003cskills_folder\u003e/\u003chandle\u003e/\u003ckit\u003e/\u003cpath\u003e.md\u003c/code\u003e — skill id \u003ccode class=\"readme-inline-code\"\u003e\u003chandle\u003e/\u003ckit\u003e/\u003cpath\u003e\u003c/code\u003e (\u003ccode class=\"readme-inline-code\"\u003eSKILL.md\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003eindex.md\u003c/code\u003e → \u003ccode class=\"readme-inline-code\"\u003eindex\u003c/code\u003e)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eworkers: { kanban: ^1.4 }\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003ecompose::add { workers: [{ worker: \"kanban\", version: \"^1.4\" }] }\u003c/code\u003e — the compose file declares the kit\u0026#39;s range\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eKit skill namespaces have two segments. They pass \u003ccode class=\"readme-inline-code\"\u003efilter_unregistered\u003c/code\u003e\n(they are not workers), and a kit\u0026#39;s local override is\n\u003ccode class=\"readme-inline-code\"\u003e\u003clocal_skills_folder\u003e/\u003chandle\u003e/\u003ckit\u003e/\u003c/code\u003e, which shadows that kit only — never\nthe author\u0026#39;s other kits. A kit installed inside \u003ccode class=\"readme-inline-code\"\u003elocal_skills_folder\u003c/code\u003e (the\ndefault \u003ccode class=\"readme-inline-code\"\u003eskills/iii\u003c/code\u003e with an author handle \u003ccode class=\"readme-inline-code\"\u003eiii\u003c/code\u003e) is the kit itself, not an\noverride.\u003c/p\u003e\n\u003ch3 id=\"kitslock\" class=\"scroll-mt-20\"\u003e\u003ccode class=\"readme-inline-code\"\u003ekits.lock\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003ekits.lock\u003c/code\u003e sits next to the compose file and is meant to be committed. The\ncompose file is \u003ccode class=\"readme-inline-code\"\u003eIII_COMPOSE_FILE\u003c/code\u003e when Compose started this worker;\notherwise it is \u003ccode class=\"readme-inline-code\"\u003eworker-compose.yaml\u003c/code\u003e in \u003ccode class=\"readme-inline-code\"\u003eIII_COMPOSE_DIR\u003c/code\u003e, or in the process\nworking directory for a standalone worker.\u003c/p\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003eversion\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 1\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003ekits\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e acme/kanban-team\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e requested\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e ^1.3.0\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # a tag, a range, or ^\u0026#x3C;version\u003e for an exact install\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e version\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 1.3.0\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e installed_at\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e 2026-10-08T14:02:11Z\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e workers\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e kanban\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e ^1.4\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e files\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e agents/product-manager.md\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e sha256\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e 4be1…\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # the content the kit installed: the merge base\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e agents/reviewer.md\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e sha256\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e 77c0…\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e skipped\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#1E754F\"\u003e true\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # you kept the file that was already there\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e skills/acme/kanban-team/tickets/flow.md\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e sha256\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e 9a3e…\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003e ignored_versions\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e [\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e1.4.0\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e]\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003ePaths are install paths: \u003ccode class=\"readme-inline-code\"\u003eagents/…\u003c/code\u003e under \u003ccode class=\"readme-inline-code\"\u003eagents_folder\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eskills/…\u003c/code\u003e under\n\u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e. A file\u0026#39;s state is computed on demand — \u003cstrong\u003eintact\u003c/strong\u003e (on-disk\nsha = base), \u003cstrong\u003eedited\u003c/strong\u003e, \u003cstrong\u003emissing\u003c/strong\u003e, or \u003cstrong\u003eskipped\u003c/strong\u003e. Bases are fetched back\nfrom the registry (\u003ccode class=\"readme-inline-code\"\u003eGET /blobs/\u003csha256\u003e\u003c/code\u003e); no copies are kept. An exact\nversion request installs that version and records its caret range\n(\u003ccode class=\"readme-inline-code\"\u003e1.3.0\u003c/code\u003e → \u003ccode class=\"readme-inline-code\"\u003e^1.3.0\u003c/code\u003e, as npm saves an exact install) so compatible releases\nare offered as updates; tags and ranges are recorded as given.\u003c/p\u003e\n\u003cp\u003ePending plans live in \u003ccode class=\"readme-inline-code\"\u003e.iii/directory/kit-plans/\u003cplan_id\u003e.json\u003c/code\u003e next to the\ncompose file (local state, not committed) and expire after 24 hours. The last\nupdate check is cached in \u003ccode class=\"readme-inline-code\"\u003e.iii/directory/kit-updates.json\u003c/code\u003e.\u003c/p\u003e\n\u003ch3 id=\"precedence-and-collisions\" class=\"scroll-mt-20\"\u003ePrecedence and collisions\u003c/h3\u003e\n\u003cp\u003eKit profiles take precedence over profiles workers ship, but an install or\nupdate never replaces an existing file silently. Every \u003ccode class=\"readme-inline-code\"\u003eagents/\u003cid\u003e.md\u003c/code\u003e has an\nowner: a kit (\u003ccode class=\"readme-inline-code\"\u003ekits.lock\u003c/code\u003e), a worker (its completion marker records the\nprofiles it wrote, with their sha256), or the project itself (\u003ccode class=\"readme-inline-code\"\u003elocal\u003c/code\u003e).\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eThe kit writes a path that…\u003c/th\u003e\n\u003cth\u003eWarning\u003c/th\u003e\n\u003cth\u003eDefault\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003ea worker\u0026#39;s bundle wrote\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eagent_overwrite\u003c/code\u003e — \u0026quot;came from worker kanban 0.1.18 and will be replaced\u0026quot;\u003c/td\u003e\n\u003ctd\u003ereplace\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eanother kit owns\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eagent_overwrite_kit\u003c/code\u003e; replacing moves the file to this kit and marks it \u003ccode class=\"readme-inline-code\"\u003eskipped\u003c/code\u003e in the other kit\u0026#39;s lock\u003c/td\u003e\n\u003ctd\u003ereplace\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ewas created in this project\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eagent_overwrite_local\u003c/code\u003e (the strongest)\u003c/td\u003e\n\u003ctd\u003ereplace\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ea user-global profile (\u003ccode class=\"readme-inline-code\"\u003e~/.iii/agents\u003c/code\u003e) has\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eagent_shadows_global\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ereplace\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eis \u003ccode class=\"readme-inline-code\"\u003edefault\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eiii\u003c/code\u003e or \u003ccode class=\"readme-inline-code\"\u003eiii-minimal\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003ebuiltin_override\u003c/code\u003e — replaces a built-in profile project-wide\u003c/td\u003e\n\u003ctd\u003ereplace\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eexists under the kit\u0026#39;s skills folder but is not in the lock\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003efile_overwrite_local\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ereplace\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eEvery collision can be answered \u003cstrong\u003ekeep\u003c/strong\u003e: the kit\u0026#39;s file is not written and\nthe lock marks it \u003ccode class=\"readme-inline-code\"\u003eskipped\u003c/code\u003e; later updates respect that until it is reverted.\nIdentical content is no collision. Worker downloads skip profiles a kit owns\nand report them in \u003ccode class=\"readme-inline-code\"\u003eagents_skipped\u003c/code\u003e. \u003ccode class=\"readme-inline-code\"\u003edirectory::agents::list\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e carry\n\u003ccode class=\"readme-inline-code\"\u003esource: { kind: kit | worker | local | global | builtin, kit?, worker?, version?, modified? }\u003c/code\u003e.\u003c/p\u003e\n\u003ch3 id=\"the-plan\" class=\"scroll-mt-20\"\u003eThe plan\u003c/h3\u003e\n\u003cp\u003eThe plan JSON is the contract between the functions, the Kits page and the\nchat cards:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e{\n \u0026quot;plan_id\u0026quot;: \u0026quot;kp_…\u0026quot;, \u0026quot;kind\u0026quot;: \u0026quot;install | update | remove\u0026quot;,\n \u0026quot;kit\u0026quot;: \u0026quot;acme/kanban-team\u0026quot;, \u0026quot;from\u0026quot;: \u0026quot;1.3.0\u0026quot;, \u0026quot;to\u0026quot;: \u0026quot;1.4.0\u0026quot;, \u0026quot;requested\u0026quot;: \u0026quot;^1.3.0\u0026quot;,\n \u0026quot;bump\u0026quot;: \u0026quot;minor\u0026quot;, \u0026quot;major\u0026quot;: false,\n \u0026quot;author\u0026quot;: { \u0026quot;handle\u0026quot;: \u0026quot;acme\u0026quot;, \u0026quot;name\u0026quot;: \u0026quot;Acme\u0026quot;, \u0026quot;verified\u0026quot;: true },\n \u0026quot;registry_url\u0026quot;: \u0026quot;\u0026lt;registry_web_url\u0026gt;/kits/acme/kanban-team\u0026quot;, \u0026quot;notes\u0026quot;: \u0026quot;…\u0026quot;,\n \u0026quot;workers\u0026quot;: [\n { \u0026quot;name\u0026quot;: \u0026quot;github\u0026quot;, \u0026quot;range\u0026quot;: \u0026quot;^2.0\u0026quot;, \u0026quot;installed\u0026quot;: null, \u0026quot;action\u0026quot;: \u0026quot;add\u0026quot;, \u0026quot;to\u0026quot;: \u0026quot;2.0.3\u0026quot;, \u0026quot;type\u0026quot;: \u0026quot;binary\u0026quot; },\n { \u0026quot;name\u0026quot;: \u0026quot;kanban\u0026quot;, \u0026quot;range\u0026quot;: \u0026quot;^1.6\u0026quot;, \u0026quot;range_from\u0026quot;: \u0026quot;^1.4\u0026quot;, \u0026quot;installed\u0026quot;: \u0026quot;1.5.2\u0026quot;, \u0026quot;action\u0026quot;: \u0026quot;update\u0026quot;, \u0026quot;to\u0026quot;: \u0026quot;1.6.1\u0026quot; }\n ],\n \u0026quot;files\u0026quot;: [\n { \u0026quot;path\u0026quot;: \u0026quot;agents/reviewer.md\u0026quot;, \u0026quot;source\u0026quot;: \u0026quot;agents/reviewer.md\u0026quot;, \u0026quot;kind\u0026quot;: \u0026quot;agent\u0026quot;, \u0026quot;id\u0026quot;: \u0026quot;reviewer\u0026quot;,\n \u0026quot;change\u0026quot;: \u0026quot;added\u0026quot;, \u0026quot;local\u0026quot;: \u0026quot;occupied\u0026quot;,\n \u0026quot;collision\u0026quot;: { \u0026quot;owner\u0026quot;: \u0026quot;worker\u0026quot;, \u0026quot;worker\u0026quot;: \u0026quot;kanban\u0026quot;, \u0026quot;version\u0026quot;: \u0026quot;1.6.1\u0026quot;, \u0026quot;sha256\u0026quot;: \u0026quot;…\u0026quot; },\n \u0026quot;default\u0026quot;: \u0026quot;overwrite\u0026quot;, \u0026quot;options\u0026quot;: [\u0026quot;overwrite\u0026quot;, \u0026quot;keep\u0026quot;], \u0026quot;agent\u0026quot;: { …frontmatter… } },\n { \u0026quot;path\u0026quot;: \u0026quot;skills/acme/kanban-team/tickets/flow.md\u0026quot;, \u0026quot;kind\u0026quot;: \u0026quot;skill\u0026quot;, \u0026quot;change\u0026quot;: \u0026quot;modified\u0026quot;,\n \u0026quot;local\u0026quot;: \u0026quot;edited\u0026quot;, \u0026quot;base\u0026quot;: \u0026quot;…\u0026quot;, \u0026quot;theirs\u0026quot;: \u0026quot;…\u0026quot;, \u0026quot;ours\u0026quot;: \u0026quot;…\u0026quot;,\n \u0026quot;merge\u0026quot;: \u0026quot;conflicts\u0026quot;, \u0026quot;conflicts\u0026quot;: 1, \u0026quot;default\u0026quot;: null, \u0026quot;options\u0026quot;: [\u0026quot;kit\u0026quot;, \u0026quot;mine\u0026quot;, \u0026quot;merged\u0026quot;] }\n ],\n \u0026quot;capabilities\u0026quot;: { \u0026quot;workers_added\u0026quot;: [\u0026quot;github\u0026quot;], \u0026quot;functions_added\u0026quot;: [ … ], \u0026quot;models_changed\u0026quot;: [ … ] },\n \u0026quot;functions\u0026quot;: [ { \u0026quot;id\u0026quot;: \u0026quot;kanban::ticket::create\u0026quot;, \u0026quot;used_by\u0026quot;: [\u0026quot;planner\u0026quot;], \u0026quot;worker\u0026quot;: \u0026quot;kanban\u0026quot;, \u0026quot;status\u0026quot;: \u0026quot;ok\u0026quot; } ],\n \u0026quot;warnings\u0026quot;: [ { \u0026quot;code\u0026quot;: \u0026quot;agent_overwrite\u0026quot;, \u0026quot;path\u0026quot;: \u0026quot;agents/reviewer.md\u0026quot;, \u0026quot;message\u0026quot;: \u0026quot;…\u0026quot; } ],\n \u0026quot;blocking\u0026quot;: [ { \u0026quot;code\u0026quot;: \u0026quot;compose_not_running\u0026quot;, \u0026quot;message\u0026quot;: \u0026quot;… `iii compose --up` …\u0026quot; } ],\n \u0026quot;counts\u0026quot;: { \u0026quot;agents\u0026quot;: 3, \u0026quot;skills\u0026quot;: 12, \u0026quot;workers\u0026quot;: 2, \u0026quot;conflicts\u0026quot;: 1, \u0026quot;decisions_required\u0026quot;: 1, … },\n \u0026quot;created_at\u0026quot;: \u0026quot;…\u0026quot;, \u0026quot;expires_at\u0026quot;: \u0026quot;…\u0026quot;\n}\u003c/code\u003e\u003c/pre\u003e\u003cul\u003e\n\u003cli\u003e\u003ccode class=\"readme-inline-code\"\u003echange\u003c/code\u003e: \u003ccode class=\"readme-inline-code\"\u003eadded\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003emodified\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eremoved\u003c/code\u003e, or \u003ccode class=\"readme-inline-code\"\u003ekept\u003c/code\u003e (a \u003ccode class=\"readme-inline-code\"\u003eskipped\u003c/code\u003e file whose\nkit version changed). \u003ccode class=\"readme-inline-code\"\u003elocal\u003c/code\u003e: \u003ccode class=\"readme-inline-code\"\u003eabsent\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eintact\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eedited\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003emissing\u003c/code\u003e, or\n\u003ccode class=\"readme-inline-code\"\u003eoccupied\u003c/code\u003e (someone else\u0026#39;s file). File bodies are not in the plan;\n\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::plan { plan_id, contents: true }\u003c/code\u003e serves them.\u003c/li\u003e\n\u003cli\u003eAn update merges a file you edited with the kit\u0026#39;s change three ways\n(\u003ccode class=\"readme-inline-code\"\u003ediffy\u003c/code\u003e): \u003ccode class=\"readme-inline-code\"\u003emerge: clean\u003c/code\u003e defaults to \u003ccode class=\"readme-inline-code\"\u003emerged\u003c/code\u003e; \u003ccode class=\"readme-inline-code\"\u003emerge: conflicts\u003c/code\u003e has no\ndefault and needs \u003ccode class=\"readme-inline-code\"\u003ekit\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003emine\u003c/code\u003e, or \u003ccode class=\"readme-inline-code\"\u003emerged\u003c/code\u003e with the resolved text. Conflict\nmarkers read \u003ccode class=\"readme-inline-code\"\u003e\u003c\u003c\u003c\u003c\u003c\u003c\u003c yours\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003e||||||| installed\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e kit\u003c/code\u003e. A file\nyou edited that the kit did not change is not in the plan. A removed file\nyou did not edit defaults to \u003ccode class=\"readme-inline-code\"\u003eremove\u003c/code\u003e; one you edited defaults to \u003ccode class=\"readme-inline-code\"\u003ekeep\u003c/code\u003e\n(it becomes an ordinary local file).\u003c/li\u003e\n\u003cli\u003eWorkers: \u003ccode class=\"readme-inline-code\"\u003eadd\u003c/code\u003e (not declared), \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e (installed version outside the\nrange), \u003ccode class=\"readme-inline-code\"\u003eredeclare\u003c/code\u003e (the compose file still declares the kit\u0026#39;s previous\nrange, which the installed version already satisfies), \u003ccode class=\"readme-inline-code\"\u003enone\u003c/code\u003e, and\n\u003ccode class=\"readme-inline-code\"\u003eremove\u003c/code\u003e for a worker the kit dropped — never removed unless named in\n\u003ccode class=\"readme-inline-code\"\u003eremove_workers\u003c/code\u003e. \u003ccode class=\"readme-inline-code\"\u003epath://\u003c/code\u003e workers are never touched.\u003c/li\u003e\n\u003cli\u003eWarnings also cover \u003ccode class=\"readme-inline-code\"\u003elocal_edits_merged\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003emerge_conflict\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003emajor_update\u003c/code\u003e\nand, on removal, \u003ccode class=\"readme-inline-code\"\u003eedited_file_kept\u003c/code\u003e. Blocking: \u003ccode class=\"readme-inline-code\"\u003ecompose_not_running\u003c/code\u003e (the\nplan adds or moves workers and \u003ccode class=\"readme-inline-code\"\u003ecompose::status\u003c/code\u003e does not answer) and\n\u003ccode class=\"readme-inline-code\"\u003ekit_deprecated\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"apply\" class=\"scroll-mt-20\"\u003eApply\u003c/h3\u003e\n\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::apply { plan_id, decisions?, remove_workers? }\u003c/code\u003e, one apply at\na time:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eRe-validate\u003c/strong\u003e: the plan has not expired, \u003ccode class=\"readme-inline-code\"\u003ekits.lock\u003c/code\u003e still holds the\nversion it was made against, and every local file it looked at is\nunchanged. Otherwise nothing is applied and a fresh plan comes back with\n\u003ccode class=\"readme-inline-code\"\u003estatus: replanned\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDownload\u003c/strong\u003e \u003ccode class=\"readme-inline-code\"\u003eGET /k/\u003ckit\u003e/download?version=…\u0026ci=…\u003c/code\u003e — counts the download\n(\u003ccode class=\"readme-inline-code\"\u003eci=true\u003c/code\u003e when \u003ccode class=\"readme-inline-code\"\u003eCI\u003c/code\u003e is set) — and check every body against the sha the plan\nreviewed.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eWorkers\u003c/strong\u003e through Compose: one \u003ccode class=\"readme-inline-code\"\u003ecompose::add\u003c/code\u003e with\n\u003ccode class=\"readme-inline-code\"\u003e{ worker, version: \u003crange\u003e }\u003c/code\u003e objects for every added, moved or\nre-declared worker (an existing container\u0026#39;s range is re-declared in place),\nthen \u003ccode class=\"readme-inline-code\"\u003ecompose::remove\u003c/code\u003e for the ticked \u003ccode class=\"readme-inline-code\"\u003eremove_workers\u003c/code\u003e, each followed through\n\u003ccode class=\"readme-inline-code\"\u003ecompose::operation\u003c/code\u003e. A failure stops here, before any file is written.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFiles\u003c/strong\u003e, one atomic write or delete at a time, journaled in the plan so a\nretried apply recognises what it already wrote (the apply is idempotent).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode class=\"readme-inline-code\"\u003ekits.lock\u003c/code\u003e\u003c/strong\u003e, last; then the plan is deleted and \u003ccode class=\"readme-inline-code\"\u003eon-change\u003c/code\u003e fires.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eWorkers added or moved get their own skills and profiles downloaded right after\nthe apply (kit-owned profiles skipped), and the kit is checked for updates.\nCompose must be running (\u003ccode class=\"readme-inline-code\"\u003eiii compose --up\u003c/code\u003e): the \u003ccode class=\"readme-inline-code\"\u003ecompose::*\u003c/code\u003e functions exist\nonly while its daemon does.\u003c/p\u003e\n\u003ch3 id=\"updates\" class=\"scroll-mt-20\"\u003eUpdates\u003c/h3\u003e\n\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::check-updates\u003c/code\u003e asks \u003ccode class=\"readme-inline-code\"\u003ePOST /k/updates\u003c/code\u003e for every installed kit\n(or one): the newest version satisfying \u003ccode class=\"readme-inline-code\"\u003erequested\u003c/code\u003e, unless it is in\n\u003ccode class=\"readme-inline-code\"\u003eignored_versions\u003c/code\u003e. It runs 15 seconds after boot, every 6 hours, after every\ninstall or update, and on demand. \u003ccode class=\"readme-inline-code\"\u003edirectory::kits::ignore { kit, version }\u003c/code\u003e\nadds a version to \u003ccode class=\"readme-inline-code\"\u003eignored_versions\u003c/code\u003e (and retires a pending update plan for\nit); \u003ccode class=\"readme-inline-code\"\u003eignore: false\u003c/code\u003e takes it back.\u003c/p\u003e\n\u003ch3 id=\"in-the-ade\" class=\"scroll-mt-20\"\u003eIn the ADE\u003c/h3\u003e\n\u003cp\u003eThe Directory page has a \u003cstrong\u003eKits\u003c/strong\u003e segment next to Skills and Agent Profiles;\nits badge counts plans waiting for review plus available updates.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eKits\u003c/strong\u003e — pending reviews, an install box, and installed kits with their\nupdate state; \u0026quot;Check for updates\u0026quot;.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAn installed kit\u003c/strong\u003e — Overview (README), Profiles and Skills (the files on\ndisk, read-only, with \u0026quot;Edit in Directory\u0026quot;), Workers (as Compose has them),\nFiles (intact / edited / missing / kept, with \u0026quot;View my changes\u0026quot; for edited\nones), Remove, and a registry link.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInstall review\u003c/strong\u003e — the collisions on top (never collapsible) with\nreplace / keep and a split diff for each, the permissions the kit asks for\n(workers and binaries it adds or moves, functions its profiles preload), the\ncontents in three columns with a preview that shows frontmatter as fields\nand the prompt as markdown, and a button that says what will happen\n(\u0026quot;Install and replace 2 profiles\u0026quot;). A blocked plan shows the block instead.\nWhile it runs, the three steps (workers → files → kits.lock) report live; a\nfailure offers \u0026quot;Try again\u0026quot;.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eUpdate review\u003c/strong\u003e — release notes, then the changes as a pull request:\nnew and changed profiles (a frontmatter summary, then the diff), workers and\nranges, new / changed / removed skills, and the permissions the update\ngrants. \u0026quot;Update\u0026quot; stays disabled while a conflict has no decision; \u0026quot;Ignore\n\u003cversion\u003e\u0026quot; skips the version. A file you edited opens the conflict view:\nthe kit\u0026#39;s changes, yours, and an editable result that starts from the\nautomatic merge.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRemoval review\u003c/strong\u003e — the files to delete (edited ones unticked) and the\nkit\u0026#39;s workers (unticked, with a note when another kit uses one).\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eChat cards render \u003ccode class=\"readme-inline-code\"\u003edownload-kit\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eplan-update\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003eremove\u003c/code\u003e (the plan summary\nand \u0026quot;Review install\u0026quot;, which opens this segment on the plan), \u003ccode class=\"readme-inline-code\"\u003eapply\u003c/code\u003e (live\nsteps, the result, and the plan summary while a harness approval is pending),\n\u003ccode class=\"readme-inline-code\"\u003echeck-updates\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003ekits::list\u003c/code\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"functions\" class=\"scroll-mt-20\"\u003eFunctions\u003c/h2\u003e\n\u003cp\u003eFunctions sit under \u003ccode class=\"readme-inline-code\"\u003edirectory::*\u003c/code\u003e. All registrations are\nnamespace-clean; this worker is intentionally agnostic to MCP and any\nother adapter.\u003c/p\u003e\n\u003ch3 id=\"directoryskills-filesystem-reader-editor\" class=\"scroll-mt-20\"\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::*\u003c/code\u003e (filesystem reader + editor)\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eFunction ID\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::download\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eDownload directory content. Flexible alias accepting either source set: \u003ccode class=\"readme-inline-code\"\u003e{repo, skill, branch?}\u003c/code\u003e (defaults \u003ccode class=\"readme-inline-code\"\u003ebranch=main\u003c/code\u003e) or \u003ccode class=\"readme-inline-code\"\u003e{worker, version?|tag?}\u003c/code\u003e (defaults \u003ccode class=\"readme-inline-code\"\u003etag=latest\u003c/code\u003e). Prefer the two explicit forms below so the source is unambiguous.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::download_from_repo\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eRepo-only form: \u003ccode class=\"readme-inline-code\"\u003e{repo, skill, branch?}\u003c/code\u003e. Copies one skill folder out of a GitHub repo; paths under \u003ccode class=\"readme-inline-code\"\u003eprompts/\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003eagents/\u003c/code\u003e are ignored.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::download_from_registry\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eRegistry-only form: \u003ccode class=\"readme-inline-code\"\u003e{worker, version?|tag?}\u003c/code\u003e. Installs a published worker\u0026#39;s bundle from \u003ccode class=\"readme-inline-code\"\u003eapi.workers.iii.dev\u003c/code\u003e, routing exact \u003ccode class=\"readme-inline-code\"\u003eagents/\u003cid\u003e.md\u003c/code\u003e entries to \u003ccode class=\"readme-inline-code\"\u003eagents_folder\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::list\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eEnriched listing of every fs-backed skill: \u003ccode class=\"readme-inline-code\"\u003e{ id, title, type, function_id, disable_model_invocation, description, bytes, modified_at }\u003c/code\u003e per row. \u003ccode class=\"readme-inline-code\"\u003etitle\u003c/code\u003e prefers the YAML frontmatter \u003ccode class=\"readme-inline-code\"\u003etitle:\u003c/code\u003e over the body H1, \u003ccode class=\"readme-inline-code\"\u003etype\u003c/code\u003e is lifted from frontmatter \u003ccode class=\"readme-inline-code\"\u003etype:\u003c/code\u003e (\u003ccode class=\"readme-inline-code\"\u003enull\u003c/code\u003e when absent), \u003ccode class=\"readme-inline-code\"\u003efunction_id\u003c/code\u003e identifies the documented bus function when present, and \u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e is the frontmatter description or first body paragraph — so consumers can render a picker without a follow-up \u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e per row.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::get\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eFetch one skill by id. Returns \u003ccode class=\"readme-inline-code\"\u003e{ id, title, type, function_id, disable_model_invocation, path, body, modified_at }\u003c/code\u003e. It shares the list row\u0026#39;s identity, classification, function, and invocation metadata, but returns the raw markdown \u003ccode class=\"readme-inline-code\"\u003ebody\u003c/code\u003e and absolute on-disk \u003ccode class=\"readme-inline-code\"\u003epath\u003c/code\u003e instead of the teaser and byte count; there is no \u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e field. The path\u0026#39;s parent directory is the skill\u0026#39;s base directory, where payload like \u003ccode class=\"readme-inline-code\"\u003escripts/\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003ereference/\u003c/code\u003e lives, and is meaningful only to callers on this worker\u0026#39;s machine. Accepts a bare id or the same id prefixed with \u003ccode class=\"readme-inline-code\"\u003eiii://\u003c/code\u003e. Pass \u003ccode class=\"readme-inline-code\"\u003eraw: true\u003c/code\u003e to additionally get the FULL on-disk file (frontmatter included) as \u003ccode class=\"readme-inline-code\"\u003eraw\u003c/code\u003e — the round-trip form \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e takes.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::update\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOverwrite one EXISTING skill file with new full-file content: \u003ccode class=\"readme-inline-code\"\u003e{ id, content }\u003c/code\u003e where \u003ccode class=\"readme-inline-code\"\u003econtent\u003c/code\u003e is the edited \u003ccode class=\"readme-inline-code\"\u003eraw\u003c/code\u003e from \u003ccode class=\"readme-inline-code\"\u003eget { raw: true }\u003c/code\u003e. Validated against the read invariants (size cap, non-empty body after frontmatter); atomic write; fans out \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"update\"\u003c/code\u003e. Never creates files (use \u003ccode class=\"readme-inline-code\"\u003ecreate\u003c/code\u003e). Refuses read-only system-installed skills under \u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e (\u003ccode class=\"readme-inline-code\"\u003eD116\u003c/code\u003e).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::create\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eCreate a NEW skill file at \u003ccode class=\"readme-inline-code\"\u003e\u003cskills_folder\u003e/\u003cid\u003e.md\u003c/code\u003e from full-file content: \u003ccode class=\"readme-inline-code\"\u003e{ id, content }\u003c/code\u003e. Frontmatter is optional (same rules as \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e: size cap, non-empty body). Refuses an \u003ccode class=\"readme-inline-code\"\u003eid\u003c/code\u003e that already resolves in the visible set — including the \u003ccode class=\"readme-inline-code\"\u003e\u003cid\u003e\u003c/code\u003e → \u003ccode class=\"readme-inline-code\"\u003e\u003cid\u003e/index\u003c/code\u003e overview alias and system-installed agents skills — or a target path that already exists on disk (\u003ccode class=\"readme-inline-code\"\u003eD114\u003c/code\u003e); an \u003ccode class=\"readme-inline-code\"\u003eid\u003c/code\u003e in a namespace reserved by a system-installed agents skill (\u003ccode class=\"readme-inline-code\"\u003eD115\u003c/code\u003e); and, while \u003ccode class=\"readme-inline-code\"\u003efilter_unregistered\u003c/code\u003e is on, an \u003ccode class=\"readme-inline-code\"\u003eid\u003c/code\u003e the visibility filter would immediately hide (\u003ccode class=\"readme-inline-code\"\u003eD115\u003c/code\u003e). Atomic write; fans out \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"create\"\u003c/code\u003e. Returns the same shape as \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::delete\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ePermanently remove one EXISTING skill file by \u003ccode class=\"readme-inline-code\"\u003e{ id }\u003c/code\u003e (same id forms as \u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e). Resolves against the same visible set as \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e, refuses read-only system-installed skills under \u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e (\u003ccode class=\"readme-inline-code\"\u003eD116\u003c/code\u003e), removes the file plus any parent directories left empty (so a deleted namespace can\u0026#39;t keep shadowing a lower-precedence root), and fans out \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"delete\"\u003c/code\u003e. Returns \u003ccode class=\"readme-inline-code\"\u003e{ id }\u003c/code\u003e (the resolved on-disk id).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::index\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eRender one short markdown entry per installed worker (skills with frontmatter \u003ccode class=\"readme-inline-code\"\u003etype: index\u003c/code\u003e). Returns \u003ccode class=\"readme-inline-code\"\u003e{ body, workers_count }\u003c/code\u003e where \u003ccode class=\"readme-inline-code\"\u003ebody\u003c/code\u003e is a ready-to-paste page: \u003ccode class=\"readme-inline-code\"\u003e# Skills index\u003c/code\u003e, then one \u003ccode class=\"readme-inline-code\"\u003e## \u003cworker title\u003e\u003c/code\u003e heading + the worker\u0026#39;s first overview paragraph + a \u003ccode class=\"readme-inline-code\"\u003eRead iii://\u003cns\u003e/index\u003c/code\u003e pointer the agent can follow with \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::get\u003c/code\u003e. Token-light by design; use \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::list\u003c/code\u003e for per-skill rows.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003ch3 id=\"directorysystem-prompts-filesystem-reader-editor\" class=\"scroll-mt-20\"\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::*\u003c/code\u003e (filesystem reader + editor)\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eFunction ID\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::list\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eMetadata-only listing of every fs-backed system prompt.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::get\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eFetch one system prompt\u0026#39;s body + \u003ccode class=\"readme-inline-code\"\u003e{name, description, modified_at}\u003c/code\u003e. Plain shape, no envelope. Pass \u003ccode class=\"readme-inline-code\"\u003eraw: true\u003c/code\u003e to additionally get the FULL on-disk file (frontmatter included) as \u003ccode class=\"readme-inline-code\"\u003eraw\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::update\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOverwrite one EXISTING system prompt file with new full-file content: \u003ccode class=\"readme-inline-code\"\u003e{ name, content }\u003c/code\u003e. The frontmatter must keep a non-empty \u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e (and a valid \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e when declared) — the same rules the scanner enforces. Atomic write; fans out \u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"update\"\u003c/code\u003e. Returns the system prompt\u0026#39;s effective name after the write.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::create\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eCreate a NEW system prompt file at \u003ccode class=\"readme-inline-code\"\u003e\u003cskills_folder\u003e/system-prompts/\u003cname\u003e.md\u003c/code\u003e from full-file content: \u003ccode class=\"readme-inline-code\"\u003e{ name, content }\u003c/code\u003e, where \u003ccode class=\"readme-inline-code\"\u003econtent\u003c/code\u003e is the FULL file including frontmatter. The frontmatter must carry a non-empty \u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e (and a \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e matching the request, when declared) — the same rules \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e enforces. Refuses a \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e that already exists anywhere in the merged system-prompt scan, and a target path that already exists on disk even if the scanner would skip it. Atomic write; fans out \u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"create\"\u003c/code\u003e. Returns \u003ccode class=\"readme-inline-code\"\u003e{ name, description, bytes, modified_at }\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::delete\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ePermanently remove one EXISTING system prompt file by \u003ccode class=\"readme-inline-code\"\u003e{ name }\u003c/code\u003e. Resolves against the same merged scan as \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e, fans out \u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"delete\"\u003c/code\u003e, and returns \u003ccode class=\"readme-inline-code\"\u003e{ name }\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003ch3 id=\"agent-profiles-directoryagents-filesystem-reader-editor\" class=\"scroll-mt-20\"\u003eAgent Profiles — \u003ccode class=\"readme-inline-code\"\u003edirectory::agents::*\u003c/code\u003e (filesystem reader + editor)\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eFunction ID\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::list\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eMetadata-only listing of every agent profile — fs-backed plus the bundled \u003ccode class=\"readme-inline-code\"\u003edefault\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003eiii\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003eiii-minimal\u003c/code\u003e profiles (\u003ccode class=\"readme-inline-code\"\u003ebuiltin: true\u003c/code\u003e until a local file shadows one): \u003ccode class=\"readme-inline-code\"\u003e{ id, name, description, logo, skill_count, model, reasoning_effort, icon, color, extends, hidden, composer_placeholder, modified_at }\u003c/code\u003e per row (\u003ccode class=\"readme-inline-code\"\u003ehidden\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003ecomposer_placeholder\u003c/code\u003e omitted when unset; \u003ccode class=\"readme-inline-code\"\u003ecomposer_placeholder\u003c/code\u003e never inherits), \u003ccode class=\"readme-inline-code\"\u003eskill_count\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003emodel\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003ereasoning_effort\u003c/code\u003e resolved through \u003ccode class=\"readme-inline-code\"\u003eextends\u003c/code\u003e (\u003ccode class=\"readme-inline-code\"\u003eskill_count: null\u003c/code\u003e = every skill; \u003ccode class=\"readme-inline-code\"\u003emodel: null\u003c/code\u003e = the send decides). A row whose chain does not resolve carries \u003ccode class=\"readme-inline-code\"\u003einheritance_error\u003c/code\u003e. Every row carries \u003ccode class=\"readme-inline-code\"\u003esource: { kind: kit | worker | local | global | builtin, kit?, worker?, version?, modified? }\u003c/code\u003e — see \u003ca href=\"#precedence-and-collisions\"\u003ePrecedence and collisions\u003c/a\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::get\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eFetch one agent profile by \u003ccode class=\"readme-inline-code\"\u003e{ id }\u003c/code\u003e: the RESOLVED \u003ccode class=\"readme-inline-code\"\u003esystem_prompt\u003c/code\u003e (each ancestor\u0026#39;s body root-first, then this file\u0026#39;s body), \u003ccode class=\"readme-inline-code\"\u003eskills\u003c/code\u003e + \u003ccode class=\"readme-inline-code\"\u003eunknown_skills\u003c/code\u003e (preloaded ids matching no visible skill — warnings), \u003ccode class=\"readme-inline-code\"\u003eskills_index\u003c/code\u003e (resolved through \u003ccode class=\"readme-inline-code\"\u003eextends\u003c/code\u003e; \u003ccode class=\"readme-inline-code\"\u003efalse\u003c/code\u003e = sessions start without the skills index, omitted when unset), \u003ccode class=\"readme-inline-code\"\u003emodel\u003c/code\u003e (\u003ccode class=\"readme-inline-code\"\u003enull\u003c/code\u003e = the send decides), provider-native \u003ccode class=\"readme-inline-code\"\u003ereasoning_effort\u003c/code\u003e, display \u003ccode class=\"readme-inline-code\"\u003eicon\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003ecolor\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eextends\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ehidden\u003c/code\u003e, the profile\u0026#39;s own \u003ccode class=\"readme-inline-code\"\u003ecomposer_placeholder\u003c/code\u003e (omitted when unset), \u003ccode class=\"readme-inline-code\"\u003ebuiltin\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003emodified_at\u003c/code\u003e, and \u003ccode class=\"readme-inline-code\"\u003einheritance_error\u003c/code\u003e when the chain does not resolve (own file served meanwhile), and the same \u003ccode class=\"readme-inline-code\"\u003esource\u003c/code\u003e as \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e. Pass \u003ccode class=\"readme-inline-code\"\u003eraw: true\u003c/code\u003e to additionally get this profile\u0026#39;s FULL on-disk file as \u003ccode class=\"readme-inline-code\"\u003eraw\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::update\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOverwrite one EXISTING agent profile file with new full-file content: \u003ccode class=\"readme-inline-code\"\u003e{ id, content }\u003c/code\u003e. Same rules the scanner enforces (required frontmatter with non-empty \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e, emoji-only \u003ccode class=\"readme-inline-code\"\u003elogo\u003c/code\u003e; the body — the system prompt — may be empty); the id stays the file stem. Updating a bundled profile creates the local file that shadows it. Atomic write; fans out \u003ccode class=\"readme-inline-code\"\u003edirectory::agents::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"update\"\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::create\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eCreate a NEW agent profile at \u003ccode class=\"readme-inline-code\"\u003e\u003cagents_folder\u003e/\u003cid\u003e.md\u003c/code\u003e from full-file content: \u003ccode class=\"readme-inline-code\"\u003e{ id, content }\u003c/code\u003e. Refuses an \u003ccode class=\"readme-inline-code\"\u003eid\u003c/code\u003e that already exists in the configured agent-profile root, and a target path that already exists on disk even if the scanner would skip it; creating a bundled id shadows the bundled copy. Atomic write; fans out \u003ccode class=\"readme-inline-code\"\u003edirectory::agents::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"create\"\u003c/code\u003e. Returns \u003ccode class=\"readme-inline-code\"\u003e{ id, name, description, logo, bytes, modified_at }\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::delete\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ePermanently remove one EXISTING agent profile file by \u003ccode class=\"readme-inline-code\"\u003e{ id }\u003c/code\u003e. Resolves against the same configured root as \u003ccode class=\"readme-inline-code\"\u003elist\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003eget\u003c/code\u003e, fans out \u003ccode class=\"readme-inline-code\"\u003edirectory::agents::on-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"delete\"\u003c/code\u003e, and returns \u003ccode class=\"readme-inline-code\"\u003e{ id }\u003c/code\u003e. Deleting the local shadow of a bundled profile falls back to the bundled copy; a bundled profile with no local file has nothing to delete (\u003ccode class=\"readme-inline-code\"\u003eD414\u003c/code\u003e). Sessions already using the profile are unaffected; profiles extending it stop resolving until fixed.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::functions::add\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ id, functions: [\"coder::tree\", …] }\u003c/code\u003e — append engine function ids to one EXISTING profile\u0026#39;s OWN \u003ccode class=\"readme-inline-code\"\u003efunctions:\u003c/code\u003e list (its \u003cem\u003epreloaded\u003c/em\u003e functions: the contracts the harness pre-loads into the system prompt of every new session running as the profile). Ids already present are kept once; only that frontmatter field is rewritten (block style), every other byte of the file is untouched; writes atomically, copy-on-writes a bundled profile\u0026#39;s shadow, fans out \u003ccode class=\"readme-inline-code\"\u003eon-change\u003c/code\u003e with \u003ccode class=\"readme-inline-code\"\u003eop: \"update\"\u003c/code\u003e. Returns \u003ccode class=\"readme-inline-code\"\u003e{ id, functions, added, unchanged?, bytes, modified_at }\u003c/code\u003e — \u003ccode class=\"readme-inline-code\"\u003eunchanged: true\u003c/code\u003e means nothing was written. \u003ccode class=\"readme-inline-code\"\u003eD416\u003c/code\u003e for a request with no valid ids (entries must be non-empty and whitespace-free).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::functions::remove\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ id, functions }\u003c/code\u003e — drop ids from one EXISTING profile\u0026#39;s OWN \u003ccode class=\"readme-inline-code\"\u003efunctions:\u003c/code\u003e list (absent ids are ignored; the field disappears when the list empties). Same write semantics and \u003ccode class=\"readme-inline-code\"\u003eD416\u003c/code\u003e; returns \u003ccode class=\"readme-inline-code\"\u003e{ id, functions, removed, unchanged?, bytes, modified_at }\u003c/code\u003e. Neither verb touches ids inherited through \u003ccode class=\"readme-inline-code\"\u003eextends\u003c/code\u003e — those stay in the resolved union and are removed on the parent that declares them.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003ch3 id=\"kits-directorydownload-kit-directorykits\" class=\"scroll-mt-20\"\u003eKits — \u003ccode class=\"readme-inline-code\"\u003edirectory::download-kit\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003edirectory::kits::*\u003c/code\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eFunction\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::download-kit\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ kit: \"\u003cauthor\u003e/\u003ckit\u003e[@version|tag|range]\", apply? }\u003c/code\u003e → \u003ccode class=\"readme-inline-code\"\u003e{ status: planned | applied | up_to_date, kit, message, plan?, report? }\u003c/code\u003e. Builds an install plan (an update plan when the kit is installed; without \u003ccode class=\"readme-inline-code\"\u003e@…\u003c/code\u003e an installed kit keeps its \u003ccode class=\"readme-inline-code\"\u003erequested\u003c/code\u003e) and stores it; writes nothing unless \u003ccode class=\"readme-inline-code\"\u003eapply: true\u003c/code\u003e and the plan has no warnings, blocks or pending decisions.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::apply\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ plan_id, decisions?, remove_workers? }\u003c/code\u003e → \u003ccode class=\"readme-inline-code\"\u003e{ status: applied | replanned, report?, plan? }\u003c/code\u003e. \u003ccode class=\"readme-inline-code\"\u003edecisions\u003c/code\u003e maps install paths to \u003ccode class=\"readme-inline-code\"\u003eoverwrite | keep | kit | mine | merged | remove\u003c/code\u003e or \u003ccode class=\"readme-inline-code\"\u003e{ choice: \"merged\", content }\u003c/code\u003e; files left out take the plan\u0026#39;s \u003ccode class=\"readme-inline-code\"\u003edefault\u003c/code\u003e. The \u003ccode class=\"readme-inline-code\"\u003ereport\u003c/code\u003e lists files written / merged / removed / kept, workers added / updated / removed, the steps, and the agent ids the kit now provides.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::plan-update\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ kit, version? }\u003c/code\u003e — plan an update (default target: the newest release matching \u003ccode class=\"readme-inline-code\"\u003erequested\u003c/code\u003e). \u003ccode class=\"readme-inline-code\"\u003eup_to_date\u003c/code\u003e when there is nothing newer.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::remove\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ kit }\u003c/code\u003e — plan a removal; apply it with \u003ccode class=\"readme-inline-code\"\u003eapply\u003c/code\u003e (\u003ccode class=\"readme-inline-code\"\u003eremove_workers\u003c/code\u003e to remove the kit\u0026#39;s workers too).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::check-updates\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ kit? }\u003c/code\u003e → \u003ccode class=\"readme-inline-code\"\u003e{ checked_at, available, kits: [{ kit, current, available, latest, major, ignored?, deprecation? }], error? }\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::list\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eInstalled kits (\u003ccode class=\"readme-inline-code\"\u003eversion\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003erequested\u003c/code\u003e, file-state counts, workers, \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e, pending plan ids) and pending plan summaries; \u003ccode class=\"readme-inline-code\"\u003eattention\u003c/code\u003e = pending plans + available updates.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::get\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ kit, registry? }\u003c/code\u003e — one installed kit with every file\u0026#39;s state and on-disk sha, its workers as Compose has them, and with \u003ccode class=\"readme-inline-code\"\u003eregistry: true\u003c/code\u003e the installed version\u0026#39;s registry detail and README.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::plan\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ plan_id, contents? }\u003c/code\u003e — a pending plan, its apply progress, and with \u003ccode class=\"readme-inline-code\"\u003econtents: true\u003c/code\u003e the bodies it refers to (\u003ccode class=\"readme-inline-code\"\u003eblobs\u003c/code\u003e by sha256, \u003ccode class=\"readme-inline-code\"\u003eours\u003c/code\u003e and \u003ccode class=\"readme-inline-code\"\u003emerged\u003c/code\u003e by install path).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::discard\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ plan_id }\u003c/code\u003e — drop a pending plan.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::ignore\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ kit, version, ignore? }\u003c/code\u003e — add a version to (or with \u003ccode class=\"readme-inline-code\"\u003eignore: false\u003c/code\u003e remove it from) \u003ccode class=\"readme-inline-code\"\u003eignored_versions\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::diff\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ kit, path }\u003c/code\u003e → \u003ccode class=\"readme-inline-code\"\u003e{ base, local, state }\u003c/code\u003e — what the kit installed and what is on disk, for \u0026quot;view my changes\u0026quot;.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eErrors: \u003ccode class=\"readme-inline-code\"\u003eD510\u003c/code\u003e unknown kit or version, \u003ccode class=\"readme-inline-code\"\u003eD511\u003c/code\u003e malformed kit ref, \u003ccode class=\"readme-inline-code\"\u003eD512\u003c/code\u003e\nexpired or unknown plan, \u003ccode class=\"readme-inline-code\"\u003eD513\u003c/code\u003e missing or invalid decisions, \u003ccode class=\"readme-inline-code\"\u003eD514\u003c/code\u003e blocked\nplan (Compose not running, deprecated kit), \u003ccode class=\"readme-inline-code\"\u003eD515\u003c/code\u003e Compose operation failed,\n\u003ccode class=\"readme-inline-code\"\u003eD516\u003c/code\u003e the registry served different content than the plan reviewed, \u003ccode class=\"readme-inline-code\"\u003eD520\u003c/code\u003e\nregistry unreachable.\u003c/p\u003e\n\u003ch3 id=\"engine-introspection-native-plus-one-wrapper\" class=\"scroll-mt-20\"\u003eEngine introspection (native, plus one wrapper)\u003c/h3\u003e\n\u003cp\u003eEngine introspection is served natively; call these ids directly — every\none takes the same filters (\u003ccode class=\"readme-inline-code\"\u003eprefix\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003esearch\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eworker\u003c/code\u003e,\n\u003ccode class=\"readme-inline-code\"\u003einclude_internal\u003c/code\u003e where applicable). One wrapper is kept for callers\nwhose policy only admits the \u003ccode class=\"readme-inline-code\"\u003edirectory::\u003c/code\u003e namespace:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eFunction ID\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::engine::functions::info\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eThin proxy to \u003ccode class=\"readme-inline-code\"\u003eengine::functions::info\u003c/code\u003e for a single \u003ccode class=\"readme-inline-code\"\u003efunction_id\u003c/code\u003e: request/response schemas, metadata, and registered triggers. The one \u003ccode class=\"readme-inline-code\"\u003edirectory::engine::*\u003c/code\u003e helper that still exists — reach for it only when you cannot call \u003ccode class=\"readme-inline-code\"\u003eengine::*\u003c/code\u003e directly.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eThe native ids:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eFunction ID\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eengine::functions::list\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eList functions registered with the engine.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eengine::functions::info\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eSingle-function detail: schemas, owning worker.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eengine::triggers::list\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eList trigger TYPES (the providers, e.g. \u003ccode class=\"readme-inline-code\"\u003ehttp\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ecron\u003c/code\u003e).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eengine::triggers::info\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eSingle trigger-type detail: configuration schema, return schema.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eengine::registered-triggers::list\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eList trigger INSTANCES (subscriber rows).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eengine::registered-triggers::info\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eSingle registered-trigger detail.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eengine::workers::list\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eList workers with an open engine WS connection. Daemon-managed providers (\u003ccode class=\"readme-inline-code\"\u003ehttp\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ecron\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003estate\u003c/code\u003e) won\u0026#39;t appear — call \u003ccode class=\"readme-inline-code\"\u003eworker::list\u003c/code\u003e from the supervisor to see those.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003eengine::workers::info\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eOne worker\u0026#39;s detail by \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003ch3 id=\"directoryregistry-workers-registry-http-proxy\" class=\"scroll-mt-20\"\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::registry::*\u003c/code\u003e (workers registry HTTP proxy)\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eFunction ID\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::registry::workers::list\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eBrowse / search published workers in \u003ccode class=\"readme-inline-code\"\u003eapi.workers.iii.dev\u003c/code\u003e. Optional free-text \u003ccode class=\"readme-inline-code\"\u003esearch\u003c/code\u003e (matched fuzzy by \u003ccode class=\"readme-inline-code\"\u003epg_trgm\u003c/code\u003e) and opaque \u003ccode class=\"readme-inline-code\"\u003ecursor\u003c/code\u003e for pagination; page size is server-authored. Response is \u003ccode class=\"readme-inline-code\"\u003e{ workers: [...], pagination: { next_cursor, has_more, page_size } }\u003c/code\u003e. Shares the core \u003ccode class=\"readme-inline-code\"\u003ename\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003edescription\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003eversion\u003c/code\u003e fields with the engine\u0026#39;s \u003ccode class=\"readme-inline-code\"\u003eengine::workers::list\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::registry::workers::info\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ePre-install card for one worker. Fans out two parallel registry calls — \u003ccode class=\"readme-inline-code\"\u003eGET /w/{slug}\u003c/code\u003e for the worker envelope (publication metadata + readme + functions + triggers) and \u003ccode class=\"readme-inline-code\"\u003eGET /w/{slug}/skills\u003c/code\u003e for the skills tree — and merges them into \u003ccode class=\"readme-inline-code\"\u003e{ worker, api_reference, skills_tree, readme? }\u003c/code\u003e. The card keeps public function/trigger names and descriptions only: request/response schemas, metadata, internal and search-excluded functions are dropped (browser\u0026#39;s schemas alone ran 65 KB; the contract is \u003ccode class=\"readme-inline-code\"\u003eengine::functions::info\u003c/code\u003e after installing), and \u003ccode class=\"readme-inline-code\"\u003ereadme\u003c/code\u003e (10–25 KB) is included only with \u003ccode class=\"readme-inline-code\"\u003ereadme: true\u003c/code\u003e. The full record stays cached in-process for \u003ccode class=\"readme-inline-code\"\u003edirectory::search_functions\u003c/code\u003e. Input still accepts \u003ccode class=\"readme-inline-code\"\u003eversion:\u003c/code\u003e (semver) or \u003ccode class=\"readme-inline-code\"\u003etag:\u003c/code\u003e (e.g. \u003ccode class=\"readme-inline-code\"\u003elatest\u003c/code\u003e); both go on the wire as \u003ccode class=\"readme-inline-code\"\u003e?version=…\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eBoth \u003ccode class=\"readme-inline-code\"\u003edirectory::registry::*\u003c/code\u003e responses are cached in-process for\n\u003ccode class=\"readme-inline-code\"\u003eregistry_cache_ttl_ms\u003c/code\u003e (default 60s).\u003c/p\u003e\n\u003cp\u003eThere is \u003cstrong\u003eno\u003c/strong\u003e \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::register\u003c/code\u003e — see\n\u003ca href=\"#migration-from-skills-v02x\"\u003eMigration\u003c/a\u003e below.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"function-search-pre-generate-hint\" class=\"scroll-mt-20\"\u003eFunction search \u0026amp; pre-generate hint\u003c/h2\u003e\n\u003cp\u003eOne-shot function search over the live engine catalog. \u003ccode class=\"readme-inline-code\"\u003ejudge\u003c/code\u003e (the default)\nranks through the optional \u003ccode class=\"readme-inline-code\"\u003ejudge\u003c/code\u003e worker when it is registered and answers,\nand otherwise behaves as \u003ccode class=\"readme-inline-code\"\u003ehybrid\u003c/code\u003e (BM25 fused with the local MiniLM model,\nreranked); \u003ccode class=\"readme-inline-code\"\u003elexical\u003c/code\u003e is BM25 only. Absorbed from the former \u003ccode class=\"readme-inline-code\"\u003ediscovery\u003c/code\u003e worker,\nit returns only compact \u003ccode class=\"readme-inline-code\"\u003e{ function_id, description }\u003c/code\u003e candidates, grouped by worker in rank order. The model chooses\nthe candidates it needs, then fetches their contracts in one\n\u003ccode class=\"readme-inline-code\"\u003eengine::functions::info { function_ids: [...] }\u003c/code\u003e call instead of walking the\ncatalog with \u003ccode class=\"readme-inline-code\"\u003eengine::functions::list\u003c/code\u003e.\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eFunction\u003c/th\u003e\n\u003cth\u003eKind\u003c/th\u003e\n\u003cth\u003eWhat it does\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::search_functions\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003epublic\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ capabilities }\u003c/code\u003e → \u003ccode class=\"readme-inline-code\"\u003e{ guidance, workers[], installable[]?, skills[]?, triggers[]?, search_mode, latency_ms }\u003c/code\u003e: rank with the configured mode over the live engine catalog in batches of six capabilities (12 candidates per batch across at most max(6, 2 × capabilities) workers, up to 3 batches) plus matching NOT-installed registry workers under \u003ccode class=\"readme-inline-code\"\u003einstallable\u003c/code\u003e. \u003ccode class=\"readme-inline-code\"\u003ecapabilities\u003c/code\u003e is a required list of non-empty unmet external capability searches (one to six is the norm); entries past the 18th are not searched and are named in \u003ccode class=\"readme-inline-code\"\u003eguidance\u003c/code\u003e. Requests to summarize provided text/content are ignored.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::pre-generate\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003einternal hook\u003c/td\u003e\n\u003ctd\u003eInjects the conditional search hint into a harness generation (at most once per turn).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::on-functions-change\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003einternal\u003c/td\u003e\n\u003ctd\u003eRefreshes the search catalog on the engine\u0026#39;s functions-available push.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::hint-preview\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003einternal\u003c/td\u003e\n\u003ctd\u003eThe exact hint text per exposure mode, for the configuration UI.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eLexical/Hybrid ranking pipeline:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eCorpus\u003c/strong\u003e: the live engine catalog (boot snapshot + push refresh),\nslimmed to name + first description sentence + argument names. \u003ccode class=\"readme-inline-code\"\u003eengine::\u003c/code\u003e\nids, functions published with \u003ccode class=\"readme-inline-code\"\u003emetadata.internal\u003c/code\u003e, and the search itself\nnever participate — the worker\u0026#39;s own public \u003ccode class=\"readme-inline-code\"\u003edirectory::*\u003c/code\u003e functions are\nsearchable like any other capability.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eScoring\u003c/strong\u003e: Okapi BM25 (k1 1.2, b 0.75) with the function name indexed at\n3× weight, camelCase segmentation (\u003ccode class=\"readme-inline-code\"\u003epresignUrl\u003c/code\u003e → presign + url), a\n22-word grammatical stoplist, conservative plural folding, JSON-key\nstripping from capability text, and a two-distinct-terms minimum match.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCapability queries\u003c/strong\u003e: each \u003ccode class=\"readme-inline-code\"\u003ecapabilities\u003c/code\u003e entry is ranked independently\nagainst its own leader and is authoritative. Include every currently unmet\nexternal capability once in the same call. Write every capability in\nEnglish, translating non-English requests while preserving proper names,\nURLs, and function ids. Requests to summarize provided text or content are\nignored. Results merge round-robin so every capability gets a candidate\nbefore any gets a rider.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePruning\u003c/strong\u003e: coverage-aware function floor (≥50% of the leader AND full\nterm coverage or ≥85% score) drops same-worker family riders; a\nnamespace-level floor (40% of the leader) drops trailing workers.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRegistry search\u003c/strong\u003e (\u003ccode class=\"readme-inline-code\"\u003eregistry_search\u003c/code\u003e, default on): every call also\nconsults the private workers registry in-process with the same capability\nqueries plus informative-term retries (all concurrent; every listed worker\nis a candidate — the registry is team-authored). Candidates merge\nround-robin across search variants; their API references are pooled and\nranked per capability with the configured mode. Hybrid fuses BM25 with the\nMiniLM dense lane (same 0.30 admission floor as the installed catalog), so a capability sharing no\nvocabulary with a contract (\u0026quot;retrieve web news articles\u0026quot; → \u003ccode class=\"readme-inline-code\"\u003eweb::fetch\u003c/code\u003e)\nstill surfaces. Returns up to 2 workers / 6 candidates per batch of six\ncapabilities (so up to 6 workers / 18 candidates across three batches; a\nworker two batches both surface keeps one entry with its functions merged)\nthat WOULD match if installed, with \u003ccode class=\"readme-inline-code\"\u003ecompose::add\u003c/code\u003e guidance.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSession memory\u003c/strong\u003e (keyed by caller-supplied OTel baggage, fail-open):\nrepeat queries omit candidates already delivered.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"judge-mode\" class=\"scroll-mt-20\"\u003eJudge mode\u003c/h3\u003e\n\u003cp\u003eFunction relevance is judged by the \u003ca href=\"../judge\"\u003e\u003ccode class=\"readme-inline-code\"\u003ejudge\u003c/code\u003e\u003c/a\u003e worker\n(\u003ccode class=\"readme-inline-code\"\u003ejudge::evaluate\u003c/code\u003e), which forwards to its configured provider\n(\u003ca href=\"../judge-typesafe\"\u003e\u003ccode class=\"readme-inline-code\"\u003ejudge-typesafe\u003c/code\u003e\u003c/a\u003e by default). Both are optional: this\nworker does not declare them as dependencies, because Compose turns a\ndependency into a \u003ccode class=\"readme-inline-code\"\u003estart_after\u003c/code\u003e edge and stops the directory whenever the\njudge exits. The Harness and dev-template stacks do not run them. Install the\nhub with \u003ccode class=\"readme-inline-code\"\u003eiii trigger compose::add worker=judge\u003c/code\u003e (it brings \u003ccode class=\"readme-inline-code\"\u003ejudge-typesafe\u003c/code\u003e)\nand set the TypeSafe key and model in the \u003cstrong\u003ejudge-typesafe\u003c/strong\u003e settings. This\nworker holds no credentials.\u003c/p\u003e\n\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003ejudge\u003c/code\u003e is the default mode for new installs. It ranks through the judge\nonly while \u003ccode class=\"readme-inline-code\"\u003ejudge::evaluate\u003c/code\u003e is in the live function catalog and answers.\n\u003cstrong\u003eWhenever the judge is unavailable the search uses Hybrid\u003c/strong\u003e (then Lexical if\nthe local model is not ready), for functions, installable workers, skills and\ntriggers alike:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode class=\"readme-inline-code\"\u003ejudge::evaluate\u003c/code\u003e is not registered: no call is made at all.\u003c/li\u003e\n\u003cli\u003ethe hub has no provider (\u003ccode class=\"readme-inline-code\"\u003eprovider_unavailable\u003c/code\u003e), or the provider has no\nAPI key (\u003ccode class=\"readme-inline-code\"\u003emissing_key\u003c/code\u003e): logged once at info.\u003c/li\u003e\n\u003cli\u003ea provider error, transport failure or invalid reply: logged once as a\nwarning.\u003c/li\u003e\n\u003cli\u003ethe judge deadline runs out: that lane alone uses Hybrid.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAfter an unavailable or failing judge (the second and third cases), every\nsearch skips it for 30 seconds and uses Hybrid, so a missing key costs one\nfast round trip per 30 s rather than one per search. A key added to\njudge-typesafe, or a judge that comes back, is used within 30 seconds. A\nmissed deadline does not pause the judge.\u003c/p\u003e\n\u003cp\u003eAn install that already stored \u003ccode class=\"readme-inline-code\"\u003efunction_search_mode: hybrid\u003c/code\u003e keeps it: the\nstored configuration wins over the new default. Set \u003ccode class=\"readme-inline-code\"\u003ejudge\u003c/code\u003e with\n\u003ccode class=\"readme-inline-code\"\u003econfiguration::set\u003c/code\u003e (or the console form) to opt in.\u003c/p\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_mode\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e judge\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_timeout_ms\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 3000\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_min_relevance\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 0.5\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_side_lane_min_relevance\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 0.3\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_question\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e choice\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#998418\"\u003efunction_search_judge_choice_min_probability\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e 0.1\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThese fields apply without a restart. The timeout is an integer from 1 to\n30000 ms and relevance a finite number from 0 to 1 inclusive. YAML seeds and\nJSON configuration updates use the same validation. The relevance floors were\ncalibrated against \u003ccode class=\"readme-inline-code\"\u003ejev-1.13.0\u003c/code\u003e; judge-typesafe defaults to the \u003ccode class=\"readme-inline-code\"\u003ejev-latest\u003c/code\u003e\nalias, so pin its model if you rely on the floors.\u003c/p\u003e\n\u003cp\u003eThe judge scores a shortlist per capability, not the whole catalog. A corpus\nof at most 16 documents goes whole, so the judge still finds functions whose\nwording shares nothing with the capability. A larger one is cut to the top 16\nof raw BM25 fused with the raw MiniLM ranking (when the index is ready). Each\ncapability is one evaluation, and all capabilities of a lane (functions,\nregistry pool, skills or triggers) travel in one \u003ccode class=\"readme-inline-code\"\u003ejudge::evaluate\u003c/code\u003e call, so\nthe provider answers them together with one model, and cancels the rest when\none fails. Requests carry normalized capabilities, function IDs, short\ndescriptions and parameter names; no conversation history or argument values.\nExact eligible IDs, internal-function exclusions, session deduplication and\nresult limits stay local.\u003c/p\u003e\n\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003efunction_search_judge_question\u003c/code\u003e sets how each capability\u0026#39;s shortlist is\nasked. \u003ccode class=\"readme-inline-code\"\u003echoice\u003c/code\u003e (the default) asks one multiple-choice question per capability\nwhose options are the shortlisted documents: 16× fewer questions, and the\ndocuments compete. The best document is always kept and every other needs\n\u003ccode class=\"readme-inline-code\"\u003efunction_search_judge_choice_min_probability\u003c/code\u003e (the relevance floors do not\napply). \u003ccode class=\"readme-inline-code\"\u003enoul\u003c/code\u003e asks one yes/no question per document and admits each by the\nrelevance floors. Local judges need \u003ccode class=\"readme-inline-code\"\u003echoice\u003c/code\u003e to fit the deadline: judge-semif answers a\ncapability in about 0.3 s on a GPU, where the Noul shortlist of every lane\ntakes it past 30 s. On 22 English capabilities over the 16-document\nshortlist, \u003ccode class=\"readme-inline-code\"\u003echoice\u003c/code\u003e with 0.1 kept a correct function in every search for both\n\u003ccode class=\"readme-inline-code\"\u003ejev-1.13.0\u003c/code\u003e (precision 0.98, 1.2 functions per capability) and judge-semif\n(precision 0.87, 1.5 functions). Providers register their \u003ccode class=\"readme-inline-code\"\u003ejudge-\u003cprovider\u003e::*\u003c/code\u003e\nfunctions as internal, so search results show only the hub\u0026#39;s \u003ccode class=\"readme-inline-code\"\u003ejudge::*\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eWith \u003ccode class=\"readme-inline-code\"\u003echoice\u003c/code\u003e, a judge whose models advertise a context window under 4096\ntokens (\u003ccode class=\"readme-inline-code\"\u003econtext_window\u003c/code\u003e in \u003ccode class=\"readme-inline-code\"\u003ejudge::models::list\u003c/code\u003e, re-read when the judge\nhub\u0026#39;s configuration changes and at least once a minute)\ngets compact options instead of the full description objects: each option is\nkeyed by the function id and reads the first eight words of its description,\nand the state names the capability plainly (\u003ccode class=\"readme-inline-code\"\u003e{\"capability\": …}\u003c/code\u003e). laya (512 tokens) shares about 190 of them among\nthe sixteen options, so the objects cut the function ids themselves: live, it\nfound the expected function in 13/22 searches with objects and 17/22 compact.\nSemIf (16384) and judges that advertise no window keep the objects.\u003c/p\u003e\n\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003etournament\u003c/code\u003e skips the Hybrid shortlist, following TypeSafe\u0026#39;s skill-suggestion\npattern (skim everything cheaply, then read the few in detail). The whole\nfunction catalog, sorted by id, is skimmed in rounds of compact Choices (the\nfunction id and the first eight words of its description) over groups of up to\n128, or 16 for a judge that advertises a context window under 4096 tokens, and\nnever more than the judge\u0026#39;s advertised \u003ccode class=\"readme-inline-code\"\u003emax_options\u003c/code\u003e (SemIf: 16); each group\u0026#39;s\nthree best go on (only the winner, for a small-window judge, whose final Choice\ndegrades with more options) until 16 or fewer remain, and those get one final\nChoice with their full descriptions, admitted like \u003ccode class=\"readme-inline-code\"\u003echoice\u003c/code\u003e. A 260-function\ncatalog takes one round of three groups, then the final Choice over nine. It\nneeds no local semantic model. Live through \u003ccode class=\"readme-inline-code\"\u003edirectory::search_functions\u003c/code\u003e over\n22 English capabilities (RX 6900 XT), hit / top-1 / precision and median search\ntime: JEV 22 / 22 / 1.00 at 2.2 s, SemIf 22 / 22 / 0.90 at 6.1 s, decider 22 /\n21 / 0.88 at 3.7 s, laya 20 / 19 / 0.80 at 2.2 s; the former winner-only rounds\nof 16 gave JEV 22 / 22 / 0.98, decider 21 / 21 / 0.81 at 9.1 s, and timed SemIf\nout at 10 s. The installed functions and the registry pools play it; skills and\ntriggers keep their shortlists. With \u003ccode class=\"readme-inline-code\"\u003echoice\u003c/code\u003e (the default), a judge that\nadvertises a context window under 4096 tokens gets a tournament automatically;\nSemIf and hosted judges keep \u003ccode class=\"readme-inline-code\"\u003echoice\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003ccode class=\"readme-inline-code\"\u003efunction_search_model_path: null\u003c/code\u003e is valid in judge mode and makes the Hybrid\nfallback BM25-only, without the local-model warning. With a configured path,\nthe worker keeps an installed MiniLM bundle and its catalog index current,\ndownloads a missing bundle at boot like Hybrid does, and uses the index both\nfor the shortlist and for the fallback.\u003c/p\u003e\n\u003cp\u003eRegistry discovery still starts with the registry API\u0026#39;s lexical search. The\njudge evaluates a shortlist of the returned contract pool and \u003cstrong\u003ecannot recover\nworkers that upstream search did not return\u003c/strong\u003e. Installable results remain\nsuggestions until installation.\u003c/p\u003e\n\u003cp\u003eEvery response carries \u003ccode class=\"readme-inline-code\"\u003esearch_mode\u003c/code\u003e — the mode that actually ranked the\nresults (\u003ccode class=\"readme-inline-code\"\u003ejudge\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ehybrid\u003c/code\u003e or \u003ccode class=\"readme-inline-code\"\u003elexical\u003c/code\u003e), which can be lower than the\nconfigured mode when the judge was unavailable or paused, or the local model\nis not loaded yet. The console\u0026#39;s search card shows it as the card\u0026#39;s badge. A\nsearch whose lanes partly fell back reports the highest tier any lane reached.\u003c/p\u003e\n\u003cp\u003eEvery mode also ranks the installed skill documents (the rows\n\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::list\u003c/code\u003e serves, minus \u003ccode class=\"readme-inline-code\"\u003edisable_model_invocation\u003c/code\u003e ones) against\nthe same capabilities and lists the matches under \u003ccode class=\"readme-inline-code\"\u003eskills\u003c/code\u003e as\n\u003ccode class=\"readme-inline-code\"\u003e{ id, title, description }\u003c/code\u003e, at most six per call round-robin across the\ncapabilities, with a guidance note to read them through\n\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::get { id }\u003c/code\u003e. Each skill\u0026#39;s id and a trimmed\n\u003ccode class=\"readme-inline-code\"\u003etitle: description\u003c/code\u003e (300 bytes) form the document. The judge judges them with\na how-to question under the same deadline as the functions; Lexical ranks them\nwith BM25 and Hybrid fuses in the dense lane, the same ad-hoc document ranking\nthe \u003ccode class=\"readme-inline-code\"\u003einstallable\u003c/code\u003e section uses, and that local ranking also serves whenever the\njudge fails. \u0026quot;Installed\u0026quot; is read off the live function catalog: a worker with\nno registered functions contributes no skills. The registered-trigger section\n(under \u003ccode class=\"readme-inline-code\"\u003etriggers\u003c/code\u003e) is ranked the same way in every mode.\u003c/p\u003e\n\u003cp\u003eA valid response with no functions at or above the relevance threshold stays\nempty. Judge failures instead trigger \u003cstrong\u003eJudge → Hybrid → Lexical\u003c/strong\u003e fallback.\nHybrid uses the existing local ranking policy; if the model is disabled,\nmissing, not yet indexed for the current catalog, or fails, Lexical serves the\nresults. A registry HTTP failure still omits the installable section.\u003c/p\u003e\n\u003cp\u003eThe judge deadline is shared by every judge call of one public search.\nCapability batches run concurrently, and each batch\u0026#39;s registry lookup runs in\nparallel with its installed-function judge call; the registry judge call then\ngets what is left of the deadline and, if nothing is, the pool is ranked\nlocally. Local Hybrid fallback runs outside the budget. Evaluations are split\nat local byte limits (48 KiB per evaluation, 16 KiB for state plus the largest\nquestion); these guards are not token counts. Retries are the provider\u0026#39;s\npolicy (judge-typesafe retries 408/429/5xx within the deadline); the 30-second\npause keeps a failing provider from being retried on every search. The hub\u0026#39;s\nreturned usage (\u003ccode class=\"readme-inline-code\"\u003estats\u003c/code\u003e) is logged per lane at debug level.\u003c/p\u003e\n\u003cp\u003eSwitch to \u003ccode class=\"readme-inline-code\"\u003elexical\u003c/code\u003e at any time to use BM25 only. Switching from \u003ccode class=\"readme-inline-code\"\u003elexical\u003c/code\u003e to\n\u003ccode class=\"readme-inline-code\"\u003ehybrid\u003c/code\u003e or \u003ccode class=\"readme-inline-code\"\u003ejudge\u003c/code\u003e prepares the local index from the current catalog. If the\nMiniLM bundle is missing, both use lexical fallback; the boot-time download and\nchanges to the local model path require a worker restart.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eUpgrading from the in-worker \u003ccode class=\"readme-inline-code\"\u003ejev\u003c/code\u003e mode:\u003c/strong\u003e the stored value\n\u003ccode class=\"readme-inline-code\"\u003efunction_search_mode: jev\u003c/code\u003e no longer parses, and the worker refuses to boot on\nit. While the old worker still runs, its schema only accepts\n\u003ccode class=\"readme-inline-code\"\u003elexical\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003ehybrid\u003c/code\u003e/\u003ccode class=\"readme-inline-code\"\u003ejev\u003c/code\u003e, so before upgrading set the mode to \u003ccode class=\"readme-inline-code\"\u003ehybrid\u003c/code\u003e (or\nremove the key) with \u003ccode class=\"readme-inline-code\"\u003econfiguration::set\u003c/code\u003e, then set \u003ccode class=\"readme-inline-code\"\u003ejudge\u003c/code\u003e once the new worker\nis up. The removed keys \u003ccode class=\"readme-inline-code\"\u003efunction_search_jev_api_key\u003c/code\u003e and\n\u003ccode class=\"readme-inline-code\"\u003efunction_search_jev_model\u003c/code\u003e are ignored, and the console form drops every\n\u003ccode class=\"readme-inline-code\"\u003efunction_search_jev_*\u003c/code\u003e key on its next save; the remaining settings are read\nunder their \u003ccode class=\"readme-inline-code\"\u003efunction_search_judge_*\u003c/code\u003e names only.\u003c/p\u003e\n\u003ch3 id=\"pre-generate-hint\" class=\"scroll-mt-20\"\u003ePre-generate hint\u003c/h3\u003e\n\u003cp\u003eThe pre-generate hook appends one \u003ccode class=\"readme-inline-code\"\u003e\u003cdiscovery_assist\u003e\u003c/code\u003e block pointing the\nmodel at \u003ccode class=\"readme-inline-code\"\u003esearch_functions\u003c/code\u003e, telling it to derive capabilities from the goal\nand current execution state and to batch selected ids through\n\u003ccode class=\"readme-inline-code\"\u003eengine::functions::info\u003c/code\u003e — at most once per turn, and only when every gate\nclears: the function is callable in the surface, no search result is in the\ncurrent task window yet, the surface spans at least \u003ccode class=\"readme-inline-code\"\u003ehint_min_workers\u003c/code\u003e distinct\nworkers, the current task (from the latest user message) has no real function\nresults yet, and it does not already name a callable function id. Measured on\n26 pre-existing e2e scenarios: an unconditional hint \u003cem\u003einduces\u003c/em\u003e redundant\ndiscovery on guided tasks (up to +110% tokens). The hook ships OFF by default\n(\u003ccode class=\"readme-inline-code\"\u003einject_hint: false\u003c/code\u003e): the harness identity prompt already teaches\n\u003ccode class=\"readme-inline-code\"\u003edirectory::search_functions\u003c/code\u003e as the default discovery path, so the hint is\nfor deployments running a custom identity prompt without that doctrine. The\nhook\u0026#39;s transcript annotations (\u003ccode class=\"readme-inline-code\"\u003eorigin.directory\u003c/code\u003e) carry only coarse\noutcome/reason and counts.\u003c/p\u003e\n\u003cp\u003eKnobs (\u003ccode class=\"readme-inline-code\"\u003einject_hint\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ehint_min_workers\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eregistry_search\u003c/code\u003e) live in the\n\u003ccode class=\"readme-inline-code\"\u003eiii-directory\u003c/code\u003e configuration entry and hot-apply — see Configuration.\u003c/p\u003e\n\u003ch2 id=\"custom-trigger-types\" class=\"scroll-mt-20\"\u003eCustom trigger types\u003c/h2\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eTrigger type\u003c/th\u003e\n\u003cth\u003eFires when\u003c/th\u003e\n\u003cth\u003ePayload to subscribers\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::skills::on-change\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eAfter a \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::download\u003c/code\u003e that wrote at least one skill markdown file, a \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::update\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ecreate\u003c/code\u003e, or \u003ccode class=\"readme-inline-code\"\u003edelete\u003c/code\u003e, or external (file pasted/edited/deleted directly on disk — including under \u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003edownload: \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"download\", \"namespace\": \"\u003cns\u003e\", \"source\": \"repo\" | \"registry\" }\u003c/code\u003e; update/create/delete: \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"\u003coperation\u003e\", \"namespace\": \"\u003cns\u003e\", \"id\": \"\u003cid\u003e\" }\u003c/code\u003e; external (file pasted/edited/deleted directly on disk): \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"external\" }\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::on-change\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eAfter a \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::download\u003c/code\u003e that wrote at least one system prompt markdown file, a \u003ccode class=\"readme-inline-code\"\u003edirectory::system-prompts::update\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ecreate\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003edelete\u003c/code\u003e, or external file change\u003c/td\u003e\n\u003ctd\u003edownload: \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"download\", \"namespace\": \"\u003cns\u003e\", \"source\": \"repo\" | \"registry\" }\u003c/code\u003e; update/create/delete: \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"\u003coperation\u003e\", \"name\": \"\u003cname\u003e\" }\u003c/code\u003e; external: \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"external\" }\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::agents::on-change\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eAfter a \u003ccode class=\"readme-inline-code\"\u003edirectory::skills::download\u003c/code\u003e that wrote at least one agent profile, a \u003ccode class=\"readme-inline-code\"\u003edirectory::agents::update\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003ecreate\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003edelete\u003c/code\u003e, or external file change\u003c/td\u003e\n\u003ctd\u003edownload: \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"download\", \"namespace\": \"\u003cns\u003e\", \"source\": \"repo\" | \"registry\" }\u003c/code\u003e; update/create/delete: \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"\u003coperation\u003e\", \"name\": \"\u003cid\u003e\" }\u003c/code\u003e; external: \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"external\" }\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003edirectory::kits::on-change\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eA kit plan is created or discarded, an apply makes progress or lands, or an update check changes the set of available updates (also fires the skills / agents on-change when an apply wrote those files)\u003c/td\u003e\n\u003ctd\u003e\u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"plan\", \"kit\", \"plan_id\", \"kind\" }\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"discard\", \"kit\", \"plan_id\" }\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"progress\", \"plan_id\", \"kit\", \"steps\": [{ id, label, state, detail? }], \"error\"? }\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"apply\", \"kit\", \"plan_id\", \"kind\" }\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"updates\", \"kit\"? }\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eDispatches are fire-and-forget (Void), so the write path doesn\u0026#39;t\nblock on downstream latency.\u003c/p\u003e\n\u003cp\u003eThe \u003ccode class=\"readme-inline-code\"\u003eexternal\u003c/code\u003e op comes from a filesystem watch over \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e,\n\u003ccode class=\"readme-inline-code\"\u003elocal_skills_folder\u003c/code\u003e, and (when it already exists) the read-only\n\u003ccode class=\"readme-inline-code\"\u003eagents_skills_folder\u003c/code\u003e. It is a doorbell, not a ledger: every read re-scans\ndisk, so a missed event costs a stale open view until the next call, never\ndata. A burst coalesces into one event per kind, and this worker\u0026#39;s own writes\nare suppressed — a \u003ccode class=\"readme-inline-code\"\u003ecreate\u003c/code\u003e or \u003ccode class=\"readme-inline-code\"\u003eupdate\u003c/code\u003e sends its precise op and never an\nextra \u003ccode class=\"readme-inline-code\"\u003eexternal\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eLoop hazard for subscribers.\u003c/strong\u003e Suppression covers writes made \u003cem\u003ethrough this\nworker\u003c/em\u003e. A subscriber that reacts to \u003ccode class=\"readme-inline-code\"\u003e{ \"op\": \"external\" }\u003c/code\u003e by writing \u003ccode class=\"readme-inline-code\"\u003e.md\u003c/code\u003e\nfiles under \u003ccode class=\"readme-inline-code\"\u003eskills_folder\u003c/code\u003e by some other route — a shell or coder worker, a\nscript — is not suppressed and will re-trigger itself. Either write through\n\u003ccode class=\"readme-inline-code\"\u003edirectory::*::update\u003c/code\u003e / \u003ccode class=\"readme-inline-code\"\u003ecreate\u003c/code\u003e, or make the reaction idempotent and gated.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"local-development-testing\" class=\"scroll-mt-20\"\u003eLocal development \u0026amp; testing\u003c/h2\u003e\n\u003ch3 id=\"run-from-source\" class=\"scroll-mt-20\"\u003eRun from source\u003c/h3\u003e\n\u003cp\u003eOn targets with a pinned static ONNX Runtime (Linux glibc x86_64/aarch64,\nApple Silicon macOS, Windows MSVC) every build links it and MiniLM retrieval\nand reranking are compiled in. With no \u003ccode class=\"readme-inline-code\"\u003eORT_LIB_PATH\u003c/code\u003e, \u003ccode class=\"readme-inline-code\"\u003eort-sys\u003c/code\u003e downloads the\nruntime for the build target at build time (SHA-256-verified). For offline or\ncached x86_64 Linux builds, provision it once and export the path it prints:\u003c/p\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#AB5959\"\u003eexport\u003c/span\u003e\u003cspan style=\"color:#B07D48\"\u003e ORT_LIB_PATH\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e$(\u003c/span\u003e\u003cspan style=\"color:#59873A\"\u003escripts/provision-onnxruntime.sh\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#B5695977\"\u003e\"\u003c/span\u003e\u003cspan style=\"color:#A0ADA0\"\u003e # idempotent, SHA-256 verified\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#AB5959\"\u003eexport\u003c/span\u003e\u003cspan style=\"color:#B07D48\"\u003e ORT_PREFER_DYNAMIC_LINK\u003c/span\u003e\u003cspan style=\"color:#999999\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#2F798A\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eOther targets (musl, armv7, Intel macOS) build the BM25-only worker and need\nnothing extra.\u003c/p\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# --config is an optional YAML seed (see config.yaml.example); omit it to\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# rely on the value stored in the `configuration` worker (or built-in defaults).\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003ecargo\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e run\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --release\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --url\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e ws://127.0.0.1:49134\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --config\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e ./config.yaml.example\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"tests\" class=\"scroll-mt-20\"\u003eTests\u003c/h3\u003e\n\u003cpre class=\"shiki vitesse-light\" style=\"background-color:#ffffff;color:#393a34\" tabindex=\"0\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# Fast, offline — exercises the pure helpers (markdown / id validators\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# / fs source) without needing an iii engine.\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003ecargo\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e test\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --lib\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# Full BDD suite — requires an iii engine on ws://127.0.0.1:49134\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# (or III_ENGINE_WS_URL). The git-backed download scenarios spin up\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# a local fixture repo via `git init`; the registry-backed scenarios\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# point a wiremock server at the worker's `registry_url` config.\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003ecargo\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e test\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# One feature group at a time. Available tags:\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#A0ADA0\"\u003e# @engine @read @download @download_repo @download_registry\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan style=\"color:#59873A\"\u003ecargo\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e test\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --test\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e bdd\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --\u003c/span\u003e\u003cspan style=\"color:#A65E2B\"\u003e --tags\u003c/span\u003e\u003cspan style=\"color:#B56959\"\u003e @download\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe BDD harness lives under \u003ca href=\"tests/\"\u003etests/\u003c/a\u003e. Feature files mirror the\nmodules in \u003ca href=\"src/functions/\"\u003esrc/functions/\u003c/a\u003e. Step definitions under\n\u003ca href=\"tests/steps/\"\u003etests/steps/\u003c/a\u003e drive each feature through the same\n\u003ccode class=\"readme-inline-code\"\u003eiii.trigger\u003c/code\u003e path the production binary uses.\u003c/p\u003e\n"])</script><script>self.__next_f.push([1,"2b:[\"$\",\"div\",null,{\"className\":\"border border-rule bg-bg\",\"children\":[[\"$\",\"div\",null,{\"className\":\"bg-panel px-3.5 py-2.5 border-b border-rule flex flex-col gap-y-1\",\"children\":[\"$\",\"span\",null,{\"className\":\"font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-ink-faint\",\"children\":\"README.md\"}]}],[\"$\",\"div\",null,{\"className\":\"px-7 py-6 readme-prose font-mono\",\"dangerouslySetInnerHTML\":{\"__html\":\"$31\"}}]]}]\n"])</script></body></html>