iii-directory
v0.8.0Engine introspection (functions / triggers / workers), workers registry proxy, and filesystem-backed skill + prompt reader.
- macOS: arm64 · x64
- Linux: arm64 · armv7 · x64
- Windows: arm64 · x64 · x86
full markdown
/workers/iii-directory.md?version=0.8.0. paste it into an llm prompt or pipe it through curl from a worker.install
configuration
- download_timeout_ms: 60000
registry_url: https://api.workers.iii.dev
skills_folder: ./skillsdependencies
readme
iii-directory
Workers registry HTTP proxy and filesystem-backed skill + prompt
reader for the iii engine. Every
public function sits under a single directory::* namespace, split
into three sub-namespaces (all MCP-agnostic):
| Surface | What clients see | When to use it |
|---|---|---|
Skills (directory::skills::*) |
Enriched listing via directory::skills::list ({ id, title, type, description, bytes, modified_at } per row), a single-skill reader directory::skills::get { id } returning { id, title, type, description, body, modified_at }, and directory::skills::index which renders a short per-worker overview document (one ## + first paragraph + read more link per type: index skill). title prefers the YAML frontmatter title: over the body H1; type is lifted from frontmatter type: (e.g. index, how-to, reference) and serialised as null when absent. |
Orientation: "when and why to use my worker's tools" |
Prompts (directory::prompts::*) |
Static prompt templates listed by directory::prompts::list and read by directory::prompts::get |
Parametric command templates the user invokes |
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::*. Earlier
versions of this crate wrapped those calls under directory::engine::*
helpers; the wrappers have been removed — call the engine ids
directly.
Skills and prompts are sourced from a single configured folder on disk
(skills_folder). The only write path is the
directory::skills::download function, which pulls markdown into
skills_folder from either the
workers registry or a GitHub repo. Once
downloaded, files belong to the developer — edit them however you want.
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
- Functions
- Custom trigger types
- Local development & testing
- Migration from skills v0.2.x
Install
iii worker add iii-directoryiii worker add fetches the binary, writes a config block into
~/.iii/config.yaml, and the engine starts the worker on the next
iii start.
Configuration
# Folder that backs every read (`directory::skills::list`,
# `directory::skills::get`, `directory::prompts::*`) and every write
# from `directory::skills::download`. Relative paths are resolved
# against the process current working directory; absolute paths are
# used as-is.
skills_folder: ./skills
# Workers registry base URL — used by `directory::skills::download`
# and the `directory::registry::*` proxies when a `worker=` source is
# specified. Override for self-hosted deployments.
registry_url: https://api.workers.iii.dev
# Timeout for a single download (`git clone` or HTTP request) in ms.
download_timeout_ms: 60000The folder is created on first download if it doesn't exist.
Quickstart: download some skills
# Pull a specific worker's skills + prompts 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, prompts_written, source }
where skills_written and prompts_written are arrays of relative
paths / prompt names that were materialised in this run.
After every successful download the worker fires the
directory::skills::on-change and/or directory::prompts::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 assumes a fixed layout under skills_folder:
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
prompts/ # ← magic marker for prompts
send-email.md # ← MCP slash-command (needs YAML frontmatter)
triage.mdA 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 honours
two keys:
title:(used bydirectory::skills::listanddirectory::skills::getin preference to a body# H1) andtype:(free-form classifier surfaced verbatim on both responses). Any other YAML keys are ignored. - Prompts live under any
*/prompts/*.mdpath. They must start with a YAML frontmatter block declaring at leastdescription;nameis optional and overrides the file-stem default. - Files anywhere else (i.e. not in a
prompts/segment) are skills.
The download function namespaces by source:
| Source | Destination |
|---|---|
repo=URL skill=NAME branch?=main |
|
worker=NAME version=… |
|
worker=NAME tag=… (default tag=latest) |
|
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().
Functions
Sixteen functions, all under directory::*. All registrations are
namespace-clean; this worker is intentionally agnostic to MCP and any
other adapter.
directory::skills::* (filesystem reader)
| Function ID | Description |
|---|---|
directory::skills::download |
Pull markdown into skills_folder. Either {repo, skill, branch?} (defaults branch=main) or `{worker, version? |
directory::skills::list |
Enriched listing of every fs-backed skill: { id, title, type, 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), and description is the first paragraph of the body — 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, description, body, modified_at } — same shape directory::skills::list rows use, plus the raw markdown body. Same title-resolution and type precedence as list. Accepts a bare id or the same id prefixed with iii://. |
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::prompts::* (filesystem reader)
| Function ID | Description |
|---|---|
directory::prompts::list |
Metadata-only listing of every fs-backed prompt. |
directory::prompts::get |
Fetch one prompt's body + {name, description, modified_at}. Plain shape, no envelope. |
Engine introspection (native)
Engine introspection is no longer wrapped here. Call the engine's
native ids directly — every one takes the same filters
(prefix, search, worker, include_internal where applicable):
| 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 (iii-http, iii-cron, iii-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 |
Full registry detail 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/prompts tree — and merges them into { worker, readme, api_reference, skills_tree }. The user-facing 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 /
directory::prompts::register — see
Migration below.
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 |
{ "op": "download", "namespace": " |
directory::prompts::on-change |
After a directory::skills::download that wrote at least one prompt markdown file |
{ "op": "download", "namespace": " |
Dispatches are fire-and-forget (Void), so the download path doesn't block on downstream latency.
Local development & testing
Run from source
cargo run --release -- --url ws://127.0.0.1:49134 --config ./config.yamlTests
# 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 @prompts @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.
api reference (json)
{
"functions": [
{
"description": "Fetch one filesystem-backed 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 (e.g. \"iii-sandbox\") — that is the id `list`/`index` hand back. Input is forgiving: \"iii-sandbox/index\", \"iii-sandbox/SKILL.md\", a trailing \".md\", and an iii:// prefix all resolve to the same overview; and if the exact id misses, the worker name is matched case-insensitively as a substring (\"sandbox\" finds \"iii-sandbox\"). `title` prefers frontmatter `title:` over the body H1; `type` is the frontmatter `type:`. There is no `description` field here (the body already opens with that paragraph) — use directory::skills::list for the teaser-only view. On a miss you get a `D110 not_found` message naming the closest ids and the next function to call.",
"metadata": {
"tool": {
"label": "Get skill"
}
},
"name": "directory::skills::get",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"description": "Skill id (the same string returned by `directory::skills::list`, e.g. `\"directory/skills/list\"`). Two ergonomic variants are also accepted: the file-path form `<id>.md` (the trailing `.md` is stripped) and the legacy `iii://{id}` URI form. Other URI schemes are rejected. The filename `SKILLS.md` is aliased to `index.md` to match the filesystem scanner.",
"type": "string"
}
},
"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"
},
"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"
},
"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",
"id",
"modified_at",
"title"
],
"title": "SkillGetOutput",
"type": "object"
}
},
{
"description": "List filesystem-backed prompts (name, description, modified_at) from skills_folder.",
"metadata": {},
"name": "directory::prompts::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ListPromptsInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"PromptEntry": {
"properties": {
"description": {
"type": "string"
},
"modified_at": {
"description": "File mtime as RFC 3339.",
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"description",
"modified_at",
"name"
],
"type": "object"
}
},
"properties": {
"prompts": {
"items": {
"$ref": "#/definitions/PromptEntry"
},
"type": "array"
}
},
"required": [
"prompts"
],
"title": "ListPromptsOutput",
"type": "object"
}
},
{
"description": "Internal: auto-download skills on worker add event.",
"metadata": {},
"name": "directory::__on_worker_added",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AnyValue"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AnyValue"
}
},
{
"description": "Fetch one filesystem-backed prompt by name. Returns the raw markdown body plus name, description, and modified_at — no envelope, no templating.",
"metadata": {},
"name": "directory::prompts::get",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"title": "PromptGetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"body": {
"description": "Raw markdown body (post-frontmatter) from disk.",
"type": "string"
},
"description": {
"type": "string"
},
"modified_at": {
"description": "File mtime as RFC 3339.",
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"body",
"description",
"modified_at",
"name"
],
"title": "PromptGetOutput",
"type": "object"
}
},
{
"description": "List skills as one row PER SKILL (id, title, type, function_id, description, bytes, modified_at) from skills_folder — use this when you need individual skill ids. A worker overview row's `id` is the bare worker name (e.g. `iii-sandbox`); pass it straight to directory::skills::get. For a per-WORKER overview instead, call directory::skills::index. Filters: `search` (case-insens. substring vs id+title+description), `prefix` (worker-namespace prefix; matches the overview row and its sub-skills), `type` (exact frontmatter type match). Pass `include_description: false` for token-light id+title+type rows (default: descriptions included). `title` prefers frontmatter `title:` over the body H1. Each row's `function_id` is the callable bus id (e.g. `sandbox::create`) — pass THAT to agent_trigger, not the row's `id` (which is a documentation address).",
"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"
},
"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",
"id",
"modified_at",
"title"
],
"type": "object"
}
},
"properties": {
"skills": {
"items": {
"$ref": "#/definitions/SkillEntry"
},
"type": "array"
}
},
"required": [
"skills"
],
"title": "ListSkillsOutput",
"type": "object"
}
},
{
"description": "Download one worker's skills + prompts from the workers registry into skills_folder. `worker` is required; pass either `version` (exact semver) OR `tag` (e.g. \"latest\", the default when both are omitted), not both. Files in the destination namespace are overwritten file-by-file. A missing worker returns a `D310 not_found` naming the next function to call. To pull from a GitHub repo instead, use directory::skills::download_from_repo.",
"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#",
"properties": {
"namespace": {
"type": "string"
},
"prompts_written": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_written": {
"items": {
"type": "string"
},
"type": "array"
},
"source": true
},
"required": [
"namespace",
"prompts_written",
"skills_written",
"source"
],
"title": "DownloadOutput",
"type": "object"
}
},
{
"description": "Download skills + prompts into skills_folder from EITHER source. Prefer the explicit directory::skills::download_from_registry / directory::skills::download_from_repo, whose schemas can't be mixed up. Pass {repo, skill, branch?} to clone one skill folder from a GitHub repo (branch defaults to \"main\"), or {worker, version?|tag?} to pull from the workers registry (tag defaults to \"latest\"). Specify exactly ONE source set. Files in the destination namespace are overwritten file-by-file.",
"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": "Source B: registry tag to pull (e.g. `latest`). Mutually exclusive with `version`. Defaults to `\"latest\"` when neither `version` nor `tag` is provided.",
"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#",
"properties": {
"namespace": {
"type": "string"
},
"prompts_written": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_written": {
"items": {
"type": "string"
},
"type": "array"
},
"source": true
},
"required": [
"namespace",
"prompts_written",
"skills_written",
"source"
],
"title": "DownloadOutput",
"type": "object"
}
},
{
"description": "List workers from the public registry (api.workers.iii.dev). Optional free-text `search` is matched fuzzily by the registry; omit it to browse by `total_downloads DESC`. Pagination is cursor-based with a server-authored page size — pass back `pagination.next_cursor` as `cursor` to fetch the next page. Shares the core `name` / `description` / `version` fields with the engine's `engine::workers::list`. Results are cached for `registry_cache_ttl_ms` (default 60s).",
"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": "Opaque cursor returned by a previous call's `pagination.next_cursor`. Pass back verbatim to fetch the next page; omit (or pass `null`) to fetch the first page.",
"type": [
"string",
"null"
]
},
"search": {
"default": null,
"description": "Optional free-text query. Forwarded to the registry as `?search=…`; the registry ranks results by `pg_trgm` similarity against `lower(name)` and `lower(description)`. When omitted, results are ordered by `total_downloads DESC`.",
"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": "Download one skill folder from a GitHub repo into skills_folder. `repo` (the repo URL) and `skill` (the subfolder under `skills/`, which also names the destination namespace) are required; `branch` defaults to \"main\". The repo URL is validated (https / ssh / git@ only). To pull a published worker instead, use directory::skills::download_from_registry.",
"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#",
"properties": {
"namespace": {
"type": "string"
},
"prompts_written": {
"items": {
"type": "string"
},
"type": "array"
},
"skills_written": {
"items": {
"type": "string"
},
"type": "array"
},
"source": true
},
"required": [
"namespace",
"prompts_written",
"skills_written",
"source"
],
"title": "DownloadOutput",
"type": "object"
}
},
{
"description": "Render a per-WORKER overview: one short markdown block per installed worker (each worker's root overview doc `<ns>/index`, whether or not it declares frontmatter `type: index`). Each block is a `## <worker title>` heading, the first paragraph of that worker's overview, and a `directory::skills::get` call to read the full reference. Token-light by design and intended for system-prompt injection; for individual per-SKILL rows call 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": "Fetch full registry metadata for one worker: worker envelope (same core fields as the engine's `engine::workers::list` row shape, plus registry-only `type` / `config` / `supported_targets` / `total_downloads` / `dependencies` / `image`), readme, full API reference (functions + triggers schemas), and the tree of skill / prompt file paths fetched from the registry's /w/{slug}/skills endpoint. Pass either `version` or `tag` (defaults to tag=\"latest\"). Results are cached for `registry_cache_ttl_ms`.",
"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"
},
"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": {
"prompts": {
"default": [],
"items": {
"$ref": "#/definitions/SkillsTreePrompt"
},
"type": "array"
},
"skills": {
"default": [],
"items": {
"$ref": "#/definitions/SkillsTreeSkill"
},
"type": "array"
}
},
"type": "object"
},
"SkillsTreePrompt": {
"properties": {
"description": {
"default": null,
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
}
},
"required": [
"name"
],
"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": "Full detail for one engine function: schemas, owning worker, and registered triggers that target it. Proxies to the engine's native engine::functions::info for the core data.",
"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"
}
}
],
"triggers": [
{
"description": "Fires after every successful directory::skills::download that wrote at least one skill markdown file.",
"invocation_schema": {},
"metadata": {},
"name": "directory::skills::on-change",
"return_schema": {}
},
{
"description": "Fires after every successful directory::skills::download that wrote at least one prompt markdown file.",
"invocation_schema": {},
"metadata": {},
"name": "directory::prompts::on-change",
"return_schema": {}
}
]
}