Skip to main content
A template is an Agent Plugins 1.0.0 directory. This page covers what goes in each part and how to test it. For the exact rules the engine validates against, see the template format reference. To publish one to the public catalog, see Submitting a template.

Anatomy

The portable surface — skills/ and mcp.json — follows the Agent Plugins spec exactly. Everything NanoClaw-specific rides in the ai.nanoco.nanoclaw/ extension directory and manifest key, which other spec-compatible clients skip by rule.
No provider, model, effort, or packages in a template. Those are set on the agent afterward with ncl groups config update. The runtime defaults to the install’s configured provider, which is what makes one template work everywhere.

The manifest

plugin.json is the only required file. It is both the identity and the marker that makes a folder a template.
$schema must be exactly that URL. name is 1–64 characters of lowercase alphanumerics, hyphens, and periods; it must start and end alphanumeric and may not contain a -- or .. run. It is the plugin’s machine name, independent of the folder path — a template at <category>/<template>/ can carry any valid name — and it is the folder the plugin is stamped under, at groups/<folder>/plugins/<name>/. extensions["ai.nanoco.nanoclaw"].agentName sets the display name of the stamped agent. Without it the agent is named after the template folder; an explicit --name beats both.

MCP servers

mcp.json declares tool servers. It has exactly two top-level fields, and every server declares its transport:
  • stdio takes command, args, and optional env and cwd. The command is a single token: a bare executable name, or a ./-relative path resolved against the plugin root inside the container.
  • streamable-http takes an HTTPS url and optional headers. The legacy sse transport is not supported.

Credentials and secrets

Hard rule: templates are public. Never commit an API key, token, or any other credential. Registry CI and NanoClaw’s stamp-time lint both reject them, but neither is a substitute for reading your own diff before you commit.
Every credential-shaped env and headers value is the literal "placeholder". The real value comes from the OneCLI Agent Vault, which injects it at request time, matched by API host. The key never sits in mcp.json, the container environment, or chat context.
Static header credentials on a plugin-owned server are unsupported by design. There is no after-the-fact edit path: the ownership guard refuses add-mcp-server and remove-mcp-server for plugin-owned names. If an endpoint genuinely requires a static header, the operator adds a separately named, user-owned server with ncl groups config add-mcp-server --headers instead.
Any value matching a known credential format is rejected outright, and the whole template fails to stamp: Task scripts may call external services, but must not contain credentials either.
Registry CI is stricter than the engine here. A credential-shaped key — anything matching TOKEN, SECRET, PASSWD, PASSWORD, API_KEY, APIKEY, CREDENTIAL, PRIVATE_KEY, PRIVATEKEY, or AUTH — with a value that isn’t "placeholder" fails CI, while NanoClaw itself only warns at stamp time. A template that stamps cleanly on your machine can still be rejected by the registry. Use "placeholder" for every credential-shaped key.

Servers that need the variable present to boot

Some MCP servers refuse to start unless an environment variable exists, even though the real credential comes from the vault. "placeholder" satisfies the boot check — it is the one value both linters always accept. Say a server won’t start unless ACME_API_KEY is set. Ship it as a dummy:
That placeholder is not the credential, and must stay as-is. Once the service is connected, the real key is injected for its API host at request time. Never replace it with a real token.
Only add a placeholder where the server actually demands one. A server that authenticates purely through the vault needs no such variable and should not get one.

Document what the template needs

A template that requires a connected service must say so in its own README.md. For each service, give: The templates already in the registry show the pattern: every service in one table, then a section per service with the steps to obtain its key. If any of those services costs money and you plan to submit the template, it also has to be declared up front.

Skills

