# Belt Agent Integration Skill

Use this document when an agent, client app, or worker device needs to connect to Belt.

## What Belt Is

Belt is a Cloudflare-native coordination service for accounts, devices, encrypted envelopes, jobs, worker leases, cursors, retention, and audit records.

Belt never stores plaintext product payloads, prompts, book content, notes, local files, model output, or product-specific semantics.

Production origin:

- https://belt.built4.fun

Important public endpoints:

- https://belt.built4.fun/health
- https://belt.built4.fun/v1/runtime/proof
- https://belt.built4.fun/app
- https://belt.built4.fun/skill.md
- https://belt.built4.fun/llms.txt

## Human Account Setup

1. Open `/app` and sign in with GitHub.
2. Create or open a Belt account from the browser dashboard. The tenant field accepts a full id such as `tenant_koto` or a slug such as `koto`.
3. Create a reusable worker key from the dashboard. Use the API when you need client or hybrid keys.
4. Use API-only one-time install sessions, legacy device links, or fallback 10-minute pairing tickets only for stricter bootstrap, recovery, or manual approval.
5. Audit connected devices and account events from the dashboard.

GitHub identifies the human principal. Do not send `githubId`, `githubLogin`, `userId`, or `externalSubject` in `/v1/me/...` requests; Belt derives them from the verified session cookie.

## Device Or Agent Setup

Preferred bootstrap: the GitHub browser dashboard creates a reusable worker enrollment key without asking for role or platform. API callers can set role and add optional platform, capability scope, expiresInSeconds, and maxClaims when they need client/hybrid keys or stricter scope. The device claims that token with local public keys. The token is not a tenant admin secret and cannot read data or create jobs.

```http
POST /v1/me/accounts/{accountId}/enrollment-keys
Cookie: belt_admin_session=...
Content-Type: application/json

{
  "role": "worker"
}
```

The response returns the plaintext `token` once plus `claimPath`. Belt stores only a salted token hash. Keys are scoped, expiring, claim-limited, and revocable.

Claim the enrollment key from the device:

```http
POST /v1/enrollment-keys/claim
Content-Type: application/json

{
  "tenantId": "tenant_koto",
  "token": "reusable-enrollment-key",
  "deviceId": "dev_worker_01",
  "platform": "macos",
  "displayName": "Desktop Worker",
  "publicKey": "recipient-encryption-public-key",
  "signingPublicKey": "hmac:shared-test-key-or-p256-spki-key",
  "capabilities": ["epub_processing"]
}
```

The registered role always comes from the enrollment key or install session. Requested capabilities must be a subset of the credential-authorized scope.

One-time install sessions remain available for stricter bootstrap:

```http
POST /v1/me/accounts/{accountId}/install-sessions
POST /v1/install-sessions/claim
```

Legacy device links remain available for manual approval flows:

```http
POST /v1/device-links
GET /v1/device-links/{linkId}?pollToken=...
```

Fallback registration still accepts a trusted pairing ticket:

```http
POST /v1/devices/register
Content-Type: application/json

{
  "ticketCode": "10-minute-code",
  "deviceId": "dev_worker_01",
  "role": "worker",
  "platform": "macos",
  "displayName": "Desktop Worker",
  "publicKey": "recipient-encryption-public-key",
  "signingPublicKey": "hmac:shared-test-key-or-p256-spki-key",
  "capabilities": ["epub_processing"]
}
```

Device roles are `client`, `worker`, or `hybrid`.

After registration, sign every device request. The canonical request fields are:

1. HTTP method
2. Path and query
3. SHA-256 hash of the exact request body
4. Nonce
5. Unix timestamp seconds

Send the signature in the `Authorization` header using the device id, nonce, timestamp, and signature. Nonces are replay-protected.

## Core Agent Flow

1. Client device creates an opaque job with required capabilities and delivery policy.
2. Worker device claims the job and receives a guarded lease.
3. Worker sets the job to running with the lease id and lease token.
4. Worker appends an encrypted envelope for resolved recipients.
5. Client syncs, decrypts locally, advances its cursor, and ACKs delivery.

Useful endpoints:

```http
POST /v1/jobs
POST /v1/jobs/{jobId}/claim
PATCH /v1/jobs/{jobId}
POST /v1/envelopes
GET /v1/sync
POST /v1/envelopes/{envelopeId}/ack
```

Delivery policies:

- `origin_device_only`: return encrypted output only to the creating device.
- `all_account_clients`: send encrypted output to every active client in the account.
- `selected_devices`: send encrypted output only to listed device ids.

Encrypted stream envelopes may include route-only `metadata` such as `frameType`, `seq`, and trace ids so recipients can construct AAD before decrypting. Do not put plaintext prompts, model output, tool output, files, notes, or product secrets in metadata.

## Security Rules For Agents

- Encrypt payloads before sending them to Belt.
- Include recipient encrypted content keys for every resolved recipient.
- Never send plaintext prompts, book text, local files, notes, or model output.
- Treat enrollment keys as reusable but scoped, claim-limited, expiring secrets. Treat install session tokens, device links, and pairing tickets as one-time secrets with a 10-minute lifetime.
- Store device signing keys locally; do not put them in GitHub, docs, logs, or browser-visible pages.
- Use `/v1/runtime/proof` before trusting a deployment.

## Runtime Proof

`GET /v1/runtime/proof` reports service version, deployed git SHA, environment, D1/R2/Durable Object probes, cleanup state, and whether GitHub OAuth is configured. It does not return secrets.

## Human Dashboard

Use `/app` for GitHub sign-in, tenant/account creation, enrollment-key generation/revocation, legacy pending device-link approval, device connection lists, and recent account audit events.
