Files
archy/docs/app-developer-guide.md
Dorian f07ce10b1a refactor: update dependencies and remove unused code
- Added new dependencies: `adler2`, `crc32fast`, `flate2`, `miniz_oxide`, and `libredox`.
- Updated existing dependencies: `tokio-rustls` to version 0.26.4 and `filetime` to version 0.2.27.
- Removed the `backup.rs` file as it is no longer needed.
- Introduced tests for configuration and credential management.
- Enhanced the `identity` module to generate W3C compliant DID documents.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 00:19:30 +00:00

7.8 KiB

Archipelago App Developer Guide

Build and publish containerized apps for the Archipelago ecosystem.

Overview

Apps run as Podman containers on user nodes. You publish app manifests to Nostr relays, where nodes discover and install them through the community marketplace.

App Manifest

Every app needs a manifest (YAML for local apps, JSON for marketplace publishing).

Template Manifest

# apps/my-app/manifest.yml
app:
  id: my-app                    # Unique, lowercase kebab-case
  name: My App
  version: 1.0.0                # Semantic versioning

container:
  image: docker.io/myorg/my-app:1.0.0   # Never use :latest
  ports:
    - container: 8080
      host: 8180
      protocol: tcp
  volumes:
    - name: data
      path: /data
  env:
    APP_MODE: production
  capabilities: []              # Only add if absolutely necessary
  readonly_root: true           # Required
  no_new_privileges: true       # Required
  run_as_user: 1000             # Must be >= 1000

metadata:
  description:
    short: "One-line description (max 120 chars)"
    long: "Detailed description of what this app does and why."
  author:
    name: "Your Name"
    did: "did:key:z6Mk..."      # Your Archipelago node DID
  category: money               # money | commerce | data | networking | home | community | other
  icon_url: "https://example.com/icon.png"
  repo_url: "https://github.com/myorg/my-app"
  license: MIT
  min_archipelago_version: "0.1.0"
  dependencies: []              # e.g., ["bitcoin-knots"] if this app needs Bitcoin

Required Fields

Field Description
app.id Unique identifier, lowercase, kebab-case only
app.name Human-readable name
app.version Semantic version (major.minor.patch)
container.image Full image reference with pinned version tag
metadata.description.short One-line description, max 120 characters
metadata.author.did Your node's DID (get via node.did RPC)

Security Requirements

These are enforced by the marketplace and the node. Non-compliant apps are flagged.

Mandatory

  1. No :latest tag — Pin a specific version: myapp:1.0.0
  2. Read-only root filesystemreadonly_root: true (use volumes for writable data)
  3. Non-root userrun_as_user: 1000 or higher
  4. No privilege escalationno_new_privileges: true
  5. Minimal capabilities — Drop all caps, only add required ones

Allowed Capabilities

Only these Linux capabilities may be requested:

Capability When Needed
CHOWN App needs to change file ownership
NET_BIND_SERVICE App binds to ports below 1024
DAC_OVERRIDE App needs to bypass file permissions
SETUID, SETGID App manages user switching (e.g., nginx)

Forbidden

  • --network host — Apps cannot share the host network
  • Mounting system paths: /, /etc, /var, /usr, /proc, /sys
  • SYS_ADMIN, SYS_PTRACE, or any privileged capability
  • Hardcoded secrets in environment variables or images

Container Best Practices

Volumes

volumes:
  - name: data           # App data persists across restarts
    path: /data
  - name: config          # Configuration files
    path: /config

Data is stored at /var/lib/archipelago/{app-id}/ on the host.

Health Checks

Define a health check endpoint in your container:

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

Logging

  • Log to stdout/stderr (Podman captures container logs)
  • Never log secrets, passwords, or keys
  • Use structured logging (JSON) for machine parsing

Networking

Apps get their own network namespace. To connect to other Archipelago apps:

# If your app needs to talk to Bitcoin
dependencies:
  - bitcoin-knots

container:
  env:
    BITCOIN_RPC_HOST: bitcoin-knots  # Container DNS name on archy-net
    BITCOIN_RPC_PORT: "8332"

