Put files where the worker finds them
A capability is a directory of files that agora overlays onto the worker’s workspace before the runtime adapter (Claude Code, etc.) starts. This guide answers the question every capability author hits: “I want my worker to have X — where do I put it?”
For the architectural model behind all this, see the MVP spec §6.3 (overlay engine) and §5.8 (runtime adapter seam). This page is the cookbook.
TL;DR — pick the right path
Section titled “TL;DR — pick the right path”| You want the worker to have… | Put it at this path in your capability dir |
|---|---|
| A Claude Code skill | .claude/skills/<skill-name>/SKILL.md (+ any supporting files) |
| Claude Code settings overrides | .claude/settings.json |
| Claude Code plugin installs | agora-plugins.json |
| A shell setup step | agora-setup.sh (⚠️ only one per dispatch — see below) |
| Arbitrary files at known paths | Just put them at the path you want |
Register the directory once with the CLI:
agora capabilities register --name <name> --from ./path/to/capability-dirOr auto-generate from an existing on-disk convention (.claude/skills/,
pokemon profiles, etc.) — see Sync capabilities & subagents.
How agora decides which file wins
Section titled “How agora decides which file wins”When a dispatch binds multiple capabilities, the worker overlays them in declared order. Conflicts at the same path are resolved per merge rule:
- Adapter-reserved paths — the runtime adapter (e.g.,
ClaudeCodeRuntimeAdapter) declares paths it owns and how to merge them. For Claude Code:.claude/settings.jsondeep-merges (unionon arrays),.claude/skills/**is last-write-wins per file. - Agora-defined manifest paths —
agora-setup.shis last-write-wins,agora-notifications.jsonis array-union,agora-channel.jsonis last-write-wins. - Everything else — last-write-wins on the file path.
The practical upshot: most things compose cleanly because each capability
writes to its own subpath. The exception is agora-setup.sh — see below.
Recipe: ship a Claude Code skill
Section titled “Recipe: ship a Claude Code skill”The skill must end up at <workspace>/.claude/skills/<name>/SKILL.md inside
the worker. The ClaudeCodeRuntimeAdapter reserves .claude/skills/**, and
the claude binary spawns with cwd=workspace, so a project-level skill at
that path is discovered natively — no setup script, no install step.
Your capability dir:
my-skill-cap/└── .claude/ └── skills/ └── my-skill/ ├── SKILL.md └── references/ └── helpful.mdRegister:
agora capabilities register --name my-skill --from ./my-skill-capMultiple capabilities can each ship their own skill — they land at different
.claude/skills/<distinct-name>/ paths, no conflict. This is exactly what
agora capabilities sync --provider claude-code automates.
Recipe: override Claude Code settings
Section titled “Recipe: override Claude Code settings”.claude/settings.json is deep-merged with array-union, so each capability
can contribute the fragment it cares about:
cap-allow-jq/└── .claude/ └── settings.json{ "permissions": { "allow": ["Bash(jq:*)"] } }Another capability adding Bash(rg:*) doesn’t clobber yours — the arrays
union, the final settings.json has both.
Recipe: install a tool in the worker
Section titled “Recipe: install a tool in the worker”Put an agora-setup.sh at your capability dir’s root:
#!/bin/shset -eapt-get update && apt-get install -y jq⚠️ Single-slot constraint. agora-setup.sh is last-write-wins on that
exact filename. If two of your bound capabilities each ship one, only
the last one in resolved order runs — the others silently disappear. Three
ways to work around this:
- One owning capability. Pick the capability that’s “primary” for the dispatch and put all setup logic there. The other capabilities deliver files only.
- Files at adapter-reserved paths — preferred when applicable. If the
runtime adapter knows about your path (
.claude/skills/,.claude/ settings.json, etc.), put the files there directly. The overlay engine handles merging per-file; no setup step needed. - One subagent, one setup script — the convention works fine when the subagent uses exactly one cap that needs install logic.
Recipe: install Claude Code plugins
Section titled “Recipe: install Claude Code plugins”The Claude Code adapter looks for agora-plugins.json after overlay and
runs claude plugins install <name> for each entry. This file’s merge rule
is array-union, so multiple capabilities can each contribute plugins
without overwriting each other:
my-plugin-cap/└── agora-plugins.json[{ "name": "@org/some-plugin" }]Recipe: ship arbitrary files
Section titled “Recipe: ship arbitrary files”Anything not at a reserved path is last-write-wins per file. If two capabilities don’t share file paths, they compose cleanly. Just put files at the path you want:
fixtures-cap/├── fixtures/│ ├── sample-input.json│ └── expected-output.jsonWorker workspace will have <workspace>/fixtures/sample-input.json etc.
What you can’t do (yet)
Section titled “What you can’t do (yet)”- Per-capability install scripts that compose. See the single-slot
constraint above. There’s no
agora-setup-<name>.shmechanism today. - Skill enumeration from the AI surface.
agora_capabilities_list/agora_subagents_listMCP tools throwNOT_IMPLEMENTED— until the storage layer growslistNames(prefix), the AI has to be told skill names out-of-band. - Auto-rebind subagents after a cap sync. Subagent capability bindings
freeze the capability
contentHashat register time. If you re-sync caps (new content → new hash), you must also re-register the subagent to pick up the new hash. The CLI doesn’t do this automatically yet.
See also
Section titled “See also”- Sync capabilities & subagents — auto-generate capabilities and
subagents from
.claude/skills/,.claude/agents/, pokemon profiles, etc. - Dispatch to a remote Docker daemon — dispatch to a remote Docker daemon over SSH.
- MVP spec §6.3 — formal definition of the overlay/merge model.
- ADR-0005 — why register/assign are not exposed on the MCP surface.