iii-directory
v0.5.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
install
configuration
- download_timeout_ms: 60000
registry_url: https://api.workers.iii.dev
skills_folder: ./skillsreadme
open as markdowniii-directory
Engine introspection, workers registry proxy, and filesystem-backed
skill + prompt reader for the iii engine.
Every public function sits under a single directory::* namespace,
split into four sub-namespaces (all MCP-agnostic):
| Surface | What clients see | When to use it |
|---|---|---|
Skills (directory::skills::*) |
Markdown documents under iii://{id} plus an iii://directory/skills index |
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 |
Engine (directory::engine::*) |
Read-side enrichment over engine::functions::list, engine::workers::list, engine::trigger-types::list, engine::triggers::list |
"What's connected to the engine right now?" |
Registry (directory::registry::*) |
HTTP proxy over api.workers.iii.dev with the same workers::{list,info} shape as directory::engine::workers::* |
"What's published in the public registry?" |
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::engine::workers::* and directory::registry::workers::*
share the same envelope shape so callers can switch between the local
engine view and the published-registry view without re-learning the API.
Table of contents
- Install
- Configuration
- Quickstart: download some skills
- On-disk layout
- URI scheme
- 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 (`iii://`, `directory::skills::fetch-skill`,
# `directory::skills::list`, `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}and the first segment must not be the literalfn(reserved for section URIs). - 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).
URI scheme
Same scheme as previous releases, anchored now on the filesystem:
| URI | Returns |
|---|---|
iii://directory/skills |
Auto-rendered markdown index of every skill in skills_folder. |
iii://{id} |
The body at . Any depth. First segment must NOT equal fn. |
iii://fn/{a}/{b}/.../{leaf} |
Trigger function a::b::...::leaf with {} and serve its output. Each / after fn/ becomes ::. |
The directory::skills::fetch-skill function is a thin batched wrapper
over the same resolver. Pass either uri (single) or uris (array) —
each entry may be a full iii:// URI or a bare skill path (the id
returned by directory::skills::list, auto-prefixed with iii://).
Sections are wrapped as # {uri}\n\n{body} and joined with
\n\n---\n\n.
There is no recursion guard on iii://fn/ URIs — the resolver
will trigger any function the engine exposes, including state::* and
engine::* infra. Adapters that surface
directory::skills::fetch-skill to untrusted callers should add their
own filtering.
Functions
Fifteen 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 |
Metadata-only listing of every fs-backed skill. |
directory::skills::fetch-skill |
Batched read across one or more iii:// URIs or bare skill paths (returns plain markdown). |
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. |
directory::engine::* (engine introspection)
| Function ID | Description |
|---|---|
directory::engine::functions::list |
List functions registered with the engine; filter by search/prefix/worker. |
directory::engine::functions::info |
Single-function detail: schemas, owning worker, registered triggers, bundled how-to. |
directory::engine::triggers::list |
List trigger TYPES registered with the engine; filter by search/prefix/worker. |
directory::engine::triggers::info |
Single trigger-type detail: configuration schema, return schema, instance count. |
directory::engine::registered-triggers::list |
List registered trigger INSTANCES (subscriber rows). |
directory::engine::registered-triggers::info |
Composite: instance + trigger-type detail + function detail. |
directory::engine::workers::list |
List workers connected to the engine; same row shape as directory::registry::workers::list. |
directory::engine::workers::info |
One worker's worker envelope + functions + trigger types + registered triggers. |
directory::registry::* (workers registry HTTP proxy)
| Function ID | Description |
|---|---|
directory::registry::workers::list |
Search published workers in api.workers.iii.dev. Same row shape as directory::engine::workers::list. |
directory::registry::workers::info |
Full registry detail for one worker: worker envelope (matching directory::engine::workers::info.worker) plus readme, api_reference, skills_tree. |
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 / URI / validators)
# 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.