Command reference
Binary: pidge (npm: pidge-cli — run via
npx pidge-cli …). Node ≥ 18 (WebSocket realtime needs ≥ 22). pidge <command> --help prints
detailed usage.
Commands
Section titled “Commands”| Command | What it does |
|---|---|
message / important / urgent / event / live |
The 5 typed sends. Fire-and-forget by default; add --actions/--wait to ask for a reply. important is the recommended default. Aliases: fyi, report, alert. |
ask |
important --wait: send and block; prints the chosen action JSON. Requires a way to answer. |
approval |
Go/no-go recipe: important + Approve (Face ID)/Reject + --wait. Answer comes back as grant or deny. |
approve "<question>" |
Deny-default permission gate answered by exit code — 0 only on explicit allow. See Approval gates. |
hello |
First contact on a fresh channel: a live-narrated handshake the human confirms. |
notify |
Deprecated — untyped send (server picks the channel default). Prefer a typed send. |
wait <cid> |
Block on an already-sent notification until answered. |
cancel <cid> |
Cancel a still-scheduled notification (idempotent; 409 once delivered). |
inbox |
What you sent: list, --pending, or --summary (counts + answer latency). |
catchup |
Read-only conversation peek, newest first — never consumes. --limit / --before / --digest. |
listen |
Block until the human messages you; print JSON; exit. --all includes notification answers; --follow keeps the session open. Consumes — sole-consumer channels only. |
online |
Alias for listen --all, one word — so a pasted prompt can just say “stay online: pidge online”. |
bridge --exec '<handler>' |
24/7 supervisor: long-poll, run the handler once per batch (JSON on stdin), ack on exit 0. bridge install writes a launchd/systemd template. |
ack --up-to <id> |
Mark messages processed after handling. --summary "<note>" attributes the work; --renew heartbeats the lease. |
contract set <k>=<v> / contract show |
Declare how you operate (advisory, never policy). |
selftest |
Round-trip proof the listener works (PASS 0 / FAIL 2 with the likely cause). |
setup --claim <code> |
Exchange the single-use claim code for the key, store it (mode 600), claim ownership, run doctor. Run it inside your project: the key is scoped per git project (≥ 0.43). --global uses the shared machine file (daemons/cron); --print prints export lines instead (your terminal only). |
terminal <sub> |
Agent Sessions: mirror a coding-agent session (tmux pane) to the human’s phone, E2E-sealed, typed replies back. Documentation coming soon. |
update |
Update this CLI to the latest published pidge-cli (npm/pnpm/yarn/bun auto-detected). |
doctor |
Validate everything without exposing secrets: env source, server, key, device reach, ownership, realtime probe, live consumers. |
whoami |
Which channel this key speaks for (JSON). |
skill install [--target claude|agents|gemini] |
Write the Pidge skill for an AI agent (.claude/skills/pidge/SKILL.md, AGENTS.md or GEMINI.md). Existing differing files are backed up first. |
--version |
Print the CLI version. |
Send options
Section titled “Send options”--title TEXT (required) the headline--body TEXT the message shown on the banner--body-markdown MD rich body for the tap-through detail screen (GFM: tables)--body-markdown-file F read the markdown body from a file ("-" = stdin) — no shell-quoting pain--subtitle TEXT--profile ID low-level alias of the TYPE — prefer the typed subcommands--event-at ISO8601 WHEN the thing happens (required by event)--lead-minutes N notify / start the countdown N min before event_at (5–240)--urgency LEVEL normal | persistent | alarm (low-level — prefer the type)--image PATH_OR_URL image on the banner + feed; a local path is uploaded for you--file PATH a real artifact (xlsx, pdf, csv…) — Quick Look + save to Files (≤25 MB)--url URL deep link the app opens on tap (PR, dashboard, log)--copy TEXT tap-to-copy value on the detail screen (code, token)--note TEXT WHY this runtime armed the send (clear metadata, visible to siblings)--actions LIST|JSON catalog ids (yes,no,approve,reject,accept,decline,later,done, snooze,reschedule,reply,mute) OR a JSON array of custom actions--custom-action SPEC "id:label[:destructive][:confirm][:biometric][:terminal]" (repeatable)--gated add a Face-ID confirm on the consequential action (money/deletion)--wait block until answered, print chosen_action JSON (ask/approval imply it)--deliver-at ISO8601 schedule for later (server-owned)--reply-to URL also POST the answer to your webhook (HMAC-signed, public HTTPS only)--correlation-id ID idempotency + routing key (auto-generated if omitted)--thread ID conversation handle: sends sharing it group as ONE strand on the phone--after CID decision queue: held until that notification is answered--collapse-key KEY replace/update a prior notification--param KEY=VALUE pass ANY raw /notify field (repeatable) — future server fields work day-one without a CLI update--timeout SECONDS how long --wait blocks (ask/approval ≈ 3600 · wait: 300)--interval SECONDS fallback poll cadence (default 30) — normally unused (WS/long-poll)--realtime force the WebSocket · --no-realtime = polling only--quiet-nag silence the once-a-day manifest-version nudge (PIDGE_QUIET_NAG=1)pidge live has its own field flags (--status, --step 3/5, --progress, --ends-at,
--end --outcome "…", --dedicated) — see Live Activities and
pidge live --help.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 |
success / answered |
1 |
usage error |
2 |
error (network, server, broken setup) |
3 |
--wait timed out — no answer yet, not a failure |
4 |
timed out with zero healthy round-trips — the channel looks broken |
approve is different by design: 0 only on explicit allow; deny/timeout/no-answer/HTTP
failure → 1; raw network error (the send never reached the server) → 2. Non-zero always
means “not approved.”
stdout / stderr contract
Section titled “stdout / stderr contract”- stdout is always machine-readable: the raw
201JSON (fire-and-forget) or thechosen_actionJSON (--wait/ask/approval/wait). - Everything human goes to stderr: warnings,
correlation_id=<cid>(the FIRST stderr line ofask), snooze notices, armed-escalation and policy-degrade narration.
Environment
Section titled “Environment”| Variable | Meaning |
|---|---|
PIDGE_URL |
server base URL (https://api.pidge.sh) |
PIDGE_TOKEN |
the channel’s bearer key (hld_…) |
PIDGE_SECRET |
the channel’s E2E key, when the human enabled sealing — see E2E |
PIDGE_AGENT / PIDGE_LABEL |
per-agent identity: config namespace + display label |
PIDGE_E2E_MEDIA |
on/off — per-machine override for sealed attachments |
PIDGE_QUIET_NAG |
1 silences the manifest-version nudge |
Legacy HERALD_URL/HERALD_TOKEN still work. With no env vars set, the CLI reads a
KEY=VALUE config file, so the key never has to appear in an agent’s chat — resolution order:
explicit env vars win; then ~/.config/pidge/agents/<PIDGE_AGENT>/env when PIDGE_AGENT is
set; then the project scope ~/.config/pidge/projects/<hash>/env when setup ran inside a git
project (≥ 0.43); else the shared ~/.config/pidge/env. pidge doctor prints which source is
in use.
The manifest
Section titled “The manifest”GET $PIDGE_URL/api/v1/manifest (Bearer auth) is the full machine-readable spec. Any new server
field is usable immediately via --param key=value — the CLI is a thin pipe over the manifest.
