App manifest
app.json is strict install intent. Unknown top-level fields are rejected, the App id anchors storage and routing, and native permissions are reviewed as part of the release.
Minimal manifest
{
"format": 1,
"frameworkApi": 1,
"id": "counter",
"title": "Counter",
"description": "A durable counter",
"version": "0.1.0",
"schemaVersion": 1,
"capabilities": ["data.sqlite"],
"resources": {},
"toolNamespace": "counter",
"tools": [],
"schedules": []
}Top-level fields
| Field | Required/effective default | Meaning and validation |
|---|---|---|
format | Must be 1 | Source package container contract |
frameworkApi | Must equal current runtime, now 1 | Compatibility with platform-owned PocketPi.* Framework |
id | Required | Stable safe component; must match apps/<id>; cannot be pi-agent for ordinary packages |
title | Non-empty | Human-facing review and Apps UI name |
description | Required string | Human/product description |
version | Non-empty | Release metadata shown to people; runtime does not impose SemVer parsing |
schemaVersion | Ordinary App: positive integer | SQLite compatibility, independent from source release version |
capabilities | [] | Unique values from data.fs, data.sqlite, net.http |
toolNamespace | App id | Every public Tool name must start with <namespace>. |
tools | [] | Public Agent Tool definitions plus local action route |
schedules | [] | Periodic local Action declarations |
nativeServices | empty HTTP/MCP lists | Exact native endpoint, connection and credential policy |
providerOperations | [] | Unique non-empty native provider operation allowlist, used by MCP Apps |
resources | {} | Named manifest-declared JSON files under assets/ |
Tool entry
{
"name": "research.search",
"action": "search",
"description": "Search and save a bounded local result set.",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string", "minLength": 1 }
},
"required": ["query"],
"additionalProperties": false
}
}namemust use this App's namespace and be globally unique among installed Apps.actionmust be a non-empty local name without a dot.- The public model definition removes
action; it receives name, description and parameters. - Installation evaluates
actions.jsand verifies that the routed function exists.
Schedule entry
{
"id": "history-cleanup",
"everyMinutes": 60,
"action": "cleanup",
"args": { "maxAgeDays": 7 }
}action follows the same local-name rule. Runtime cadence is at least one minute.args defaults to JSON null if omitted; prefer an explicit object for reviewability.
HTTP service policy
"nativeServices": {
"http": [{
"method": "POST",
"urls": ["https://api.example.com/search"],
"allowedRequestHeaders": ["accept", "content-type"],
"credential": {
"id": "example.api-key",
"header": "authorization",
"prefix": "Bearer "
}
}]
}credential may be null/omitted for an endpoint that needs no secret.
MCP service policy
"nativeServices": {
"mcp": [{
"connection": "portfolio",
"url": "https://provider.example.com/mcp",
"credential": {
"id": "portfolio.oauth-token",
"header": "authorization",
"prefix": "Bearer "
}
}]
},
"providerOperations": ["get_accounts", "get_portfolio"]Resource entry
"resources": {
"toolCatalog": {
"path": "assets/tool-catalog.json",
"type": "json"
}
}Declared resource paths must exactly equal the files under assets/. Resource names, App ids and path components accept ASCII letters, digits, dot, dash and underscore, excluding empty, . and .. components.
Complete examples: Exa ↗ and Robinhood ↗.