From 9f8083578fae831f679b7da15d10d5d5b02e22a9 Mon Sep 17 00:00:00 2001 From: Alex Godoroja Date: Tue, 9 Jun 2026 13:32:35 -0700 Subject: [PATCH] docs: add App Store documentation - New /docs/app-store (+ plain mirror): install & use (catalogue, list, call), the help discovery convention with fast/med/slow latency classes, building an app (manifest + ipc), publishing (sign, release, catalogue PR), and catalogue-vs-sideload trust. - Fix outdated commands on the App Store landing page (pilotctl appstore install; manifest.json) and fill in the publish flow. - Register App Store in the docs nav + plain index. --- src/data/docsNav.ts | 2 + src/pages/app-store.astro | 20 +-- src/pages/docs/app-store.astro | 180 +++++++++++++++++++++++++++ src/pages/plain/docs/app-store.astro | 83 ++++++++++++ src/pages/plain/docs/index.astro | 1 + 5 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 src/pages/docs/app-store.astro create mode 100644 src/pages/plain/docs/app-store.astro diff --git a/src/data/docsNav.ts b/src/data/docsNav.ts index e3dd120..9fc0444 100644 --- a/src/data/docsNav.ts +++ b/src/data/docsNav.ts @@ -41,6 +41,8 @@ export const docsNav: NavItem[] = [ icon: '' }, { label: 'Service Agents', href: '/docs/service-agents', slug: 'service-agents', icon: '' }, + { label: 'App Store', href: '/docs/app-store', slug: 'app-store', + icon: '' }, // Enterprise { section: 'Enterprise', label: 'Enterprise Overview', href: '/docs/enterprise', slug: 'enterprise', icon: '' }, diff --git a/src/pages/app-store.astro b/src/pages/app-store.astro index a38c833..ccc5661 100644 --- a/src/pages/app-store.astro +++ b/src/pages/app-store.astro @@ -66,9 +66,9 @@ const canonicalUrl = "https://pilotprotocol.network/app-store";
02
Install
- One command: pilot app install <name>. - Dependencies resolved, permissions requested, app live - in seconds. + One command: pilotctl appstore install <id>. + Fetched, signature-verified, permissions requested, and + auto-spawned by the daemon — live in seconds.
@@ -127,18 +127,20 @@ const canonicalUrl = "https://pilotprotocol.network/app-store";
Manifest
Declare your app
- An agent app is defined by a pilot.app.json manifest: - name, version, capabilities, and entry point. No Docker, no - Kubernetes — the protocol handles distribution. + An agent app is defined by a manifest.json: id, + version, the methods it exposes, a sha256-pinned binary, and the + grants it requests. No Docker, no Kubernetes — the protocol handles + distribution.
Submit
One PR to publish
- - Submission guidelines and the publishing pipeline are being finalized. - For early access, reach out to the team. + Sign the manifest, attach the bundle to a GitHub release, and add + one entry to catalogue.json by PR. Once merged, + pilotctl appstore install <id> works everywhere. + See the App Store docs.
diff --git a/src/pages/docs/app-store.astro b/src/pages/docs/app-store.astro new file mode 100644 index 0000000..db337a6 --- /dev/null +++ b/src/pages/docs/app-store.astro @@ -0,0 +1,180 @@ +--- +import DocLayout from "../../layouts/DocLayout.astro"; + +const bodyContent = `

App Store

+

Installable agent apps that run locally on your daemon as typed IPC services - JSON in, JSON out, auto-spawned on install. Discover, install, call.

+ + + +

Overview

+ +

Where list-agents is the phonebook for live data on the overlay, the App Store is for installable capability apps. An app is a small binary plus a signed manifest.json. The daemon fetches it from the catalogue, verifies it, and supervises it: it spawns the binary, hands it a unix socket, and brokers IPC calls to it. Each app method is a typed call - JSON in, JSON out.

+ +

Apps are:

+ + +

The whole loop an agent runs is: discover → install → call.

+ +

Using apps

+ +

Discovery and install go through the catalogue - a signed list the daemon fetches. Install verifies the bundle and the daemon auto-spawns it; call is then the workhorse.

+ +
# 1. Discover what's installable
+pilotctl appstore catalogue
+
+# 2. Install by id - fetch + verify sha + install; the daemon auto-spawns it
+pilotctl appstore install io.pilot.cosift
+
+# 3. Confirm it's ready (lists installed apps + the methods each exposes)
+pilotctl appstore list
+pilotctl appstore status io.pilot.cosift
+
+# 4. Call a method - JSON in, JSON out on stdout
+pilotctl appstore call io.pilot.cosift cosift.search '{"q":"raft consensus","k":"5"}'
+ +
+

No config step. A well-built app ships with sane defaults, so install then call is all an agent needs. Apps may read an optional config.json next to their manifest for overrides (e.g. a self-hosted backend).

+
+ +

Discovery & the help convention

+ +

pilotctl appstore list and status surface a flat list of method names - enough to know what exists, not how to call it. The convention for richer discovery is a <app>.help method: a single local call (no backend round-trip) that returns every method with its parameters, a kind (utility / status / meta), and an expected-latency class.

+ +
pilotctl appstore call io.pilot.cosift cosift.help '{}'
+ +

The latency class lets an agent pick the cheapest method for its need before spending a slow one:

+ + + +

Each method entry also carries a measured, warm round-trip estimate, so an agent can budget a call end-to-end (agent → daemon → app → backend → back).

+ +

Lifecycle

+ +
pilotctl appstore restart io.pilot.cosift    # respawn (e.g. after writing a config.json)
+pilotctl appstore audit io.pilot.cosift      # supervisor log: spawn / exit / verify-fail
+pilotctl appstore install io.pilot.cosift --force  # upgrade to a new version
+pilotctl appstore uninstall io.pilot.cosift --yes
+ +
+

Upgrades key on the version. The supervisor respawns an app when its app_version changes. Bump the version for every new build, or a re-release of the same version won't roll running nodes onto the new binary.

+
+ +

Building an app

+ +

An app is a binary that listens on the socket the daemon hands it and speaks the app-store IPC protocol. The manifest declares its identity, the methods it exposes, the pinned binary, and the grants it needs.

+ +
{
+  "id": "io.pilot.cosift",
+  "app_version": "0.1.2",
+  "manifest_version": 1,
+  "binary": { "runtime": "go", "path": "bin/cosift-app", "sha256": "<pinned>" },
+  "exposes": ["cosift.search", "cosift.answer", "cosift.research",
+              "cosift.stats", "cosift.health", "cosift.help"],
+  "grants": [
+    { "cap": "net.dial", "target": "cosift.pilotprotocol.network",
+      "if": { "kind": "rate", "params": { "per": "min", "limit": 120 } } },
+    { "cap": "fs.read",  "target": "$APP/config.json" },
+    { "cap": "audit.log", "target": "*" }
+  ],
+  "protection": "shareable",
+  "store": { "publisher": "ed25519:...", "signature": "..." }
+}
+ +

The binary registers one handler per method and serves them over the socket. In Go, that's the app-store/pkg/ipc contract:

+ +
d := ipc.NewDispatcher()
+d.Register("cosift.search", func(ctx, req) (json.RawMessage, error) { ... })
+// ... one Register per exposed method ...
+ipc.Serve(ctx, conn, d)   // on the --socket the daemon supplies
+ +

The daemon spawns the binary with a fixed set of lifecycle flags (--socket, --manifest, --addr, --db, --identity, --cap-state). An app must accept all of them (even if it ignores most) or it will fail to start. Method names in the code must match the manifest's exposes list, or the daemon won't broker them.

+ +

Publishing an app

+ +

Three steps: sign, release, and add one catalogue entry by PR.

+ +
# 1. One-time: generate a publisher keypair (keep the private key safe)
+pilotctl appstore gen-key publisher.key
+
+# 2. Sign the manifest (after pinning binary.sha256) and package the bundle
+pilotctl appstore sign --key publisher.key bundle/manifest.json
+tar -czf io.pilot.cosift-0.1.2.tar.gz -C bundle .
+
+# 3. Attach the tarball to a GitHub release
+gh release create cosift-v0.1.2 io.pilot.cosift-0.1.2.tar.gz
+ +

Then add one entry to catalogue.json (pinning the tarball's sha256) and open a PR. Once merged, pilotctl appstore install <id> resolves it everywhere:

+ +
{
+  "id": "io.pilot.cosift",
+  "version": "0.1.2",
+  "description": "cosift search / answer / research over the public web corpus.",
+  "bundle_url": "https://github.com/.../releases/download/cosift-v0.1.2/io.pilot.cosift-0.1.2.tar.gz",
+  "bundle_sha256": "<sha256 of the tarball>"
+}
+ +

Two integrity layers protect every install, both re-checked at each spawn: the catalogue pins the tarball sha256 (a swapped CDN byte fails), and the manifest pins the binary sha256 under an ed25519 signature.

+ +

Catalogue vs sideload

+ +

There are two install paths, with different trust:

+ + + +
+

To stage a release locally before publishing, point $PILOT_APPSTORE_CATALOG_URL at a file:// catalogue and install by id - the same code path as production, with your own tarball.

+
+ +

Worked example: io.pilot.cosift

+ +

The cosift app is a stateless adapter to a search / answer / research API over a multi-million-document web corpus. It exposes three utility methods and several status/discovery ones:

+ +
# Discover the surface + latencies
+pilotctl appstore call io.pilot.cosift cosift.help '{}'
+
+# search (fast) - ranked URLs + excerpts
+pilotctl appstore call io.pilot.cosift cosift.search '{"q":"raft leader election","retriever":"hybrid","rerank":"true","k":"5"}'
+
+# answer / chat (med) - grounded synthesis with citations
+pilotctl appstore call io.pilot.cosift cosift.answer '{"q":"What is HNSW?"}'
+
+# research (slow) - plan -> multi-retrieval -> report
+pilotctl appstore call io.pilot.cosift cosift.research '{"q":"compare raft and paxos"}'
+ +

Its source is a public reference for app authors: a tiny adapter, a manifest, and the publish flow above.

+`; +--- + + + + diff --git a/src/pages/plain/docs/app-store.astro b/src/pages/plain/docs/app-store.astro new file mode 100644 index 0000000..db42be3 --- /dev/null +++ b/src/pages/plain/docs/app-store.astro @@ -0,0 +1,83 @@ +--- +// Plain mirror of /docs/app-store. Keep in sync with src/pages/docs/app-store.astro. +import PlainLayout from '../../../layouts/PlainLayout.astro'; +--- + + +

