Bellwire
Connect repository state and events to the user's Bellwire cards, inbox, and iPhone. New projects are Private by default: Bellwire relays only an opaque wake while the phone fetches content directly from the user's HTTPS service. Hosted storage is opt-in and requires approval in the App.
Workflow
Inspect the repository, its secret-management convention, tests, and the exact successful or failed state that should trigger the event.
Clarify only product decisions that code cannot answer: notification frequency, sensitive values, and whether a high-priority interruption is justified.
Ensure BELLWIRE_AGENT_TOKEN is available outside tracked files. If it is missing, ask the user for the six-digit code shown in the iOS app and run:
bellwire_secret_dir="$(mktemp -d)"
node <skill-dir>/scripts/bellwire.mjs bind \
--code 123456 \
--name "Codex on Mac" \
--secret-output "$bellwire_secret_dir/agent-token"
The CLI creates the file with mode 0600 and never prints the Token. Import it
into the user's approved secret store without displaying it, then remove the
temporary file. Never commit it.
Run list-projects, then create or reuse the Bellwire project. Search existing configuration before creating another project. Never create a second project just to change delivery mode.
Keep the project Private unless the user explicitly wants Bellwire Cloud to store Event, Inbox, and Surface content:
- Private: implement signed Direct v2 notification, inbox, and surfaces endpoints; persist device keys, one-time nonces, an opaque-reference outbox, and the 24-hour reference expiry in the user's real database. Read direct-connections.md.
- Hosted: request the change with
request-mode-change; stop until the signed-in user approves it in Bellwire. Then create Hosted schemas, Surfaces, and Ingest Tokens.
For Private runtime delivery, create a wake-only token, store it in the source app's real secret manager, and call private-wakes best-effort after the source transaction and outbox record commit. Bellwire must never receive title, body, data, Logo URL, project name, or service hostname.
Choose the display primitive:
- Surface: current state that updates in place. Read surfaces.md.
- Inbox event: durable history, completion, failure, recovery, or a decision boundary. In Private mode it stays in the user's service; in Hosted mode use event-spec.md.
Use stable Surface keys and opaque, random references. Reuse a stable idempotency key for retries of the same wake or Hosted write.
Modify the smallest reliable trigger point. Send only after the underlying business operation commits.
- Prefer a direct post-commit Bellwire call when the application owns the business operation.
- When a payment, commerce, deployment, or automation provider is the source of truth, read webhooks.md and add a provider-specific webhook adapter.
Run unit tests for signature, timestamp, unknown key, tampered target, and atomic nonce replay; then run conformance-direct.mjs. If the database cannot atomically consume a nonce, stop and explain the safety blocker.
Run the repository's existing tests plus a focused trigger test. Never weaken a business test to make Bellwire pass.
Persist and deploy the source-side adapter and its secrets through the repository's real source of truth.
Complete one real source operation and verify the outbox, wake acceptance, delivery, signed phone fetch, and displayed result using production-verification.md. A manual wake is not production verification.
Integration status
Use these exact boundaries in progress and final reports:
- Configured: the Bellwire project, schema, token, Surface, or test Event exists. This is not a production integration.
- Integrated, awaiting production verification: source-side adapter code, runtime secrets, focused tests, and deployment are present, but no real source operation has completed the path.
- Production verified: a real business operation created the expected Event or Surface, Delivery was checked, and any claimed device presentation was confirmed by the user.
Never describe send-test, a manually upserted Surface, or secret creation as an actual production integration.
Commands
Use scripts/bellwire.mjs for API operations. It defaults to the official hosted API and accepts BELLWIRE_API_URL for self-hosted installations.
bellwire_secret_dir="$(mktemp -d)"
node <skill-dir>/scripts/bellwire.mjs list-projects
node <skill-dir>/scripts/bellwire.mjs create-project --name "VideoSays" --logo-url "https://videosays.com/logo.png"
node <skill-dir>/scripts/bellwire.mjs create-wake-token --project <id> --name production --secret-output "$bellwire_secret_dir/wake-token"
node <skill-dir>/scripts/bellwire.mjs generate-reference
node <skill-dir>/scripts/bellwire.mjs send-wake --project <id> --reference <opaque-ref> --idempotency-key <stable-key>
node <skill-dir>/scripts/bellwire.mjs request-mode-change --project <id> --to hosted
node <skill-dir>/scripts/bellwire.mjs update-project --project <id> --logo-url "https://cdn.example.com/logo.png"
node <skill-dir>/scripts/bellwire.mjs set-project-order --project <id> --order 10
node <skill-dir>/scripts/bellwire.mjs delete-project --project <id>
node <skill-dir>/scripts/bellwire.mjs create-schema --project <id> --file event-spec.json
node <skill-dir>/scripts/bellwire.mjs create-token --project <id> --name production --secret-output "$bellwire_secret_dir/ingest-token"
node <skill-dir>/scripts/bellwire.mjs upsert-surface --project <id> --key prod-api --file surface.json
node <skill-dir>/scripts/bellwire.mjs list-surfaces --project <id>
node <skill-dir>/scripts/bellwire.mjs list-direct-recoveries
node <skill-dir>/scripts/bellwire.mjs set-surface-order --project <id> --key prod-api --order 20
node <skill-dir>/scripts/bellwire.mjs send-test --project <id> --file test-event.json
node <skill-dir>/scripts/bellwire.mjs event --event <event-id>
node <skill-dir>/scripts/bellwire.mjs health --project <id>
node <skill-dir>/scripts/bellwire.mjs publish-direct-connection \
--device-key-id <id> \
--agreement-public-key <base64> \
--file direct-connection.json
node <skill-dir>/scripts/conformance-direct.mjs \
--manifest direct-connection.json \
--device-key-id <id> \
--reference <known-test-reference>
Run node <skill-dir>/scripts/bellwire.mjs --help for validation, revocation,
deletion, and encryption commands. Secret-returning commands require
--secret-output; never read their Token into chat or command output.
delete-project is permanent and cascades through the project's schemas, tokens, events,
deliveries, and live Surfaces. Resolve the exact project ID and require explicit user intent
before running it.
Use --json for machine-readable non-secret output. Read api.md when adding another operation or diagnosing an error response.
Adapter routing
- Read adapters.md for Node.js, Cloudflare Worker, Shell, and GitHub Actions patterns.
- Read webhooks.md when receiving Stripe-like payment events or any third-party callback before updating Bellwire.
- Prefer the project's existing HTTP client. Do not add an SDK dependency for one request.
- Treat event sending as a bounded side effect: set a timeout, avoid logging payloads, and decide explicitly whether notification failure may affect the business operation. Default to best-effort after the business operation succeeds.
- Keep token values out of generated diffs, test snapshots, CI logs, and error telemetry.
Private rules
- Generate at least 128 random bits for each reference and encode it as 22–200 URL-safe characters. Never derive it from an order, email, task, customer, or timestamp.
- Write notification detail to a database-backed outbox before sending the wake. Expire the reference after at most 24 hours.
- A wake call is bounded and best-effort after commit. Do not roll back the real business operation because Bellwire is unavailable.
MONTHLY_SIGNAL_LIMIT_REACHED is terminal until the returned UTC reset time or an upgrade. Do not loop or retry it.
- Private detail and Inbox responses come from the user's service and may be cached on the phone for 30 days; Bellwire Cloud never receives them.
Hosted Event rules
- Use lowercase dotted names such as
payment.success, deployment.failed, or agent.waiting.
- Include only fields needed for the inbox, notification, deep link, or diagnosis.
- Never reference a sensitive field in a notification template; the API rejects it.
- Use order IDs, deployment IDs, task IDs, or run IDs for Hosted idempotency. Do not expose those identifiers as Private references.
- Avoid high-frequency progress events. Prefer completion, failure, recovery, and decision-required boundaries.
- Ask for explicit user approval before requesting
priority: high.
Surface rules
- Reuse a meaningful stable key such as
sales-today, prod-api, or nightly-backup.
- Preserve the assigned
displayOrder during routine updates. Change it only when the user explicitly asks to reorder a card.
- Send display-ready values. For example, compute revenue in the source system and send
¥2,430; Bellwire does not infer business aggregation from raw events.
- For private or customer-derived metrics, prefer a signed Bellwire Direct endpoint so the card payload never enters Bellwire storage.
- Choose one of the supported native types. Never embed HTML, JavaScript, Swift, CSS, or arbitrary rendering instructions.
- Prefer a Surface for frequent progress and metric updates; avoid flooding the Event inbox.
- Use
open_url actions only when the destination is expected and safe for the user.
- Project logos must be public HTTPS images no larger than 5 MB. Bellwire uses
them in native avatars and expanded rich notifications, then falls back to a
project monogram if the image is missing or cannot be downloaded.
Verification and recovery
If setup fails, read troubleshooting.md. Check in this order:
- API reachability and management-token scope.
- Project ID and active schema version.
- Secret availability in the actual runtime.
- Payload type and required fields.
- Stable
Idempotency-Key behavior.
- Source adapter presence in the deployed version and a real source operation.
- Event detail, Surface state, and Delivery status.
- iOS notification permission, device registration, and sandbox versus production APNs environment.
Never rotate, revoke, or replace a working token unless the user requested it or compromise is suspected.
1---2name: bellwire3description: Add, update, test, diagnose, or maintain Private-first Bellwire live cards, inbox events, and phone notifications in application backends, Node.js, Cloudflare Workers, CI/CD workflows, and shell automation. Use for Bellwire binding, signed Direct v2 endpoints, opaque references and outboxes, wake tokens, Hosted Events and Surfaces, mode-change approval, provider webhooks, delivery checks, conformance, or notification troubleshooting.4license: MIT-05---67# Bellwire89Connect repository state and events to the user's Bellwire cards, inbox, and iPhone. New projects are Private by default: Bellwire relays only an opaque wake while the phone fetches content directly from the user's HTTPS service. Hosted storage is opt-in and requires approval in the App.1011## Workflow12131. Inspect the repository, its secret-management convention, tests, and the exact successful or failed state that should trigger the event.142. Clarify only product decisions that code cannot answer: notification frequency, sensitive values, and whether a high-priority interruption is justified.153. Ensure `BELLWIRE_AGENT_TOKEN` is available outside tracked files. If it is missing, ask the user for the six-digit code shown in the iOS app and run:1617 ```bash18 bellwire_secret_dir="$(mktemp -d)"19 node <skill-dir>/scripts/bellwire.mjs bind \20 --code 123456 \21 --name "Codex on Mac" \22 --secret-output "$bellwire_secret_dir/agent-token"23 ```2425 The CLI creates the file with mode `0600` and never prints the Token. Import it26 into the user's approved secret store without displaying it, then remove the27 temporary file. Never commit it.284. Run `list-projects`, then create or reuse the Bellwire project. Search existing configuration before creating another project. Never create a second project just to change delivery mode.295. Keep the project Private unless the user explicitly wants Bellwire Cloud to store Event, Inbox, and Surface content:30 - Private: implement signed Direct v2 notification, inbox, and surfaces endpoints; persist device keys, one-time nonces, an opaque-reference outbox, and the 24-hour reference expiry in the user's real database. Read [direct-connections.md](references/direct-connections.md).31 - Hosted: request the change with `request-mode-change`; stop until the signed-in user approves it in Bellwire. Then create Hosted schemas, Surfaces, and Ingest Tokens.326. For Private runtime delivery, create a wake-only token, store it in the source app's real secret manager, and call `private-wakes` best-effort after the source transaction and outbox record commit. Bellwire must never receive title, body, data, Logo URL, project name, or service hostname.337. Choose the display primitive:34 - Surface: current state that updates in place. Read [surfaces.md](references/surfaces.md).35 - Inbox event: durable history, completion, failure, recovery, or a decision boundary. In Private mode it stays in the user's service; in Hosted mode use [event-spec.md](references/event-spec.md).368. Use stable Surface keys and opaque, random references. Reuse a stable idempotency key for retries of the same wake or Hosted write.379. Modify the smallest reliable trigger point. Send only after the underlying business operation commits.38 - Prefer a direct post-commit Bellwire call when the application owns the business operation.39 - When a payment, commerce, deployment, or automation provider is the source of truth, read [webhooks.md](references/webhooks.md) and add a provider-specific webhook adapter.4010. Run unit tests for signature, timestamp, unknown key, tampered target, and atomic nonce replay; then run `conformance-direct.mjs`. If the database cannot atomically consume a nonce, stop and explain the safety blocker.4111. Run the repository's existing tests plus a focused trigger test. Never weaken a business test to make Bellwire pass.4212. Persist and deploy the source-side adapter and its secrets through the repository's real source of truth.4313. Complete one real source operation and verify the outbox, wake acceptance, delivery, signed phone fetch, and displayed result using [production-verification.md](references/production-verification.md). A manual wake is not production verification.4445## Integration status4647Use these exact boundaries in progress and final reports:4849- **Configured:** the Bellwire project, schema, token, Surface, or test Event exists. This is not a production integration.50- **Integrated, awaiting production verification:** source-side adapter code, runtime secrets, focused tests, and deployment are present, but no real source operation has completed the path.51- **Production verified:** a real business operation created the expected Event or Surface, Delivery was checked, and any claimed device presentation was confirmed by the user.5253Never describe `send-test`, a manually upserted Surface, or secret creation as an actual production integration.5455## Commands5657Use [scripts/bellwire.mjs](scripts/bellwire.mjs) for API operations. It defaults to the official hosted API and accepts `BELLWIRE_API_URL` for self-hosted installations.5859```bash60bellwire_secret_dir="$(mktemp -d)"61node <skill-dir>/scripts/bellwire.mjs list-projects62node <skill-dir>/scripts/bellwire.mjs create-project --name "VideoSays" --logo-url "https://videosays.com/logo.png"63node <skill-dir>/scripts/bellwire.mjs create-wake-token --project <id> --name production --secret-output "$bellwire_secret_dir/wake-token"64node <skill-dir>/scripts/bellwire.mjs generate-reference65node <skill-dir>/scripts/bellwire.mjs send-wake --project <id> --reference <opaque-ref> --idempotency-key <stable-key>66node <skill-dir>/scripts/bellwire.mjs request-mode-change --project <id> --to hosted67node <skill-dir>/scripts/bellwire.mjs update-project --project <id> --logo-url "https://cdn.example.com/logo.png"68node <skill-dir>/scripts/bellwire.mjs set-project-order --project <id> --order 1069node <skill-dir>/scripts/bellwire.mjs delete-project --project <id>70node <skill-dir>/scripts/bellwire.mjs create-schema --project <id> --file event-spec.json71node <skill-dir>/scripts/bellwire.mjs create-token --project <id> --name production --secret-output "$bellwire_secret_dir/ingest-token"72node <skill-dir>/scripts/bellwire.mjs upsert-surface --project <id> --key prod-api --file surface.json73node <skill-dir>/scripts/bellwire.mjs list-surfaces --project <id>74node <skill-dir>/scripts/bellwire.mjs list-direct-recoveries75node <skill-dir>/scripts/bellwire.mjs set-surface-order --project <id> --key prod-api --order 2076node <skill-dir>/scripts/bellwire.mjs send-test --project <id> --file test-event.json77node <skill-dir>/scripts/bellwire.mjs event --event <event-id>78node <skill-dir>/scripts/bellwire.mjs health --project <id>79node <skill-dir>/scripts/bellwire.mjs publish-direct-connection \80 --device-key-id <id> \81 --agreement-public-key <base64> \82 --file direct-connection.json83node <skill-dir>/scripts/conformance-direct.mjs \84 --manifest direct-connection.json \85 --device-key-id <id> \86 --reference <known-test-reference>87```8889Run `node <skill-dir>/scripts/bellwire.mjs --help` for validation, revocation,90deletion, and encryption commands. Secret-returning commands require91`--secret-output`; never read their Token into chat or command output.9293`delete-project` is permanent and cascades through the project's schemas, tokens, events,94deliveries, and live Surfaces. Resolve the exact project ID and require explicit user intent95before running it.9697Use `--json` for machine-readable non-secret output. Read [api.md](references/api.md) when adding another operation or diagnosing an error response.9899## Adapter routing100101- Read [adapters.md](references/adapters.md) for Node.js, Cloudflare Worker, Shell, and GitHub Actions patterns.102- Read [webhooks.md](references/webhooks.md) when receiving Stripe-like payment events or any third-party callback before updating Bellwire.103- Prefer the project's existing HTTP client. Do not add an SDK dependency for one request.104- Treat event sending as a bounded side effect: set a timeout, avoid logging payloads, and decide explicitly whether notification failure may affect the business operation. Default to best-effort after the business operation succeeds.105- Keep token values out of generated diffs, test snapshots, CI logs, and error telemetry.106107## Private rules108109- Generate at least 128 random bits for each reference and encode it as 22–200 URL-safe characters. Never derive it from an order, email, task, customer, or timestamp.110- Write notification detail to a database-backed outbox before sending the wake. Expire the reference after at most 24 hours.111- A wake call is bounded and best-effort after commit. Do not roll back the real business operation because Bellwire is unavailable.112- `MONTHLY_SIGNAL_LIMIT_REACHED` is terminal until the returned UTC reset time or an upgrade. Do not loop or retry it.113- Private detail and Inbox responses come from the user's service and may be cached on the phone for 30 days; Bellwire Cloud never receives them.114115## Hosted Event rules116117- Use lowercase dotted names such as `payment.success`, `deployment.failed`, or `agent.waiting`.118- Include only fields needed for the inbox, notification, deep link, or diagnosis.119- Never reference a sensitive field in a notification template; the API rejects it.120- Use order IDs, deployment IDs, task IDs, or run IDs for Hosted idempotency. Do not expose those identifiers as Private references.121- Avoid high-frequency progress events. Prefer completion, failure, recovery, and decision-required boundaries.122- Ask for explicit user approval before requesting `priority: high`.123124## Surface rules125126- Reuse a meaningful stable key such as `sales-today`, `prod-api`, or `nightly-backup`.127- Preserve the assigned `displayOrder` during routine updates. Change it only when the user explicitly asks to reorder a card.128- Send display-ready values. For example, compute revenue in the source system and send `¥2,430`; Bellwire does not infer business aggregation from raw events.129- For private or customer-derived metrics, prefer a signed Bellwire Direct endpoint so the card payload never enters Bellwire storage.130- Choose one of the supported native types. Never embed HTML, JavaScript, Swift, CSS, or arbitrary rendering instructions.131- Prefer a Surface for frequent progress and metric updates; avoid flooding the Event inbox.132- Use `open_url` actions only when the destination is expected and safe for the user.133- Project logos must be public HTTPS images no larger than 5 MB. Bellwire uses134 them in native avatars and expanded rich notifications, then falls back to a135 project monogram if the image is missing or cannot be downloaded.136137## Verification and recovery138139If setup fails, read [troubleshooting.md](references/troubleshooting.md). Check in this order:1401411. API reachability and management-token scope.1422. Project ID and active schema version.1433. Secret availability in the actual runtime.1444. Payload type and required fields.1455. Stable `Idempotency-Key` behavior.1466. Source adapter presence in the deployed version and a real source operation.1477. Event detail, Surface state, and Delivery status.1488. iOS notification permission, device registration, and sandbox versus production APNs environment.149150Never rotate, revoke, or replace a working token unless the user requested it or compromise is suspected.