npm.io
1.0.10 • Published 3d agoCLI

brivio

Licence
MIT
Version
1.0.10
Deps
0
Size
191 kB
Vulns
0
Weekly
0

Brivio CLI

Command-line tool for Brivio — let a coding agent (or any script) report progress to your iPhone as updatable notifications and Live Activities (Lock Screen + Dynamic Island).

brivio speaks the AgentPacket JSON envelope defined in PACKET_SCHEMA.md. It POSTs that envelope to the Brivio iOS app over your LAN (http://<iphone-ip>:8473/v1/packet), or to a relay over HTTPS when you're off the local network.

  • Zero dependencies. Pure Node.js built-ins. No build step.
  • Node 18+.

Install

npm install -g brivio@latest

It's a single executable script: no compile step and no runtime dependencies. Use brivio in docs, scripts, and local development.

For repo development, run npm link inside cli/ or call node cli/bin/brivio.js directly.


Codex usage

brivio codex usage --json
brivio codex live --interval 60

codex usage fetches Codex 5-hour and weekly usage from codex app-server and writes ~/.brivio/codex-usage.json. The macOS app reads that file for a local usage panel.


Connect

Use the same flow shown in the iPhone onboarding:

brivio qr

Scan the generated QR image in Brivio, or choose Pair with Code and enter the 10-character code printed under it. First run creates relay credentials automatically and stores them at ~/.brivio/config.json. Delivery defaults to auto: saved LAN host, then Bonjour-discovered LAN devices, then relay only if local delivery fails.

brivio config set --host 192.168.1.42 --port 8473
brivio config show
brivio up                                    show QR + short pairing code
brivio status                                show saved/discovered devices
brivio reset-pairing                         delete saved iPhone connection
brivio qr                                      show QR image + short pairing code
brivio health        # confirm the phone answers

Config is stored at ~/.brivio/config.json (mode 0600):

{
  "host": "192.168.1.42",
  "port": 8473,
  "relayUrl": "wss://relay.example/…",
  "token": "…",
  "via": "auto",
  "devices": [{ "id": "iphone-17e", "name": "iPhone 17e" }]
}
Off the LAN — relay

When the agent runs somewhere that can't reach the phone directly, configure a relay. In auto mode the CLI still tries local network first, then POSTs to <relay>/v1/packet?token=<token> over HTTPS.

brivio config set --relay wss://relay.example.com --token YOUR_TOKEN
Precedence

Every setting can come from (highest wins) flags → env vars → config file → defaults:

Setting Flag Env var Default
host --host BRIVIO_HOST
port --port BRIVIO_PORT 8473
relay --relay BRIVIO_RELAY
token --token BRIVIO_TOKEN
via --via BRIVIO_VIA auto

--via auto (default) prefers the LAN and falls back to the relay if the phone is unreachable. Force one with --via lan or --via relay.

Global flags work before or after the command:

brivio --host 192.168.1.42 ping
brivio ping --host 192.168.1.42

Add --json to any command for machine-readable output. Every command exits nonzero on failure.


Commands

brivio config set    --host <ip> [--port 8473] [--relay <wss-url>] [--token <t>] [--via auto|lan|relay]
brivio config show
brivio pair <aa1.code>                       save iPhone pairing code
brivio devices                               show paired/discovered iPhones in a table, including alarm status
brivio devices rename <id> <name>            rename saved iPhone connection
brivio devices remove                        delete saved iPhone connection
brivio health                                    GET /health on the LAN server
brivio ping [--to <id> | --all] connectivity check (no UI)
brivio blockage --project <id> --body <blocker> [--request <next step>] [--destination-url <url>]
brivio notify --project <id> [--name <n>] --title <t> [--destination-url <url>] [--to <id> | --all]
brivio notify update --id <id> --project <id> [--progress] [--body] [--status] [--image] [--to <id> | --all]
brivio notify dismiss --id <id> --project <id> [--to <id> | --all]
brivio live start    [--project <id>] [--name <n>] --title <t> [...]   → prints the activity id
brivio live update --id <id> --project <id> [...] (also: --id --id b, or --project p, --to <id> | --all)
brivio live end --id <id> --project <id> [--dismiss immediate|default|after:<sec>] [--to <id> | --all]
brivio alarm set     --title <t> (--at <iso-date> | --in <duration>) prints alarm UUID
brivio alarm cancel  --id <uuid>
brivio artifact <file.md|file.html> [--artifact-id id] [--title …] [--type plan] [--ttl-days 7] [--passcode 1234] [--no-notify]  publish a shareable artifact
brivio artifacts [--json] [--to <id> | --all] list active/archived/expired/deleted artifacts
brivio codex usage [--cached]                  fetch/store or show Codex usage
brivio codex live [--once] [--interval 120]    stream usage to Live Activity
brivio list          [--json] [--local]         list ongoing Live Activities (aliases: ps, activities)
brivio logs                                      list active Live Activities
brivio discover                                  mDNS scan for servers on the LAN (optional)

Run brivio <command> --help for the full flag list of any command.

Codex usage

brivio codex usage reads Codex 5-hour and 7-day windows through the Codex app-server and stores the latest sample at ~/.brivio/codex-usage.json.

brivio codex usage --json
brivio codex live --interval 120

Notifications

Blockage alerts

When an agent is blocked on user input, use blockage instead of a vague ping. It sends one updatable sound notification with the exact blocker and optional next step. Tapping it opens --destination-url, or the current Codex/ChatGPT URL from env (BRIVIO_DESTINATION_URL, CODEX_TASK_URL, CODEX_THREAD_URL, etc.) when available.

brivio blockage \
  --project build \
  --body "Missing OPENAI_API_KEY in .env" \
  --request "Add the key, then reply done"

Reuse --id to update the same blocker instead of stacking alerts. Use --dry-run --json to inspect the packet without sending it.

An updatable banner. Reuse the same --id to update it in place — no new-banner spam. If you omit --id on a fresh notify, one is generated and printed/returned so you can update it later.

# present a notification with a progress bar
brivio notify \
  --project deploy --name "Deploy" \
  --title "Deploying to prod" \
  --body "Uploading build…" \
  --progress 0.15 \
  --destination-url "https://example.com/report.html" \
  --id deploy-42 \
  --symbol "arrow.up.circle.fill" --tint "#0A84FF" --sound

# update it in place
brivio notify update --id deploy-42 --project deploy \
  --progress 0.8 --body "Running migrations…"

# remove it
brivio notify dismiss --id deploy-42 --project deploy

--image accepts an https://… URL, a data:image/png;base64,… data URL, or raw base64 — the phone downloads/decodes it and attaches it.

--destination-url opens when the notification is tapped.

Notification progress example (one-liner loop)
ID=build-$(date +%s)
brivio notify --project ci --title "CI build" --id "$ID" --progress 0.0 --body "Queued"
for p in 0.25 0.5 0.75 1.0; do
  brivio notify update --id "$ID" --project ci --progress "$p" --body "Building… ${p}"
  sleep 2
done
brivio notify update --id "$ID" --project ci --progress 1.0 --body "Done ✅" --sound

Alarms

brivio alarm set schedules an actual iOS AlarmKit alarm. Use it when a user asks to be reminded, called, alerted when work finishes, or alerted at a milestone. Scheduling requires alarm access enabled in Brivio onboarding/settings and starts a companion Live Activity shortly before the alarm. Scheduled alarms appear in the iOS Alerts tab, where the user can cancel them; CLI cancellation uses the same alarm id.

brivio alarm set --title "Check build" --body "Tests should be done" --in 10m --ringtone retroBell --alarm-lead-minutes 5
brivio alarm set --title "Review artifact" --in 10m --symbol doc.richtext.fill --tint "#34C759" --image "$IMG" --destination-url "$URL" --alarm-button-title "Open artifact"
brivio alarm set --title "Stand up" --at 2026-06-30T15:00:00Z
brivio alarm cancel --id <uuid>

--in accepts 30s, 10m, 2h, 1d. --ringtone accepts systemDefault, retroBell, digitalPulse, cosmicAlert, rhythmAlarm, or bubbleChime. --symbol, --tint, --image, --destination-url, and --alarm-button-title brand the app-owned Alerts row and companion Live Activity; native AlarmKit currently uses the title, tint, and button labels. Actual AlarmKit alarms are created on device, so LAN and connected relay delivery can create them; the APNs worker cannot create a local alarm unless the app receives and handles the packet.

brivio devices prints ALARMS, AGENT, and AUTH columns. ALARMS means this Mac can schedule alarms on that iPhone, AGENT is the phone-wide agent-alarm switch, and AUTH is iOS alarm permission. Enable per-device alarm access in the iPhone app under Settings → Connections.

Artifacts

brivio artifact publishes a local Markdown or HTML file through the relay Worker and prints a public, unguessable URL (<relay>/r/<id>) you can open on any device. .md files are rendered to a standalone, dark-mode-friendly HTML page; .html files are uploaded verbatim.

# publish a Markdown report (rendered to HTML); the link expires in 7 days
brivio artifact build-summary.md

# stable artifact id; each upload to same id increments version
brivio artifact plan.html --artifact-id q3-migration-plan

# custom title, 14-day expiry, and a 4-digit passcode gate
brivio artifact perf.html --title "Perf regression deep-dive" \
  --type audit --ttl-days 14 --passcode 4821

# machine-readable output, and skip the phone notification
brivio artifact notes.md --json --no-notify

# list artifacts created by this relay token
brivio artifacts
  • The artifact is stored by the relay Worker and auto-deletes after --ttl-days (integer 1–30, default 7).
  • --artifact-id reuses the same public URL and increments version / versionCount on each upload.
  • Published artifacts include CLI provenance: hostname, working directory, git branch/commit/subject/dirty state, and CI run info when present.
  • --title defaults to the first # heading (Markdown), the <title> tag (HTML), or the filename.
  • --type controls the artifact icon: report, plan, preview, design, audit, code, or data. If omitted, the CLI infers one from title/name.
  • --passcode NNNN (exactly 4 digits) makes viewers unlock the page first; repeated wrong guesses lock it out and eventually destroy the artifact.
  • Uploads are capped at 2 MB of HTML.
  • Unless --no-notify, the CLI also sends a notification whose destinationURL is the report URL, so tapping the alert on the iPhone opens the report. Use --to <id> / --all to pick devices, as with notify.
  • Requires relay credentials — brivio config set --relay <url> --token <t>, or pair via brivio connect.
  • --json prints the Worker's raw response: { "ok": true, "id": "…", "url": "https://…/r/…", "expiresAt": 1751…, "locked": false }.

Live Activities

A persistent Lock Screen + Dynamic Island widget. live start prints the activity id on its own line (and returns it as id in --json) — capture it to address subsequent updates and the end.

Styles: bar (linear progress), ring (circular), tasks (checklist), pulse (indeterminate working state).

--destination-url sets the URL opened when the Live Activity is tapped. On Codex runs, live start uses exact-link env (BRIVIO_DESTINATION_URL, CODEX_DESTINATION_URL, CODEX_TASK_URL, CODEX_THREAD_URL, CHATGPT_CODEX_URL) first, then ChatGPT universal links from CODEX_SHARE_ID, CODEX_TASK_ID, or CODEX_CONVERSATION_ID.

ID=$(brivio live start \
  --project build --name "Build pipeline" \
--title "Compiling" --status "Resolving deps" \
--style bar --symbol "hammer.fill" --tint "#34C759" \
--destination-url "$CODEX_TASK_URL" \
--total 8 --completed 0)

brivio live update --id "$ID" --project build \
  --status "Compiling module 4/8" --completed 4 --progress 0.5

brivio live end --id "$ID" --project build --dismiss after:5
--tasks

For the tasks style, pass a comma-separated list; each item is name or name:done:

brivio live update --id "$ID" --project build \
  --tasks "Lint:done,Typecheck:done,Build,Test,Deploy"

becomes:

"tasks": [
  { "id": "lint", "name": "Lint", "done": true },
  { "id": "typecheck", "name": "Typecheck", "done": true },
  { "id": "build", "name": "Build", "done": false },
  { "id": "test", "name": "Test", "done": false },
  { "id": "deploy", "name": "Deploy", "done": false }
]
--dismiss

How the activity disappears when you end it: immediate, default, or after:<seconds> (e.g. after:300 keeps the final state up for 5 minutes).


Enumerate ongoing activities — list (ps, activities)

brivio list fetches the device's GET /v1/activities and prints a clean, aligned table of the Live Activities currently running — so an agent can discover which projects/ids are live and act on them. ps and activities are aliases.

brivio list
# Ongoing Live Activities (3):
# ID       PROJECT  STATUS     PROGRESS  PHASE    UPDATED
# act-aaa  build    Compiling  50%       running  2m ago
# act-bbb  build    Linking    —         running  31s ago
# act-ccc  deploy   Uploading  20%       running  just now
  • PROGRESS is shown as 0–100%, or when indeterminate (negative/omitted).
  • UPDATED is a relative time derived from the activity's updatedAt (blank if the device doesn't provide one).
  • --json emits the raw activities array (straight from GET /v1/activities), ideal for scripting.
  • If the device is unreachable you get the same friendly error as the other LAN commands, and a nonzero exit.
