Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.pinata.cloud/llms.txt

Use this file to discover all available pages before exploring further.

manifest.json lives at the root of every agent’s workspace. It controls identity, lifecycle scripts, secrets, skills, routes, channels, scheduled tasks, and (for templates) marketplace metadata. This page documents every field at the version 1 schema. The schema is published at:
https://agents.pinata.cloud/schemas/manifest.v1.json
Add a $schema line so editors can autocomplete and validate:
{
  "$schema": "https://agents.pinata.cloud/schemas/manifest.v1.json",
  "version": 1,
  "engine": "openclaw",
  "agent": { "name": "My Agent" }
}

Top-level fields

FieldTypeRequiredDescription
$schemastringoptionalSchema URL for editor support
versionintegeryesManifest version - currently 1
enginestringoptionalContainer engine - openclaw (default) or hermes
agentobjectyesAgent identity (see below)
modelstringoptionalDefault model in <provider>/<model> form
secretsarrayoptionalEncrypted credentials this agent requires
skillsarrayoptionalUp to 10 skill slugs or CIDs
tasksarrayoptionalUp to 20 scheduled tasks
scriptsobjectoptionalLifecycle hooks (build, start)
routesarrayoptionalUp to 10 port-forwarding rules
channelsobjectoptionalMessaging channel configuration
templateobjectoptionalMarketplace listing metadata (only for templates)

agent

Defines the agent’s identity. All fields are written into the workspace (mostly IDENTITY.md) at deploy time.
"agent": {
  "name": "Social Bot",
  "description": "You manage Socials",
  "vibe": "Resourceful and opinionated",
  "emoji": "🤖"
}
FieldTypeLimitNotes
namestring1-100 chars, requiredDisplay name
descriptionstring≤ 10000 charsPersonality / role
vibestring≤ 200 charsOne-line tagline
emojistring≤ 32 charsVisible in lists and avatars

model

A single default model identifier in <provider>/<model> form:
"model": "anthropic/claude-sonnet-4-6"
Provider must match a connected provider in the Secrets Vault. If a task or session specifies a model that isn’t enabled on the agent, the request falls back to this default.

secrets

Declares the secrets this agent needs. These are env-var names - the actual values come from the Secrets Vault at attach time.
"secrets": [
  { "name": "OPENROUTER_API_KEY" },
  { "name": "TELEGRAM_BOT_TOKEN", "description": "BotFather token", "required": false }
]
FieldTypeNotes
namestringEnvironment variable name (e.g. ANTHROPIC_API_KEY)
descriptionstringShown on the deploy form
requiredbooleanDefault true. false makes the field optional in the deploy wizard

skills

Up to 10 skills. Each entry is an object with a name plus either a clawhub_slug (resolves to the latest published version) or a cid (byte-stable, pinned to a specific upload).
"skills": [
  { "clawhub_slug": "@pinata/api", "name": "Pinata API" },
  { "clawhub_slug": "@pinata/memory-salience", "name": "Memory Salience" },
  { "cid": "bafybeicglyjdb6wrrcbfyu6i2fe4lpxdxgvfvlht7yzdim7cvwt656whue", "name": "My Custom Skill" }
]
FieldTypeNotes
namestringDisplay name shown in the UI. Required.
clawhub_slugstringClawHub slug like @pinata/api. Mutually exclusive with cid.
cidstringIPFS CID of an uploaded skill. Mutually exclusive with clawhub_slug.
Each attached skill is unpacked under workspace/skills/<skill-name>/. See Skills.

tasks

Scheduled prompts. Up to 20 per agent. Full reference in Tasks.
"tasks": [
  {
    "name": "daily-check-in",
    "schedule": { "kind": "cron", "expr": "0 9 * * *", "tz": "America/Los_Angeles" },
    "payload": { "kind": "agentTurn", "text": "Summarize yesterday." },
    "delivery": { "mode": "announce", "channel": "telegram", "to": "123" }
  }
]
Schedule kinds: at (one-shot ISO timestamp), every (everyMs interval, optional staggerMs), cron (expr with optional tz). Payload kinds: agentTurn (chat message; supports model, thinking, timeoutSeconds) or systemEvent (system trigger; provide message). Delivery modes: none (default), announce (to a channel - set channel and to), or webhook (set to to a URL). bestEffort: true swallows delivery failures. sessionTarget is main or isolated. wakeMode is now or next-heartbeat.