← Docs index

+ +

App Store

+ +

Installable agent apps that run locally on your daemon as typed IPC services - JSON in, JSON out, auto-spawned on install. The loop is: discover, install, call.

+ +

Overview

+

Where list-agents is the phonebook for live data on the overlay, the App Store is for installable capability apps. An app is a small binary plus a signed manifest.json. The daemon fetches it from the catalogue, verifies it, spawns the binary, hands it a unix socket, and brokers IPC calls to it. Each method is JSON in, JSON out.

+
    +
  • Local: one process per host. The heavy backend lives elsewhere; the installed binary is a thin, stateless adapter.
  • +
  • Typed: every method maps to a JSON request/response.
  • +
  • Signature-verified: the manifest pins the binary sha256 and carries an ed25519 signature; re-checked on every spawn.
  • +
  • Grant-scoped: the manifest declares what the app may do (network, file I/O); accepted at install time.
  • +
  • Auto-spawned: once installed, the daemon's supervisor keeps it running. No manual start.
  • +
+ +

Using apps

+
# Discover what's installable
+pilotctl appstore catalogue
+
+# Install by id - fetch + verify sha + install; the daemon auto-spawns it
+pilotctl appstore install io.pilot.cosift
+
+# Confirm it's ready (installed apps + the methods each exposes)
+pilotctl appstore list
+pilotctl appstore status io.pilot.cosift
+
+# Call a method - JSON in, JSON out on stdout
+pilotctl appstore call io.pilot.cosift cosift.search '{"q":"raft consensus","k":"5"}'
+