brivio list --json | jq -r '.[].id'      # just the ongoing ids
Local id cache — list --local

Every live start records { id, project, title, startedAt } to ~/.brivio/activities.json, and every live end removes that id. This lets an agent re-discover the ids it started even while offline (no device round trip):

brivio list --local
# Locally-tracked Live Activities (2):
# ID            PROJECT  TITLE          STARTED
# act-18dbb14d  web      Building web   just now
# act-470d05b9  api      Building api   30s ago

brivio list --local --json               # raw cache records

The cache is small and self-healing: if the file is missing or corrupt it is treated as empty and recreated on the next write — it never blocks a live start/end.

Update many activities at once

Each activity is addressable by its own id (returned by live start). To update several in one call:

# 1) Repeat --id to target specific activities:
brivio live update --id act-aaa --id act-bbb \
  --status "Paused for review" --phase waiting

# 2) Omit --id and pass --project to update EVERY ongoing activity in that
#    project. The CLI fetches /v1/activities, finds all whose projectID matches,
#    and applies the update to each — printing one result line per id:
brivio live update --project build \
  --phase success --status "Build succeeded" --tint "#34C759"
# ✓ act-aaa
# ✓ act-bbb

A single --id behaves exactly as before. With --json, multi-update emits { ok, count, results:[{ id, ok }] }. The command exits nonzero if any individual update failed.