Each immediate subfolder of skills/ is one skill, named after the folder. The whole folder is copied, so put SKILL.md (with name and description frontmatter) and any references/*.md inside it, following the usual skill conventions. Skills land in the group’s private skills overlay — keyed to that group, never shared with others. Each skill’s name and description are always in the prompt, and that’s what the auto-trigger matches on; only the body is read on demand. A non-conforming skill is skipped with a named notice at stamp time, never silently dropped.

The persona

ai.nanoco.nanoclaw/context/instructions.md is the agent’s standing brief. It is written to the provider-neutral instructions.prepend.md and inlined at the top of the agent’s CLAUDE.md/AGENTS.md every spawn — system-prompt tier on any provider.
Keep it under roughly 200 lines. It is always in the agent’s prompt, and some providers cap that document (Codex at ~32 KB), so an over-long persona gets truncated. Put bulk material in skills/ or additional_context/ instead.
The persona is optional — the registry recommends one but doesn’t require it. A plain conformant plugin with no extension directory stamps fine — the agent simply uses NanoClaw’s default project doc. CI only checks that instructions.md is non-empty if you ship one. Ship a persona when it makes the template useful out of the box; skip it when the skills and MCP servers are the whole point.

Extra context

Other .md files under ai.nanoco.nanoclaw/context/ — by convention in an additional_context/ subfolder — are copied into the agent’s workspace preserving their position relative to instructions.md. A file at ai.nanoco.nanoclaw/context/additional_context/pricing.md is readable by the agent as additional_context/pricing.md. Nothing is injected automatically. The agent only reads an extra file if instructions.md points to it, so reference every file you ship — by plain relative path, not @-syntax, which keeps it working under any provider:

Recurring tasks

Each immediate Markdown file under ai.nanoco.nanoclaw/tasks/ defines one recurring task. The filename becomes the task name, the frontmatter supplies the cron schedule, and the body is the prompt:
schedule is required. script is optional, and may be a single-line or multiline YAML string. The frontmatter accepts no other fields, so a typo can’t silently change behavior. Template tasks use the same creation path as ncl tasks create — cron validation, the group timezone, isolated task sessions, and frequency limits all apply. Ungated tasks are limited to four fires in the next 24 hours; tasks with a script gate may run more often. Templates cannot create one-time tasks or override the frequency limit. See Scheduled tasks for the script contract.
Tasks are created paused, so stamping never starts background work without consent. Users activate them with ncl tasks resume <task-id>.

What stamping does with it

Stamping copies the whole plugin to groups/<folder>/plugins/<name>/, mounted read-only in the container at /workspace/agent/plugins/<name>. A writable sibling, plugin-data/<name>/, holds per-plugin state. Because the whole plugin is present, a skill can reference sibling files — a TROUBLESHOOTING.md at the plugin root, say — and they exist in the container. stdio servers declared by the plugin get the spec’s runtime contract: PLUGIN_ROOT and PLUGIN_DATA in their environment, and ${PLUGIN_ROOT}/${PLUGIN_DATA} expansion in args elements and env values. See the runtime contract.

Testing locally

Stamp your template and drive it before you rely on it — or before you open a pull request.
--template resolves against your NanoClaw install’s templates directory, not your clone of the registry. Stamping a bare ref from inside your clone will not find it — and prefixing the command with NANOCLAW_TEMPLATES_DIR=… will not help, because the host process reads that variable once at startup and ncl is only a socket client.
templates/ ships with only a README, so create the category directory first:
Re-copy after every edit — the stamp reads the copy, not your clone.
Then verify what stamped:
Check the create response for a templateReport array. Any entry there means a component was skipped or ignored — a non-conforming skill, an unsupported MCP transport, an unknown manifest field. Registry CI catches the first two, but an unknown manifest field passes it — check-templates.mjs validates only $schema and name in the manifest — so fix every entry before submitting; nothing in the report is silently stripped. When you’re done with the test agent, ncl groups delete --id <agent-group-id> removes it — see removing a test agent for the on-disk leftovers it leaves behind.

Migrating from the pre-plugin layout

Templates written for the pre-plugin layout used a bare context/instructions.md as the discovery marker and .mcp.json for servers. That layout is no longer read — stamping one fails with a migration error. Re-fetch the template from the registry, or convert it:
1

Add plugin.json

With the exact 1.0.0 $schema and a valid name. This is what makes the folder discoverable.
2

Rename .mcp.json to mcp.json

Add the MCP $schema, and give every server an explicit "type" of stdio or streamable-http. A leftover .mcp.json is ignored with a notice.
3

Move context/ and tasks/ under ai.nanoco.nanoclaw/

So they become ai.nanoco.nanoclaw/context/ and ai.nanoco.nanoclaw/tasks/.

Submitting a template

Registry standards, the checks script, and the PR checklist.

Template format reference

Field-level validation rules, limits, and the runtime contract.

Writing skills

Conventions a skills/<name>/ folder follows.

Updating a stamped agent

Deliver template changes to agents already running.
Last modified on August 13, 2026