The archy-net Podman network provides DNS resolution between containers.

Publishing to the Marketplace

1. Build and Push Your Image

podman build -t docker.io/myorg/my-app:1.0.0 .
podman push docker.io/myorg/my-app:1.0.0

2. Get Your Node's DID

curl -b cookies.txt -X POST http://localhost/rpc/v1 \
  -d '{"method":"node.did"}'
# Returns: {"result":{"did":"did:key:z6Mk..."}}

3. Publish via RPC

curl -b cookies.txt -X POST http://localhost/rpc/v1 \
  -H "Content-Type: application/json" \
  -d '{
    "method": "marketplace.publish",
    "params": {
      "app_id": "my-app",
      "name": "My App",
      "version": "1.0.0",
      "description": {"short": "A useful tool", "long": "Detailed description..."},
      "author": {"name": "Dev Name", "did": "did:key:z6Mk...", "nostr_pubkey": ""},
      "container": {
        "image": "docker.io/myorg/my-app:1.0.0",
        "ports": [{"container": 8080, "host": 8180, "protocol": "tcp"}],
        "volumes": [],
        "env": {},
        "capabilities": [],
        "readonly_root": true,
        "no_new_privileges": true,
        "run_as_user": 1000
      },
      "category": "other",
      "icon_url": "",
      "repo_url": "https://github.com/myorg/my-app",
      "license": "MIT",
      "min_archipelago_version": "0.1.0",
      "dependencies": []
    }
  }'

The manifest is published to all configured Nostr relays as a NIP-78 event (kind 30078).

4. Verify Discovery

curl -b cookies.txt -X POST http://localhost/rpc/v1 \
  -d '{"method":"marketplace.discover"}'
# Your app should appear in the results

Trust Model

Published apps receive trust scores (0-100) based on:

Factor Points How to Maximize
Valid DID in author 30 Always include your node's DID
Found on multiple relays 5-20 Configure many relays in your node
Developer in federation 20 Have federated peers who trust you
Proper semver version 10 Use major.minor.patch format
Repository URL present 5 Include your repo URL
Security compliance 15 Meet all security requirements

Trust Tiers

Score Tier User Experience
80-100 Verified One-click install
50-79 Community Install with confirmation
20-49 Unverified Install with warning
0-19 Untrusted Requires explicit override

Testing Your App

Local Testing

# Run your container locally
podman run -d --name my-app \
  -p 8180:8080 \
  --read-only \
  --security-opt no-new-privileges \
  --user 1000:1000 \
  docker.io/myorg/my-app:1.0.0

# Verify it works
curl http://localhost:8180/health

# Check logs
podman logs my-app

On an Archipelago Node

  1. Install via the marketplace UI or RPC:
    curl -b cookies.txt -X POST http://192.168.1.228/rpc/v1 \
      -d '{"method":"package.install","params":{"id":"my-app","dockerImage":"docker.io/myorg/my-app:1.0.0"}}'
    
  2. Verify the container is running:
    curl -b cookies.txt -X POST http://192.168.1.228/rpc/v1 \
      -d '{"method":"container-list"}'
    
  3. Check the UI at http://192.168.1.228/app/my-app/

Validate Manifest

curl -b cookies.txt -X POST http://localhost/rpc/v1 \
  -H "Content-Type: application/json" \
  -d '{"method":"marketplace.verify","params":{...your manifest...}}'
# Returns: {"result":{"valid":true,"issues":[],"trust_score":65,"trust_tier":"community"}}

Updating Your App

  1. Build and push the new version: docker.io/myorg/my-app:1.1.0
  2. Publish an updated manifest with the new version
  3. NIP-33 replaceable events: the latest publish overwrites the previous one on relays
  4. Nodes running your app can see the update in their marketplace

App Icon

  • Provide a URL to your app icon (PNG, WebP, or SVG)
  • Recommended size: 256x256 pixels
  • Square aspect ratio
  • If no icon URL, a generic placeholder is shown in the marketplace