Targeting multiple devices

devices output includes stable id values. Use them to control where packets go:

brivio devices                    # find registered IDs
brivio ping --to test-device      # only this device
brivio ping --all                 # all paired devices
brivio live update --id "$ID" --project build --to test-device --status "Step 1"
brivio live end --id "$ID" --project build --to test-device --dismiss after:5

If neither --to nor --all is used, CLI uses activeDeviceId from config (or first paired device).

Full example — an agent reports build progress

A realistic sequence an agent would run: start an activity, push several updates, flip to success, and end it.

#!/usr/bin/env bash
set -euo pipefail

PROJECT="ios-app"

# 1) Start the Live Activity (capture the id it prints).
ACT=$(brivio live start \
  --project "$PROJECT" --name "iOS App" \
  --title "Build & Test" --status "Starting…" \
  --style tasks --symbol "gearshape.2.fill" --tint "#5E5CE6" \
  --total 4 --completed 0 \
  --tasks "Install deps,Compile,Test,Archive")

echo "Live Activity: $ACT"

# 2) Step through the work, updating status / progress / tasks.
brivio live update --id "$ACT" --project "$PROJECT" \
  --status "Installing dependencies" --completed 1 --progress 0.25 \
  --tasks "Install deps:done,Compile,Test,Archive"