A well-built app ships with sane defaults, so install then call is all an agent needs. Apps may read an optional config.json next to their manifest for overrides (e.g. a self-hosted backend).

+ +

Discovery and the help convention

+

list and status surface a flat list of method names. The convention for richer discovery is a <app>.help method: a single local call (no backend round-trip) that returns every method with its parameters, a kind (utility/status/meta), and an expected-latency class.

+
pilotctl appstore call io.pilot.cosift cosift.help '{}'
+

Latency classes let an agent pick the cheapest method before spending a slow one:

+
    +
  • fast - under ~1s: status or cheap retrieval.
  • +
  • med - ~1-5s: an LLM rerank or single-pass synthesis.
  • +
  • slow - ~5-30s: multi-step work such as research.
  • +
+ +

Lifecycle

+
pilotctl appstore restart io.pilot.cosift          # respawn (e.g. after writing config.json)
+pilotctl appstore audit io.pilot.cosift            # supervisor log: spawn / exit / verify-fail
+pilotctl appstore install io.pilot.cosift --force  # upgrade to a new version
+pilotctl appstore uninstall io.pilot.cosift --yes
+

Upgrades key on the version: the supervisor respawns an app when its app_version changes. Bump the version for every new build.

+ +

Building an app

+

An app is a binary that listens on the socket the daemon hands it and speaks the app-store IPC protocol. The manifest declares its id, the methods it exposes (exposes[]), a sha256-pinned binary, and the grants it needs. In Go, register one handler per method on an ipc.Dispatcher and call ipc.Serve on the --socket the daemon supplies. Method names in code must match the manifest's exposes list. The daemon spawns the binary with fixed lifecycle flags (--socket, --manifest, --addr, --db, --identity, --cap-state); the app must accept all of them.

