Marketplace developer docs
Build + test + ship skills, integrations, agent templates, workflow templates, and squad templates.
<a id="overview"></a>
Overview
The Enclaw Marketplace lets anyone author and ship five kinds of asset that get installed into a tenant with one click:
| Kind | Used for | Cloned-on-install? |
|---|---|---|
| Skill | A callable tool — wraps an API, runs a transformation, calls an external service | Reference (binds to tenant via tool-registry) |
| Integration | Auth + tool family for an external service (Slack, Notion, etc.) | Reference + tenant provides config |
| Agent template | Pre-built agent: identity prompt, model, default skills | Yes — cloned into agent_templates |
| Workflow template | Frozen workflow steps + trigger | Yes — cloned into workflow_templates |
| Squad template | Multi-agent collaboration recipe | Yes — cloned into squad_templates |
Every listing has:
- A slug (unique within its kind), title, summary, readme.
- One or more versions (semver). The latest
approvedversion is what installers get when they click "Install". - A kind-specific payload — the JSON snapshot the installer clones.
Once submitted, listings go to pending_review until a platform
operator approves them. Approved listings are visible to every tenant on
the deployment.
<a id="local-sdk"></a>
Local SDK (@enclaw/marketplace-sdk)
Author + iterate without an Enclaw instance.
npm i -g @enclaw/marketplace-sdk
| Command | What it does |
|---|---|
enclaw-mp validate <manifest.json> | Schema check against the top-level shape AND the kind-specific payload. Exit 1 + structured paths on errors. |
enclaw-mp test <manifest.json> --input '<json>' | Skills only. Imports the entrypoint module and invokes its run(input) function. Pretty-prints the result. |
enclaw-mp publish <manifest.json> --api <url> --token <bearer> | Creates the listing, uploads the version, submits for moderator review in one shot. --api + --token default to ENCLAW_API_URL + ENCLAW_TOKEN env vars. |
Or use it as a library:
import { validate, runSkill, publish } from "@enclaw/marketplace-sdk";
const result = validate(manifest);
if (!result.ok) {
for (const e of result.errors) console.error(`${e.path}: ${e.message}`);
}
const out = await runSkill("./skill.mjs", { input: "..." });
await publish(manifest, { apiBaseUrl: "https://api.enclaw.example", token: "..." });
<a id="manifest-shape"></a>
Manifest shape (all kinds)
Every kind shares the same top-level wrapper. Only payload shape
changes per kind.
{
"kind": "skill",
"slug": "my-skill",
"title": "My Skill",
"summary": "One-line description.",
"readmeMd": "# Long-form readme — markdown.",
"iconUrl": "https://example.com/icon.png",
"tags": ["productivity", "marketing"],
"version": "1.0.0",
"changelogMd": "Initial release",
"payload": { /* kind-specific */ }
}
Constraints (enforced by the SDK + the API):
slug: lowercase letters / digits / hyphens; must not start or end with a hyphen; 3-80 chars. Unique within its kind.version: semver (MAJOR.MINOR.PATCHwith optional-prerelease).summary: 500 chars max.tags: small arbitrary strings shown as chips.
<a id="skills"></a>
Authoring a skill
A skill is a single callable function. The marketplace stores the tool schema (so agents can discover + invoke it) and the entrypoint path (so the local SDK can run it for testing).
payload shape
{
"toolSchema": {
"name": "do_thing",
"description": "Run the skill.",
"input_schema": {
"type": "object",
"properties": { "x": { "type": "string" } },
"required": ["x"]
}
},
"language": "javascript",
"entrypoint": "./skill.mjs",
"requiresVision": false
}
Entrypoint contract
A skill exports a run function (or default-exports it). It receives
the validated input as a plain object and returns any JSON-serialisable
value.
// skill.mjs
export async function run({ csv, hasHeader = true }) {
const rows = csv.split("\n").filter(Boolean).map((r) => r.split(","));
if (rows.length === 0) return { markdown: "" };
const header = hasHeader ? rows.shift() : rows[0].map((_, i) => `col${i + 1}`);
const md = [
`| ${header.join(" | ")} |`,
`| ${header.map(() => "---").join(" | ")} |`,
...rows.map((r) => `| ${r.join(" | ")} |`),
].join("\n");
return { markdown: md };
}
Test locally
enclaw-mp validate ./manifest.json
enclaw-mp test ./manifest.json --input '{"csv":"name,age\nalice,30\nbob,25"}'
<a id="integrations"></a>
Authoring an integration
An integration bundles auth + a family of tools that talk to an external service. The marketplace listing describes:
- The
typediscriminator (e.g.notion,linear). - The
configSchema(what the tenant admin types when installing). - The list of
toolsthe integration surfaces to agents.
payload shape
{
"type": "notion",
"configSchema": {
"type": "object",
"required": ["notionToken"],
"properties": {
"notionToken": {
"type": "string",
"description": "Internal integration secret",
"secret": true
}
}
},
"tools": [
"notion_search_pages",
"notion_create_page",
"notion_append_block"
]
}
secret: true on a property → the install UI renders a password field
and the API stores the value encrypted.
Reference vs cloned: integrations are reference-style. The actual tool implementations live in the Enclaw core; the marketplace listing declares which ones the tenant can use after installing.
<a id="agent-templates"></a>
Authoring an agent template
A template is a frozen agent config that gets cloned into the tenant's
agent_templates table on install.
payload shape
{
"identityMd": "You are a senior copywriter...",
"modelId": "claude-sonnet-4-6",
"modelConfig": { "temperature": 0.7 },
"defaultConfig": {},
"includedSkills": [
{ "source": "marketplace", "name": "url-readability-extract" }
],
"requiredIntegrations": ["mailchimp"],
"category": "marketing",
"icon": null
}
Field reference
| Field | What |
|---|---|
identityMd | The system prompt. Long-form markdown — be specific about role, constraints, output format. |
modelId | Default model. Tenant can override after install. |
modelConfig | Temperature / top_p / max_tokens overrides. |
defaultConfig | Arbitrary tenant-overridable config (e.g. { sprintLengthDays: 14 }). |
includedSkills | Marketplace skills auto-bound on install. source is marketplace / builtin / cli. |
requiredIntegrations | Listed on the install screen so tenants know they need to configure these first. |
category | One of: engineering, pm, marketing, hr, support, sales, leadership, general. |
Writing identity prompts
- Lead with role (
You are a senior ...). - State constraints explicitly (
NEVER auto-approve. Always cite line numbers.). - Specify output format (
Output: { fit: 0-100, reasoning: ... }). - Add examples of good behaviour if behaviour is non-obvious.
<a id="workflow-templates"></a>
Authoring a workflow template
A workflow is a sequence of steps. Each step has a type and
type-specific config. The full step shape comes from the
@enclaw/workflow-ui types.
payload shape
{
"steps": [
{
"id": "fetch_issues",
"type": "tool",
"tool": "linear_search_issues",
"input": { "filter": "completed", "sinceDays": 7 }
},
{
"id": "summarise",
"type": "llm",
"prompt": "Draft a weekly update from {{fetch_issues}}. 3-5 bullets max."
},
{
"id": "post",
"type": "tool",
"tool": "slack_send_message",
"input": { "channel": "#product-updates", "text": "{{summarise}}" }
}
],
"trigger": {
"type": "cron",
"expression": "0 16 * * 5",
"timezone": "Australia/Sydney"
},
"requiredSkills": [],
"requiredIntegrations": ["linear", "slack"],
"category": "pm"
}
Step types
type | What it does |
|---|---|
tool | Call any tool (builtin / installed skill / integration). |
llm | One-shot LLM call with a prompt template. |
transform | JSONata expression over previous step outputs. |
branch | If/else routing (PR-C feature; reference only in v1). |
loop | forEach / repeat-N. |
approval | Pause for human approval. |
subflow | Call another workflow. |
agent | Delegate to an agent. |
Variable references
Inside step config, reference previous step outputs with {{stepId}}
or property paths {{stepId.field}}. The trigger payload is
{{trigger}}.
<a id="squad-templates"></a>
Authoring a squad template
A squad is a group of agents that collaborate. The template describes roles + collaboration rules.
payload shape
{
"members": [
{
"role": "writer",
"agentTemplateId": "content-marketer",
"responsibilities": "Drafts long-form content."
},
{
"role": "reviewer",
"agentName": "SEO Analyst",
"responsibilities": "Keyword research + meta optimisation."
}
],
"rules": {
"handoff": "writer → reviewer",
"sharedMemory": true,
"approvalRequired": ["reviewer"]
},
"requiredSkills": ["url-readability-extract"],
"requiredIntegrations": ["mailchimp"],
"category": "marketing"
}
Member resolution
agentTemplateId(preferred) → on install, the marketplace clones that agent-template listing into the tenant'sagent_templatesand binds the squad member to it.agentName→ tenant is prompted to pick an existing agent matching this role on install.
<a id="publishing"></a>
Publishing + moderation
- Run
enclaw-mp validate ./manifest.jsonuntil clean. - (Skills only)
enclaw-mp test ./manifest.json --input '...'until happy. enclaw-mp publish ./manifest.json --api $ENCLAW_API_URL --token $ENCLAW_TOKEN.- Status flips to
pending_review. Track it under My Listings. - A platform operator approves or rejects via the operator console at
/admin/saas/marketplacein the web app. - On approve → status flips to
approvedand the listing appears in the public catalog. Reviewer notes (if any) are visible to you in the My Listings dashboard.
Versioning
Subsequent releases:
# Bump version in manifest.json, edit changelogMd, then:
enclaw-mp publish ./manifest.json
The new version goes to pending and only becomes the
"latest" once an operator approves. Old approved versions remain
installable — tenants on an old version don't break when you ship a
new one.
Deprecation
If you want to retire a listing (it shouldn't get new installs but existing installs keep working), the publisher (or a platform admin) can hit:
POST /api/marketplace/listings/{id}/deprecate
Existing installs are unaffected; the listing disappears from search.
<a id="examples"></a>
Worked examples
Real listings already in the marketplace ship with full readmes and payloads — use them as templates:
- CSV → Markdown Table (skill, JS, single file) →
/listingsfilter by Skills. - Sprint Planner (agent template, Linear required) → filter by Agents.
- Weekly Product Update (workflow, cron-triggered) → filter by Workflows.
- Marketing Launch Crew (squad, 3 members) → filter by Squads.