brivio live update --id "$ACT" --project "$PROJECT" \
  --status "Compiling" --completed 2 --progress 0.50 \
  --tasks "Install deps:done,Compile:done,Test,Archive"

brivio live update --id "$ACT" --project "$PROJECT" \
  --status "Running tests" --completed 3 --progress 0.75 \
  --tasks "Install deps:done,Compile:done,Test:done,Archive"

brivio live update --id "$ACT" --project "$PROJECT" \
  --status "Archiving" --completed 4 --progress 1.0 \
  --tasks "Install deps:done,Compile:done,Test:done,Archive:done"

# 3) Flip to a success state, then end (keep it visible 30s).
brivio live update --id "$ACT" --project "$PROJECT" \
  --status "Build succeeded ✅" --phase success --tint "#34C759"

brivio live end --id "$ACT" --project "$PROJECT" --dismiss after:30

On failure, an agent would instead:

brivio live update --id "$ACT" --project "$PROJECT" \
  --status "Tests failed" --phase failure --tint "#FF453A" --symbol "xmark.octagon.fill"
brivio live end --id "$ACT" --project "$PROJECT" --dismiss default

# …and optionally fire a notification so it shows up even if the activity was dismissed:
brivio notify --project "$PROJECT" --title "Build failed" \
  --body "3 tests failing in CheckoutTests" --tint "#FF453A" --sound