+ +

Publishing an app

+
# 1. One-time: generate a publisher keypair (keep the private key safe)
+pilotctl appstore gen-key publisher.key
+
+# 2. Sign the manifest (after pinning binary.sha256) and package the bundle
+pilotctl appstore sign --key publisher.key bundle/manifest.json
+tar -czf io.pilot.cosift-0.1.2.tar.gz -C bundle .
+
+# 3. Attach the tarball to a GitHub release
+gh release create cosift-v0.1.2 io.pilot.cosift-0.1.2.tar.gz
+

Then add one entry to catalogue.json (id, version, bundle_url, bundle_sha256) and open a PR. Once merged, pilotctl appstore install <id> resolves it everywhere. Two integrity layers protect each install: the catalogue pins the tarball sha256, and the manifest pins the binary sha256 under an ed25519 signature.

+ +

Catalogue vs sideload

+
    +
  • Catalogue (install <id>): the reviewed path. Signature-verified, installs with the grants the manifest declares including net.dial. How any net-using app is distributed.
  • +
  • Sideload (install <dir> --local): for local dev. Clamped to a sandbox - fs.read/fs.write under $APP and audit.log only. No net.dial. A net-using app must go through the catalogue.
  • +
+

To stage a release locally, point $PILOT_APPSTORE_CATALOG_URL at a file:// catalogue and install by id - the same code path as production.

+ +

Worked example: io.pilot.cosift

+
pilotctl appstore call io.pilot.cosift cosift.help '{}'
+pilotctl appstore call io.pilot.cosift cosift.search '{"q":"raft leader election","retriever":"hybrid","rerank":"true","k":"5"}'
+pilotctl appstore call io.pilot.cosift cosift.answer '{"q":"What is HNSW?"}'
+pilotctl appstore call io.pilot.cosift cosift.research '{"q":"compare raft and paxos"}'
+ +
diff --git a/src/pages/plain/docs/index.astro b/src/pages/plain/docs/index.astro index 533a99c..e44a66f 100644 --- a/src/pages/plain/docs/index.astro +++ b/src/pages/plain/docs/index.astro @@ -25,6 +25,7 @@ import PlainLayout from '../../../layouts/PlainLayout.astro';
  • Webhooks: Receive real-time HTTP notifications for daemon events.
  • Gateway: Bridge IP traffic to the overlay - use curl, browsers, any TCP tool.
  • Tags & Discovery: Label your agent with capability tags for peer discovery.
  • +
  • App Store: Install and build agent apps - typed IPC capabilities, one command to install, one PR to publish.
  • Diagnostics: Ping, traceroute, bench, connections, and peer inspection.
  • Configuration: Config files, environment variables, directory structure, and daemon flags.
  • Integration: OpenClaw, heartbeat patterns, webhook-driven agents, and custom workflows.