iii-directory
v1.2.41Engine 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.
Install
iii trigger compose::add worker=iii-directoryRun in your project with the iii engine running. Exact versions are immutable and digest-pinned.
Full markdown
/registry/workers/iii-directory.md. Paste it into an LLM prompt or pipe it through curl from a worker.Install
iii trigger compose::add worker=iii-directory@1.2.41Dependencies
Readme
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 ## + first paragraph + read more link per type: index skill). Authored by create, edited by update, removed by delete. title prefers the YAML frontmatter title: (then name:) over the body H1; type is lifted from frontmatter type: (e.g. index, how-to, reference) and serialised as null when absent. System-installed agent skills under the read-only agents_skills_folder are served too (see On-disk layout). |
Orientation: "when and why to use my worker's tools" |
System prompts (directory::system-prompts::*) |
Identity prompts listed by list, read by get, authored by create, edited by update, and removed by delete. The list response keeps its prompts field name. Stored under any system-prompts/ path segment; create writes . |
What the chat's system-prompt picker offers as an identity prompt (enrich or replace) |
Agent Profiles (directory::agents::*) |
Reusable session identities whose file body is the system prompt, with display name, emoji logo, preloaded skills and functions (bodies and contracts the harness freezes into every session's prompt), and optional model + reasoning_effort in required frontmatter. list rows carry the display/configuration metadata and get adds system_prompt and unknown_skills. Stored as direct files. See Agent profile storage. |
A named identity selected with harness::send { options: { agent } } |
Search (directory::search_functions) |
One to six external capabilities → compact function-id candidates (installed, plus registry workers under installable), with a conditional pre-generate hint pointing agents at it. The response also carries skills (installed how-to documents) and triggers (registered bindings that already fire, schedule, or hook a function, minus ephemeral console listeners), ranked in the same mode as the functions; search_mode reports the mode that actually ranked. |
"Which functions do I call for this task?" |
Kits (directory::download-kit, directory::kits::*) |
Install, update and remove kits — agent profiles, skills and registry workers published together as — through plans a human reviews (ADE → Directory → Kits) before anything is written. kits.lock records what is installed. See Kits. |
"Install the kanban team kit", "what does 1.1.0 change?" |
Registry (directory::registry::*) |
HTTP proxy over api.workers.iii.dev with workers::{list,info}. Rows share the core name / description / version fields with the engine's engine::workers::list and add publication metadata (type, config, supported_targets, total_downloads, dependencies, optional image). workers::list is cursor-paginated with a server-authored page size. |
"What's published in the public registry?" |
Engine introspection (functions / triggers / registered triggers /
workers) is served by the engine natively at
engine::functions::*, engine::triggers::*,
engine::registered-triggers::*, and engine::workers::*. Call the
engine ids directly. One wrapper survives for callers that can only
reach the directory:: namespace: directory::engine::functions::info
proxies a single function's schema (see its row below).
This worker is where an agent's identity text LIVES. skills/system-prompts/iii-runtime.md
ships here and is the one copy of "how to work against a live iii engine" —
claude-code and pi fetch it with directory::system-prompts::get name=iii-runtime (plus directory::skills::index) 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.
Skills and system prompts are sourced from skills_folder; agent profiles
use the dedicated agents_folder. Writes are the
directory::skills::download* functions, which pull markdown from either
the workers registry or a GitHub repo and route each
supported family to its configured root, plus the
per-kind single-file editors — directory::skills::{create,update,delete},
directory::system-prompts::{create,update,delete} and
directory::agents::{create,update,delete}. 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
on-change with op: "external" (see Custom trigger
types).
directory::registry::workers::* and the engine's engine::workers::*
share the core name / description / version fields so a parser
that touches only those keys works against either surface; the
registry view also surfaces publication metadata (type, config,
supported_targets, total_downloads, dependencies, optional
image) and the engine view adds runtime / connection state.
Table of contents
- Install
- Configuration
- Quickstart: download some skills
- On-disk layout
- Skill ids
- Kits
- Functions
- Function search & pre-generate hint
- Custom trigger types
- Local development & testing
- Migration from skills v0.2.x
Install
iii trigger compose::add worker=iii-directoryiii trigger compose::add resolves the worker and its dependencies, writes
exact declarations to worker-compose.yaml, and reconciles the Compose project.
For container settings, fetch compose::schema { function_id: "compose::add" } and use
its workers list. For example, after registering the completion wake described below:
{
"operation_id": "<operation-id>",
"workers": [
"state",
{
"worker": "iii-directory",
"start_after": ["state"],
"config_override": { "registry_search": true }
}
]
}The list can mix worker names and objects. Each object accepts scripts, config_name,
config_override, working_dir, environment, env_file, startup_timeout, and
package version as well as worker and start_after. scripts.run is for local
workers only. Supplied maps replace the whole field; omitted settings are retained.
The returned install.payload from function search is a minimal shorthand. If the worker
needs settings, replace its singular worker with an object in workers.
Register a one-shot compose-operation wake before calling compose::add, use the same
operation_id 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
container settings example and completion flow
for field behavior, path resolution, and recovery.
Skills
Install the iii-directory agent skill for Claude Code, Cursor, and 30+ other agents:
npx skills add iii-hq/workers --skill iii-directoryBrowse or install every worker skill at once:
npx skills add iii-hq/workers --list
npx skills add iii-hq/workers --allConfiguration
Runtime settings live in the configuration worker under id
iii-directory (the same pattern database and storage use). At boot
the worker registers its JSON Schema, reads the live value via
configuration::get (the configuration worker env-expands ${VAR}), and binds
a configuration trigger so it re-fetches on change.
Persisted values default to ./data/configuration/iii-directory.yaml (fs
adapter). Edit that file directly, call configuration::set id=iii-directory,
or use the Console's global Settings modal — all three propagate without a redeploy.
Fields
# TOPOLOGY — changing any of these requires a worker restart.
skills_folder: skills # under III_COMPOSE_DIR, or the process cwd standalone
local_skills_folder: skills/iii # project-scoped overrides (whole-namespace local-wins)
agents_folder: agents # direct <id>.md agent profiles
agents_skills_folder: .agents/skills # READ-ONLY agent skills, with the same relative-path base
auto_download: true # subscribe to worker-add + run the boot reconcile
# function_search_model_path: ~/.cache/iii/all-MiniLM-L6-v2-<revision> # pinned Hybrid bundle; null disables it
function_search_model_download: true # download the pinned bundle at boot in Hybrid mode
# TUNABLE — hot-reload live on `configuration:updated`.
registry_url: https://api.workers.iii.dev # workers registry base URL (workers and kits)
# registry_web_url: https://workers.iii.dev # registry web app for "open in registry" links; default: registry_url without its leading `api.`
download_timeout_ms: 60000 # per git-clone / HTTP request timeout (ms)
registry_cache_ttl_ms: 60000 # in-process TTL for registry::workers::* responses
filter_unregistered: true # hide skills whose namespace isn't an installed worker
inject_hint: false # bind the directory::pre-generate search-hint hook (off: the harness identity prompt already teaches directory-first discovery)
hint_min_workers: 2 # minimum surface width before the hint fires (0 = always)
registry_search: true # include installable registry workers in every search
function_search_mode: judge # lexical | hybrid | judge (default)
function_search_judge_timeout_ms: 3000 # integer 1..30000; shared judge deadline per public search
function_search_judge_min_relevance: 0.5 # finite 0..1 inclusive; noul floor (initial calibration value)
function_search_judge_side_lane_min_relevance: 0.3 # finite 0..1 inclusive; noul floor for the skills and triggers sections
function_search_judge_question: choice # 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)
function_search_judge_choice_min_probability: 0.1 # finite 0..1 inclusive; with choice, the floor for all but the best documentThe writable skills_folder and agents_folder roots are created when needed.
Zero-config default + seed
With no seed and no stored value the worker uses built-in defaults. Relative
folder paths use III_COMPOSE_DIR when set and the process current directory
otherwise (skills_folder: skills, agents_folder: agents,
registry_url: https://api.workers.iii.dev).
Pass --config to supply a YAML seed: when present and no value is
stored yet, its contents become initial_value on configuration::register
(see config.yaml.example). Engine-managed deployments
inline the config under the worker entry; the engine delivers it via --config.
Hot reload
On configuration::set (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 registry_url takes effect
immediately. Topology changes (skills_folder / local_skills_folder /
agents_folder / agents_skills_folder / auto_download /
function_search_model_path / function_search_model_download) are refused with a "restart
required" log; the previous configuration is kept until the worker restarts.
function_search_mode and all function_search_judge_* options hot-reload.
Judge credentials and the model name are the judge-typesafe worker's
settings, not this worker's.
The writable skills_folder, local_skills_folder, and agents_folder are
watch roots, and the watcher creates each one at boot if it is missing.
Direct edits under agents_folder fire
directory::agents::on-change with op: "external"; nested files are ignored.
agents_skills_folder 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 external doorbell
is missing until then. local_skills_folder defaults to skills/iii under
III_COMPOSE_DIR, 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.
Quickstart: download some skills
# Pull a specific worker's directory bundle at a fixed semver from
# the registry. Files land under `<skills_folder>/agent-memory/`.
iii trigger --function-id=directory::skills::download \
--payload='{"worker": "agent-memory", "version": "1.2.3"}'
# Same, but always fetch whatever's tagged `latest` (also the default
# when neither version nor tag is given).
iii trigger --function-id=directory::skills::download \
--payload='{"worker": "agent-memory"}'
# Pull a single subfolder out of a public GitHub repo via
# `git clone --depth 1 --branch main`. Files land under
# `<skills_folder>/frontend-design/`. The `branch` field defaults to
# `main`; pass `"master"` for older repos that haven't migrated.
iii trigger --function-id=directory::skills::download \
--payload='{
"repo": "https://github.com/anthropics/skills",
"skill": "frontend-design"
}'The response is
{ namespace, skills_written, system_prompts_written, agents_written, agents_skipped?, source }.
The three *_written fields list the files materialised in this run.
Registry entries shaped exactly as agents/ land in
; repo downloads do not install agent profiles.
A registry entry whose profile id an installed kit owns (kits.lock) is not
written — kit profiles take precedence — and is reported in
agents_skipped: [{ id, owned_by }].
A registry download (explicit or automatic) writes
with the worker, the resolved
version and, per agent profile it wrote, agents: { . That
is how directory::agents::list attributes a profile to a worker.
After every successful download the worker fires the
directory::skills::on-change, directory::system-prompts::on-change,
and/or directory::agents::on-change trigger types so that
subscribers like the mcp worker can
forward MCP notifications/list_changed to their clients.
On-disk layout
The worker uses separate roots for directory content and agent profiles:
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 baseThree agent profiles ship inside the worker binary:
default— shown as Default in the chat's new-session gallery: the minimal directory-first identity (the same text as the bundlediii-minimalsystem prompt), with a composer example. New sessions in the ADE start on it.iii— the harness default identity, verbatim.hidden: truekeeps it out of the gallery; it stays a validextendsparent and runs by id.iii-minimal— the previous id ofdefault, kept as a hidden alias (extends: default, no body of its own) so existingextends: iii-minimalchains, saved sessions, and explicit invocations resolve to the same identity. New profiles should useextends: default.
Each is always listed (builtin: true), a local agents_folder/
shadows it, update 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.
An optional composer_placeholder: 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 extends, 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.
An optional skills_index: boolean turns off the skills index for sessions
running as that profile: with skills_index: false the harness starts them
without the names-only block in the prompt (this is the
prompt block, not the directory::skills::index function). It inherits
through extends like model — the nearest profile that sets it wins, and
true in a child turns the index back on. The profile's preloaded skills
still render, and directory::skills::get stays callable when the session's
policy allows it. A value that is not a YAML boolean makes the profile
invalid, like hidden.
A second, READ-ONLY root — agents_skills_folder (default .agents/skills
under the same Compose or standalone base) — serves agent skills. It is
scanned shallowly: only becomes an entry
(id , displayed as ); a skill's
reference/, scripts/, or other support payload is never listed. A
missing directory is silently empty. These skills bypass
filter_unregistered (their namespaces are skills, not workers), stay
out of directory::skills::index (a per-WORKER surface), and are
refused by update/delete — edit them with their owning tool, or
copy one into skills_folder on disk to fork it. Precedence is
local_skills_folder > skills_folder > agents_skills_folder,
namespace-wise: a top-level namespace directory in a higher root
shadows the same namespace below.
A few rules:
- Skill ids are the relative path under
skills_folderwith.mdstripped. Each segment must satisfy[a-z0-9_-]{1,64}. - Skill frontmatter is optional. When present, the reader recognises
title:(preferred title),name:(title fallback),type:(free-form classifier),function_id:(canonical bus function id surfaced bylistandget),description:(preferredlistteaser), anddisable-model-invocation:(boolean, defaultfalse, surfaced asdisable_model_invocationby 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. - System prompts live under any
*/system-prompts/*.mdpath, with YAML frontmatter (descriptionrequired,nameoptional). A path carrying both apromptsand asystem-promptssegment is a system prompt becausesystem-promptsis classified first. Other paths containing apromptssegment are ignored by scans and downloads. - What a system prompt can do, by design. The console's chat picker
can send a selected system prompt with
system_prompt_strategy: "override", which replaces the harness's built-in identity prompt with that file's body verbatim. Files reachsystem-prompts/either by local authoring or viadirectory::skills::downloadfrom 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 ownsskills_folder. Worth knowing before you pointskills_folderat a directory other people can write to. - Agent profiles are direct
files (unrelated to the read-only/ .md agents_skills_folderabove, which holds external tools' skills). Nested profiles and the formerlayout are ignored. Frontmatter is required and must declare a non-empty/**/agents/*.md name(the display name — the id is always the file stem);descriptionmay be empty,logois emoji-only (≤16 bytes, no path characters),skills:filters the skill index (absent/empty = every skill), andmodel:names a model id for sessions using this profile (absent = the send decides), and optionalreasoning_effort: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. Unknownskillsids are warnings surfaced byget, never load failures. - Agent profiles declare preloaded functions.
functions:lists engine function ids (coder::tree,coder::search, …) 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 ablock (id, description, compacted request schema), so the model calls them on the first step instead of spending adirectory::search_functions+engine::functions::inforound-trip per session; everything else still goes through discovery. Ids are stored verbatim (non-empty, no whitespace; duplicates collapse, order kept);getreports ids the engine does not currently know inunknown_functions(a warning — the harness renders them as unavailable),listcarriesfunction_count.directory::agents::functions::add/::remove { id, functions }edit only that frontmatter field — the rest of the file stays byte-identical — and fan outon-changeas an update. The console's profile editor picks them from the live registry with the same keyboard-first search + Selected/Available lists as skills. - Agent profiles inherit.
extends:names one parent profile (chains allowed, at most 8 hops). The resolved system prompt served bygetis 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;modelandreasoning_effortfall back to the nearest ancestor that sets them when omitted, whileskillsandfunctionsinherit ADDITIVELY (the union of the chain's lists, root first, no duplicates — a child adds to what its parents allow / preload, it cannot remove);name,description,logo,iconandcolorare always the profile's own. A chain that does not resolve (unknown parent, loop, too deep) is reported bylist/getasinheritance_error(D415text) while the profile still serves its own file (so the editor can fix it); the harness refuses to run it. - Under a skills root, files outside
prompts/,system-prompts/, and reservedagents/segments are skills.
The download function namespaces by source:
| Source | Destination |
|---|---|
repo=URL skill=NAME branch?=main |
|
worker=NAME version=… |
Skills/prompts under ; exact agents/ entries under |
worker=NAME tag=… (default tag=latest) |
Same routing as the version form |
Re-pulling the same source overwrites files file-by-file — existing siblings outside the response set are preserved (so hand-edited additions survive a re-pull).
Skill ids
Skills are addressed by their relative path under skills_folder with
.md stripped — e.g. →
id "agent-memory/observe". The same string is what
directory::skills::list returns and what directory::skills::get
expects in { "id": ... }. The legacy iii://{id} link form is still
accepted on get (the prefix is auto-stripped), but the worker no
longer parses any other iii:// URI shape — bodies are read solely by
id, and the auto-rendered tree-shaped index that previous releases
served at iii://directory/skills is gone. Consumers that want a
tree-shaped picker iterate list rows themselves and indent by
id.matches('/').count().
Kits
A kit is a publishable bundle of agent profiles (agents/), skills
(skills/**.md) and registry workers declared by semver range, addressed as
and versioned in the registry
(registry_url, endpoints under /k). Install one with
iii trigger directory::download-kit kit=acme/kanban-team # latest
iii trigger directory::download-kit kit=acme/kanban-team@1.3.0 # or a tag, or a range (@^1.3)Nothing is written by that call: it builds a plan and answers with it.
Review the plan in the ADE (Directory → Kits) or apply it from a script
with iii trigger directory::kits::apply plan_id=kp_…. apply=true on
download-kit applies at once only when the plan has no warnings, nothing
blocking it and no file that needs a decision.
What lands where
| Kit file | Installed at |
|---|---|
agents/ |
(flat ids, like every profile) |
skills/ |
— skill id (SKILL.md / index.md → index) |
workers: { kanban: ^1.4 } |
compose::add { workers: [{ worker: "kanban", version: "^1.4" }] } — the compose file declares the kit's range |
Kit skill namespaces have two segments. They pass filter_unregistered
(they are not workers), and a kit's local override is
, which shadows that kit only — never
the author's other kits. A kit installed inside local_skills_folder (the
default skills/iii with an author handle iii) is the kit itself, not an
override.
kits.lock
kits.lock sits next to the compose file and is meant to be committed. The
compose file is III_COMPOSE_FILE when Compose started this worker;
otherwise it is worker-compose.yaml in III_COMPOSE_DIR, or in the process
working directory for a standalone worker.
version: 1
kits:
acme/kanban-team:
requested: ^1.3.0 # a tag, a range, or ^<version> for an exact install
version: 1.3.0
installed_at: 2026-10-08T14:02:11Z
workers:
kanban: ^1.4
files:
agents/product-manager.md:
sha256: 4be1… # the content the kit installed: the merge base
agents/reviewer.md:
sha256: 77c0…
skipped: true # you kept the file that was already there
skills/acme/kanban-team/tickets/flow.md:
sha256: 9a3e…
ignored_versions: [1.4.0]Paths are install paths: agents/… under agents_folder, skills/… under
skills_folder. A file's state is computed on demand — intact (on-disk
sha = base), edited, missing, or skipped. Bases are fetched back
from the registry (GET /blobs/); no copies are kept. An exact
version request installs that version and records its caret range
(1.3.0 → ^1.3.0, as npm saves an exact install) so compatible releases
are offered as updates; tags and ranges are recorded as given.
Pending plans live in .iii/directory/kit-plans/ next to the
compose file (local state, not committed) and expire after 24 hours. The last
update check is cached in .iii/directory/kit-updates.json.
Precedence and collisions
Kit profiles take precedence over profiles workers ship, but an install or
update never replaces an existing file silently. Every agents/ has an
owner: a kit (kits.lock), a worker (its completion marker records the
profiles it wrote, with their sha256), or the project itself (local).
| The kit writes a path that… | Warning | Default |
|---|---|---|
| a worker's bundle wrote | agent_overwrite — "came from worker kanban 0.1.18 and will be replaced" |
replace |
| another kit owns | agent_overwrite_kit; replacing moves the file to this kit and marks it skipped in the other kit's lock |
replace |
| was created in this project | agent_overwrite_local (the strongest) |
replace |
a user-global profile (~/.iii/agents) has |
agent_shadows_global |
replace |
is default, iii or iii-minimal |
builtin_override — replaces a built-in profile project-wide |
replace |
| exists under the kit's skills folder but is not in the lock | file_overwrite_local |
replace |
Every collision can be answered keep: the kit's file is not written and
the lock marks it skipped; later updates respect that until it is reverted.
Identical content is no collision. Worker downloads skip profiles a kit owns
and report them in agents_skipped. directory::agents::list / get carry
source: { kind: kit | worker | local | global | builtin, kit?, worker?, version?, modified? }.
The plan
The plan JSON is the contract between the functions, the Kits page and the chat cards:
{
"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": "…"
}change:added,modified,removed, orkept(askippedfile whose kit version changed).local:absent,intact,edited,missing, oroccupied(someone else's file). File bodies are not in the plan;directory::kits::plan { plan_id, contents: true }serves them.- An update merges a file you edited with the kit's change three ways
(
diffy):merge: cleandefaults tomerged;merge: conflictshas no default and needskit,mine, ormergedwith the resolved text. Conflict markers read<<<<<<< yours/||||||| installed/>>>>>>> kit. A file you edited that the kit did not change is not in the plan. A removed file you did not edit defaults toremove; one you edited defaults tokeep(it becomes an ordinary local file). - Workers:
add(not declared),update(installed version outside the range),redeclare(the compose file still declares the kit's previous range, which the installed version already satisfies),none, andremovefor a worker the kit dropped — never removed unless named inremove_workers.path://workers are never touched. - Warnings also cover
local_edits_merged,merge_conflict,major_updateand, on removal,edited_file_kept. Blocking:compose_not_running(the plan adds or moves workers andcompose::statusdoes not answer) andkit_deprecated.
Apply
directory::kits::apply { plan_id, decisions?, remove_workers? }, one apply at
a time:
- Re-validate: the plan has not expired,
kits.lockstill 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 withstatus: replanned. - Download
GET /k/— counts the download (/download?version=…&ci=… ci=truewhenCIis set) — and check every body against the sha the plan reviewed. - Workers through Compose: one
compose::addwith{ worker, version:objects for every added, moved or re-declared worker (an existing container's range is re-declared in place), then} compose::removefor the tickedremove_workers, each followed throughcompose::operation. A failure stops here, before any file is written. - Files, 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).
kits.lock, last; then the plan is deleted andon-changefires.
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 (iii compose --up): the compose::* functions exist
only while its daemon does.
Updates
directory::kits::check-updates asks POST /k/updates for every installed kit
(or one): the newest version satisfying requested, unless it is in
ignored_versions. It runs 15 seconds after boot, every 6 hours, after every
install or update, and on demand. directory::kits::ignore { kit, version }
adds a version to ignored_versions (and retires a pending update plan for
it); ignore: false takes it back.
In the ADE
The Directory page has a Kits segment next to Skills and Agent Profiles; its badge counts plans waiting for review plus available updates.
- Kits — pending reviews, an install box, and installed kits with their update state; "Check for updates".
- An installed kit — 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.
- Install review — 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".
- Update review — 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
" 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. - Removal review — the files to delete (edited ones unticked) and the kit's workers (unticked, with a note when another kit uses one).
Chat cards render download-kit, plan-update and remove (the plan summary
and "Review install", which opens this segment on the plan), apply (live
steps, the result, and the plan summary while a harness approval is pending),
check-updates and kits::list.
Functions
Functions sit under directory::*. All registrations are
namespace-clean; this worker is intentionally agnostic to MCP and any
other adapter.
directory::skills::* (filesystem reader + editor)
| Function ID | Description |
|---|---|
directory::skills::download |
Download directory content. Flexible alias accepting either source set: {repo, skill, branch?} (defaults branch=main) or {worker, version?|tag?} (defaults tag=latest). Prefer the two explicit forms below so the source is unambiguous. |
directory::skills::download_from_repo |
Repo-only form: {repo, skill, branch?}. Copies one skill folder out of a GitHub repo; paths under prompts/ and agents/ are ignored. |
directory::skills::download_from_registry |
Registry-only form: {worker, version?|tag?}. Installs a published worker's bundle from api.workers.iii.dev, routing exact agents/ entries to agents_folder. |
directory::skills::list |
Enriched listing of every fs-backed skill: { id, title, type, function_id, disable_model_invocation, description, bytes, modified_at } per row. title prefers the YAML frontmatter title: over the body H1, type is lifted from frontmatter type: (null when absent), function_id identifies the documented bus function when present, and description is the frontmatter description or first body paragraph — so consumers can render a picker without a follow-up get per row. |
directory::skills::get |
Fetch one skill by id. Returns { id, title, type, function_id, disable_model_invocation, path, body, modified_at }. It shares the list row's identity, classification, function, and invocation metadata, but returns the raw markdown body and absolute on-disk path instead of the teaser and byte count; there is no description field. The path's parent directory is the skill's base directory, where payload like scripts/ and reference/ lives, and is meaningful only to callers on this worker's machine. Accepts a bare id or the same id prefixed with iii://. Pass raw: true to additionally get the FULL on-disk file (frontmatter included) as raw — the round-trip form update takes. |
directory::skills::update |
Overwrite one EXISTING skill file with new full-file content: { id, content } where content is the edited raw from get { raw: true }. Validated against the read invariants (size cap, non-empty body after frontmatter); atomic write; fans out directory::skills::on-change with op: "update". Never creates files (use create). Refuses read-only system-installed skills under agents_skills_folder (D116). |
directory::skills::create |
Create a NEW skill file at from full-file content: { id, content }. Frontmatter is optional (same rules as update: size cap, non-empty body). Refuses an id that already resolves in the visible set — including the → overview alias and system-installed agents skills — or a target path that already exists on disk (D114); an id in a namespace reserved by a system-installed agents skill (D115); and, while filter_unregistered is on, an id the visibility filter would immediately hide (D115). Atomic write; fans out directory::skills::on-change with op: "create". Returns the same shape as update. |
directory::skills::delete |
Permanently remove one EXISTING skill file by { id } (same id forms as get). Resolves against the same visible set as list/get, refuses read-only system-installed skills under agents_skills_folder (D116), removes the file plus any parent directories left empty (so a deleted namespace can't keep shadowing a lower-precedence root), and fans out directory::skills::on-change with op: "delete". Returns { id } (the resolved on-disk id). |
directory::skills::index |
Render one short markdown entry per installed worker (skills with frontmatter type: index). Returns { body, workers_count } where body is a ready-to-paste page: # Skills index, then one ## heading + the worker's first overview paragraph + a Read iii:// pointer the agent can follow with directory::skills::get. Token-light by design; use directory::skills::list for per-skill rows. |
directory::system-prompts::* (filesystem reader + editor)
| Function ID | Description |
|---|---|
directory::system-prompts::list |
Metadata-only listing of every fs-backed system prompt. |
directory::system-prompts::get |
Fetch one system prompt's body + {name, description, modified_at}. Plain shape, no envelope. Pass raw: true to additionally get the FULL on-disk file (frontmatter included) as raw. |
directory::system-prompts::update |
Overwrite one EXISTING system prompt file with new full-file content: { name, content }. The frontmatter must keep a non-empty description (and a valid name when declared) — the same rules the scanner enforces. Atomic write; fans out directory::system-prompts::on-change with op: "update". Returns the system prompt's effective name after the write. |
directory::system-prompts::create |
Create a NEW system prompt file at from full-file content: { name, content }, where content is the FULL file including frontmatter. The frontmatter must carry a non-empty description (and a name matching the request, when declared) — the same rules update enforces. Refuses a name 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 directory::system-prompts::on-change with op: "create". Returns { name, description, bytes, modified_at }. |
directory::system-prompts::delete |
Permanently remove one EXISTING system prompt file by { name }. Resolves against the same merged scan as list/get, fans out directory::system-prompts::on-change with op: "delete", and returns { name }. |
Agent Profiles — directory::agents::* (filesystem reader + editor)
| Function ID | Description |
|---|---|
directory::agents::list |
Metadata-only listing of every agent profile — fs-backed plus the bundled default / iii / iii-minimal profiles (builtin: true until a local file shadows one): { id, name, description, logo, skill_count, model, reasoning_effort, icon, color, extends, hidden, composer_placeholder, modified_at } per row (hidden and composer_placeholder omitted when unset; composer_placeholder never inherits), skill_count/model/reasoning_effort resolved through extends (skill_count: null = every skill; model: null = the send decides). A row whose chain does not resolve carries inheritance_error. Every row carries source: { kind: kit | worker | local | global | builtin, kit?, worker?, version?, modified? } — see Precedence and collisions. |
directory::agents::get |
Fetch one agent profile by { id }: the RESOLVED system_prompt (each ancestor's body root-first, then this file's body), skills + unknown_skills (preloaded ids matching no visible skill — warnings), skills_index (resolved through extends; false = sessions start without the skills index, omitted when unset), model (null = the send decides), provider-native reasoning_effort, display icon/color, extends, hidden, the profile's own composer_placeholder (omitted when unset), builtin, modified_at, and inheritance_error when the chain does not resolve (own file served meanwhile), and the same source as list. Pass raw: true to additionally get this profile's FULL on-disk file as raw. |
directory::agents::update |
Overwrite one EXISTING agent profile file with new full-file content: { id, content }. Same rules the scanner enforces (required frontmatter with non-empty name, emoji-only logo; 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 directory::agents::on-change with op: "update". |
directory::agents::create |
Create a NEW agent profile at from full-file content: { id, content }. Refuses an id 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 directory::agents::on-change with op: "create". Returns { id, name, description, logo, bytes, modified_at }. |
directory::agents::delete |
Permanently remove one EXISTING agent profile file by { id }. Resolves against the same configured root as list/get, fans out directory::agents::on-change with op: "delete", and returns { id }. 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 (D414). Sessions already using the profile are unaffected; profiles extending it stop resolving until fixed. |
directory::agents::functions::add |
{ id, functions: ["coder::tree", …] } — append engine function ids to one EXISTING profile's OWN functions: list (its preloaded 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 on-change with op: "update". Returns { id, functions, added, unchanged?, bytes, modified_at } — unchanged: true means nothing was written. D416 for a request with no valid ids (entries must be non-empty and whitespace-free). |
directory::agents::functions::remove |
{ id, functions } — drop ids from one EXISTING profile's OWN functions: list (absent ids are ignored; the field disappears when the list empties). Same write semantics and D416; returns { id, functions, removed, unchanged?, bytes, modified_at }. Neither verb touches ids inherited through extends — those stay in the resolved union and are removed on the parent that declares them. |
Kits — directory::download-kit, directory::kits::*
| Function | Description |
|---|---|
directory::download-kit |
{ kit: " → { status: planned | applied | up_to_date, kit, message, plan?, report? }. Builds an install plan (an update plan when the kit is installed; without @… an installed kit keeps its requested) and stores it; writes nothing unless apply: true and the plan has no warnings, blocks or pending decisions. |
directory::kits::apply |
{ plan_id, decisions?, remove_workers? } → { status: applied | replanned, report?, plan? }. decisions maps install paths to overwrite | keep | kit | mine | merged | remove or { choice: "merged", content }; files left out take the plan's default. The report lists files written / merged / removed / kept, workers added / updated / removed, the steps, and the agent ids the kit now provides. |
directory::kits::plan-update |
{ kit, version? } — plan an update (default target: the newest release matching requested). up_to_date when there is nothing newer. |
directory::kits::remove |
{ kit } — plan a removal; apply it with apply (remove_workers to remove the kit's workers too). |
directory::kits::check-updates |
{ kit? } → { checked_at, available, kits: [{ kit, current, available, latest, major, ignored?, deprecation? }], error? }. |
directory::kits::list |
Installed kits (version, requested, file-state counts, workers, update, pending plan ids) and pending plan summaries; attention = pending plans + available updates. |
directory::kits::get |
{ kit, registry? } — one installed kit with every file's state and on-disk sha, its workers as Compose has them, and with registry: true the installed version's registry detail and README. |
directory::kits::plan |
{ plan_id, contents? } — a pending plan, its apply progress, and with contents: true the bodies it refers to (blobs by sha256, ours and merged by install path). |
directory::kits::discard |
{ plan_id } — drop a pending plan. |
directory::kits::ignore |
{ kit, version, ignore? } — add a version to (or with ignore: false remove it from) ignored_versions. |
directory::kits::diff |
{ kit, path } → { base, local, state } — what the kit installed and what is on disk, for "view my changes". |
Errors: D510 unknown kit or version, D511 malformed kit ref, D512
expired or unknown plan, D513 missing or invalid decisions, D514 blocked
plan (Compose not running, deprecated kit), D515 Compose operation failed,
D516 the registry served different content than the plan reviewed, D520
registry unreachable.
Engine introspection (native, plus one wrapper)
Engine introspection is served natively; call these ids directly — every
one takes the same filters (prefix, search, worker,
include_internal where applicable). One wrapper is kept for callers
whose policy only admits the directory:: namespace:
| Function ID | Description |
|---|---|
directory::engine::functions::info |
Thin proxy to engine::functions::info for a single function_id: request/response schemas, metadata, and registered triggers. The one directory::engine::* helper that still exists — reach for it only when you cannot call engine::* directly. |
The native ids:
| Function ID | Description |
|---|---|
engine::functions::list |
List functions registered with the engine. |
engine::functions::info |
Single-function detail: schemas, owning worker. |
engine::triggers::list |
List trigger TYPES (the providers, e.g. http, cron). |
engine::triggers::info |
Single trigger-type detail: configuration schema, return schema. |
engine::registered-triggers::list |
List trigger INSTANCES (subscriber rows). |
engine::registered-triggers::info |
Single registered-trigger detail. |
engine::workers::list |
List workers with an open engine WS connection. Daemon-managed providers (http, cron, state) won't appear — call worker::list from the supervisor to see those. |
engine::workers::info |
One worker's detail by name. |
directory::registry::* (workers registry HTTP proxy)
| Function ID | Description |
|---|---|
directory::registry::workers::list |
Browse / search published workers in api.workers.iii.dev. Optional free-text search (matched fuzzy by pg_trgm) and opaque cursor for pagination; page size is server-authored. Response is { workers: [...], pagination: { next_cursor, has_more, page_size } }. Shares the core name / description / version fields with the engine's engine::workers::list. |
directory::registry::workers::info |
Pre-install card for one worker. Fans out two parallel registry calls — GET /w/{slug} for the worker envelope (publication metadata + readme + functions + triggers) and GET /w/{slug}/skills for the skills tree — and merges them into { worker, api_reference, skills_tree, readme? }. 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 engine::functions::info after installing), and readme (10–25 KB) is included only with readme: true. The full record stays cached in-process for directory::search_functions. Input still accepts version: (semver) or tag: (e.g. latest); both go on the wire as ?version=…. |
Both directory::registry::* responses are cached in-process for
registry_cache_ttl_ms (default 60s).
There is no directory::skills::register — see
Migration below.
Function search & pre-generate hint
One-shot function search over the live engine catalog. judge (the default)
ranks through the optional judge worker when it is registered and answers,
and otherwise behaves as hybrid (BM25 fused with the local MiniLM model,
reranked); lexical is BM25 only. Absorbed from the former discovery worker,
it returns only compact { function_id, description } candidates, grouped by worker in rank order. The model chooses
the candidates it needs, then fetches their contracts in one
engine::functions::info { function_ids: [...] } call instead of walking the
catalog with engine::functions::list.
| Function | Kind | What it does |
|---|---|---|
directory::search_functions |
public | { capabilities } → { guidance, workers[], installable[]?, skills[]?, triggers[]?, search_mode, latency_ms }: 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 installable. capabilities 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 guidance. Requests to summarize provided text/content are ignored. |
directory::pre-generate |
internal hook | Injects the conditional search hint into a harness generation (at most once per turn). |
directory::on-functions-change |
internal | Refreshes the search catalog on the engine's functions-available push. |
directory::hint-preview |
internal | The exact hint text per exposure mode, for the configuration UI. |
Lexical/Hybrid ranking pipeline:
- Corpus: the live engine catalog (boot snapshot + push refresh),
slimmed to name + first description sentence + argument names.
engine::ids, functions published withmetadata.internal, and the search itself never participate — the worker's own publicdirectory::*functions are searchable like any other capability. - Scoring: Okapi BM25 (k1 1.2, b 0.75) with the function name indexed at
3× weight, camelCase segmentation (
presignUrl→ presign + url), a 22-word grammatical stoplist, conservative plural folding, JSON-key stripping from capability text, and a two-distinct-terms minimum match. - Capability queries: each
capabilitiesentry 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. - Pruning: 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.
- Registry search (
registry_search, 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" →web::fetch) 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, withcompose::addguidance. - Session memory (keyed by caller-supplied OTel baggage, fail-open): repeat queries omit candidates already delivered.
Judge mode
Function relevance is judged by the judge worker
(judge::evaluate), which forwards to its configured provider
(judge-typesafe by default). Both are optional: this
worker does not declare them as dependencies, because Compose turns a
dependency into a start_after edge and stops the directory whenever the
judge exits. The Harness and dev-template stacks do not run them. Install the
hub with iii trigger compose::add worker=judge (it brings judge-typesafe)
and set the TypeSafe key and model in the judge-typesafe settings. This
worker holds no credentials.
judge is the default mode for new installs. It ranks through the judge
only while judge::evaluate is in the live function catalog and answers.
Whenever the judge is unavailable the search uses Hybrid (then Lexical if
the local model is not ready), for functions, installable workers, skills and
triggers alike:
judge::evaluateis not registered: no call is made at all.- the hub has no provider (
provider_unavailable), or the provider has no API key (missing_key): logged once at info. - a provider error, transport failure or invalid reply: logged once as a warning.
- the judge deadline runs out: that lane alone uses Hybrid.
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.
An install that already stored function_search_mode: hybrid keeps it: the
stored configuration wins over the new default. Set judge with
configuration::set (or the console form) to opt in.
function_search_mode: judge
function_search_judge_timeout_ms: 3000
function_search_judge_min_relevance: 0.5
function_search_judge_side_lane_min_relevance: 0.3
function_search_judge_question: choice
function_search_judge_choice_min_probability: 0.1These 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 jev-1.13.0; judge-typesafe defaults to the jev-latest
alias, so pin its model if you rely on the floors.
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 judge::evaluate 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.
function_search_judge_question sets how each capability's shortlist is
asked. choice (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
function_search_judge_choice_min_probability (the relevance floors do not
apply). noul asks one yes/no question per document and admits each by the
relevance floors. Local judges need choice 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, choice with 0.1 kept a correct function in every search for both
jev-1.13.0 (precision 0.98, 1.2 functions per capability) and judge-semif
(precision 0.87, 1.5 functions). Providers register their judge-
functions as internal, so search results show only the hub's judge::*.
With choice, a judge whose models advertise a context window under 4096
tokens (context_window in judge::models::list, 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 ({"capability": …}). 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.
tournament 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 max_options (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 choice. A 260-function
catalog takes one round of three groups, then the final Choice over nine. It
needs no local semantic model. Live through directory::search_functions 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 choice (the default), a judge that
advertises a context window under 4096 tokens gets a tournament automatically;
SemIf and hosted judges keep choice.
function_search_model_path: null 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.
Registry discovery still starts with the registry API's lexical search. The judge evaluates a shortlist of the returned contract pool and cannot recover workers that upstream search did not return. Installable results remain suggestions until installation.
Every response carries search_mode — the mode that actually ranked the
results (judge, hybrid or lexical), 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.
Every mode also ranks the installed skill documents (the rows
directory::skills::list serves, minus disable_model_invocation ones) against
the same capabilities and lists the matches under skills as
{ id, title, description }, at most six per call round-robin across the
capabilities, with a guidance note to read them through
directory::skills::get { id }. Each skill's id and a trimmed
title: description (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 installable 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 triggers) is ranked the same way in every mode.
A valid response with no functions at or above the relevance threshold stays empty. Judge failures instead trigger Judge → Hybrid → Lexical 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.
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 (stats) is logged per lane at debug level.
Switch to lexical at any time to use BM25 only. Switching from lexical to
hybrid or judge 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.
Upgrading from the in-worker jev mode: the stored value
function_search_mode: jev no longer parses, and the worker refuses to boot on
it. While the old worker still runs, its schema only accepts
lexical/hybrid/jev, so before upgrading set the mode to hybrid (or
remove the key) with configuration::set, then set judge once the new worker
is up. The removed keys function_search_jev_api_key and
function_search_jev_model are ignored, and the console form drops every
function_search_jev_* key on its next save; the remaining settings are read
under their function_search_judge_* names only.
Pre-generate hint
The pre-generate hook appends one block pointing the
model at search_functions, telling it to derive capabilities from the goal
and current execution state and to batch selected ids through
engine::functions::info — 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 hint_min_workers 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 induces redundant
discovery on guided tasks (up to +110% tokens). The hook ships OFF by default
(inject_hint: false): the harness identity prompt already teaches
directory::search_functions as the default discovery path, so the hint is
for deployments running a custom identity prompt without that doctrine. The
hook's transcript annotations (origin.directory) carry only coarse
outcome/reason and counts.
Knobs (inject_hint, hint_min_workers, registry_search) live in the
iii-directory configuration entry and hot-apply — see Configuration.
Custom trigger types
| Trigger type | Fires when | Payload to subscribers |
|---|---|---|
directory::skills::on-change |
After a directory::skills::download that wrote at least one skill markdown file, a directory::skills::update, create, or delete, or external (file pasted/edited/deleted directly on disk — including under agents_skills_folder) |
download: { "op": "download", "namespace": "; update/create/delete: { "op": "; external (file pasted/edited/deleted directly on disk): { "op": "external" } |
directory::system-prompts::on-change |
After a directory::skills::download that wrote at least one system prompt markdown file, a directory::system-prompts::update, create, delete, or external file change |
download: { "op": "download", "namespace": "; update/create/delete: { "op": "; external: { "op": "external" } |
directory::agents::on-change |
After a directory::skills::download that wrote at least one agent profile, a directory::agents::update, create, delete, or external file change |
download: { "op": "download", "namespace": "; update/create/delete: { "op": "; external: { "op": "external" } |
directory::kits::on-change |
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) | { "op": "plan", "kit", "plan_id", "kind" }, { "op": "discard", "kit", "plan_id" }, { "op": "progress", "plan_id", "kit", "steps": [{ id, label, state, detail? }], "error"? }, { "op": "apply", "kit", "plan_id", "kind" }, { "op": "updates", "kit"? } |
Dispatches are fire-and-forget (Void), so the write path doesn't block on downstream latency.
The external op comes from a filesystem watch over skills_folder,
local_skills_folder, and (when it already exists) the read-only
agents_skills_folder. 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 create or update sends its precise op and never an
extra external.
Loop hazard for subscribers. Suppression covers writes made through this
worker. A subscriber that reacts to { "op": "external" } by writing .md
files under skills_folder by some other route — a shell or coder worker, a
script — is not suppressed and will re-trigger itself. Either write through
directory::*::update / create, or make the reaction idempotent and gated.
Local development & testing
Run from source
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 ORT_LIB_PATH, ort-sys 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:
export ORT_LIB_PATH="$(scripts/provision-onnxruntime.sh)" # idempotent, SHA-256 verified
export ORT_PREFER_DYNAMIC_LINK=0Other targets (musl, armv7, Intel macOS) build the BM25-only worker and need nothing extra.
# --config is an optional YAML seed (see config.yaml.example); omit it to
# rely on the value stored in the `configuration` worker (or built-in defaults).
cargo run --release -- --url ws://127.0.0.1:49134 --config ./config.yaml.exampleTests
# Fast, offline — exercises the pure helpers (markdown / id validators
# / fs source) without needing an iii engine.
cargo test --lib
# Full BDD suite — requires an iii engine on ws://127.0.0.1:49134
# (or III_ENGINE_WS_URL). The git-backed download scenarios spin up
# a local fixture repo via `git init`; the registry-backed scenarios
# point a wiremock server at the worker's `registry_url` config.
cargo test
# One feature group at a time. Available tags:
# @engine @read @download @download_repo @download_registry
cargo test --test bdd -- --tags @downloadThe BDD harness lives under tests/. Feature files mirror the
modules in src/functions/. Step definitions under
tests/steps/ drive each feature through the same
iii.trigger path the production binary uses.
Skills
API reference (JSON)
{
"functions": [
{
"description": "Internal: auto-download skills on worker add event.",
"metadata": {
"internal": true
},
"name": "directory::__on_worker_added",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "`worker` trigger payload for `directory::__on_worker_added`. Only `worker` is read; declared as a struct so the function publishes a typed schema.",
"properties": {
"worker": {
"default": null,
"type": [
"string",
"null"
]
}
},
"title": "WorkerAddedEvent",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ok": {
"type": "boolean"
}
},
"required": [
"ok"
],
"title": "WorkerAddedAck",
"type": "object"
}
},
{
"description": "Create a new agent profile at <agents_folder>/<id>.md from full-file markdown (frontmatter with a non-empty `name`, emoji-only `logo`, optional `skills:` preloads, `skills_index: false` to start sessions without the skills index, and `functions:` list of engine function ids to pre-load into sessions; the body is the system prompt and may be empty). Rejects ids or paths that already exist; a bundled id is shadowed.",
"metadata": {
"tool": {
"label": "Create agent profile"
}
},
"name": "directory::agents::create",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"content": {
"description": "Full file content, frontmatter included; `name` is required, the body is the system prompt and may be empty.",
"type": "string"
},
"id": {
"description": "New profile id, used as the file stem; lowercase ASCII, digits, `-` and `_` only, and not already taken.",
"type": "string"
}
},
"required": [
"content",
"id"
],
"title": "AgentCreateInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"bytes": {
"description": "Bytes written.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"logo": {
"type": [
"string",
"null"
]
},
"modified_at": {
"description": "File mtime after the write, RFC 3339.",
"type": "string"
},
"name": {
"description": "Display name parsed from the (new) frontmatter.",
"type": "string"
}
},
"required": [
"bytes",
"description",
"id",
"modified_at",
"name"
],
"title": "AgentWriteOutput",
"type": "object"
}
},
{
"description": "Delete one existing agent profile's markdown file by id. Deleting the local shadow of a bundled profile falls back to the bundled copy; profiles that extend it stop resolving until fixed.",
"metadata": {
"tool": {
"label": "Delete agent profile"
}
},
"name": "directory::agents::delete",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"description": "Existing agent profile id, as returned by `directory::agents::list`.",
"type": "string"
}
},
"required": [
"id"
],
"title": "AgentDeleteInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"title": "AgentDeleteOutput",
"type": "object"
}
},
{
"description": "Add preloaded functions to one existing agent profile: appends the given engine function ids (e.g. `coder::tree`) to the profile's own `functions:` list — the contracts the harness pre-loads into the system prompt of every new session running as this profile. Ids already present are kept once; the rest of the file is untouched. Editing a bundled profile creates the local file that shadows it.",
"metadata": {
"tool": {
"label": "Add agent profile functions"
}
},
"name": "directory::agents::functions::add",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"functions": {
"description": "Engine function ids (e.g. `coder::tree`), verbatim, one per entry.",
"items": {
"type": "string"
},
"type": "array"
},
"id": {
"description": "Existing agent profile id, as returned by `directory::agents::list`.",
"type": "string"
}
},
"required": [
"functions",
"id"
],
"title": "AgentFunctionsInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"added": {
"description": "Ids this call actually added (already-present ids are not repeated).",
"items": {
"type": "string"
},
"type": "array"
},
"bytes": {
"description": "Bytes on disk after the call.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"functions": {
"description": "The profile's OWN `functions:` list after the write (not resolved through `extends`), in file order.",
"items": {
"type": "string"
},
"type": "array"
},
"id": {
"type": "string"
},
"modified_at": {
"description": "File mtime after the call, RFC 3339.",
"type": "string"
},
"removed": {
"description": "Ids this call actually removed (absent ids are ignored).",
"items": {
"type": "string"
},
"type": "array"
},
"unchanged": {
"description": "True when the request changed nothing; the file was not rewritten.",
"type": "boolean"
}
},
"required": [
"added",
"bytes",
"functions",
"id",
"modified_at",
"removed",
"unchanged"
],
"title": "AgentFunctionsOutput",
"type": "object"
}
},
{
"description": "Remove preloaded functions from one existing agent profile: drops the given engine function ids from the profile's own `functions:` list (ids not present are ignored); the rest of the file is untouched. Only the profile's OWN list is edited; ids inherited through `extends` stay (the resolved list is the union of the chain) and are removed on the parent.",
"metadata": {
"tool": {
"label": "Remove agent profile functions"
}
},
"name": "directory::agents::functions::remove",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"functions": {
"description": "Engine function ids (e.g. `coder::tree`), verbatim, one per entry.",
"items": {
"type": "string"
},
"type": "array"
},
"id": {
"description": "Existing agent profile id, as returned by `directory::agents::list`.",
"type": "string"
}
},
"required": [
"functions",
"id"
],
"title": "AgentFunctionsInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"added": {
"description": "Ids this call actually added (already-present ids are not repeated).",
"items": {
"type": "string"
},
"type": "array"
},
"bytes": {
"description": "Bytes on disk after the call.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"functions": {
"description": "The profile's OWN `functions:` list after the write (not resolved through `extends`), in file order.",
"items": {
"type": "string"
},
"type": "array"
},
"id": {
"type": "string"
},
"modified_at": {
"description": "File mtime after the call, RFC 3339.",
"type": "string"
},
"removed": {
"description": "Ids this call actually removed (absent ids are ignored).",
"items": {
"type": "string"
},
"type": "array"
},
"unchanged": {
"description": "True when the request changed nothing; the file was not rewritten.",
"type": "boolean"
}
},
"required": [
"added",
"bytes",
"functions",
"id",
"modified_at",
"removed",
"unchanged"
],
"title": "AgentFunctionsOutput",
"type": "object"
}
},
{
"description": "Fetch one agent profile by id: the system prompt resolved through its `extends` chain, display fields, preloaded `skills` (skill ids whose bodies the harness pre-loads into the session prompt) plus `unknown_skills`, preloaded `functions` (engine function ids the harness pre-loads into the session prompt) plus `unknown_functions`, model, reasoning_effort, `skills_index` (false = sessions start without the skills index), and `inheritance_error` when the chain does not resolve. Pass raw: true for the exact on-disk file to edit with directory::agents::update.",
"metadata": {},
"name": "directory::agents::get",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string"
},
"raw": {
"default": null,
"description": "When true, also return the exact on-disk file (frontmatter included) as `raw`, ready for directory::agents::update.",
"type": [
"boolean",
"null"
]
}
},
"required": [
"id"
],
"title": "AgentGetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AgentSource": {
"description": "`source` on `directory::agents::list` / `get` rows.",
"properties": {
"kind": {
"$ref": "#/definitions/SourceKind"
},
"kit": {
"description": "Owning kit (`<handle>/<name>`) when `kind` is `kit`.",
"type": [
"string",
"null"
]
},
"modified": {
"description": "The file differs from what its kit or worker wrote.",
"type": [
"boolean",
"null"
]
},
"version": {
"description": "Version of the kit or worker that wrote the file.",
"type": [
"string",
"null"
]
},
"worker": {
"description": "Owning worker when `kind` is `worker`.",
"type": [
"string",
"null"
]
}
},
"required": [
"kind"
],
"type": "object"
},
"SourceKind": {
"enum": [
"kit",
"worker",
"local",
"global",
"builtin"
],
"type": "string"
}
},
"properties": {
"builtin": {
"description": "Bundled with the worker, no file behind it (see `list`).",
"type": "boolean"
},
"color": {
"description": "Harness subagent color token (closed set, validated at write time); `null` = neutral.",
"type": [
"string",
"null"
]
},
"composer_placeholder": {
"description": "Example request for the chat's empty composer (see `list`): this profile's own value, never inherited; omitted when absent or blank.",
"type": [
"string",
"null"
]
},
"description": {
"type": "string"
},
"extends": {
"description": "Parent profile id (`extends:`), as declared; `null` = none.",
"type": [
"string",
"null"
]
},
"functions": {
"description": "Preloaded functions, resolved through `extends` (the nearest profile with a non-empty list): engine function ids whose contracts the harness pre-loads into the system prompt of every session running as this profile, so the model calls them without discovery or a contract lookup. Empty = none.",
"items": {
"type": "string"
},
"type": "array"
},
"hidden": {
"description": "Hidden from the chat's new-session gallery (still selectable by id).",
"type": "boolean"
},
"icon": {
"description": "Harness subagent icon token (closed set, validated at write time); `null` = caller picks.",
"type": [
"string",
"null"
]
},
"id": {
"type": "string"
},
"inheritance_error": {
"description": "Set when the `extends` chain does not resolve (unknown parent, loop, deeper than 8): `system_prompt` and the inherited fields then come from this file alone, `raw` still round-trips so the chain can be fixed, and the harness refuses to run the profile meanwhile.",
"type": [
"string",
"null"
]
},
"logo": {
"type": [
"string",
"null"
]
},
"model": {
"description": "Model id for sessions using this profile, resolved through `extends`; `null` = the send decides. Served verbatim — resolution against the live model catalog happens where it is used.",
"type": [
"string",
"null"
]
},
"modified_at": {
"description": "File mtime as RFC 3339; empty for a bundled profile.",
"type": "string"
},
"name": {
"type": "string"
},
"raw": {
"description": "FULL on-disk file content (this profile's own file, ancestors excluded). Present only when the request set `raw: true`.",
"type": [
"string",
"null"
]
},
"reasoning_effort": {
"description": "Provider-native reasoning effort paired with `model`, resolved through `extends`; `null` = the model/provider default. Served verbatim and validated at use time.",
"type": [
"string",
"null"
]
},
"skills": {
"description": "Preloaded skills, resolved through `extends` (the union of the chain's lists, root first): skill ids whose bodies the harness pre-loads into the system prompt of every session running as this profile. Empty = none. Never a filter on the skills index.",
"items": {
"type": "string"
},
"type": "array"
},
"skills_index": {
"description": "`false` = sessions running as this profile start without the names-only skills index (`<available_skills>`), resolved through `extends`; omitted when no profile in the chain sets it (on).",
"type": [
"boolean",
"null"
]
},
"source": {
"allOf": [
{
"$ref": "#/definitions/AgentSource"
}
],
"description": "Where the file came from (see `list`)."
},
"system_prompt": {
"description": "The RESOLVED identity: every ancestor's body root-first, then this file's body, frontmatter stripped, joined by a blank line; blank bodies are skipped, so a profile with no prompt of its own serves its parent chain unchanged and a prompt-less profile without `extends` serves `\"\"`. A profile that has a body and no `extends` serves that body verbatim.",
"type": "string"
},
"unknown_functions": {
"description": "`functions` entries the engine does not currently know (not registered right now, or a typo). Warnings — the profile still loads and the harness skips them; an empty list also results when the engine could not be asked.",
"items": {
"type": "string"
},
"type": "array"
},
"unknown_skills": {
"description": "`skills` entries that resolve to no currently visible skill. Warnings — the agent profile still loads and the harness renders them as unavailable.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"builtin",
"description",
"functions",
"hidden",
"id",
"modified_at",
"name",
"skills",
"source",
"system_prompt",
"unknown_functions",
"unknown_skills"
],
"title": "AgentGetOutput",
"type": "object"
}
},
{
"description": "List agent profiles (id, name, description, logo, icon, color, model, reasoning_effort, skill_count, function_count, extends, hidden, composer_placeholder, source, modified_at) from the agents folder plus the bundled ones (`builtin: true`). `source` says where each file came from: kit, worker, local, global or builtin. Inherited fields resolve through `extends` (composer_placeholder never inherits); skill_count null means no preloaded skills, function_count counts the preloaded functions (contracts injected into new sessions).",
"metadata": {},
"name": "directory::agents::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ListAgentsInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AgentEntry": {
"properties": {
"builtin": {
"description": "Bundled with the worker, no file behind it: editing it creates the local file (which then shadows this entry); there is nothing to delete.",
"type": "boolean"
},
"color": {
"description": "Harness subagent color token for display identities; `null` = neutral.",
"type": [
"string",
"null"
]
},
"composer_placeholder": {
"description": "Example request for the chat's empty composer, from this profile's OWN frontmatter (never inherited through `extends`); omitted when absent or blank. Presentation only — never part of the prompt.",
"type": [
"string",
"null"
]
},
"description": {
"type": "string"
},
"extends": {
"description": "Parent profile id (`extends:`), as declared; `null` = none.",
"type": [
"string",
"null"
]
},
"function_count": {
"description": "Number of preloaded functions (contracts the harness pre-loads into the session prompt), resolved through `extends`; `0` = none.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"hidden": {
"description": "Hidden from the chat's new-session gallery (still selectable by id).",
"type": "boolean"
},
"icon": {
"description": "Harness subagent icon token for spawn display identities; `null` = caller picks.",
"type": [
"string",
"null"
]
},
"id": {
"description": "Flat agent profile id (the file stem) — what `harness::send { options: { agent } }` will take.",
"type": "string"
},
"inheritance_error": {
"description": "Set when the `extends` chain does not resolve (unknown parent, loop, too deep): the row carries the profile's own fields only, and the harness refuses to run it until the chain is fixed.",
"type": [
"string",
"null"
]
},
"logo": {
"description": "Emoji logo, `null` when the agent profile has none.",
"type": [
"string",
"null"
]
},
"model": {
"description": "Model id for sessions using this profile, resolved through `extends`; `null` = the send decides.",
"type": [
"string",
"null"
]
},
"modified_at": {
"description": "File mtime as RFC 3339; empty for a bundled profile.",
"type": "string"
},
"name": {
"description": "Display name from frontmatter (`name:`).",
"type": "string"
},
"reasoning_effort": {
"description": "Provider-native reasoning effort paired with `model`, resolved through `extends`; `null` = the model/provider default.",
"type": [
"string",
"null"
]
},
"skill_count": {
"description": "Number of preloaded skills (bodies the harness pre-loads into the session prompt), resolved through `extends`; `null` = none.",
"format": "uint",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"source": {
"allOf": [
{
"$ref": "#/definitions/AgentSource"
}
],
"description": "Where the file came from: an installed kit (`kits.lock`), a worker's skills bundle (its completion marker), the project itself (`local`), the user-global root (`global`) or the worker binary (`builtin`). `modified` says whether a kit's or worker's file was edited here."
}
},
"required": [
"builtin",
"description",
"function_count",
"hidden",
"id",
"modified_at",
"name",
"source"
],
"type": "object"
},
"AgentSource": {
"description": "`source` on `directory::agents::list` / `get` rows.",
"properties": {
"kind": {
"$ref": "#/definitions/SourceKind"
},
"kit": {
"description": "Owning kit (`<handle>/<name>`) when `kind` is `kit`.",
"type": [
"string",
"null"
]
},
"modified": {
"description": "The file differs from what its kit or worker wrote.",
"type": [
"boolean",
"null"
]
},
"version": {
"description": "Version of the kit or worker that wrote the file.",
"type": [
"string",
"null"
]
},
"worker": {
"description": "Owning worker when `kind` is `worker`.",
"type": [
"string",
"null"
]
}
},
"required": [
"kind"
],
"type": "object"
},
"SourceKind": {
"enum": [
"kit",
"worker",
"local",
"global",
"builtin"
],
"type": "string"
}
},
"properties": {
"agents": {
"items": {
"$ref": "#/definitions/AgentEntry"
},
"type": "array"
}
},
"required": [
"agents"
],
"title": "ListAgentsOutput",
"type": "object"
}
},
{
"description": "Overwrite one existing agent profile with full-file markdown (frontmatter with a non-empty `name`, emoji-only `logo`, optional `skills:` and `functions:` lists and `skills_index`; the body is the system prompt and may be empty). Updating a bundled profile creates a local file that shadows it. To change only the preloaded functions, prefer directory::agents::functions::add / remove.",
"metadata": {
"tool": {
"label": "Update agent profile"
}
},
"name": "directory::agents::update",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"content": {
"description": "FULL new file content, frontmatter block included — the string `directory::agents::get { raw: true }` returns, edited.",
"type": "string"
},
"id": {
"description": "Existing agent profile id, as returned by `directory::agents::list`.",
"type": "string"
}
},
"required": [
"content",
"id"
],
"title": "AgentUpdateInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"bytes": {
"description": "Bytes written.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"logo": {
"type": [
"string",
"null"
]
},
"modified_at": {
"description": "File mtime after the write, RFC 3339.",
"type": "string"
},
"name": {
"description": "Display name parsed from the (new) frontmatter.",
"type": "string"
}
},
"required": [
"bytes",
"description",
"id",
"modified_at",
"name"
],
"title": "AgentWriteOutput",
"type": "object"
}
},
{
"description": "Plan the install of a kit — agent profiles, skills and registry workers published as <author>/<kit>[@version|tag|range] — without writing anything; an installed kit gets an update plan. The plan lists every file, collisions with existing profiles (kit profiles win, with a warning), worker changes and the functions the profiles preload. Review it in the ADE (Directory → Kits) or apply it with directory::kits::apply plan_id=…. apply=true applies at once only when the plan has no warnings, blocks or pending decisions.",
"metadata": {
"tool": {
"label": "Download kit"
}
},
"name": "directory::download-kit",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apply": {
"default": null,
"description": "Apply right away when the plan has no warnings, no blocking issue and no file that needs a decision (for scripts). Otherwise the plan waits for review.",
"type": [
"boolean",
"null"
]
},
"kit": {
"description": "`<author>/<kit>`, optionally `@<version|tag|range>` (default: the installed kit's `requested`, else `latest`).",
"type": "string"
}
},
"required": [
"kit"
],
"title": "DownloadKitInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AgentChanges": {
"description": "Changed frontmatter of a profile between two kit versions.",
"properties": {
"fields": {
"additionalProperties": {
"items": [
{
"type": [
"string",
"null"
]
},
{
"type": [
"string",
"null"
]
}
],
"maxItems": 2,
"minItems": 2,
"type": "array"
},
"description": "Scalar fields that changed: `field → [from, to]`.",
"type": "object"
},
"functions_added": {
"items": {
"type": "string"
},
"type": "array"
},
"functions_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_added": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_removed": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"AgentEntry": {
"description": "`AgentEntry`: parsed frontmatter of `agents/<id>.md`.",
"properties": {
"color": {
"default": null,
"type": [
"string",
"null"
]
},
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"extends": {
"default": null,
"type": [
"string",
"null"
]
},
"functions": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"hidden": {
"default": null,
"type": [
"boolean",
"null"
]
},
"icon": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"logo": {
"default": null,
"type": [
"string",
"null"
]
},
"model": {
"default": null,
"type": [
"string",
"null"
]
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"path": {
"default": "",
"type": "string"
},
"reasoning_effort": {
"default": null,
"type": [
"string",
"null"
]
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"skills": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"ApplyReport": {
"properties": {
"agents": {
"description": "Agent profile ids this kit now provides.",
"items": {
"type": "string"
},
"type": "array"
},
"agents_changed": {
"type": "boolean"
},
"files_kept": {
"description": "Files left as they are (kept, skipped, or mine).",
"items": {
"type": "string"
},
"type": "array"
},
"files_merged": {
"items": {
"type": "string"
},
"type": "array"
},
"files_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"files_written": {
"items": {
"type": "string"
},
"type": "array"
},
"from": {
"type": [
"string",
"null"
]
},
"kind": {
"anyOf": [
{
"$ref": "#/definitions/PlanKind"
},
{
"type": "null"
}
]
},
"kit": {
"type": "string"
},
"lock_path": {
"type": "string"
},
"plan_id": {
"type": "string"
},
"skills_changed": {
"type": "boolean"
},
"steps": {
"items": {
"$ref": "#/definitions/ApplyStep"
},
"type": "array"
},
"to": {
"type": [
"string",
"null"
]
},
"workers_added": {
"items": {
"type": "string"
},
"type": "array"
},
"workers_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"workers_updated": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"agents",
"agents_changed",
"files_kept",
"files_merged",
"files_removed",
"files_written",
"kit",
"lock_path",
"plan_id",
"skills_changed",
"steps",
"workers_added",
"workers_removed",
"workers_updated"
],
"type": "object"
},
"ApplyStep": {
"properties": {
"detail": {
"type": [
"string",
"null"
]
},
"id": {
"description": "`workers` | `files` | `lock`.",
"type": "string"
},
"label": {
"type": "string"
},
"state": {
"$ref": "#/definitions/StepState"
}
},
"required": [
"id",
"label",
"state"
],
"type": "object"
},
"Author": {
"properties": {
"handle": {
"default": "",
"type": "string"
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"verified": {
"default": false,
"type": "boolean"
}
},
"type": "object"
},
"Capabilities": {
"properties": {
"functions_added": {
"default": [],
"items": {
"$ref": "#/definitions/FunctionAdded"
},
"type": "array"
},
"models_changed": {
"default": [],
"items": {
"$ref": "#/definitions/ModelChanged"
},
"type": "array"
},
"workers_added": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"Change": {
"oneOf": [
{
"enum": [
"added",
"modified",
"removed"
],
"type": "string"
},
{
"description": "The lock keeps the user's choice to skip this file; the kit's version changed and is offered again.",
"enum": [
"kept"
],
"type": "string"
}
]
},
"Collision": {
"properties": {
"kit": {
"type": [
"string",
"null"
]
},
"modified": {
"description": "The owner's copy was edited locally.",
"type": [
"boolean",
"null"
]
},
"owner": {
"allOf": [
{
"$ref": "#/definitions/SourceKind"
}
],
"description": "Who owns the file at the path today."
},
"sha256": {
"description": "sha256 of the file there now.",
"type": [
"string",
"null"
]
},
"version": {
"type": [
"string",
"null"
]
},
"worker": {
"type": [
"string",
"null"
]
}
},
"required": [
"owner"
],
"type": "object"
},
"Decision": {
"description": "A per-file choice.",
"oneOf": [
{
"description": "Write the kit's file over what is there.",
"enum": [
"overwrite"
],
"type": "string"
},
{
"description": "Keep what is there; the lock marks the kit's file `skipped`.",
"enum": [
"keep"
],
"type": "string"
},
{
"description": "Take the kit's new version (drops local edits).",
"enum": [
"kit"
],
"type": "string"
},
{
"description": "Keep the local file as it is.",
"enum": [
"mine"
],
"type": "string"
},
{
"description": "Write the merge result (the plan's, or `content` from the caller).",
"enum": [
"merged"
],
"type": "string"
},
{
"description": "Delete the file.",
"enum": [
"remove"
],
"type": "string"
}
]
},
"Deprecation": {
"properties": {
"message": {
"default": null,
"type": [
"string",
"null"
]
},
"replaced_by": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"FileKind": {
"enum": [
"agent",
"skill"
],
"type": "string"
},
"FunctionAdded": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"function": {
"default": "",
"type": "string"
}
},
"type": "object"
},
"Issue": {
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"path": {
"type": [
"string",
"null"
]
}
},
"required": [
"code",
"message"
],
"type": "object"
},
"KitFunction": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"status": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"worker": {
"default": null,
"type": [
"string",
"null"
]
},
"worker_version": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"LocalState": {
"description": "What the file is on disk right now, relative to the plan.",
"oneOf": [
{
"description": "Nothing at the path.",
"enum": [
"absent"
],
"type": "string"
},
{
"description": "Matches the kit's base (or, on install, the kit's content).",
"enum": [
"intact"
],
"type": "string"
},
{
"description": "Differs from the base the kit installed.",
"enum": [
"edited"
],
"type": "string"
},
{
"description": "The lock lists it but the file was deleted.",
"enum": [
"missing"
],
"type": "string"
},
{
"description": "Someone else's file sits at the path.",
"enum": [
"occupied"
],
"type": "string"
}
]
},
"MergeStatus": {
"enum": [
"clean",
"conflicts"
],
"type": "string"
},
"ModelChanged": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"from": {
"default": null,
"type": [
"string",
"null"
]
},
"to": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"Plan": {
"properties": {
"author": {
"anyOf": [
{
"$ref": "#/definitions/Author"
},
{
"type": "null"
}
]
},
"blocking": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"bump": {
"description": "`major` | `minor` | `patch` | `prerelease` (update).",
"type": [
"string",
"null"
]
},
"capabilities": {
"$ref": "#/definitions/Capabilities"
},
"counts": {
"$ref": "#/definitions/PlanCounts"
},
"created_at": {
"type": "string"
},
"deprecation": {
"anyOf": [
{
"$ref": "#/definitions/Deprecation"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"expires_at": {
"type": "string"
},
"files": {
"items": {
"$ref": "#/definitions/PlanFile"
},
"type": "array"
},
"from": {
"description": "Installed version (update, remove).",
"type": [
"string",
"null"
]
},
"functions": {
"description": "Functions the kit's profiles preload, with the worker that provides each.",
"items": {
"$ref": "#/definitions/KitFunction"
},
"type": "array"
},
"kind": {
"$ref": "#/definitions/PlanKind"
},
"kit": {
"type": "string"
},
"license": {
"type": [
"string",
"null"
]
},
"major": {
"type": "boolean"
},
"notes": {
"type": [
"string",
"null"
]
},
"plan_id": {
"type": "string"
},
"published_at": {
"type": [
"string",
"null"
]
},
"registry_url": {
"description": "The kit's page in the registry web app.",
"type": "string"
},
"repo": {
"type": [
"string",
"null"
]
},
"requested": {
"description": "What was asked for (tag, version or range) — stored in the lock.",
"type": "string"
},
"review": {
"description": "Where a human reviews it.",
"type": "string"
},
"to": {
"description": "Version this plan installs (install, update).",
"type": [
"string",
"null"
]
},
"warnings": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"workers": {
"items": {
"$ref": "#/definitions/PlanWorker"
},
"type": "array"
}
},
"required": [
"blocking",
"capabilities",
"counts",
"created_at",
"expires_at",
"files",
"functions",
"kind",
"kit",
"major",
"plan_id",
"registry_url",
"requested",
"review",
"warnings",
"workers"
],
"type": "object"
},
"PlanCounts": {
"properties": {
"added": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"agents": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"collisions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"decisions_required": {
"description": "Files whose `default` is `null`.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"functions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"modified": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"removed": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"skills": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"unchanged": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"workers": {
"format": "uint",
"minimum": 0,
"type": "integer"
}
},
"required": [
"added",
"agents",
"collisions",
"conflicts",
"decisions_required",
"functions",
"modified",
"removed",
"skills",
"unchanged",
"workers"
],
"type": "object"
},
"PlanFile": {
"properties": {
"agent": {
"anyOf": [
{
"$ref": "#/definitions/AgentEntry"
},
{
"type": "null"
}
],
"description": "Kit profile frontmatter (agents; the side this plan installs, or the removed one)."
},
"agent_changes": {
"anyOf": [
{
"$ref": "#/definitions/AgentChanges"
},
{
"type": "null"
}
],
"description": "Frontmatter changes versus the installed version (modified agents)."
},
"base": {
"description": "Content hash the kit installed (the merge base).",
"type": [
"string",
"null"
]
},
"body_changed": {
"type": [
"boolean",
"null"
]
},
"change": {
"$ref": "#/definitions/Change"
},
"collision": {
"anyOf": [
{
"$ref": "#/definitions/Collision"
},
{
"type": "null"
}
]
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"default": {
"anyOf": [
{
"$ref": "#/definitions/Decision"
},
{
"type": "null"
}
],
"description": "Applied when the caller decides nothing; `null` = a decision is required."
},
"id": {
"description": "Agent profile id, or skill id.",
"type": "string"
},
"kind": {
"$ref": "#/definitions/FileKind"
},
"local": {
"$ref": "#/definitions/LocalState"
},
"merge": {
"anyOf": [
{
"$ref": "#/definitions/MergeStatus"
},
{
"type": "null"
}
]
},
"note": {
"description": "One-line explanation for the review.",
"type": [
"string",
"null"
]
},
"options": {
"description": "Choices the apply accepts for this file.",
"items": {
"$ref": "#/definitions/Decision"
},
"type": "array"
},
"ours": {
"description": "Content hash of the local file when the plan was made.",
"type": [
"string",
"null"
]
},
"path": {
"description": "Logical install path (`agents/<id>.md`, `skills/<handle>/<kit>/…`).",
"type": "string"
},
"skill": {
"anyOf": [
{
"$ref": "#/definitions/SkillEntry"
},
{
"type": "null"
}
],
"description": "Skill frontmatter (skills)."
},
"skipped": {
"description": "The lock says the user kept someone else's file here.",
"type": "boolean"
},
"source": {
"description": "Path inside the kit (`agents/<id>.md`, `skills/…`).",
"type": "string"
},
"theirs": {
"description": "Content hash of the kit's version this plan installs.",
"type": [
"string",
"null"
]
}
},
"required": [
"change",
"id",
"kind",
"local",
"options",
"path",
"source"
],
"type": "object"
},
"PlanKind": {
"enum": [
"install",
"update",
"remove"
],
"type": "string"
},
"PlanStatus": {
"oneOf": [
{
"description": "A plan is waiting for review (or for `directory::kits::apply`).",
"enum": [
"planned"
],
"type": "string"
},
{
"description": "`apply=true` and the plan needed no review: it was applied.",
"enum": [
"applied"
],
"type": "string"
},
{
"description": "The installed version is already the one asked for.",
"enum": [
"up_to_date"
],
"type": "string"
},
{
"description": "The project changed since the plan was made; this is a fresh plan.",
"enum": [
"replanned"
],
"type": "string"
}
]
},
"PlanWorker": {
"properties": {
"action": {
"$ref": "#/definitions/WorkerAction"
},
"container": {
"type": [
"string",
"null"
]
},
"declared": {
"description": "`version:` selector in the compose file.",
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"installed": {
"description": "Version Compose has installed.",
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"path": {
"description": "The operator's `path://` build; kits never manage it.",
"type": "boolean"
},
"range": {
"description": "Range the kit declares (absent for a worker the kit dropped).",
"type": [
"string",
"null"
]
},
"range_from": {
"description": "Range the installed kit version declared.",
"type": [
"string",
"null"
]
},
"registry_url": {
"type": "string"
},
"to": {
"description": "Version the range resolves to in the registry today.",
"type": [
"string",
"null"
]
},
"type": {
"description": "Worker type (`binary`, `image`, …).",
"type": [
"string",
"null"
]
},
"used_by": {
"description": "Other installed kits that declare this worker.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"action",
"name",
"registry_url"
],
"type": "object"
},
"SkillEntry": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"path": {
"default": "",
"type": "string"
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"title": {
"default": null,
"type": [
"string",
"null"
]
},
"type": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"SourceKind": {
"enum": [
"kit",
"worker",
"local",
"global",
"builtin"
],
"type": "string"
},
"StepState": {
"enum": [
"pending",
"running",
"done",
"failed",
"skipped"
],
"type": "string"
},
"WorkerAction": {
"oneOf": [
{
"enum": [
"none"
],
"type": "string"
},
{
"description": "Not in the compose file: `compose::add` declares it with the kit's range.",
"enum": [
"add"
],
"type": "string"
},
{
"description": "Declared, but the installed version is outside the kit's range: `compose::add` re-declares the range and Compose moves the worker.",
"enum": [
"update"
],
"type": "string"
},
{
"description": "The range changed and the compose file still declares the kit's old range; the installed version already satisfies the new one, so only the declaration moves.",
"enum": [
"redeclare"
],
"type": "string"
},
{
"description": "The kit no longer declares it. Never removed unless asked (`remove_workers`).",
"enum": [
"remove"
],
"type": "string"
}
]
}
},
"description": "Response of `directory::download-kit`, `plan-update`, `remove` and `apply`.",
"properties": {
"kit": {
"type": "string"
},
"message": {
"description": "One sentence for a terminal user.",
"type": "string"
},
"plan": {
"anyOf": [
{
"$ref": "#/definitions/Plan"
},
{
"type": "null"
}
]
},
"report": {
"anyOf": [
{
"$ref": "#/definitions/ApplyReport"
},
{
"type": "null"
}
]
},
"status": {
"$ref": "#/definitions/PlanStatus"
}
},
"required": [
"kit",
"message",
"status"
],
"title": "KitPlanResponse",
"type": "object"
}
},
{
"description": "Read full detail for one engine function: schemas, owning worker, and registered triggers that target it. Proxies to the engine's native engine::functions::info.",
"metadata": {},
"name": "directory::engine::functions::info",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"function_id": {
"description": "Fully-qualified function id on the bus (e.g. `sandbox::create`).",
"type": "string"
}
},
"required": [
"function_id"
],
"title": "FunctionInfoInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"RegisteredTriggerSummary": {
"description": "Trigger instance summary for the response envelope.",
"properties": {
"config": true,
"id": {
"type": "string"
},
"trigger_type": {
"type": "string"
}
},
"required": [
"config",
"id",
"trigger_type"
],
"type": "object"
}
},
"description": "Response shape for `directory::engine::functions::info`.\n\nMirrors the shape of the old `directory::engine::functions::info` but WITHOUT the `how_guide` and `related_skills` fields.",
"properties": {
"description": {
"type": [
"string",
"null"
]
},
"function_id": {
"type": "string"
},
"metadata": true,
"registered_triggers": {
"items": {
"$ref": "#/definitions/RegisteredTriggerSummary"
},
"type": "array"
},
"request_schema": true,
"response_schema": true,
"worker_name": {
"type": [
"string",
"null"
]
}
},
"required": [
"function_id",
"registered_triggers"
],
"title": "FunctionInfoOutput",
"type": "object"
}
},
{
"description": "Internal: the exact search-hint text per exposure mode, for the configuration UI.",
"metadata": {
"internal": true,
"trace_hidden": true
},
"name": "directory::hint-preview",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "HintPreviewRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "The exact hint text per exposure mode, for the configuration UI. The live block's `functions_generation` attribute varies per generation; the preview renders it as 0.",
"properties": {
"agent_trigger": {
"type": "string"
},
"native": {
"type": "string"
}
},
"required": [
"agent_trigger",
"native"
],
"title": "HintPreviewResponse",
"type": "object"
}
},
{
"description": "Apply a kit plan from directory::download-kit / plan-update / remove: re-checks the project, downloads the kit (counted), adds or moves its workers through Compose, writes the files atomically and records kits.lock last. decisions maps install paths to overwrite|keep|kit|mine|merged|remove (or {choice: merged, content}); files left out take the plan's default. If the project changed since the plan, nothing is applied and a fresh plan comes back (status replanned).",
"metadata": {
"tool": {
"label": "Apply kit plan"
}
},
"name": "directory::kits::apply",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Decision": {
"description": "A per-file choice.",
"oneOf": [
{
"description": "Write the kit's file over what is there.",
"enum": [
"overwrite"
],
"type": "string"
},
{
"description": "Keep what is there; the lock marks the kit's file `skipped`.",
"enum": [
"keep"
],
"type": "string"
},
{
"description": "Take the kit's new version (drops local edits).",
"enum": [
"kit"
],
"type": "string"
},
{
"description": "Keep the local file as it is.",
"enum": [
"mine"
],
"type": "string"
},
{
"description": "Write the merge result (the plan's, or `content` from the caller).",
"enum": [
"merged"
],
"type": "string"
},
{
"description": "Delete the file.",
"enum": [
"remove"
],
"type": "string"
}
]
},
"DecisionInput": {
"anyOf": [
{
"$ref": "#/definitions/Decision"
},
{
"properties": {
"choice": {
"$ref": "#/definitions/Decision"
},
"content": {
"default": null,
"type": [
"string",
"null"
]
}
},
"required": [
"choice"
],
"type": "object"
}
],
"description": "A caller's choice for one file: a bare decision, or a decision with the content to write (`merged` from the conflict editor)."
}
},
"properties": {
"decisions": {
"additionalProperties": {
"$ref": "#/definitions/DecisionInput"
},
"default": null,
"description": "Per-file choices by install path: `\"overwrite\" | \"keep\" | \"kit\" | \"mine\" | \"merged\" | \"remove\"`, or `{ \"choice\": \"merged\", \"content\": \"…\" }`. Files left out take the plan's `default`.",
"type": [
"object",
"null"
]
},
"plan_id": {
"type": "string"
},
"remove_workers": {
"default": null,
"description": "Workers the kit no longer declares (update) or declares (removal) to remove from the compose file. Never removed otherwise.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
}
},
"required": [
"plan_id"
],
"title": "ApplyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AgentChanges": {
"description": "Changed frontmatter of a profile between two kit versions.",
"properties": {
"fields": {
"additionalProperties": {
"items": [
{
"type": [
"string",
"null"
]
},
{
"type": [
"string",
"null"
]
}
],
"maxItems": 2,
"minItems": 2,
"type": "array"
},
"description": "Scalar fields that changed: `field → [from, to]`.",
"type": "object"
},
"functions_added": {
"items": {
"type": "string"
},
"type": "array"
},
"functions_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_added": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_removed": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"AgentEntry": {
"description": "`AgentEntry`: parsed frontmatter of `agents/<id>.md`.",
"properties": {
"color": {
"default": null,
"type": [
"string",
"null"
]
},
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"extends": {
"default": null,
"type": [
"string",
"null"
]
},
"functions": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"hidden": {
"default": null,
"type": [
"boolean",
"null"
]
},
"icon": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"logo": {
"default": null,
"type": [
"string",
"null"
]
},
"model": {
"default": null,
"type": [
"string",
"null"
]
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"path": {
"default": "",
"type": "string"
},
"reasoning_effort": {
"default": null,
"type": [
"string",
"null"
]
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"skills": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"ApplyReport": {
"properties": {
"agents": {
"description": "Agent profile ids this kit now provides.",
"items": {
"type": "string"
},
"type": "array"
},
"agents_changed": {
"type": "boolean"
},
"files_kept": {
"description": "Files left as they are (kept, skipped, or mine).",
"items": {
"type": "string"
},
"type": "array"
},
"files_merged": {
"items": {
"type": "string"
},
"type": "array"
},
"files_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"files_written": {
"items": {
"type": "string"
},
"type": "array"
},
"from": {
"type": [
"string",
"null"
]
},
"kind": {
"anyOf": [
{
"$ref": "#/definitions/PlanKind"
},
{
"type": "null"
}
]
},
"kit": {
"type": "string"
},
"lock_path": {
"type": "string"
},
"plan_id": {
"type": "string"
},
"skills_changed": {
"type": "boolean"
},
"steps": {
"items": {
"$ref": "#/definitions/ApplyStep"
},
"type": "array"
},
"to": {
"type": [
"string",
"null"
]
},
"workers_added": {
"items": {
"type": "string"
},
"type": "array"
},
"workers_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"workers_updated": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"agents",
"agents_changed",
"files_kept",
"files_merged",
"files_removed",
"files_written",
"kit",
"lock_path",
"plan_id",
"skills_changed",
"steps",
"workers_added",
"workers_removed",
"workers_updated"
],
"type": "object"
},
"ApplyStep": {
"properties": {
"detail": {
"type": [
"string",
"null"
]
},
"id": {
"description": "`workers` | `files` | `lock`.",
"type": "string"
},
"label": {
"type": "string"
},
"state": {
"$ref": "#/definitions/StepState"
}
},
"required": [
"id",
"label",
"state"
],
"type": "object"
},
"Author": {
"properties": {
"handle": {
"default": "",
"type": "string"
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"verified": {
"default": false,
"type": "boolean"
}
},
"type": "object"
},
"Capabilities": {
"properties": {
"functions_added": {
"default": [],
"items": {
"$ref": "#/definitions/FunctionAdded"
},
"type": "array"
},
"models_changed": {
"default": [],
"items": {
"$ref": "#/definitions/ModelChanged"
},
"type": "array"
},
"workers_added": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"Change": {
"oneOf": [
{
"enum": [
"added",
"modified",
"removed"
],
"type": "string"
},
{
"description": "The lock keeps the user's choice to skip this file; the kit's version changed and is offered again.",
"enum": [
"kept"
],
"type": "string"
}
]
},
"Collision": {
"properties": {
"kit": {
"type": [
"string",
"null"
]
},
"modified": {
"description": "The owner's copy was edited locally.",
"type": [
"boolean",
"null"
]
},
"owner": {
"allOf": [
{
"$ref": "#/definitions/SourceKind"
}
],
"description": "Who owns the file at the path today."
},
"sha256": {
"description": "sha256 of the file there now.",
"type": [
"string",
"null"
]
},
"version": {
"type": [
"string",
"null"
]
},
"worker": {
"type": [
"string",
"null"
]
}
},
"required": [
"owner"
],
"type": "object"
},
"Decision": {
"description": "A per-file choice.",
"oneOf": [
{
"description": "Write the kit's file over what is there.",
"enum": [
"overwrite"
],
"type": "string"
},
{
"description": "Keep what is there; the lock marks the kit's file `skipped`.",
"enum": [
"keep"
],
"type": "string"
},
{
"description": "Take the kit's new version (drops local edits).",
"enum": [
"kit"
],
"type": "string"
},
{
"description": "Keep the local file as it is.",
"enum": [
"mine"
],
"type": "string"
},
{
"description": "Write the merge result (the plan's, or `content` from the caller).",
"enum": [
"merged"
],
"type": "string"
},
{
"description": "Delete the file.",
"enum": [
"remove"
],
"type": "string"
}
]
},
"Deprecation": {
"properties": {
"message": {
"default": null,
"type": [
"string",
"null"
]
},
"replaced_by": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"FileKind": {
"enum": [
"agent",
"skill"
],
"type": "string"
},
"FunctionAdded": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"function": {
"default": "",
"type": "string"
}
},
"type": "object"
},
"Issue": {
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"path": {
"type": [
"string",
"null"
]
}
},
"required": [
"code",
"message"
],
"type": "object"
},
"KitFunction": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"status": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"worker": {
"default": null,
"type": [
"string",
"null"
]
},
"worker_version": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"LocalState": {
"description": "What the file is on disk right now, relative to the plan.",
"oneOf": [
{
"description": "Nothing at the path.",
"enum": [
"absent"
],
"type": "string"
},
{
"description": "Matches the kit's base (or, on install, the kit's content).",
"enum": [
"intact"
],
"type": "string"
},
{
"description": "Differs from the base the kit installed.",
"enum": [
"edited"
],
"type": "string"
},
{
"description": "The lock lists it but the file was deleted.",
"enum": [
"missing"
],
"type": "string"
},
{
"description": "Someone else's file sits at the path.",
"enum": [
"occupied"
],
"type": "string"
}
]
},
"MergeStatus": {
"enum": [
"clean",
"conflicts"
],
"type": "string"
},
"ModelChanged": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"from": {
"default": null,
"type": [
"string",
"null"
]
},
"to": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"Plan": {
"properties": {
"author": {
"anyOf": [
{
"$ref": "#/definitions/Author"
},
{
"type": "null"
}
]
},
"blocking": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"bump": {
"description": "`major` | `minor` | `patch` | `prerelease` (update).",
"type": [
"string",
"null"
]
},
"capabilities": {
"$ref": "#/definitions/Capabilities"
},
"counts": {
"$ref": "#/definitions/PlanCounts"
},
"created_at": {
"type": "string"
},
"deprecation": {
"anyOf": [
{
"$ref": "#/definitions/Deprecation"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"expires_at": {
"type": "string"
},
"files": {
"items": {
"$ref": "#/definitions/PlanFile"
},
"type": "array"
},
"from": {
"description": "Installed version (update, remove).",
"type": [
"string",
"null"
]
},
"functions": {
"description": "Functions the kit's profiles preload, with the worker that provides each.",
"items": {
"$ref": "#/definitions/KitFunction"
},
"type": "array"
},
"kind": {
"$ref": "#/definitions/PlanKind"
},
"kit": {
"type": "string"
},
"license": {
"type": [
"string",
"null"
]
},
"major": {
"type": "boolean"
},
"notes": {
"type": [
"string",
"null"
]
},
"plan_id": {
"type": "string"
},
"published_at": {
"type": [
"string",
"null"
]
},
"registry_url": {
"description": "The kit's page in the registry web app.",
"type": "string"
},
"repo": {
"type": [
"string",
"null"
]
},
"requested": {
"description": "What was asked for (tag, version or range) — stored in the lock.",
"type": "string"
},
"review": {
"description": "Where a human reviews it.",
"type": "string"
},
"to": {
"description": "Version this plan installs (install, update).",
"type": [
"string",
"null"
]
},
"warnings": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"workers": {
"items": {
"$ref": "#/definitions/PlanWorker"
},
"type": "array"
}
},
"required": [
"blocking",
"capabilities",
"counts",
"created_at",
"expires_at",
"files",
"functions",
"kind",
"kit",
"major",
"plan_id",
"registry_url",
"requested",
"review",
"warnings",
"workers"
],
"type": "object"
},
"PlanCounts": {
"properties": {
"added": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"agents": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"collisions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"decisions_required": {
"description": "Files whose `default` is `null`.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"functions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"modified": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"removed": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"skills": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"unchanged": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"workers": {
"format": "uint",
"minimum": 0,
"type": "integer"
}
},
"required": [
"added",
"agents",
"collisions",
"conflicts",
"decisions_required",
"functions",
"modified",
"removed",
"skills",
"unchanged",
"workers"
],
"type": "object"
},
"PlanFile": {
"properties": {
"agent": {
"anyOf": [
{
"$ref": "#/definitions/AgentEntry"
},
{
"type": "null"
}
],
"description": "Kit profile frontmatter (agents; the side this plan installs, or the removed one)."
},
"agent_changes": {
"anyOf": [
{
"$ref": "#/definitions/AgentChanges"
},
{
"type": "null"
}
],
"description": "Frontmatter changes versus the installed version (modified agents)."
},
"base": {
"description": "Content hash the kit installed (the merge base).",
"type": [
"string",
"null"
]
},
"body_changed": {
"type": [
"boolean",
"null"
]
},
"change": {
"$ref": "#/definitions/Change"
},
"collision": {
"anyOf": [
{
"$ref": "#/definitions/Collision"
},
{
"type": "null"
}
]
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"default": {
"anyOf": [
{
"$ref": "#/definitions/Decision"
},
{
"type": "null"
}
],
"description": "Applied when the caller decides nothing; `null` = a decision is required."
},
"id": {
"description": "Agent profile id, or skill id.",
"type": "string"
},
"kind": {
"$ref": "#/definitions/FileKind"
},
"local": {
"$ref": "#/definitions/LocalState"
},
"merge": {
"anyOf": [
{
"$ref": "#/definitions/MergeStatus"
},
{
"type": "null"
}
]
},
"note": {
"description": "One-line explanation for the review.",
"type": [
"string",
"null"
]
},
"options": {
"description": "Choices the apply accepts for this file.",
"items": {
"$ref": "#/definitions/Decision"
},
"type": "array"
},
"ours": {
"description": "Content hash of the local file when the plan was made.",
"type": [
"string",
"null"
]
},
"path": {
"description": "Logical install path (`agents/<id>.md`, `skills/<handle>/<kit>/…`).",
"type": "string"
},
"skill": {
"anyOf": [
{
"$ref": "#/definitions/SkillEntry"
},
{
"type": "null"
}
],
"description": "Skill frontmatter (skills)."
},
"skipped": {
"description": "The lock says the user kept someone else's file here.",
"type": "boolean"
},
"source": {
"description": "Path inside the kit (`agents/<id>.md`, `skills/…`).",
"type": "string"
},
"theirs": {
"description": "Content hash of the kit's version this plan installs.",
"type": [
"string",
"null"
]
}
},
"required": [
"change",
"id",
"kind",
"local",
"options",
"path",
"source"
],
"type": "object"
},
"PlanKind": {
"enum": [
"install",
"update",
"remove"
],
"type": "string"
},
"PlanStatus": {
"oneOf": [
{
"description": "A plan is waiting for review (or for `directory::kits::apply`).",
"enum": [
"planned"
],
"type": "string"
},
{
"description": "`apply=true` and the plan needed no review: it was applied.",
"enum": [
"applied"
],
"type": "string"
},
{
"description": "The installed version is already the one asked for.",
"enum": [
"up_to_date"
],
"type": "string"
},
{
"description": "The project changed since the plan was made; this is a fresh plan.",
"enum": [
"replanned"
],
"type": "string"
}
]
},
"PlanWorker": {
"properties": {
"action": {
"$ref": "#/definitions/WorkerAction"
},
"container": {
"type": [
"string",
"null"
]
},
"declared": {
"description": "`version:` selector in the compose file.",
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"installed": {
"description": "Version Compose has installed.",
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"path": {
"description": "The operator's `path://` build; kits never manage it.",
"type": "boolean"
},
"range": {
"description": "Range the kit declares (absent for a worker the kit dropped).",
"type": [
"string",
"null"
]
},
"range_from": {
"description": "Range the installed kit version declared.",
"type": [
"string",
"null"
]
},
"registry_url": {
"type": "string"
},
"to": {
"description": "Version the range resolves to in the registry today.",
"type": [
"string",
"null"
]
},
"type": {
"description": "Worker type (`binary`, `image`, …).",
"type": [
"string",
"null"
]
},
"used_by": {
"description": "Other installed kits that declare this worker.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"action",
"name",
"registry_url"
],
"type": "object"
},
"SkillEntry": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"path": {
"default": "",
"type": "string"
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"title": {
"default": null,
"type": [
"string",
"null"
]
},
"type": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"SourceKind": {
"enum": [
"kit",
"worker",
"local",
"global",
"builtin"
],
"type": "string"
},
"StepState": {
"enum": [
"pending",
"running",
"done",
"failed",
"skipped"
],
"type": "string"
},
"WorkerAction": {
"oneOf": [
{
"enum": [
"none"
],
"type": "string"
},
{
"description": "Not in the compose file: `compose::add` declares it with the kit's range.",
"enum": [
"add"
],
"type": "string"
},
{
"description": "Declared, but the installed version is outside the kit's range: `compose::add` re-declares the range and Compose moves the worker.",
"enum": [
"update"
],
"type": "string"
},
{
"description": "The range changed and the compose file still declares the kit's old range; the installed version already satisfies the new one, so only the declaration moves.",
"enum": [
"redeclare"
],
"type": "string"
},
{
"description": "The kit no longer declares it. Never removed unless asked (`remove_workers`).",
"enum": [
"remove"
],
"type": "string"
}
]
}
},
"description": "Response of `directory::download-kit`, `plan-update`, `remove` and `apply`.",
"properties": {
"kit": {
"type": "string"
},
"message": {
"description": "One sentence for a terminal user.",
"type": "string"
},
"plan": {
"anyOf": [
{
"$ref": "#/definitions/Plan"
},
{
"type": "null"
}
]
},
"report": {
"anyOf": [
{
"$ref": "#/definitions/ApplyReport"
},
{
"type": "null"
}
]
},
"status": {
"$ref": "#/definitions/PlanStatus"
}
},
"required": [
"kit",
"message",
"status"
],
"title": "KitPlanResponse",
"type": "object"
}
},
{
"description": "Ask the registry whether installed kits (or one) have a newer release matching what they were installed with. Ignored versions are skipped. Also runs at boot and every 6 hours.",
"metadata": {
"tool": {
"label": "Check kit updates"
}
},
"name": "directory::kits::check-updates",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"kit": {
"default": null,
"description": "Check only this installed kit (default: every installed kit).",
"type": [
"string",
"null"
]
}
},
"title": "CheckUpdatesInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Deprecation": {
"properties": {
"message": {
"default": null,
"type": [
"string",
"null"
]
},
"replaced_by": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"KitUpdateEntry": {
"properties": {
"available": {
"description": "Newest version satisfying `requested`, unless the user ignored it.",
"type": [
"string",
"null"
]
},
"current": {
"type": "string"
},
"deprecation": {
"anyOf": [
{
"$ref": "#/definitions/Deprecation"
},
{
"type": "null"
}
]
},
"ignored": {
"description": "`available` would be this version, but the user ignored it.",
"type": [
"string",
"null"
]
},
"kit": {
"type": "string"
},
"latest": {
"type": [
"string",
"null"
]
},
"major": {
"type": "boolean"
},
"not_found": {
"type": "boolean"
}
},
"required": [
"current",
"kit",
"major"
],
"type": "object"
}
},
"description": "Response of `directory::kits::check-updates`.",
"properties": {
"available": {
"description": "Installed kits with an update to offer.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"checked_at": {
"type": [
"string",
"null"
]
},
"error": {
"description": "Why the last check could not reach the registry, if it could not.",
"type": [
"string",
"null"
]
},
"kits": {
"items": {
"$ref": "#/definitions/KitUpdateEntry"
},
"type": "array"
}
},
"required": [
"available",
"kits"
],
"title": "CheckUpdatesOutput",
"type": "object"
}
},
{
"description": "The two sides of an installed kit file: `base` (what the kit installed, from the registry) and `local` (the file on disk), for a \"view my changes\" diff.",
"metadata": {},
"name": "directory::kits::diff",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"kit": {
"description": "Installed kit, `<author>/<kit>`.",
"type": "string"
},
"path": {
"description": "Install path from `directory::kits::get` (`agents/<id>.md`, `skills/…`).",
"type": "string"
}
},
"required": [
"kit",
"path"
],
"title": "DiffInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"FileState": {
"description": "Local state of an installed file relative to its lock entry.",
"oneOf": [
{
"enum": [
"intact",
"edited",
"missing"
],
"type": "string"
},
{
"description": "The lock records the user's choice to keep someone else's file.",
"enum": [
"skipped"
],
"type": "string"
}
]
}
},
"description": "`directory::kits::diff`: the base the kit installed and the file on disk. Response of `directory::kits::diff`.",
"properties": {
"base": {
"description": "What the kit installed (the lock's base), from the registry; `null` when the registry does not have it.",
"type": [
"string",
"null"
]
},
"kit": {
"type": "string"
},
"local": {
"description": "The file on disk, `null` when it is missing.",
"type": [
"string",
"null"
]
},
"path": {
"type": "string"
},
"state": {
"$ref": "#/definitions/FileState"
}
},
"required": [
"kit",
"path",
"state"
],
"title": "FileSides",
"type": "object"
}
},
{
"description": "Discard a pending kit plan.",
"metadata": {},
"name": "directory::kits::discard",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"plan_id": {
"type": "string"
}
},
"required": [
"plan_id"
],
"title": "PlanIdInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"discarded": {
"type": "boolean"
},
"plan_id": {
"type": "string"
}
},
"required": [
"discarded",
"plan_id"
],
"title": "DiscardOutput",
"type": "object"
}
},
{
"description": "One installed kit: every file with its state (intact, edited, missing, skipped), its workers as Compose has them, and with registry=true the installed version's detail and README.",
"metadata": {},
"name": "directory::kits::get",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"kit": {
"description": "Installed kit, `<author>/<kit>`.",
"type": "string"
},
"registry": {
"default": null,
"description": "Also fetch the installed version's registry detail and README.",
"type": [
"boolean",
"null"
]
}
},
"required": [
"kit"
],
"title": "GetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AgentEntry": {
"description": "`AgentEntry`: parsed frontmatter of `agents/<id>.md`.",
"properties": {
"color": {
"default": null,
"type": [
"string",
"null"
]
},
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"extends": {
"default": null,
"type": [
"string",
"null"
]
},
"functions": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"hidden": {
"default": null,
"type": [
"boolean",
"null"
]
},
"icon": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"logo": {
"default": null,
"type": [
"string",
"null"
]
},
"model": {
"default": null,
"type": [
"string",
"null"
]
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"path": {
"default": "",
"type": "string"
},
"reasoning_effort": {
"default": null,
"type": [
"string",
"null"
]
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"skills": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"Author": {
"properties": {
"handle": {
"default": "",
"type": "string"
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"verified": {
"default": false,
"type": "boolean"
}
},
"type": "object"
},
"Deprecation": {
"properties": {
"message": {
"default": null,
"type": [
"string",
"null"
]
},
"replaced_by": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"FileCounts": {
"properties": {
"agents": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"edited": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"intact": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"missing": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"skills": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"skipped": {
"format": "uint",
"minimum": 0,
"type": "integer"
}
},
"required": [
"agents",
"edited",
"intact",
"missing",
"skills",
"skipped"
],
"type": "object"
},
"FileState": {
"description": "Local state of an installed file relative to its lock entry.",
"oneOf": [
{
"enum": [
"intact",
"edited",
"missing"
],
"type": "string"
},
{
"description": "The lock records the user's choice to keep someone else's file.",
"enum": [
"skipped"
],
"type": "string"
}
]
},
"InstalledFile": {
"properties": {
"id": {
"description": "Agent id, or the skill id.",
"type": "string"
},
"kind": {
"type": "string"
},
"local_sha256": {
"description": "sha256 on disk, `null` when missing.",
"type": [
"string",
"null"
]
},
"path": {
"type": "string"
},
"sha256": {
"description": "Base sha256 from the lock.",
"type": "string"
},
"state": {
"$ref": "#/definitions/FileState"
}
},
"required": [
"id",
"kind",
"path",
"sha256",
"state"
],
"type": "object"
},
"KitCounts": {
"properties": {
"agents": {
"default": 0,
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"skills": {
"default": 0,
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"workers": {
"default": 0,
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"type": "object"
},
"KitDetail": {
"description": "`KitDetail` (`GET /k/:author/:name?version=`).",
"properties": {
"agents": {
"default": [],
"items": {
"$ref": "#/definitions/AgentEntry"
},
"type": "array"
},
"author": {
"allOf": [
{
"$ref": "#/definitions/Author"
}
],
"default": {
"handle": "",
"name": null,
"verified": false
}
},
"counts": {
"allOf": [
{
"$ref": "#/definitions/KitCounts"
}
],
"default": {
"agents": 0,
"skills": 0,
"workers": 0
}
},
"deprecation": {
"anyOf": [
{
"$ref": "#/definitions/Deprecation"
},
{
"type": "null"
}
],
"default": null
},
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"experimental": {
"default": null,
"type": [
"boolean",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"license": {
"default": null,
"type": [
"string",
"null"
]
},
"name": {
"default": "",
"type": "string"
},
"notes": {
"default": null,
"type": [
"string",
"null"
]
},
"published_at": {
"default": null,
"type": [
"string",
"null"
]
},
"release_tags": {
"additionalProperties": {
"type": "string"
},
"default": {},
"type": "object"
},
"repo": {
"default": null,
"type": [
"string",
"null"
]
},
"skills": {
"default": [],
"items": {
"$ref": "#/definitions/SkillEntry"
},
"type": "array"
},
"tags": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"total_downloads": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"version": {
"default": "",
"type": "string"
},
"workers": {
"default": [],
"items": {
"$ref": "#/definitions/KitWorker"
},
"type": "array"
}
},
"type": "object"
},
"KitUpdate": {
"properties": {
"available": {
"description": "Newest version satisfying `requested`, unless the user ignored it.",
"type": [
"string",
"null"
]
},
"current": {
"type": "string"
},
"deprecation": {
"anyOf": [
{
"$ref": "#/definitions/Deprecation"
},
{
"type": "null"
}
]
},
"ignored": {
"description": "`available` would be this version, but the user ignored it.",
"type": [
"string",
"null"
]
},
"latest": {
"type": [
"string",
"null"
]
},
"major": {
"type": "boolean"
},
"not_found": {
"type": "boolean"
}
},
"required": [
"current",
"major"
],
"type": "object"
},
"KitWorker": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"name": {
"default": "",
"type": "string"
},
"range": {
"default": "",
"type": "string"
},
"resolved": {
"default": null,
"type": [
"string",
"null"
]
},
"type": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"SkillEntry": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"path": {
"default": "",
"type": "string"
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"title": {
"default": null,
"type": [
"string",
"null"
]
},
"type": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
}
},
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/KitDetail"
},
{
"type": "null"
}
],
"description": "Registry detail of the installed version, when reachable."
},
"file_list": {
"items": {
"$ref": "#/definitions/InstalledFile"
},
"type": "array"
},
"files": {
"$ref": "#/definitions/FileCounts"
},
"installed_at": {
"type": "string"
},
"kit": {
"type": "string"
},
"pending": {
"description": "Plans of this kit waiting for review.",
"items": {
"type": "string"
},
"type": "array"
},
"readme": {
"type": [
"string",
"null"
]
},
"registry_url": {
"type": "string"
},
"requested": {
"type": "string"
},
"update": {
"anyOf": [
{
"$ref": "#/definitions/KitUpdate"
},
{
"type": "null"
}
]
},
"version": {
"type": "string"
},
"worker_status": {
"description": "Workers as Compose has them now.",
"items": true,
"type": "array"
},
"workers": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"required": [
"file_list",
"files",
"installed_at",
"kit",
"pending",
"registry_url",
"requested",
"version",
"worker_status",
"workers"
],
"title": "KitInfo",
"type": "object"
}
},
{
"description": "Skip (or, with ignore=false, stop skipping) one version of an installed kit in update checks; recorded in kits.lock ignored_versions.",
"metadata": {},
"name": "directory::kits::ignore",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ignore": {
"default": null,
"description": "`false` takes the version back off the list (default `true`).",
"type": [
"boolean",
"null"
]
},
"kit": {
"description": "Installed kit, `<author>/<kit>`.",
"type": "string"
},
"version": {
"description": "Version to skip in update checks.",
"type": "string"
}
},
"required": [
"kit",
"version"
],
"title": "IgnoreInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Response of `directory::kits::ignore`.",
"properties": {
"ignored_versions": {
"items": {
"type": "string"
},
"type": "array"
},
"kit": {
"type": "string"
}
},
"required": [
"ignored_versions",
"kit"
],
"title": "IgnoreOutput",
"type": "object"
}
},
{
"description": "Installed kits (version, file states, worker ranges, available update) and the plans waiting for review. `attention` counts both.",
"metadata": {},
"name": "directory::kits::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ListInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Deprecation": {
"properties": {
"message": {
"default": null,
"type": [
"string",
"null"
]
},
"replaced_by": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"FileCounts": {
"properties": {
"agents": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"edited": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"intact": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"missing": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"skills": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"skipped": {
"format": "uint",
"minimum": 0,
"type": "integer"
}
},
"required": [
"agents",
"edited",
"intact",
"missing",
"skills",
"skipped"
],
"type": "object"
},
"InstalledKit": {
"properties": {
"files": {
"$ref": "#/definitions/FileCounts"
},
"installed_at": {
"type": "string"
},
"kit": {
"type": "string"
},
"pending": {
"description": "Plans of this kit waiting for review.",
"items": {
"type": "string"
},
"type": "array"
},
"registry_url": {
"type": "string"
},
"requested": {
"type": "string"
},
"update": {
"anyOf": [
{
"$ref": "#/definitions/KitUpdate"
},
{
"type": "null"
}
]
},
"version": {
"type": "string"
},
"workers": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"required": [
"files",
"installed_at",
"kit",
"pending",
"registry_url",
"requested",
"version",
"workers"
],
"type": "object"
},
"KitUpdate": {
"properties": {
"available": {
"description": "Newest version satisfying `requested`, unless the user ignored it.",
"type": [
"string",
"null"
]
},
"current": {
"type": "string"
},
"deprecation": {
"anyOf": [
{
"$ref": "#/definitions/Deprecation"
},
{
"type": "null"
}
]
},
"ignored": {
"description": "`available` would be this version, but the user ignored it.",
"type": [
"string",
"null"
]
},
"latest": {
"type": [
"string",
"null"
]
},
"major": {
"type": "boolean"
},
"not_found": {
"type": "boolean"
}
},
"required": [
"current",
"major"
],
"type": "object"
}
},
"properties": {
"attention": {
"description": "Pending plans plus available updates: what the Kits badge counts.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"kits": {
"items": {
"$ref": "#/definitions/InstalledKit"
},
"type": "array"
},
"lock_path": {
"type": "string"
},
"pending": {
"description": "Pending plans (summaries).",
"items": true,
"type": "array"
},
"updates_checked_at": {
"type": [
"string",
"null"
]
},
"updates_error": {
"type": [
"string",
"null"
]
}
},
"required": [
"attention",
"kits",
"lock_path",
"pending"
],
"title": "KitsListing",
"type": "object"
}
},
{
"description": "Read a pending kit plan, with contents=true the file bodies it refers to (kit blobs by sha256, local files and merge results by install path).",
"metadata": {},
"name": "directory::kits::plan",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"contents": {
"default": null,
"description": "Include file bodies (`blobs` by sha256, `ours` and `merged` by path).",
"type": [
"boolean",
"null"
]
},
"plan_id": {
"type": "string"
}
},
"required": [
"plan_id"
],
"title": "PlanGetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AgentChanges": {
"description": "Changed frontmatter of a profile between two kit versions.",
"properties": {
"fields": {
"additionalProperties": {
"items": [
{
"type": [
"string",
"null"
]
},
{
"type": [
"string",
"null"
]
}
],
"maxItems": 2,
"minItems": 2,
"type": "array"
},
"description": "Scalar fields that changed: `field → [from, to]`.",
"type": "object"
},
"functions_added": {
"items": {
"type": "string"
},
"type": "array"
},
"functions_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_added": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_removed": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"AgentEntry": {
"description": "`AgentEntry`: parsed frontmatter of `agents/<id>.md`.",
"properties": {
"color": {
"default": null,
"type": [
"string",
"null"
]
},
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"extends": {
"default": null,
"type": [
"string",
"null"
]
},
"functions": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"hidden": {
"default": null,
"type": [
"boolean",
"null"
]
},
"icon": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"logo": {
"default": null,
"type": [
"string",
"null"
]
},
"model": {
"default": null,
"type": [
"string",
"null"
]
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"path": {
"default": "",
"type": "string"
},
"reasoning_effort": {
"default": null,
"type": [
"string",
"null"
]
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"skills": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"ApplyProgress": {
"description": "What an apply has done so far for this plan.",
"properties": {
"error": {
"type": [
"string",
"null"
]
},
"started_at": {
"type": [
"string",
"null"
]
},
"steps": {
"items": {
"$ref": "#/definitions/ApplyStep"
},
"type": "array"
},
"written": {
"additionalProperties": {
"type": "string"
},
"default": {},
"description": "Install path → sha written (or `\"\"` for a deletion) by an earlier, interrupted attempt. Re-validation accepts these as expected.",
"type": "object"
}
},
"required": [
"steps"
],
"type": "object"
},
"ApplyStep": {
"properties": {
"detail": {
"type": [
"string",
"null"
]
},
"id": {
"description": "`workers` | `files` | `lock`.",
"type": "string"
},
"label": {
"type": "string"
},
"state": {
"$ref": "#/definitions/StepState"
}
},
"required": [
"id",
"label",
"state"
],
"type": "object"
},
"Author": {
"properties": {
"handle": {
"default": "",
"type": "string"
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"verified": {
"default": false,
"type": "boolean"
}
},
"type": "object"
},
"Capabilities": {
"properties": {
"functions_added": {
"default": [],
"items": {
"$ref": "#/definitions/FunctionAdded"
},
"type": "array"
},
"models_changed": {
"default": [],
"items": {
"$ref": "#/definitions/ModelChanged"
},
"type": "array"
},
"workers_added": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"Change": {
"oneOf": [
{
"enum": [
"added",
"modified",
"removed"
],
"type": "string"
},
{
"description": "The lock keeps the user's choice to skip this file; the kit's version changed and is offered again.",
"enum": [
"kept"
],
"type": "string"
}
]
},
"Collision": {
"properties": {
"kit": {
"type": [
"string",
"null"
]
},
"modified": {
"description": "The owner's copy was edited locally.",
"type": [
"boolean",
"null"
]
},
"owner": {
"allOf": [
{
"$ref": "#/definitions/SourceKind"
}
],
"description": "Who owns the file at the path today."
},
"sha256": {
"description": "sha256 of the file there now.",
"type": [
"string",
"null"
]
},
"version": {
"type": [
"string",
"null"
]
},
"worker": {
"type": [
"string",
"null"
]
}
},
"required": [
"owner"
],
"type": "object"
},
"Decision": {
"description": "A per-file choice.",
"oneOf": [
{
"description": "Write the kit's file over what is there.",
"enum": [
"overwrite"
],
"type": "string"
},
{
"description": "Keep what is there; the lock marks the kit's file `skipped`.",
"enum": [
"keep"
],
"type": "string"
},
{
"description": "Take the kit's new version (drops local edits).",
"enum": [
"kit"
],
"type": "string"
},
{
"description": "Keep the local file as it is.",
"enum": [
"mine"
],
"type": "string"
},
{
"description": "Write the merge result (the plan's, or `content` from the caller).",
"enum": [
"merged"
],
"type": "string"
},
{
"description": "Delete the file.",
"enum": [
"remove"
],
"type": "string"
}
]
},
"Deprecation": {
"properties": {
"message": {
"default": null,
"type": [
"string",
"null"
]
},
"replaced_by": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"FileKind": {
"enum": [
"agent",
"skill"
],
"type": "string"
},
"FunctionAdded": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"function": {
"default": "",
"type": "string"
}
},
"type": "object"
},
"Issue": {
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"path": {
"type": [
"string",
"null"
]
}
},
"required": [
"code",
"message"
],
"type": "object"
},
"KitFunction": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"status": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"worker": {
"default": null,
"type": [
"string",
"null"
]
},
"worker_version": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"LocalState": {
"description": "What the file is on disk right now, relative to the plan.",
"oneOf": [
{
"description": "Nothing at the path.",
"enum": [
"absent"
],
"type": "string"
},
{
"description": "Matches the kit's base (or, on install, the kit's content).",
"enum": [
"intact"
],
"type": "string"
},
{
"description": "Differs from the base the kit installed.",
"enum": [
"edited"
],
"type": "string"
},
{
"description": "The lock lists it but the file was deleted.",
"enum": [
"missing"
],
"type": "string"
},
{
"description": "Someone else's file sits at the path.",
"enum": [
"occupied"
],
"type": "string"
}
]
},
"MergeStatus": {
"enum": [
"clean",
"conflicts"
],
"type": "string"
},
"ModelChanged": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"from": {
"default": null,
"type": [
"string",
"null"
]
},
"to": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"Plan": {
"properties": {
"author": {
"anyOf": [
{
"$ref": "#/definitions/Author"
},
{
"type": "null"
}
]
},
"blocking": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"bump": {
"description": "`major` | `minor` | `patch` | `prerelease` (update).",
"type": [
"string",
"null"
]
},
"capabilities": {
"$ref": "#/definitions/Capabilities"
},
"counts": {
"$ref": "#/definitions/PlanCounts"
},
"created_at": {
"type": "string"
},
"deprecation": {
"anyOf": [
{
"$ref": "#/definitions/Deprecation"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"expires_at": {
"type": "string"
},
"files": {
"items": {
"$ref": "#/definitions/PlanFile"
},
"type": "array"
},
"from": {
"description": "Installed version (update, remove).",
"type": [
"string",
"null"
]
},
"functions": {
"description": "Functions the kit's profiles preload, with the worker that provides each.",
"items": {
"$ref": "#/definitions/KitFunction"
},
"type": "array"
},
"kind": {
"$ref": "#/definitions/PlanKind"
},
"kit": {
"type": "string"
},
"license": {
"type": [
"string",
"null"
]
},
"major": {
"type": "boolean"
},
"notes": {
"type": [
"string",
"null"
]
},
"plan_id": {
"type": "string"
},
"published_at": {
"type": [
"string",
"null"
]
},
"registry_url": {
"description": "The kit's page in the registry web app.",
"type": "string"
},
"repo": {
"type": [
"string",
"null"
]
},
"requested": {
"description": "What was asked for (tag, version or range) — stored in the lock.",
"type": "string"
},
"review": {
"description": "Where a human reviews it.",
"type": "string"
},
"to": {
"description": "Version this plan installs (install, update).",
"type": [
"string",
"null"
]
},
"warnings": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"workers": {
"items": {
"$ref": "#/definitions/PlanWorker"
},
"type": "array"
}
},
"required": [
"blocking",
"capabilities",
"counts",
"created_at",
"expires_at",
"files",
"functions",
"kind",
"kit",
"major",
"plan_id",
"registry_url",
"requested",
"review",
"warnings",
"workers"
],
"type": "object"
},
"PlanContents": {
"description": "File bodies a plan refers to, stored beside it.",
"properties": {
"blobs": {
"additionalProperties": {
"type": "string"
},
"default": {},
"description": "Kit blobs by sha256 (theirs and bases).",
"type": "object"
},
"merged": {
"additionalProperties": {
"type": "string"
},
"default": {},
"description": "Three-way merge results, by install path.",
"type": "object"
},
"ours": {
"additionalProperties": {
"type": "string"
},
"default": {},
"description": "Local file bodies when the plan was made, by install path.",
"type": "object"
}
},
"type": "object"
},
"PlanCounts": {
"properties": {
"added": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"agents": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"collisions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"decisions_required": {
"description": "Files whose `default` is `null`.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"functions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"modified": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"removed": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"skills": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"unchanged": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"workers": {
"format": "uint",
"minimum": 0,
"type": "integer"
}
},
"required": [
"added",
"agents",
"collisions",
"conflicts",
"decisions_required",
"functions",
"modified",
"removed",
"skills",
"unchanged",
"workers"
],
"type": "object"
},
"PlanFile": {
"properties": {
"agent": {
"anyOf": [
{
"$ref": "#/definitions/AgentEntry"
},
{
"type": "null"
}
],
"description": "Kit profile frontmatter (agents; the side this plan installs, or the removed one)."
},
"agent_changes": {
"anyOf": [
{
"$ref": "#/definitions/AgentChanges"
},
{
"type": "null"
}
],
"description": "Frontmatter changes versus the installed version (modified agents)."
},
"base": {
"description": "Content hash the kit installed (the merge base).",
"type": [
"string",
"null"
]
},
"body_changed": {
"type": [
"boolean",
"null"
]
},
"change": {
"$ref": "#/definitions/Change"
},
"collision": {
"anyOf": [
{
"$ref": "#/definitions/Collision"
},
{
"type": "null"
}
]
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"default": {
"anyOf": [
{
"$ref": "#/definitions/Decision"
},
{
"type": "null"
}
],
"description": "Applied when the caller decides nothing; `null` = a decision is required."
},
"id": {
"description": "Agent profile id, or skill id.",
"type": "string"
},
"kind": {
"$ref": "#/definitions/FileKind"
},
"local": {
"$ref": "#/definitions/LocalState"
},
"merge": {
"anyOf": [
{
"$ref": "#/definitions/MergeStatus"
},
{
"type": "null"
}
]
},
"note": {
"description": "One-line explanation for the review.",
"type": [
"string",
"null"
]
},
"options": {
"description": "Choices the apply accepts for this file.",
"items": {
"$ref": "#/definitions/Decision"
},
"type": "array"
},
"ours": {
"description": "Content hash of the local file when the plan was made.",
"type": [
"string",
"null"
]
},
"path": {
"description": "Logical install path (`agents/<id>.md`, `skills/<handle>/<kit>/…`).",
"type": "string"
},
"skill": {
"anyOf": [
{
"$ref": "#/definitions/SkillEntry"
},
{
"type": "null"
}
],
"description": "Skill frontmatter (skills)."
},
"skipped": {
"description": "The lock says the user kept someone else's file here.",
"type": "boolean"
},
"source": {
"description": "Path inside the kit (`agents/<id>.md`, `skills/…`).",
"type": "string"
},
"theirs": {
"description": "Content hash of the kit's version this plan installs.",
"type": [
"string",
"null"
]
}
},
"required": [
"change",
"id",
"kind",
"local",
"options",
"path",
"source"
],
"type": "object"
},
"PlanKind": {
"enum": [
"install",
"update",
"remove"
],
"type": "string"
},
"PlanWorker": {
"properties": {
"action": {
"$ref": "#/definitions/WorkerAction"
},
"container": {
"type": [
"string",
"null"
]
},
"declared": {
"description": "`version:` selector in the compose file.",
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"installed": {
"description": "Version Compose has installed.",
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"path": {
"description": "The operator's `path://` build; kits never manage it.",
"type": "boolean"
},
"range": {
"description": "Range the kit declares (absent for a worker the kit dropped).",
"type": [
"string",
"null"
]
},
"range_from": {
"description": "Range the installed kit version declared.",
"type": [
"string",
"null"
]
},
"registry_url": {
"type": "string"
},
"to": {
"description": "Version the range resolves to in the registry today.",
"type": [
"string",
"null"
]
},
"type": {
"description": "Worker type (`binary`, `image`, …).",
"type": [
"string",
"null"
]
},
"used_by": {
"description": "Other installed kits that declare this worker.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"action",
"name",
"registry_url"
],
"type": "object"
},
"SkillEntry": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"path": {
"default": "",
"type": "string"
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"title": {
"default": null,
"type": [
"string",
"null"
]
},
"type": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"SourceKind": {
"enum": [
"kit",
"worker",
"local",
"global",
"builtin"
],
"type": "string"
},
"StepState": {
"enum": [
"pending",
"running",
"done",
"failed",
"skipped"
],
"type": "string"
},
"WorkerAction": {
"oneOf": [
{
"enum": [
"none"
],
"type": "string"
},
{
"description": "Not in the compose file: `compose::add` declares it with the kit's range.",
"enum": [
"add"
],
"type": "string"
},
{
"description": "Declared, but the installed version is outside the kit's range: `compose::add` re-declares the range and Compose moves the worker.",
"enum": [
"update"
],
"type": "string"
},
{
"description": "The range changed and the compose file still declares the kit's old range; the installed version already satisfies the new one, so only the declaration moves.",
"enum": [
"redeclare"
],
"type": "string"
},
{
"description": "The kit no longer declares it. Never removed unless asked (`remove_workers`).",
"enum": [
"remove"
],
"type": "string"
}
]
}
},
"description": "Response of `directory::kits::plan`.",
"properties": {
"contents": {
"anyOf": [
{
"$ref": "#/definitions/PlanContents"
},
{
"type": "null"
}
],
"description": "File bodies the plan refers to; only with `contents=true`."
},
"plan": {
"$ref": "#/definitions/Plan"
},
"progress": {
"anyOf": [
{
"$ref": "#/definitions/ApplyProgress"
},
{
"type": "null"
}
]
}
},
"required": [
"plan"
],
"title": "PlanGetOutput",
"type": "object"
}
},
{
"description": "Plan the update of an installed kit to `version` (default: the newest release matching what it was installed with). Files you edited are merged three-way; conflicts need a decision before directory::kits::apply.",
"metadata": {
"tool": {
"label": "Plan kit update"
}
},
"name": "directory::kits::plan-update",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"kit": {
"description": "Installed kit, `<author>/<kit>`.",
"type": "string"
},
"version": {
"default": null,
"description": "Target version, tag or range (default: what the kit was installed with).",
"type": [
"string",
"null"
]
}
},
"required": [
"kit"
],
"title": "PlanUpdateInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AgentChanges": {
"description": "Changed frontmatter of a profile between two kit versions.",
"properties": {
"fields": {
"additionalProperties": {
"items": [
{
"type": [
"string",
"null"
]
},
{
"type": [
"string",
"null"
]
}
],
"maxItems": 2,
"minItems": 2,
"type": "array"
},
"description": "Scalar fields that changed: `field → [from, to]`.",
"type": "object"
},
"functions_added": {
"items": {
"type": "string"
},
"type": "array"
},
"functions_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_added": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_removed": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"AgentEntry": {
"description": "`AgentEntry`: parsed frontmatter of `agents/<id>.md`.",
"properties": {
"color": {
"default": null,
"type": [
"string",
"null"
]
},
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"extends": {
"default": null,
"type": [
"string",
"null"
]
},
"functions": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"hidden": {
"default": null,
"type": [
"boolean",
"null"
]
},
"icon": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"logo": {
"default": null,
"type": [
"string",
"null"
]
},
"model": {
"default": null,
"type": [
"string",
"null"
]
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"path": {
"default": "",
"type": "string"
},
"reasoning_effort": {
"default": null,
"type": [
"string",
"null"
]
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"skills": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"ApplyReport": {
"properties": {
"agents": {
"description": "Agent profile ids this kit now provides.",
"items": {
"type": "string"
},
"type": "array"
},
"agents_changed": {
"type": "boolean"
},
"files_kept": {
"description": "Files left as they are (kept, skipped, or mine).",
"items": {
"type": "string"
},
"type": "array"
},
"files_merged": {
"items": {
"type": "string"
},
"type": "array"
},
"files_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"files_written": {
"items": {
"type": "string"
},
"type": "array"
},
"from": {
"type": [
"string",
"null"
]
},
"kind": {
"anyOf": [
{
"$ref": "#/definitions/PlanKind"
},
{
"type": "null"
}
]
},
"kit": {
"type": "string"
},
"lock_path": {
"type": "string"
},
"plan_id": {
"type": "string"
},
"skills_changed": {
"type": "boolean"
},
"steps": {
"items": {
"$ref": "#/definitions/ApplyStep"
},
"type": "array"
},
"to": {
"type": [
"string",
"null"
]
},
"workers_added": {
"items": {
"type": "string"
},
"type": "array"
},
"workers_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"workers_updated": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"agents",
"agents_changed",
"files_kept",
"files_merged",
"files_removed",
"files_written",
"kit",
"lock_path",
"plan_id",
"skills_changed",
"steps",
"workers_added",
"workers_removed",
"workers_updated"
],
"type": "object"
},
"ApplyStep": {
"properties": {
"detail": {
"type": [
"string",
"null"
]
},
"id": {
"description": "`workers` | `files` | `lock`.",
"type": "string"
},
"label": {
"type": "string"
},
"state": {
"$ref": "#/definitions/StepState"
}
},
"required": [
"id",
"label",
"state"
],
"type": "object"
},
"Author": {
"properties": {
"handle": {
"default": "",
"type": "string"
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"verified": {
"default": false,
"type": "boolean"
}
},
"type": "object"
},
"Capabilities": {
"properties": {
"functions_added": {
"default": [],
"items": {
"$ref": "#/definitions/FunctionAdded"
},
"type": "array"
},
"models_changed": {
"default": [],
"items": {
"$ref": "#/definitions/ModelChanged"
},
"type": "array"
},
"workers_added": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"Change": {
"oneOf": [
{
"enum": [
"added",
"modified",
"removed"
],
"type": "string"
},
{
"description": "The lock keeps the user's choice to skip this file; the kit's version changed and is offered again.",
"enum": [
"kept"
],
"type": "string"
}
]
},
"Collision": {
"properties": {
"kit": {
"type": [
"string",
"null"
]
},
"modified": {
"description": "The owner's copy was edited locally.",
"type": [
"boolean",
"null"
]
},
"owner": {
"allOf": [
{
"$ref": "#/definitions/SourceKind"
}
],
"description": "Who owns the file at the path today."
},
"sha256": {
"description": "sha256 of the file there now.",
"type": [
"string",
"null"
]
},
"version": {
"type": [
"string",
"null"
]
},
"worker": {
"type": [
"string",
"null"
]
}
},
"required": [
"owner"
],
"type": "object"
},
"Decision": {
"description": "A per-file choice.",
"oneOf": [
{
"description": "Write the kit's file over what is there.",
"enum": [
"overwrite"
],
"type": "string"
},
{
"description": "Keep what is there; the lock marks the kit's file `skipped`.",
"enum": [
"keep"
],
"type": "string"
},
{
"description": "Take the kit's new version (drops local edits).",
"enum": [
"kit"
],
"type": "string"
},
{
"description": "Keep the local file as it is.",
"enum": [
"mine"
],
"type": "string"
},
{
"description": "Write the merge result (the plan's, or `content` from the caller).",
"enum": [
"merged"
],
"type": "string"
},
{
"description": "Delete the file.",
"enum": [
"remove"
],
"type": "string"
}
]
},
"Deprecation": {
"properties": {
"message": {
"default": null,
"type": [
"string",
"null"
]
},
"replaced_by": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"FileKind": {
"enum": [
"agent",
"skill"
],
"type": "string"
},
"FunctionAdded": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"function": {
"default": "",
"type": "string"
}
},
"type": "object"
},
"Issue": {
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"path": {
"type": [
"string",
"null"
]
}
},
"required": [
"code",
"message"
],
"type": "object"
},
"KitFunction": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"status": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"worker": {
"default": null,
"type": [
"string",
"null"
]
},
"worker_version": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"LocalState": {
"description": "What the file is on disk right now, relative to the plan.",
"oneOf": [
{
"description": "Nothing at the path.",
"enum": [
"absent"
],
"type": "string"
},
{
"description": "Matches the kit's base (or, on install, the kit's content).",
"enum": [
"intact"
],
"type": "string"
},
{
"description": "Differs from the base the kit installed.",
"enum": [
"edited"
],
"type": "string"
},
{
"description": "The lock lists it but the file was deleted.",
"enum": [
"missing"
],
"type": "string"
},
{
"description": "Someone else's file sits at the path.",
"enum": [
"occupied"
],
"type": "string"
}
]
},
"MergeStatus": {
"enum": [
"clean",
"conflicts"
],
"type": "string"
},
"ModelChanged": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"from": {
"default": null,
"type": [
"string",
"null"
]
},
"to": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"Plan": {
"properties": {
"author": {
"anyOf": [
{
"$ref": "#/definitions/Author"
},
{
"type": "null"
}
]
},
"blocking": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"bump": {
"description": "`major` | `minor` | `patch` | `prerelease` (update).",
"type": [
"string",
"null"
]
},
"capabilities": {
"$ref": "#/definitions/Capabilities"
},
"counts": {
"$ref": "#/definitions/PlanCounts"
},
"created_at": {
"type": "string"
},
"deprecation": {
"anyOf": [
{
"$ref": "#/definitions/Deprecation"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"expires_at": {
"type": "string"
},
"files": {
"items": {
"$ref": "#/definitions/PlanFile"
},
"type": "array"
},
"from": {
"description": "Installed version (update, remove).",
"type": [
"string",
"null"
]
},
"functions": {
"description": "Functions the kit's profiles preload, with the worker that provides each.",
"items": {
"$ref": "#/definitions/KitFunction"
},
"type": "array"
},
"kind": {
"$ref": "#/definitions/PlanKind"
},
"kit": {
"type": "string"
},
"license": {
"type": [
"string",
"null"
]
},
"major": {
"type": "boolean"
},
"notes": {
"type": [
"string",
"null"
]
},
"plan_id": {
"type": "string"
},
"published_at": {
"type": [
"string",
"null"
]
},
"registry_url": {
"description": "The kit's page in the registry web app.",
"type": "string"
},
"repo": {
"type": [
"string",
"null"
]
},
"requested": {
"description": "What was asked for (tag, version or range) — stored in the lock.",
"type": "string"
},
"review": {
"description": "Where a human reviews it.",
"type": "string"
},
"to": {
"description": "Version this plan installs (install, update).",
"type": [
"string",
"null"
]
},
"warnings": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"workers": {
"items": {
"$ref": "#/definitions/PlanWorker"
},
"type": "array"
}
},
"required": [
"blocking",
"capabilities",
"counts",
"created_at",
"expires_at",
"files",
"functions",
"kind",
"kit",
"major",
"plan_id",
"registry_url",
"requested",
"review",
"warnings",
"workers"
],
"type": "object"
},
"PlanCounts": {
"properties": {
"added": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"agents": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"collisions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"decisions_required": {
"description": "Files whose `default` is `null`.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"functions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"modified": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"removed": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"skills": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"unchanged": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"workers": {
"format": "uint",
"minimum": 0,
"type": "integer"
}
},
"required": [
"added",
"agents",
"collisions",
"conflicts",
"decisions_required",
"functions",
"modified",
"removed",
"skills",
"unchanged",
"workers"
],
"type": "object"
},
"PlanFile": {
"properties": {
"agent": {
"anyOf": [
{
"$ref": "#/definitions/AgentEntry"
},
{
"type": "null"
}
],
"description": "Kit profile frontmatter (agents; the side this plan installs, or the removed one)."
},
"agent_changes": {
"anyOf": [
{
"$ref": "#/definitions/AgentChanges"
},
{
"type": "null"
}
],
"description": "Frontmatter changes versus the installed version (modified agents)."
},
"base": {
"description": "Content hash the kit installed (the merge base).",
"type": [
"string",
"null"
]
},
"body_changed": {
"type": [
"boolean",
"null"
]
},
"change": {
"$ref": "#/definitions/Change"
},
"collision": {
"anyOf": [
{
"$ref": "#/definitions/Collision"
},
{
"type": "null"
}
]
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"default": {
"anyOf": [
{
"$ref": "#/definitions/Decision"
},
{
"type": "null"
}
],
"description": "Applied when the caller decides nothing; `null` = a decision is required."
},
"id": {
"description": "Agent profile id, or skill id.",
"type": "string"
},
"kind": {
"$ref": "#/definitions/FileKind"
},
"local": {
"$ref": "#/definitions/LocalState"
},
"merge": {
"anyOf": [
{
"$ref": "#/definitions/MergeStatus"
},
{
"type": "null"
}
]
},
"note": {
"description": "One-line explanation for the review.",
"type": [
"string",
"null"
]
},
"options": {
"description": "Choices the apply accepts for this file.",
"items": {
"$ref": "#/definitions/Decision"
},
"type": "array"
},
"ours": {
"description": "Content hash of the local file when the plan was made.",
"type": [
"string",
"null"
]
},
"path": {
"description": "Logical install path (`agents/<id>.md`, `skills/<handle>/<kit>/…`).",
"type": "string"
},
"skill": {
"anyOf": [
{
"$ref": "#/definitions/SkillEntry"
},
{
"type": "null"
}
],
"description": "Skill frontmatter (skills)."
},
"skipped": {
"description": "The lock says the user kept someone else's file here.",
"type": "boolean"
},
"source": {
"description": "Path inside the kit (`agents/<id>.md`, `skills/…`).",
"type": "string"
},
"theirs": {
"description": "Content hash of the kit's version this plan installs.",
"type": [
"string",
"null"
]
}
},
"required": [
"change",
"id",
"kind",
"local",
"options",
"path",
"source"
],
"type": "object"
},
"PlanKind": {
"enum": [
"install",
"update",
"remove"
],
"type": "string"
},
"PlanStatus": {
"oneOf": [
{
"description": "A plan is waiting for review (or for `directory::kits::apply`).",
"enum": [
"planned"
],
"type": "string"
},
{
"description": "`apply=true` and the plan needed no review: it was applied.",
"enum": [
"applied"
],
"type": "string"
},
{
"description": "The installed version is already the one asked for.",
"enum": [
"up_to_date"
],
"type": "string"
},
{
"description": "The project changed since the plan was made; this is a fresh plan.",
"enum": [
"replanned"
],
"type": "string"
}
]
},
"PlanWorker": {
"properties": {
"action": {
"$ref": "#/definitions/WorkerAction"
},
"container": {
"type": [
"string",
"null"
]
},
"declared": {
"description": "`version:` selector in the compose file.",
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"installed": {
"description": "Version Compose has installed.",
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"path": {
"description": "The operator's `path://` build; kits never manage it.",
"type": "boolean"
},
"range": {
"description": "Range the kit declares (absent for a worker the kit dropped).",
"type": [
"string",
"null"
]
},
"range_from": {
"description": "Range the installed kit version declared.",
"type": [
"string",
"null"
]
},
"registry_url": {
"type": "string"
},
"to": {
"description": "Version the range resolves to in the registry today.",
"type": [
"string",
"null"
]
},
"type": {
"description": "Worker type (`binary`, `image`, …).",
"type": [
"string",
"null"
]
},
"used_by": {
"description": "Other installed kits that declare this worker.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"action",
"name",
"registry_url"
],
"type": "object"
},
"SkillEntry": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"path": {
"default": "",
"type": "string"
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"title": {
"default": null,
"type": [
"string",
"null"
]
},
"type": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"SourceKind": {
"enum": [
"kit",
"worker",
"local",
"global",
"builtin"
],
"type": "string"
},
"StepState": {
"enum": [
"pending",
"running",
"done",
"failed",
"skipped"
],
"type": "string"
},
"WorkerAction": {
"oneOf": [
{
"enum": [
"none"
],
"type": "string"
},
{
"description": "Not in the compose file: `compose::add` declares it with the kit's range.",
"enum": [
"add"
],
"type": "string"
},
{
"description": "Declared, but the installed version is outside the kit's range: `compose::add` re-declares the range and Compose moves the worker.",
"enum": [
"update"
],
"type": "string"
},
{
"description": "The range changed and the compose file still declares the kit's old range; the installed version already satisfies the new one, so only the declaration moves.",
"enum": [
"redeclare"
],
"type": "string"
},
{
"description": "The kit no longer declares it. Never removed unless asked (`remove_workers`).",
"enum": [
"remove"
],
"type": "string"
}
]
}
},
"description": "Response of `directory::download-kit`, `plan-update`, `remove` and `apply`.",
"properties": {
"kit": {
"type": "string"
},
"message": {
"description": "One sentence for a terminal user.",
"type": "string"
},
"plan": {
"anyOf": [
{
"$ref": "#/definitions/Plan"
},
{
"type": "null"
}
]
},
"report": {
"anyOf": [
{
"$ref": "#/definitions/ApplyReport"
},
{
"type": "null"
}
]
},
"status": {
"$ref": "#/definitions/PlanStatus"
}
},
"required": [
"kit",
"message",
"status"
],
"title": "KitPlanResponse",
"type": "object"
}
},
{
"description": "Plan the removal of an installed kit: its files (edited ones are kept unless chosen) and, only if ticked in apply's remove_workers, its workers. Apply with directory::kits::apply.",
"metadata": {
"tool": {
"label": "Plan kit removal"
}
},
"name": "directory::kits::remove",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"kit": {
"description": "Installed kit, `<author>/<kit>`.",
"type": "string"
}
},
"required": [
"kit"
],
"title": "KitInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AgentChanges": {
"description": "Changed frontmatter of a profile between two kit versions.",
"properties": {
"fields": {
"additionalProperties": {
"items": [
{
"type": [
"string",
"null"
]
},
{
"type": [
"string",
"null"
]
}
],
"maxItems": 2,
"minItems": 2,
"type": "array"
},
"description": "Scalar fields that changed: `field → [from, to]`.",
"type": "object"
},
"functions_added": {
"items": {
"type": "string"
},
"type": "array"
},
"functions_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_added": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_removed": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"AgentEntry": {
"description": "`AgentEntry`: parsed frontmatter of `agents/<id>.md`.",
"properties": {
"color": {
"default": null,
"type": [
"string",
"null"
]
},
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"extends": {
"default": null,
"type": [
"string",
"null"
]
},
"functions": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"hidden": {
"default": null,
"type": [
"boolean",
"null"
]
},
"icon": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"logo": {
"default": null,
"type": [
"string",
"null"
]
},
"model": {
"default": null,
"type": [
"string",
"null"
]
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"path": {
"default": "",
"type": "string"
},
"reasoning_effort": {
"default": null,
"type": [
"string",
"null"
]
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"skills": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"ApplyReport": {
"properties": {
"agents": {
"description": "Agent profile ids this kit now provides.",
"items": {
"type": "string"
},
"type": "array"
},
"agents_changed": {
"type": "boolean"
},
"files_kept": {
"description": "Files left as they are (kept, skipped, or mine).",
"items": {
"type": "string"
},
"type": "array"
},
"files_merged": {
"items": {
"type": "string"
},
"type": "array"
},
"files_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"files_written": {
"items": {
"type": "string"
},
"type": "array"
},
"from": {
"type": [
"string",
"null"
]
},
"kind": {
"anyOf": [
{
"$ref": "#/definitions/PlanKind"
},
{
"type": "null"
}
]
},
"kit": {
"type": "string"
},
"lock_path": {
"type": "string"
},
"plan_id": {
"type": "string"
},
"skills_changed": {
"type": "boolean"
},
"steps": {
"items": {
"$ref": "#/definitions/ApplyStep"
},
"type": "array"
},
"to": {
"type": [
"string",
"null"
]
},
"workers_added": {
"items": {
"type": "string"
},
"type": "array"
},
"workers_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"workers_updated": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"agents",
"agents_changed",
"files_kept",
"files_merged",
"files_removed",
"files_written",
"kit",
"lock_path",
"plan_id",
"skills_changed",
"steps",
"workers_added",
"workers_removed",
"workers_updated"
],
"type": "object"
},
"ApplyStep": {
"properties": {
"detail": {
"type": [
"string",
"null"
]
},
"id": {
"description": "`workers` | `files` | `lock`.",
"type": "string"
},
"label": {
"type": "string"
},
"state": {
"$ref": "#/definitions/StepState"
}
},
"required": [
"id",
"label",
"state"
],
"type": "object"
},
"Author": {
"properties": {
"handle": {
"default": "",
"type": "string"
},
"name": {
"default": null,
"type": [
"string",
"null"
]
},
"verified": {
"default": false,
"type": "boolean"
}
},
"type": "object"
},
"Capabilities": {
"properties": {
"functions_added": {
"default": [],
"items": {
"$ref": "#/definitions/FunctionAdded"
},
"type": "array"
},
"models_changed": {
"default": [],
"items": {
"$ref": "#/definitions/ModelChanged"
},
"type": "array"
},
"workers_added": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"Change": {
"oneOf": [
{
"enum": [
"added",
"modified",
"removed"
],
"type": "string"
},
{
"description": "The lock keeps the user's choice to skip this file; the kit's version changed and is offered again.",
"enum": [
"kept"
],
"type": "string"
}
]
},
"Collision": {
"properties": {
"kit": {
"type": [
"string",
"null"
]
},
"modified": {
"description": "The owner's copy was edited locally.",
"type": [
"boolean",
"null"
]
},
"owner": {
"allOf": [
{
"$ref": "#/definitions/SourceKind"
}
],
"description": "Who owns the file at the path today."
},
"sha256": {
"description": "sha256 of the file there now.",
"type": [
"string",
"null"
]
},
"version": {
"type": [
"string",
"null"
]
},
"worker": {
"type": [
"string",
"null"
]
}
},
"required": [
"owner"
],
"type": "object"
},
"Decision": {
"description": "A per-file choice.",
"oneOf": [
{
"description": "Write the kit's file over what is there.",
"enum": [
"overwrite"
],
"type": "string"
},
{
"description": "Keep what is there; the lock marks the kit's file `skipped`.",
"enum": [
"keep"
],
"type": "string"
},
{
"description": "Take the kit's new version (drops local edits).",
"enum": [
"kit"
],
"type": "string"
},
{
"description": "Keep the local file as it is.",
"enum": [
"mine"
],
"type": "string"
},
{
"description": "Write the merge result (the plan's, or `content` from the caller).",
"enum": [
"merged"
],
"type": "string"
},
{
"description": "Delete the file.",
"enum": [
"remove"
],
"type": "string"
}
]
},
"Deprecation": {
"properties": {
"message": {
"default": null,
"type": [
"string",
"null"
]
},
"replaced_by": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"FileKind": {
"enum": [
"agent",
"skill"
],
"type": "string"
},
"FunctionAdded": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"function": {
"default": "",
"type": "string"
}
},
"type": "object"
},
"Issue": {
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"path": {
"type": [
"string",
"null"
]
}
},
"required": [
"code",
"message"
],
"type": "object"
},
"KitFunction": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"status": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"worker": {
"default": null,
"type": [
"string",
"null"
]
},
"worker_version": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"LocalState": {
"description": "What the file is on disk right now, relative to the plan.",
"oneOf": [
{
"description": "Nothing at the path.",
"enum": [
"absent"
],
"type": "string"
},
{
"description": "Matches the kit's base (or, on install, the kit's content).",
"enum": [
"intact"
],
"type": "string"
},
{
"description": "Differs from the base the kit installed.",
"enum": [
"edited"
],
"type": "string"
},
{
"description": "The lock lists it but the file was deleted.",
"enum": [
"missing"
],
"type": "string"
},
{
"description": "Someone else's file sits at the path.",
"enum": [
"occupied"
],
"type": "string"
}
]
},
"MergeStatus": {
"enum": [
"clean",
"conflicts"
],
"type": "string"
},
"ModelChanged": {
"properties": {
"agent": {
"default": "",
"type": "string"
},
"from": {
"default": null,
"type": [
"string",
"null"
]
},
"to": {
"default": null,
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"Plan": {
"properties": {
"author": {
"anyOf": [
{
"$ref": "#/definitions/Author"
},
{
"type": "null"
}
]
},
"blocking": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"bump": {
"description": "`major` | `minor` | `patch` | `prerelease` (update).",
"type": [
"string",
"null"
]
},
"capabilities": {
"$ref": "#/definitions/Capabilities"
},
"counts": {
"$ref": "#/definitions/PlanCounts"
},
"created_at": {
"type": "string"
},
"deprecation": {
"anyOf": [
{
"$ref": "#/definitions/Deprecation"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"expires_at": {
"type": "string"
},
"files": {
"items": {
"$ref": "#/definitions/PlanFile"
},
"type": "array"
},
"from": {
"description": "Installed version (update, remove).",
"type": [
"string",
"null"
]
},
"functions": {
"description": "Functions the kit's profiles preload, with the worker that provides each.",
"items": {
"$ref": "#/definitions/KitFunction"
},
"type": "array"
},
"kind": {
"$ref": "#/definitions/PlanKind"
},
"kit": {
"type": "string"
},
"license": {
"type": [
"string",
"null"
]
},
"major": {
"type": "boolean"
},
"notes": {
"type": [
"string",
"null"
]
},
"plan_id": {
"type": "string"
},
"published_at": {
"type": [
"string",
"null"
]
},
"registry_url": {
"description": "The kit's page in the registry web app.",
"type": "string"
},
"repo": {
"type": [
"string",
"null"
]
},
"requested": {
"description": "What was asked for (tag, version or range) — stored in the lock.",
"type": "string"
},
"review": {
"description": "Where a human reviews it.",
"type": "string"
},
"to": {
"description": "Version this plan installs (install, update).",
"type": [
"string",
"null"
]
},
"warnings": {
"items": {
"$ref": "#/definitions/Issue"
},
"type": "array"
},
"workers": {
"items": {
"$ref": "#/definitions/PlanWorker"
},
"type": "array"
}
},
"required": [
"blocking",
"capabilities",
"counts",
"created_at",
"expires_at",
"files",
"functions",
"kind",
"kit",
"major",
"plan_id",
"registry_url",
"requested",
"review",
"warnings",
"workers"
],
"type": "object"
},
"PlanCounts": {
"properties": {
"added": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"agents": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"collisions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"decisions_required": {
"description": "Files whose `default` is `null`.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"functions": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"modified": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"removed": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"skills": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"unchanged": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"workers": {
"format": "uint",
"minimum": 0,
"type": "integer"
}
},
"required": [
"added",
"agents",
"collisions",
"conflicts",
"decisions_required",
"functions",
"modified",
"removed",
"skills",
"unchanged",
"workers"
],
"type": "object"
},
"PlanFile": {
"properties": {
"agent": {
"anyOf": [
{
"$ref": "#/definitions/AgentEntry"
},
{
"type": "null"
}
],
"description": "Kit profile frontmatter (agents; the side this plan installs, or the removed one)."
},
"agent_changes": {
"anyOf": [
{
"$ref": "#/definitions/AgentChanges"
},
{
"type": "null"
}
],
"description": "Frontmatter changes versus the installed version (modified agents)."
},
"base": {
"description": "Content hash the kit installed (the merge base).",
"type": [
"string",
"null"
]
},
"body_changed": {
"type": [
"boolean",
"null"
]
},
"change": {
"$ref": "#/definitions/Change"
},
"collision": {
"anyOf": [
{
"$ref": "#/definitions/Collision"
},
{
"type": "null"
}
]
},
"conflicts": {
"format": "uint",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"default": {
"anyOf": [
{
"$ref": "#/definitions/Decision"
},
{
"type": "null"
}
],
"description": "Applied when the caller decides nothing; `null` = a decision is required."
},
"id": {
"description": "Agent profile id, or skill id.",
"type": "string"
},
"kind": {
"$ref": "#/definitions/FileKind"
},
"local": {
"$ref": "#/definitions/LocalState"
},
"merge": {
"anyOf": [
{
"$ref": "#/definitions/MergeStatus"
},
{
"type": "null"
}
]
},
"note": {
"description": "One-line explanation for the review.",
"type": [
"string",
"null"
]
},
"options": {
"description": "Choices the apply accepts for this file.",
"items": {
"$ref": "#/definitions/Decision"
},
"type": "array"
},
"ours": {
"description": "Content hash of the local file when the plan was made.",
"type": [
"string",
"null"
]
},
"path": {
"description": "Logical install path (`agents/<id>.md`, `skills/<handle>/<kit>/…`).",
"type": "string"
},
"skill": {
"anyOf": [
{
"$ref": "#/definitions/SkillEntry"
},
{
"type": "null"
}
],
"description": "Skill frontmatter (skills)."
},
"skipped": {
"description": "The lock says the user kept someone else's file here.",
"type": "boolean"
},
"source": {
"description": "Path inside the kit (`agents/<id>.md`, `skills/…`).",
"type": "string"
},
"theirs": {
"description": "Content hash of the kit's version this plan installs.",
"type": [
"string",
"null"
]
}
},
"required": [
"change",
"id",
"kind",
"local",
"options",
"path",
"source"
],
"type": "object"
},
"PlanKind": {
"enum": [
"install",
"update",
"remove"
],
"type": "string"
},
"PlanStatus": {
"oneOf": [
{
"description": "A plan is waiting for review (or for `directory::kits::apply`).",
"enum": [
"planned"
],
"type": "string"
},
{
"description": "`apply=true` and the plan needed no review: it was applied.",
"enum": [
"applied"
],
"type": "string"
},
{
"description": "The installed version is already the one asked for.",
"enum": [
"up_to_date"
],
"type": "string"
},
{
"description": "The project changed since the plan was made; this is a fresh plan.",
"enum": [
"replanned"
],
"type": "string"
}
]
},
"PlanWorker": {
"properties": {
"action": {
"$ref": "#/definitions/WorkerAction"
},
"container": {
"type": [
"string",
"null"
]
},
"declared": {
"description": "`version:` selector in the compose file.",
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"installed": {
"description": "Version Compose has installed.",
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"path": {
"description": "The operator's `path://` build; kits never manage it.",
"type": "boolean"
},
"range": {
"description": "Range the kit declares (absent for a worker the kit dropped).",
"type": [
"string",
"null"
]
},
"range_from": {
"description": "Range the installed kit version declared.",
"type": [
"string",
"null"
]
},
"registry_url": {
"type": "string"
},
"to": {
"description": "Version the range resolves to in the registry today.",
"type": [
"string",
"null"
]
},
"type": {
"description": "Worker type (`binary`, `image`, …).",
"type": [
"string",
"null"
]
},
"used_by": {
"description": "Other installed kits that declare this worker.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"action",
"name",
"registry_url"
],
"type": "object"
},
"SkillEntry": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"id": {
"default": "",
"type": "string"
},
"path": {
"default": "",
"type": "string"
},
"sha256": {
"default": "",
"type": "string"
},
"size_bytes": {
"default": null,
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"title": {
"default": null,
"type": [
"string",
"null"
]
},
"type": {
"default": null,
"type": [
"string",
"null"
]
},
"used_by": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"SourceKind": {
"enum": [
"kit",
"worker",
"local",
"global",
"builtin"
],
"type": "string"
},
"StepState": {
"enum": [
"pending",
"running",
"done",
"failed",
"skipped"
],
"type": "string"
},
"WorkerAction": {
"oneOf": [
{
"enum": [
"none"
],
"type": "string"
},
{
"description": "Not in the compose file: `compose::add` declares it with the kit's range.",
"enum": [
"add"
],
"type": "string"
},
{
"description": "Declared, but the installed version is outside the kit's range: `compose::add` re-declares the range and Compose moves the worker.",
"enum": [
"update"
],
"type": "string"
},
{
"description": "The range changed and the compose file still declares the kit's old range; the installed version already satisfies the new one, so only the declaration moves.",
"enum": [
"redeclare"
],
"type": "string"
},
{
"description": "The kit no longer declares it. Never removed unless asked (`remove_workers`).",
"enum": [
"remove"
],
"type": "string"
}
]
}
},
"description": "Response of `directory::download-kit`, `plan-update`, `remove` and `apply`.",
"properties": {
"kit": {
"type": "string"
},
"message": {
"description": "One sentence for a terminal user.",
"type": "string"
},
"plan": {
"anyOf": [
{
"$ref": "#/definitions/Plan"
},
{
"type": "null"
}
]
},
"report": {
"anyOf": [
{
"$ref": "#/definitions/ApplyReport"
},
{
"type": "null"
}
]
},
"status": {
"$ref": "#/definitions/PlanStatus"
}
},
"required": [
"kit",
"message",
"status"
],
"title": "KitPlanResponse",
"type": "object"
}
},
{
"description": "Internal: reload tunable iii-directory settings from the authoritative configuration when it changes.",
"metadata": {
"internal": true
},
"name": "directory::on-config-change",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Trigger payload for `directory::on-config-change`. The handler ignores it (it re-fetches from the authoritative configuration); the empty struct exists so the function publishes a typed request schema rather than AnyValue.",
"title": "OnConfigChangeRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ok": {
"type": "boolean"
}
},
"required": [
"ok"
],
"title": "OnConfigChangeResponse",
"type": "object"
}
},
{
"description": "Internal: refresh the search catalog after the engine function set changes.",
"metadata": {
"internal": true,
"trace_hidden": true
},
"name": "directory::on-functions-change",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"event": {
"type": [
"string",
"null"
]
}
},
"title": "OnFunctionsChangeEvent",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ok": {
"type": "boolean"
}
},
"required": [
"ok"
],
"title": "AckResponse",
"type": "object"
}
},
{
"description": "Internal: inject the conditional search hint into one harness generation.",
"metadata": {
"internal": true,
"trace_hidden": true
},
"name": "directory::pre-generate",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ExposeKind": {
"oneOf": [
{
"enum": [
"agent_trigger",
"native"
],
"type": "string"
},
{
"description": "Forward compatibility: an exposure mode this build does not know gets the mode-neutral call instruction rather than a deserialization error.",
"enum": [
"other"
],
"type": "string"
}
]
},
"GeneratePayload": {
"properties": {
"expose": {
"allOf": [
{
"$ref": "#/definitions/ExposeKind"
}
],
"description": "How the harness exposes functions to the model for this generation. Absent on harnesses that predate the field, which only ever exposed through agent_trigger by default."
},
"functions_generation": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"messages": {
"items": true,
"type": "array"
},
"system_prompt": {
"type": "string"
},
"tools": {
"items": {
"$ref": "#/definitions/ToolSchema"
},
"type": "array"
}
},
"required": [
"functions_generation",
"messages",
"system_prompt",
"tools"
],
"type": "object"
},
"ToolSchema": {
"description": "One catalog entry: the contract fields search runs on.",
"properties": {
"description": {
"type": "string"
},
"name": {
"type": "string"
},
"parameters": true
},
"required": [
"description",
"name",
"parameters"
],
"type": "object"
}
},
"properties": {
"depth": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"generate": {
"$ref": "#/definitions/GeneratePayload"
},
"session_id": {
"type": "string"
},
"step": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"turn_id": {
"type": "string"
}
},
"required": [
"depth",
"generate",
"session_id",
"step",
"turn_id"
],
"title": "PreGenerateHookRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"DiscoveryOutcome": {
"enum": [
"hint_injected",
"skipped"
],
"type": "string"
},
"DiscoveryPassV1": {
"description": "The durable transcript row for one hook pass. Coarse by design: outcome, reason, and counts only — no prompts, messages, tool contracts, session ids, or timings ever leave the hook.",
"properties": {
"allowed_functions": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"functions_generation": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"outcome": {
"$ref": "#/definitions/DiscoveryOutcome"
},
"reason": {
"anyOf": [
{
"$ref": "#/definitions/DiscoveryReason"
},
{
"type": "null"
}
]
}
},
"required": [
"allowed_functions",
"functions_generation",
"outcome"
],
"type": "object"
},
"DiscoveryReason": {
"enum": [
"search_unavailable",
"already_searched",
"narrow_surface",
"already_operating",
"task_guided",
"hint_already_sent"
],
"type": "string"
},
"DiscoveryTranscriptAnnotation": {
"properties": {
"data": {
"$ref": "#/definitions/DiscoveryPassV1"
},
"summary": {
"type": "string"
},
"type": {
"type": "string"
},
"version": {
"format": "uint8",
"minimum": 0,
"type": "integer"
}
},
"required": [
"data",
"summary",
"type",
"version"
],
"type": "object"
},
"PreGenerateAnnotations": {
"properties": {
"directory": {
"$ref": "#/definitions/DiscoveryTranscriptAnnotation"
}
},
"required": [
"directory"
],
"type": "object"
},
"PreGenerateMutations": {
"properties": {
"append_messages": {
"description": "Ephemeral tail messages for this generation only. The hint rides here rather than as a system-prompt mutation: the system prompt is the provider's first input item, and a once-per-turn append there invalidated the entire prompt-cache prefix twice per turn.",
"items": true,
"type": "array"
}
},
"required": [
"append_messages"
],
"type": "object"
}
},
"properties": {
"annotations": {
"$ref": "#/definitions/PreGenerateAnnotations"
},
"decision": {
"type": "string"
},
"mutations": {
"anyOf": [
{
"$ref": "#/definitions/PreGenerateMutations"
},
{
"type": "null"
}
]
}
},
"required": [
"annotations",
"decision"
],
"title": "PreGenerateHookResponse",
"type": "object"
}
},
{
"description": "Preview one registry worker before installing: envelope (version, kind, dependencies, config), its public function and trigger names with descriptions, and skill file paths. Schemas are omitted — install, then read contracts with engine::functions::info. Pass `readme: true` for the README prose; `version` or `tag` (default tag \"latest\").",
"metadata": {},
"name": "directory::registry::workers::info",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "`directory::registry::workers::info` input. Pass either `version` or `tag`; if neither is provided we fall back to `tag: \"latest\"`.",
"properties": {
"name": {
"description": "Worker name in the registry (e.g. `\"resend\"`).",
"type": "string"
},
"readme": {
"default": false,
"description": "Include the README markdown (10–25 KB for most workers). Off by default: the card is for judging fit before `compose::add`; the README is for setup prose and examples.",
"type": "boolean"
},
"tag": {
"default": null,
"type": [
"string",
"null"
]
},
"version": {
"default": null,
"description": "Mutually exclusive with `tag`. If neither is provided we fall back to `tag: \"latest\"`.",
"type": [
"string",
"null"
]
}
},
"required": [
"name"
],
"title": "WorkerInfoInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ApiReference": {
"properties": {
"functions": {
"default": [],
"items": {
"$ref": "#/definitions/ApiReferenceFunction"
},
"type": "array"
},
"triggers": {
"default": [],
"items": {
"$ref": "#/definitions/ApiReferenceTrigger"
},
"type": "array"
}
},
"type": "object"
},
"ApiReferenceFunction": {
"properties": {
"description": {
"type": [
"string",
"null"
]
},
"metadata": true,
"name": {
"type": "string"
},
"request_schema": true,
"response_schema": true
},
"required": [
"name"
],
"type": "object"
},
"ApiReferenceTrigger": {
"properties": {
"description": {
"type": [
"string",
"null"
]
},
"invocation_schema": true,
"metadata": true,
"name": {
"type": "string"
},
"return_schema": true
},
"required": [
"name"
],
"type": "object"
},
"Dependency": {
"description": "Worker dependency entry. Mirrors the `Dependency` schema in `openapi.yaml`.",
"properties": {
"name": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": [
"name",
"version"
],
"type": "object"
},
"SkillsTree": {
"properties": {
"skills": {
"default": [],
"items": {
"$ref": "#/definitions/SkillsTreeSkill"
},
"type": "array"
}
},
"type": "object"
},
"SkillsTreeSkill": {
"properties": {
"path": {
"type": "string"
}
},
"required": [
"path"
],
"type": "object"
},
"Worker": {
"description": "Shared worker envelope used by both `directory::registry::workers::list` rows and the `worker` field of `directory::registry::workers::info`. Field names match the OpenAPI `WorkerListItem` schema. The shared core fields (`name`, `description`, `version`) line up with the engine's `engine::workers::list` row shape so callers learn one envelope across local + registry surfaces.",
"properties": {
"author": {
"anyOf": [
{
"$ref": "#/definitions/WorkerAuthor"
},
{
"type": "null"
}
],
"default": null
},
"config": {
"default": {},
"description": "Free-form runtime configuration block from the publish payload."
},
"dependencies": {
"default": [],
"items": {
"$ref": "#/definitions/Dependency"
},
"type": "array"
},
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"image": {
"description": "Container image tag, populated only for `type=image` workers.",
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"repo": {
"default": null,
"type": [
"string",
"null"
]
},
"supported_targets": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"total_downloads": {
"default": 0,
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"type": {
"default": null,
"description": "Worker kind — `binary`, `image`, or `engine`.",
"type": [
"string",
"null"
]
},
"version": {
"default": null,
"description": "Latest published version (worker-list) or the resolved version (worker-info, when called with `version` / `tag`).",
"type": [
"string",
"null"
]
}
},
"required": [
"name"
],
"type": "object"
},
"WorkerAuthor": {
"description": "Author block for a published worker. Field names match the `WorkerAuthor` schema in `openapi.yaml` (`pfp`, `verified`).",
"properties": {
"name": {
"type": [
"string",
"null"
]
},
"pfp": {
"default": null,
"description": "Profile picture URL. `null` when the author hasn't uploaded one.",
"type": [
"string",
"null"
]
},
"verified": {
"default": false,
"type": "boolean"
}
},
"type": "object"
}
},
"properties": {
"api_reference": {
"$ref": "#/definitions/ApiReference"
},
"readme": {
"type": [
"string",
"null"
]
},
"skills_tree": {
"$ref": "#/definitions/SkillsTree"
},
"worker": {
"allOf": [
{
"$ref": "#/definitions/Worker"
}
],
"description": "Same shape as `directory::registry::workers::list` rows (and the engine's `engine::workers::list` rows for the shared core fields)."
}
},
"required": [
"api_reference",
"skills_tree",
"worker"
],
"title": "WorkerInfoOutput",
"type": "object"
}
},
{
"description": "List workers from the public registry, optionally filtered by fuzzy `search` (default order: downloads). Cursor-paginated: pass back `pagination.next_cursor` as `cursor`.",
"metadata": {},
"name": "directory::registry::workers::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "`directory::registry::workers::list` input. Mirrors the engine's `engine::workers::list` search input so callers can switch between local and registry surfaces without re-learning the API. Adds `cursor` for paging because the registry is paged (server-authored page size — the client cannot override it).",
"properties": {
"cursor": {
"default": null,
"description": "Cursor from a previous call's `pagination.next_cursor`; omit for the first page.",
"type": [
"string",
"null"
]
},
"search": {
"default": null,
"description": "Optional free-text query, fuzzy-matched by the registry; omitted means ordered by downloads.",
"type": [
"string",
"null"
]
}
},
"title": "WorkerListInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Dependency": {
"description": "Worker dependency entry. Mirrors the `Dependency` schema in `openapi.yaml`.",
"properties": {
"name": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": [
"name",
"version"
],
"type": "object"
},
"Pagination": {
"description": "Pagination envelope returned alongside a worker-list page. Mirrors the OpenAPI `Pagination` schema.",
"properties": {
"has_more": {
"default": false,
"type": "boolean"
},
"next_cursor": {
"default": null,
"description": "Opaque cursor for the next page. `null` on the last page.",
"type": [
"string",
"null"
]
},
"page_size": {
"default": 0,
"description": "Server-authored page size. The client cannot override this.",
"format": "uint32",
"minimum": 0,
"type": "integer"
}
},
"type": "object"
},
"Worker": {
"description": "Shared worker envelope used by both `directory::registry::workers::list` rows and the `worker` field of `directory::registry::workers::info`. Field names match the OpenAPI `WorkerListItem` schema. The shared core fields (`name`, `description`, `version`) line up with the engine's `engine::workers::list` row shape so callers learn one envelope across local + registry surfaces.",
"properties": {
"author": {
"anyOf": [
{
"$ref": "#/definitions/WorkerAuthor"
},
{
"type": "null"
}
],
"default": null
},
"config": {
"default": {},
"description": "Free-form runtime configuration block from the publish payload."
},
"dependencies": {
"default": [],
"items": {
"$ref": "#/definitions/Dependency"
},
"type": "array"
},
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"image": {
"description": "Container image tag, populated only for `type=image` workers.",
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"repo": {
"default": null,
"type": [
"string",
"null"
]
},
"supported_targets": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"total_downloads": {
"default": 0,
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"type": {
"default": null,
"description": "Worker kind — `binary`, `image`, or `engine`.",
"type": [
"string",
"null"
]
},
"version": {
"default": null,
"description": "Latest published version (worker-list) or the resolved version (worker-info, when called with `version` / `tag`).",
"type": [
"string",
"null"
]
}
},
"required": [
"name"
],
"type": "object"
},
"WorkerAuthor": {
"description": "Author block for a published worker. Field names match the `WorkerAuthor` schema in `openapi.yaml` (`pfp`, `verified`).",
"properties": {
"name": {
"type": [
"string",
"null"
]
},
"pfp": {
"default": null,
"description": "Profile picture URL. `null` when the author hasn't uploaded one.",
"type": [
"string",
"null"
]
},
"verified": {
"default": false,
"type": "boolean"
}
},
"type": "object"
}
},
"properties": {
"pagination": {
"$ref": "#/definitions/Pagination"
},
"workers": {
"items": {
"$ref": "#/definitions/Worker"
},
"type": "array"
}
},
"required": [
"pagination",
"workers"
],
"title": "WorkerListOutput",
"type": "object"
}
},
{
"description": "Search available functions for the unmet external capabilities of a step (usually one to six, at most eighteen per call); returns compact function-id candidates grouped by worker, plus matching installed skill documents under `skills` and registered trigger bindings under `triggers`.",
"metadata": {},
"name": "directory::search_functions",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"capabilities": {
"description": "Non-empty capability searches derived from the goal and current execution state, usually one to six and at most eighteen per call (searched in batches of six). For one search at each decision point, include all unmet external capabilities once. Exclude intrinsic reasoning, summarization, planning, or formatting, and do not repeat needs already represented or satisfied. Requests to summarize provided text or content are ignored. Write every entry in English, translating non-English user requests while preserving proper names, URLs, and function IDs.",
"items": {
"minLength": 1,
"type": "string"
},
"minItems": 1,
"type": "array",
"uniqueItems": true
}
},
"required": [
"capabilities"
],
"title": "SearchFunctionsRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"FunctionCandidate": {
"properties": {
"description": {
"description": "First description sentence, capped at 160 bytes.",
"type": "string"
},
"function_id": {
"type": "string"
}
},
"required": [
"description",
"function_id"
],
"type": "object"
},
"FunctionSearchMode": {
"enum": [
"lexical",
"hybrid",
"judge"
],
"type": "string"
},
"InstallCall": {
"description": "A ready-made `compose::add` target and payload. Under agent-trigger exposure, the caller still supplies the wrapper's user-facing `description`.",
"properties": {
"function": {
"type": "string"
},
"payload": true
},
"required": [
"function",
"payload"
],
"type": "object"
},
"InstallableWorker": {
"description": "A registry worker that is NOT installed but carries functions matching the requested capabilities. `name` is the registry slug `compose::add` installs.",
"properties": {
"description": {
"type": "string"
},
"functions": {
"description": "Compact candidates only. If the remaining task needs these functions, reuse their IDs and fetch the required contracts through `engine::functions::info`.",
"items": {
"$ref": "#/definitions/FunctionCandidate"
},
"type": "array"
},
"install": {
"allOf": [
{
"$ref": "#/definitions/InstallCall"
}
],
"description": "The `compose::add` target and payload; agent-trigger callers add `description`."
},
"name": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": [
"description",
"functions",
"install",
"name",
"version"
],
"type": "object"
},
"SearchWorker": {
"properties": {
"functions": {
"items": {
"$ref": "#/definitions/FunctionCandidate"
},
"type": "array"
},
"namespace": {
"type": "string"
}
},
"required": [
"functions",
"namespace"
],
"type": "object"
},
"SkillCandidate": {
"description": "An installed skill document (a `directory::skills::list` row) whose content matches a requested capability.",
"properties": {
"description": {
"description": "First description sentence, capped at 160 bytes.",
"type": "string"
},
"id": {
"description": "Pass to `directory::skills::get { id }` to read the document.",
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"description",
"id",
"title"
],
"type": "object"
},
"TriggerCandidate": {
"description": "A registered trigger binding (an `engine::registered-triggers::list` row) whose event, schedule, or hook matches a requested capability.",
"properties": {
"config": {
"description": "The binding's configuration (cron expression, hook filters, …)."
},
"function_id": {
"description": "The function the trigger runs; inspect it with `engine::functions::info`.",
"type": "string"
},
"id": {
"type": "string"
},
"trigger_type": {
"type": "string"
},
"worker_name": {
"type": [
"string",
"null"
]
}
},
"required": [
"config",
"function_id",
"id",
"trigger_type"
],
"type": "object"
}
},
"properties": {
"guidance": {
"type": "string"
},
"installable": {
"description": "Matching workers from the private registry. Their functions are NOT callable until the worker is installed.",
"items": {
"$ref": "#/definitions/InstallableWorker"
},
"type": "array"
},
"latency_ms": {
"format": "double",
"type": "number"
},
"search_mode": {
"allOf": [
{
"$ref": "#/definitions/FunctionSearchMode"
}
],
"description": "The search mode that actually produced these results: `judge`, `hybrid` or `lexical`. It can be lower than the configured mode when a batch fell back (judge worker absent or failing, or no local model)."
},
"skills": {
"description": "Installed skill documents matching the capabilities. Read one with `directory::skills::get { id }` before acting on it.",
"items": {
"$ref": "#/definitions/SkillCandidate"
},
"type": "array"
},
"triggers": {
"description": "Registered trigger bindings matching the capabilities: what already fires, schedules, or hooks a function for them.",
"items": {
"$ref": "#/definitions/TriggerCandidate"
},
"type": "array"
},
"workers": {
"items": {
"$ref": "#/definitions/SearchWorker"
},
"type": "array"
}
},
"required": [
"guidance",
"latency_ms",
"search_mode",
"workers"
],
"title": "SearchFunctionsResponse",
"type": "object"
}
},
{
"description": "Create a new skill at <skills_folder>/<id>.md from full-file markdown (frontmatter optional, non-empty body). Rejects ids or paths that already exist, including system-installed skills. Use directory::skills::update to edit existing skills.",
"metadata": {
"tool": {
"label": "Create skill"
}
},
"name": "directory::skills::create",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"content": {
"description": "Full file content, frontmatter optional; only the size cap and a non-empty body are enforced.",
"type": "string"
},
"id": {
"description": "New skill id, used as the file path under skills_folder (`/`-separated segments of `[a-z0-9_-]`), not already taken.",
"type": "string"
}
},
"required": [
"content",
"id"
],
"title": "SkillCreateInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"bytes": {
"description": "Bytes written.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"function_id": {
"description": "Frontmatter `function_id:` of the content, `null` when absent.",
"type": [
"string",
"null"
]
},
"id": {
"description": "The created skill's id (normalized form of the input id).",
"type": "string"
},
"modified_at": {
"description": "File mtime after the write, RFC 3339.",
"type": "string"
},
"title": {
"description": "Title resolved from the content (frontmatter `title:`, then `name:`, then body H1, then the id) — what `list` rows will show.",
"type": "string"
},
"type": {
"description": "Frontmatter `type:` of the content, `null` when absent.",
"type": [
"string",
"null"
]
}
},
"required": [
"bytes",
"id",
"modified_at",
"title"
],
"title": "SkillCreateOutput",
"type": "object"
}
},
{
"description": "Delete one existing skill's markdown file by id (same id forms as directory::skills::get); refuses read-only system-installed skills.",
"metadata": {
"tool": {
"label": "Delete skill"
}
},
"name": "directory::skills::delete",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"description": "Existing skill id — the same forms `directory::skills::get` accepts (bare id, `<id>.md`, `SKILL(S).md`, `iii://<id>`).",
"type": "string"
}
},
"required": [
"id"
],
"title": "SkillDeleteInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"description": "Id of the skill whose file was removed — the RESOLVED on-disk id (e.g. `ns/index` for input `ns`), not the input form.",
"type": "string"
}
},
"required": [
"id"
],
"title": "SkillDeleteOutput",
"type": "object"
}
},
{
"description": "Download skills into skills_folder from exactly one source: {repo, skill, branch?} clones a GitHub skill folder; {worker, version?|tag?} pulls from the workers registry. Prefer the explicit download_from_registry / download_from_repo.",
"metadata": {
"tool": {
"label": "Download skills"
}
},
"name": "directory::skills::download",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"branch": {
"default": null,
"description": "Source A: branch to clone. Defaults to `\"main\"`. Pass `\"master\"` (or any other branch name) for repos whose default branch is not `main`.",
"type": [
"string",
"null"
]
},
"repo": {
"default": null,
"description": "Source A: GitHub repo URL. Pair with `skill`.",
"type": [
"string",
"null"
]
},
"skill": {
"default": null,
"description": "Source A: subfolder under `skills/` inside the repo. Doubles as the destination namespace inside `skills_folder`.",
"type": [
"string",
"null"
]
},
"tag": {
"default": null,
"description": "Registry tag to pull (default `latest`); mutually exclusive with `version`.",
"type": [
"string",
"null"
]
},
"version": {
"default": null,
"description": "Source B: explicit semver to pull. Mutually exclusive with `tag`.",
"type": [
"string",
"null"
]
},
"worker": {
"default": null,
"description": "Source B: workers registry name. Pair with exactly one of `version` / `tag`.",
"type": [
"string",
"null"
]
}
},
"title": "DownloadInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SkippedAgent": {
"description": "An agent profile a registry download did not write because a kit owns that id (`kits.lock`): kit profiles take precedence over worker ones.",
"properties": {
"id": {
"type": "string"
},
"owned_by": {
"description": "The owning kit, `<handle>/<name>`.",
"type": "string"
}
},
"required": [
"id",
"owned_by"
],
"type": "object"
}
},
"properties": {
"agents_skipped": {
"description": "Agent profiles the bundle ships but an installed kit owns: left as the kit wrote them (kit profiles take precedence).",
"items": {
"$ref": "#/definitions/SkippedAgent"
},
"type": "array"
},
"agents_written": {
"items": {
"type": "string"
},
"type": "array"
},
"namespace": {
"type": "string"
},
"skills_written": {
"items": {
"type": "string"
},
"type": "array"
},
"source": true,
"system_prompts_written": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"agents_skipped",
"agents_written",
"namespace",
"skills_written",
"source",
"system_prompts_written"
],
"title": "DownloadOutput",
"type": "object"
}
},
{
"description": "Download one worker's directory bundle from the workers registry into skills_folder. `worker` is required; pass `version` (exact semver) or `tag` (default \"latest\"), not both. Files are overwritten file-by-file.",
"metadata": {
"tool": {
"label": "Download skills (registry)"
}
},
"name": "directory::skills::download_from_registry",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Input for `directory::skills::download_from_registry`. The required `worker` field is what makes this function's source unambiguous at the schema level.",
"properties": {
"tag": {
"default": null,
"description": "Registry tag to pull (e.g. `\"latest\"`). Mutually exclusive with `version`. Defaults to `\"latest\"` when neither is provided.",
"type": [
"string",
"null"
]
},
"version": {
"default": null,
"description": "Explicit semver to pull. Mutually exclusive with `tag`.",
"type": [
"string",
"null"
]
},
"worker": {
"description": "Worker name in the registry (e.g. `\"shell\"`).",
"type": "string"
}
},
"required": [
"worker"
],
"title": "RegistryDownloadInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SkippedAgent": {
"description": "An agent profile a registry download did not write because a kit owns that id (`kits.lock`): kit profiles take precedence over worker ones.",
"properties": {
"id": {
"type": "string"
},
"owned_by": {
"description": "The owning kit, `<handle>/<name>`.",
"type": "string"
}
},
"required": [
"id",
"owned_by"
],
"type": "object"
}
},
"properties": {
"agents_skipped": {
"description": "Agent profiles the bundle ships but an installed kit owns: left as the kit wrote them (kit profiles take precedence).",
"items": {
"$ref": "#/definitions/SkippedAgent"
},
"type": "array"
},
"agents_written": {
"items": {
"type": "string"
},
"type": "array"
},
"namespace": {
"type": "string"
},
"skills_written": {
"items": {
"type": "string"
},
"type": "array"
},
"source": true,
"system_prompts_written": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"agents_skipped",
"agents_written",
"namespace",
"skills_written",
"source",
"system_prompts_written"
],
"title": "DownloadOutput",
"type": "object"
}
},
{
"description": "Download one skill folder from a GitHub repo into skills_folder: `repo` (https/ssh/git@ URL) and `skill` (subfolder under `skills/`, also the destination namespace) are required; `branch` defaults to \"main\".",
"metadata": {
"tool": {
"label": "Download skills (repo)"
}
},
"name": "directory::skills::download_from_repo",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Input for `directory::skills::download_from_repo`. The required `repo` + `skill` fields make this function's source unambiguous at the schema level.",
"properties": {
"branch": {
"default": null,
"description": "Branch to clone. Defaults to `\"main\"`.",
"type": [
"string",
"null"
]
},
"repo": {
"description": "GitHub repo URL (validated: https / ssh / git@ only).",
"type": "string"
},
"skill": {
"description": "Subfolder under `skills/` inside the repo. Doubles as the destination namespace inside `skills_folder`.",
"type": "string"
}
},
"required": [
"repo",
"skill"
],
"title": "RepoDownloadInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SkippedAgent": {
"description": "An agent profile a registry download did not write because a kit owns that id (`kits.lock`): kit profiles take precedence over worker ones.",
"properties": {
"id": {
"type": "string"
},
"owned_by": {
"description": "The owning kit, `<handle>/<name>`.",
"type": "string"
}
},
"required": [
"id",
"owned_by"
],
"type": "object"
}
},
"properties": {
"agents_skipped": {
"description": "Agent profiles the bundle ships but an installed kit owns: left as the kit wrote them (kit profiles take precedence).",
"items": {
"$ref": "#/definitions/SkippedAgent"
},
"type": "array"
},
"agents_written": {
"items": {
"type": "string"
},
"type": "array"
},
"namespace": {
"type": "string"
},
"skills_written": {
"items": {
"type": "string"
},
"type": "array"
},
"source": true,
"system_prompts_written": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"agents_skipped",
"agents_written",
"namespace",
"skills_written",
"source",
"system_prompts_written"
],
"title": "DownloadOutput",
"type": "object"
}
},
{
"description": "Fetch one skill by id and return its raw markdown body plus id, title, type, function_id, and modified_at. A worker overview is addressed by the bare worker name; `<id>.md` and `iii://<id>` forms are accepted. On a miss, D110 names the closest ids.",
"metadata": {
"tool": {
"label": "Get skill"
}
},
"name": "directory::skills::get",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"description": "Skill id as returned by directory::skills::list (e.g. `directory/skills/list`); `<id>.md` and `iii://<id>` forms are accepted.",
"type": "string"
},
"raw": {
"default": null,
"description": "When true, also return the exact on-disk file (frontmatter included) as `raw`, ready for directory::skills::update.",
"type": [
"boolean",
"null"
]
}
},
"required": [
"id"
],
"title": "SkillGetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"body": {
"description": "Raw markdown body (post-frontmatter) from disk.\n\nNote: there is no `description` field. `description` is the body's first paragraph, which is already inside `body` — every caller asking for the body would otherwise pay for the prefix twice. Use `directory::skills::list` rows when you want the teaser without the full body.",
"type": "string"
},
"disable_model_invocation": {
"description": "Whether model-facing indexes should omit this skill from invocation candidates.",
"type": "boolean"
},
"function_id": {
"description": "Frontmatter `function_id:` when present — the canonical bus function id this skill documents (e.g. `sandbox::create`). The response's `id` field is the SKILL path on disk; `function_id` is what the agent should pass to `agent_trigger`. `null` when the skill isn't 1:1 with a single function.",
"type": [
"string",
"null"
]
},
"id": {
"type": "string"
},
"modified_at": {
"description": "File mtime as RFC 3339.",
"type": "string"
},
"path": {
"description": "Absolute on-disk path of the skill file. Its parent directory is the skill's base directory — where payload the body references by relative path (`scripts/`, `reference/`, agent-skills convention) lives. Only meaningful to callers sharing this worker's filesystem (shell/file tools on the same machine).",
"type": "string"
},
"raw": {
"description": "FULL on-disk file content (frontmatter block included). Present only when the request set `raw: true`. This is the exact string to hand back to `directory::skills::update`; fallback notes that `get` may prepend to `body` are never added here.",
"type": [
"string",
"null"
]
},
"title": {
"description": "Frontmatter `title:` when present and non-empty, otherwise the first `# H1` line in the body, otherwise the bare `id`.",
"type": "string"
},
"type": {
"description": "Frontmatter `type:` (e.g. `index`, `how-to`, `reference`). `null` when the file has no frontmatter or omits the key.",
"type": [
"string",
"null"
]
}
},
"required": [
"body",
"disable_model_invocation",
"id",
"modified_at",
"path",
"title"
],
"title": "SkillGetOutput",
"type": "object"
}
},
{
"description": "Read a per-worker overview: one markdown block per installed worker (title, first paragraph, and the directory::skills::get call for the reference). For per-skill rows use directory::skills::list.",
"metadata": {},
"name": "directory::skills::index",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "IndexSkillsInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"body": {
"description": "Rendered markdown document — one short `## <title>` block per installed worker (each worker's root overview doc, whether or not it declares frontmatter `type: index`), carrying the worker's first-paragraph overview and a `directory::skills::get` call to read the full reference. Sorted lex by id.",
"type": "string"
},
"workers_count": {
"description": "Number of worker entries rendered (i.e. the count of worker overview rows that survived the filter). Cheap sanity check that doesn't require re-parsing the body.",
"format": "uint",
"minimum": 0,
"type": "integer"
}
},
"required": [
"body",
"workers_count"
],
"title": "IndexSkillsOutput",
"type": "object"
}
},
{
"description": "List skills, one row per skill (id, title, type, function_id, description, bytes, modified_at). Filters: `search` (substring on id/title/description), `prefix` (worker namespace), `type`; `include_description: false` for lighter rows. Pass a row's `function_id`, not its `id`, to agent_trigger.",
"metadata": {},
"name": "directory::skills::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"include_description": {
"default": null,
"description": "When `false`, the response omits the first-paragraph `description` field on every row. Useful for token-light pickers that only need `id` + `title` + `type`. Default `true`.",
"type": [
"boolean",
"null"
]
},
"prefix": {
"default": null,
"description": "Exact prefix match against `id`. Combine with `search` to scope a fuzzy match to one worker namespace, e.g. `prefix: \"sandbox/\"`.",
"type": [
"string",
"null"
]
},
"search": {
"default": null,
"description": "Case-insensitive substring match against `id`, `title`, and (when `include_description` is true) the first body paragraph. Omitted rows are filtered out cheaply on the FsSkill { id } pass before the per-file frontmatter read, so a narrowed list is dramatically cheaper for the caller than the unfiltered one.",
"type": [
"string",
"null"
]
},
"type": {
"default": null,
"description": "Exact match against the frontmatter `type:` field (`index`, `how-to`, `reference`, ...). `null` for entries with no frontmatter `type:`.",
"type": [
"string",
"null"
]
}
},
"title": "ListSkillsInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SkillEntry": {
"properties": {
"bytes": {
"format": "uint",
"minimum": 0,
"type": "integer"
},
"description": {
"description": "First paragraph of the body, empty when the file has only headings. Also empty when the caller passed `list { include_description: false }` for a token-light row.",
"type": "string"
},
"disable_model_invocation": {
"description": "Whether model-facing indexes should omit this skill from invocation candidates.",
"type": "boolean"
},
"function_id": {
"description": "Frontmatter `function_id:` when present — the canonical bus function id this skill documents (e.g. `sandbox::create`). The row's `id` field is the SKILL path on disk (e.g. `sandbox/skills/sandbox/create`); `function_id` is what an agent should pass to `agent_trigger`. `null` for skills that aren't 1:1 with a single function (index/reference).",
"type": [
"string",
"null"
]
},
"id": {
"type": "string"
},
"modified_at": {
"description": "File mtime as RFC 3339 (best effort; empty if unavailable).",
"type": "string"
},
"title": {
"description": "Frontmatter `title:` when present and non-empty, otherwise the first `# H1` line in the body, otherwise the bare `id`.",
"type": "string"
},
"type": {
"description": "Frontmatter `type:` (e.g. `index`, `how-to`, `reference`). `null` when the file has no frontmatter or omits the key.",
"type": [
"string",
"null"
]
}
},
"required": [
"bytes",
"description",
"disable_model_invocation",
"id",
"modified_at",
"title"
],
"type": "object"
}
},
"properties": {
"skills": {
"items": {
"$ref": "#/definitions/SkillEntry"
},
"type": "array"
}
},
"required": [
"skills"
],
"title": "ListSkillsOutput",
"type": "object"
}
},
{
"description": "Overwrite one existing skill with full-file markdown (pass back the `raw` from directory::skills::get { raw: true }, edited). Never creates files; refuses read-only system-installed skills.",
"metadata": {
"tool": {
"label": "Update skill"
}
},
"name": "directory::skills::update",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"content": {
"description": "FULL new file content, frontmatter block included — the string `directory::skills::get { raw: true }` returns, edited.",
"type": "string"
},
"id": {
"description": "Skill id to overwrite (same forms directory::skills::get accepts); the file must already exist.",
"type": "string"
}
},
"required": [
"content",
"id"
],
"title": "SkillUpdateInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"bytes": {
"description": "Bytes written.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"function_id": {
"description": "Frontmatter `function_id:` of the new content, `null` when absent.",
"type": [
"string",
"null"
]
},
"id": {
"description": "The id that was updated (normalized form of the input id).",
"type": "string"
},
"modified_at": {
"description": "File mtime after the write, RFC 3339.",
"type": "string"
},
"title": {
"description": "Title resolved from the NEW content (frontmatter `title:`, then body H1, then the id) — what `list` rows will now show.",
"type": "string"
},
"type": {
"description": "Frontmatter `type:` of the new content, `null` when absent.",
"type": [
"string",
"null"
]
}
},
"required": [
"bytes",
"id",
"modified_at",
"title"
],
"title": "SkillUpdateOutput",
"type": "object"
}
},
{
"description": "Create a new system prompt at <skills_folder>/system-prompts/<name>.md from full-file markdown (non-empty frontmatter `description` required; a declared `name` must match). Rejects names or paths that already exist.",
"metadata": {
"tool": {
"label": "Create system prompt"
}
},
"name": "directory::system-prompts::create",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"content": {
"description": "Full file content, frontmatter included; `description` is required and a declared `name` must match.",
"type": "string"
},
"name": {
"description": "New system prompt name, used as the file stem; same charset as listed names and not already taken.",
"type": "string"
}
},
"required": [
"content",
"name"
],
"title": "SystemPromptCreateInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"bytes": {
"description": "Bytes written.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"description": {
"description": "Description parsed from the frontmatter.",
"type": "string"
},
"modified_at": {
"description": "File mtime after the write, RFC 3339.",
"type": "string"
},
"name": {
"description": "The created system prompt's name (as requested).",
"type": "string"
}
},
"required": [
"bytes",
"description",
"modified_at",
"name"
],
"title": "SystemPromptCreateOutput",
"type": "object"
}
},
{
"description": "Permanently delete one EXISTING filesystem-backed system prompt by name. Resolves against the same merged scan as directory::system-prompts::list, removes only that prompt's markdown file, and fans out directory::system-prompts::on-change with { op: \"delete\" }.",
"metadata": {
"tool": {
"label": "Delete system prompt"
}
},
"name": "directory::system-prompts::delete",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"description": "Existing system prompt name, as returned by `directory::system-prompts::list`.",
"type": "string"
}
},
"required": [
"name"
],
"title": "SystemPromptDeleteInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"description": "Name of the system prompt whose file was removed.",
"type": "string"
}
},
"required": [
"name"
],
"title": "SystemPromptDeleteOutput",
"type": "object"
}
},
{
"description": "Fetch one system prompt by name — a filesystem-backed entry, or a worker-bundled one (`builtin: true`) when no local file shadows it. Returns the raw markdown body plus name, description, and modified_at — no envelope, no templating.",
"metadata": {},
"name": "directory::system-prompts::get",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string"
},
"raw": {
"default": null,
"description": "When `true`, the response includes the full on-disk file content (frontmatter included) as `raw`, ready for `directory::system-prompts::update`.",
"type": [
"boolean",
"null"
]
}
},
"required": [
"name"
],
"title": "SystemPromptGetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"body": {
"type": "string"
},
"builtin": {
"description": "Served from the copy bundled with the worker (no local file yet): an update creates the local file.",
"type": "boolean"
},
"description": {
"type": "string"
},
"modified_at": {
"type": "string"
},
"name": {
"type": "string"
},
"raw": {
"type": [
"string",
"null"
]
}
},
"required": [
"body",
"builtin",
"description",
"modified_at",
"name"
],
"title": "SystemPromptGetOutput",
"type": "object"
}
},
{
"description": "List system prompts (name, description, modified_at) from skills_folder's `system-prompts/` plus the ones bundled with this worker (`builtin: true` until a local file shadows one).",
"metadata": {},
"name": "directory::system-prompts::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ListSystemPromptsInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SystemPromptEntry": {
"properties": {
"builtin": {
"description": "Bundled with the worker, no file behind it: editing it creates the local file (which then shadows this entry); there is nothing to delete.",
"type": "boolean"
},
"description": {
"type": "string"
},
"modified_at": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"builtin",
"description",
"modified_at",
"name"
],
"type": "object"
}
},
"properties": {
"prompts": {
"items": {
"$ref": "#/definitions/SystemPromptEntry"
},
"type": "array"
}
},
"required": [
"prompts"
],
"title": "ListSystemPromptsOutput",
"type": "object"
}
},
{
"description": "Overwrite one existing system prompt with full-file markdown; the frontmatter must keep a non-empty `description`. Updating a bundled prompt (`builtin: true`) creates a local file that shadows it. Returns the effective name (frontmatter `name:` wins over the file stem).",
"metadata": {
"tool": {
"label": "Update system prompt"
}
},
"name": "directory::system-prompts::update",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"content": {
"description": "Full file content, frontmatter included; `description` must stay non-empty.",
"type": "string"
},
"name": {
"description": "System prompt name to overwrite, as listed; a bundled prompt (`builtin: true`) is copied to a local file first.",
"type": "string"
}
},
"required": [
"content",
"name"
],
"title": "SystemPromptUpdateInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"bytes": {
"description": "Bytes written.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"description": {
"description": "Description parsed from the new frontmatter.",
"type": "string"
},
"modified_at": {
"description": "File mtime after the write, RFC 3339.",
"type": "string"
},
"name": {
"description": "The system prompt's EFFECTIVE name after the write: the new frontmatter `name:` when declared, otherwise the file stem. Differs from the input name when the update renames the system prompt.",
"type": "string"
}
},
"required": [
"bytes",
"description",
"modified_at",
"name"
],
"title": "SystemPromptUpdateOutput",
"type": "object"
}
},
{
"description": "Serve the iii-directory worker's injected console UI assets (content function for its console:script / console:style / console:module triggers).",
"metadata": {
"internal": true
},
"name": "iii-directory::ui-content",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Input of the content function: the console asks for one asset by path.",
"properties": {
"path": {
"description": "The asset path from the trigger config (e.g. `state/page.js`).",
"type": "string"
}
},
"required": [
"path"
],
"title": "UiContentInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Output of the content function.",
"properties": {
"content": {
"description": "The asset source, verbatim.",
"type": "string"
},
"content_type": {
"description": "MIME type the console should serve the asset with.",
"type": "string"
}
},
"required": [
"content",
"content_type"
],
"title": "UiContentResult",
"type": "object"
}
}
],
"triggers": [
{
"description": "Fires after a directory::skills::download that wrote at least one agent profile, or a directory::agents::update, create, or delete. Also fires with { op: \"external\" } when a watched agents file changes on disk outside this worker.",
"invocation_schema": {},
"metadata": {},
"name": "directory::agents::on-change",
"return_schema": {}
},
{
"description": "Fires when kit state changes: a plan is created or discarded ({ op: \"plan\" | \"discard\", kit, plan_id }), an apply makes progress or finishes ({ op: \"progress\", plan_id, steps } / { op: \"apply\", kit, plan_id }), or an update check finds a different set of available updates ({ op: \"updates\" }).",
"invocation_schema": {},
"metadata": {},
"name": "directory::kits::on-change",
"return_schema": {}
},
{
"description": "Fires after a directory::skills::download that wrote at least one skill markdown file, or a directory::skills::update, create, or delete. Also fires with { op: \"external\" } when a watched skills root changes on disk outside this worker — including the read-only agents skills root, when that root exists at startup.",
"invocation_schema": {},
"metadata": {},
"name": "directory::skills::on-change",
"return_schema": {}
},
{
"description": "Fires after a directory::skills::download that wrote at least one system prompt, or a directory::system-prompts::update, create, or delete. Also fires with { op: \"external\" } when a watched system-prompts root changes on disk outside this worker.",
"invocation_schema": {},
"metadata": {},
"name": "directory::system-prompts::on-change",
"return_schema": {}
}
]
}