Full example — an agent fans out across many activities

Start three activities, list them, update one by id, update a whole project at once, then end them. Copy-paste friendly:

#!/usr/bin/env bash
set -euo pipefail

# 1) Start three Live Activities (two in "build", one in "deploy").
#    Each `live start` prints its id on the last line — capture it.
A=$(brivio live start --project build  --name "Build" --title "Frontend"  --style bar | tail -1)
B=$(brivio live start --project build  --name "Build" --title "Backend"   --style bar | tail -1)
C=$(brivio live start --project deploy --name "Deploy" --title "Staging"  --style pulse | tail -1)
echo "started: $A $B $C"

# 2) See what's ongoing (from the device). The same ids appear here.
brivio list
#   …or, offline, the ids THIS machine started:
brivio list --local

# 3) Update a single activity by its id.
brivio live update --id "$A" --project build --progress 0.4 --status "Bundling"

# 4) Update EVERY ongoing activity in the "build" project at once
#    (omit --id, pass --project). One result line per id is printed.
brivio live update --project build --phase success --status "Build done" --progress 1.0

# 5) End them. Repeat --id to end several explicit ids in one call;
#    `live end` also removes each id from the local cache.
brivio live update --id "$A" --id "$B" --status "Wrapping up"
brivio live end --id "$A" --project build  --dismiss after:5
brivio live end --id "$B" --project build  --dismiss after:5
brivio live end --id "$C" --project deploy --dismiss after:5

brivio list --local        # now empty

Discover (optional, mDNS)

If your network allows multicast DNS, you can scan for the app instead of typing the IP:

brivio discover
# Found 1 service(s):
#   Brivio  192.168.1.42:8473
#     brivio config set --host 192.168.1.42 --port 8473

mDNS is best-effort — VPNs and isolated/guest Wi-Fi often block it. If nothing shows up, just use config set --host <ip> directly. Discovery failures never throw; the command exits 0 with guidance.


Output & exit codes

  • Human-readable by default; --json prints the server's { ok, id, message } response (or { ok:false, error } on failure).
  • Exit code 0 on success, non-zero on any error (bad flags, unreachable host, HTTP 4xx/5xx, auth rejection).
  • Set NO_COLOR=1 to disable ANSI colors.

Wire format

Every command builds one AgentPacket JSON envelope and POSTs it. The shape is the single source of truth in PACKET_SCHEMA.md:

{
  "kind": "notify" | "activity" | "ping",
  "action": "present|update|dismiss" | "start|update|end",
  "project": "build", "projectName": "Build", "id": "stable-id",
  "title": "…", "body": "…", "status": "…",
  "destinationURL": "https://chatgpt.com/codex/tasks/…",
  "progress": 0.37, "completed": 3, "total": 8,
  "symbol": "hammer.fill", "emoji": "🛠️", "tint": "#34C759",
  "style": "bar|ring|tasks|pulse", "phase": "running|waiting|success|failure",
  "tasks": [ { "id": "t1", "name": "Lint", "done": true } ],
  "image": "https://… | data:image/png;base64,… | <raw base64>",
  "sound": true, "dismiss": "immediate|default|after:300"
}

Endpoints used: GET /health, POST /v1/packet (ping), POST /v1/notify, POST /v1/activity, GET /v1/activities (list/logs), and POST /v1/artifacts on the relay Worker (artifact); /v1/reports remains a compatibility alias.

The local id cache (~/.brivio/activities.json) is CLI-only state — it is written on live start/end and read by list --local; it is never sent to the device.

Keywords