scripts

Lifecycle hooks. Both fields are shell commands run by the agent’s runner.
"scripts": {
  "build": "cd workspace/projects/app && npm install --include=dev",
  "start": "cd workspace/projects/app && npx vite --host 0.0.0.0"
}
HookWhen it runsWorking directoryOutput logTimeout
buildAfter deploy, after each git push, on Retry Scripts/home/node/clawd/tmp/user-build.log5 min
startAfter a successful build, on agent boot/home/node/clawd/tmp/user-start.logNone - runs detached
If build fails, start does not run. If start crashes, the agent is still healthy - only the user-defined process exits. Retry the lifecycle: POST /v0/agents/{agentId}/scripts/retry (or the action on the Danger tab). Bind servers to 0.0.0.0, not localhost, so the gateway can reach them. See Routes.

routes

Port-forwarding rules. Up to 10. Each entry maps an external path prefix to a container port.
"routes": [
  { "port": 5173, "path": "/app", "protected": false },
  { "port": 3000, "path": "/api", "protected": true }
]
FieldTypeNotes
portintegerContainer port. 1025-65535. 18789 is reserved.
pathstringURL path prefix. Stripped from the request before reaching your service.
protectedbooleantrue requires a gateway token. Defaults to false.
For custom domains, register them through the UI or the Domains API - they aren’t declared in manifest.json.

channels

Configures the messaging channels for this agent. Tokens are usually injected from secrets to avoid leaking into the manifest.
"channels": {
  "telegram": {
    "botToken": "env:TELEGRAM_BOT_TOKEN",
    "dmPolicy": "pairing",
    "allowFrom": ["123456789"]
  },
  "slack": {
    "botToken": "env:SLACK_BOT_TOKEN",
    "appToken": "env:SLACK_APP_TOKEN"
  },
  "discord": {
    "botToken": "env:DISCORD_BOT_TOKEN"
  }
}
ChannelRequired fieldsNotes
telegrambotTokendmPolicy (open / pairing), allowFrom (user IDs)
slackbotToken, appTokenSocket Mode + scopes per Channels
discordbotToken
whatsappdmPolicy, allowFromLinking happens on the agent. Coming soon.
Use env:VAR_NAME to read from an environment variable instead of embedding a literal token.

template

Only used when the manifest is the source for a marketplace template. Ignored for direct deploys.
"template": {
  "slug": "useful-assistant",
  "category": "general",
  "partnerName": "Pinata",
  "tags": ["assistant", "personal", "productivity"]
}
FieldNotes
slugMarketplace URL slug. Lowercase, hyphens.
categoryOne of the marketplace categories (e.g. general, defi, social)
partnerNameDisplay name shown on the template card
tagsArray of free-text tags for filtering
paidOptional. Set { "amount": "1.00", "currency": "USDC" } for x402 paid templates

Validation

manifest.json is different from openclaw.json - see Concepts → manifest vs openclaw config. The /v0/agents/{agentId}/config/validate endpoint validates openclaw.json, not manifest.json.
To validate manifest.json ahead of committing, run it through the template validator (which checks manifest.json + README.md + workspace/):
# CLI
pinata agents templates validate https://github.com/user/my-template
# Or hit the API directly with the repo URL + ref
curl -X POST \
  -H "Authorization: Bearer $PINATA_JWT" \
  -H "Content-Type: application/json" \
  -d '{"gitUrl":"https://github.com/user/my-template","ref":"refs/heads/main"}' \
  https://agents.pinata.cloud/v0/templates/validate
The response is { valid: boolean, errors: string[], manifest, readme, files } — any problems with the manifest show up in the errors array. Schema constraints to keep in mind while authoring:
FieldConstraint
versionMust be 1
agentRequired; agent.name is required and ≤ 100 chars
agent.description≤ 10000 chars
agent.vibe≤ 200 chars
agent.emoji≤ 32 chars
skills≤ 10 entries
routes≤ 10 entries; ports 102565535, excluding 18789
tasks≤ 20 entries; minimum interval 1 minute
channels.*.botTokenRequired on initial setup (Slack also requires appToken)
See Errors for the full HTTP status code reference.

Minimal Example

The smallest valid manifest:
{
  "version": 1,
  "agent": { "name": "Hello" }
}
This boots the default openclaw engine with no skills, no scripts, and no routes - just a workspace and a chat interface.