A carrier between
Claude and you.
Claude sends questions and status updates to your phone mid-task. You reply from anywhere. Work doesn't stop waiting for you to come back to the laptop.
instance
server
phone
reply
continues
pidginroost.com server, skip Step 1 entirely โ you never touch wrangler.toml, Cloudflare resources, or a cloned repo. Cloning to a local path and the com.* bundle IDs only matter if you're self-hosting your own server or building the Apple apps from source.Server
Pidgin's backend is a Cloudflare Worker that stores messages in D1, documents in R2, sessions in KV, and pushes via APNs.
If the server is already running, you just need two values from it.
Get your API key
wrangler secret list --name pidgin-server
If you need to reset it:
wrangler secret put API_KEY --name pidgin-server
Confirm the server is healthy
curl -sf https://pidginroost.com/health | jq .
# โ {"ok":true,"data":{"status":"healthy"}}
If that returns ok: true, skip ahead to Apps.
Prerequisites
- Node.js โฅ 18 and npm
- Wrangler CLI:
npm i -g wrangler - A Cloudflare account with a zone (for the custom domain)
- An APNs Auth Key (.p8) from Apple Developer with Push Notifications enabled
- A Resend API key or Cloudflare Email Routing configured for your sender address
Clone and install
git clone https://github.com/ashrocket/pidgin.git cd pidgin/server npm install
Create secrets file
You're now in the server/ directory of your clone โ the rest of the commands in this section run from there.
cat > .dev.vars << 'EOF' API_KEY=your-random-secret-here OWNER_EMAIL=you@example.com MAIL_FROM=Pidgin <pidgin@yourdomain.com> WORKER_URL=https://yourdomain.com APNS_KEY_ID=ABC123XYZ APNS_TEAM_ID=DEF456UVW APNS_PRIVATE_KEY=-----BEGIN PRIVATE KEY----- ...paste your .p8 content here... -----END PRIVATE KEY----- APNS_IOS_TOPIC=com.pidginroost.pidgin APNS_MACOS_TOPIC=com.pidginroost.pidgin.mac EOF
wrangler.toml first. The committed config points at the author's domain and Cloudflare resources. Before deploying, update [[routes]] to your own custom domain, the [vars] block (WORKER_URL, MAIL_FROM, APNS_IOS_TOPIC, APNS_MACOS_TOPIC), and create your own D1 / KV / R2 resources, pasting their IDs into the [[d1_databases]], [[kv_namespaces]], and [[r2_buckets]] blocks.Run migrations and deploy
npm run db:migrate # local D1 for testing npm run db:migrate:prod # production D1 npm run deploy # push to Cloudflare
Upload secrets to production
wrangler secret put API_KEY wrangler secret put APNS_KEY_ID wrangler secret put APNS_TEAM_ID wrangler secret put APNS_PRIVATE_KEY wrangler secret put OWNER_EMAIL
MAIL_FROM must be a verified custom address with a confirmed destination inbox.iOS & macOS Apps
The native apps receive push notifications, display messages, and let you reply. iOS and macOS share a single XcodeGen project at clients/apple.
Install via Xcode
You'll need Xcode 16+ and an Apple Developer account with a connected device.
Generate the project
cd pidgin/clients/apple # from your repo clone brew install xcodegen # if needed xcodegen generate open Pidgin.xcodeproj
Run on iPhone
- Select the Pidgin-iOS scheme and your connected iPhone as destination
- Press Run (โR)
- Trust the developer certificate: Settings โ General โ VPN & Device Management
Run the macOS app
- Switch scheme to Pidgin-macOS and press Run (โR)
aps-environment: development entitlement is set โ and the server must send to the sandbox APNs endpoint for those builds.Connect the Apps to Your Server
Each app logs in with a magic link, then registers its APNs device token so the server knows where to push.
iOS app
- Open the Pidgin iOS app and enter your email (must match
OWNER_EMAILon a single-user server, or an active invited user on a multi-user server) - Use
https://pidginroost.com/onboardingfrom the app's setup guide link if you need the browser walkthrough - Tap Send magic link โ check your email
- Tap the link (or paste it in Safari if universal links aren't working yet) to complete login
- Allow notifications when prompted โ device token is registered automatically
macOS app
- Same magic link flow as iOS
- Allow notifications in System Settings โ Notifications if you missed the prompt
Confirm device registration
Use the API key from the Server step. (You'll add it to your shell permanently in the Claude Code step โ for now, set it inline.)
export PIDGIN_API_KEY="your-api-key" curl -s https://pidginroost.com/api/registry -H "Authorization: Bearer $PIDGIN_API_KEY" | jq '.data[]'
You should see your device listed with a recent registered_at timestamp.
Claude Code
Two env vars and a plugin. Once wired up, Claude can send push notifications mid-task and poll for your reply before continuing.
Step 1 โ Set environment variables
Add to your shell profile (~/.zshrc or ~/.zprofile):
export PIDGIN_URL="https://pidginroost.com" export PIDGIN_API_KEY="your-api-key-here"
source ~/.zshrc
~/.zshrc are available in every session automatically.Step 2 โ Install the plugin
In a Claude Code session, add the marketplace and then install the plugin โ adding a marketplace alone doesn't install anything:
/plugin marketplace add ashrocket/pidgin /plugin install pidgin@pidgin
Or, if you've cloned the repo locally:
/plugin marketplace add /path/to/your/pidgin /plugin install pidgin@pidgin
The argument is <plugin>@<marketplace> โ both are named pidgin here. Trust the plugin when prompted. This registers the following commands:
Step 3 โ Verify
/pidgin-setup
This checks env vars, curl/jq, server connectivity, and sends a test push. Watch for the notification โ if it arrives, you're done.
Natural language triggers
The Pidgin skill activates automatically when you say:
- "Pigeon it to me" โ send the last output as a push
- "Send it to my phone" or "notify me" โ push notification
- "Email it to me" โ Gmail draft if Gmail MCP is connected, otherwise push
- "Ask me when you get to the auth step" โ Claude pauses and sends a question mid-task
- "Text me" โ iMessage if available, push as fallback
Codex and shell-based agents
Codex and other terminal agents can use the same API client script directly. Set the same environment variables, then call the script from this repo:
export PIDGIN_URL="https://pidginroost.com" export PIDGIN_API_KEY="your-api-key-here" bash ~/ashcode/pidgin/scripts/pidgin.sh send \ --type message \ --title "Codex is connected" \ --body "Pidgin is available from this Codex workflow." \ --project "codex"
For durable Codex workflows, add those environment variables to the shell or task runner that launches Codex, and have agents call scripts/pidgin.sh when a task needs a phone notification, a user question, or a shareable document.
Claude Desktop
/pidgin skills and hooks that power the Claude Code integration aren't available in the desktop app.You can still reach Pidgin from Claude Desktop by wiring env vars into your MCP server config. Claude Desktop doesn't inherit ~/.zshrc, so add them explicitly in ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"your-existing-server": {
"command": "...",
"args": [...],
"env": {
"PIDGIN_URL": "https://pidginroost.com",
"PIDGIN_API_KEY": "your-api-key-here"
}
}
}
}
For document workflows, Claude Desktop can also use the remote MCP endpoint at https://pidginroost.com/mcp if your MCP client supports remote OAuth. The current MCP tools cover document list, search, retrieval, publishing, and share-link generation. Push notifications still use the Claude Code plugin or the REST script.
MCP & Browser Clients
Pidgin exposes a remote MCP endpoint for document workflows and a browser UI for clients that do not have a native Pidgin plugin.
Remote MCP
https://pidginroost.com/mcp
The Worker publishes OAuth metadata for remote clients:
https://pidginroost.com/.well-known/oauth-protected-resource/mcp https://pidginroost.com/.well-known/oauth-authorization-server
- ChatGPT โ add the remote MCP server URL if the workspace supports custom remote MCP connectors, then complete the Pidgin OAuth login.
- Claude Desktop / Claude Design-style work โ use the remote MCP URL for document tools, or keep using Claude Code for push notifications and reply polling.
- Codex โ use
scripts/pidgin.shfor push/reply workflows and the MCP endpoint when the environment supports remote MCP. - Perplexity and browser agents โ use the browser UI and public/share links today; use the same MCP URL if the client supports remote MCP + OAuth.
Browser fallback
Any browser-capable agent can use the web UI:
https://pidginroost.com https://pidginroost.com/onboarding https://pidginroost.com/setup
Use the browser path for login, setup, reading documents, generating share links, and checking the inbox when a tool client cannot call the REST API or MCP endpoint directly.
Verify Everything Works
Run this end-to-end check from a terminal. It should produce a push on your phone within a few seconds.
curl -X POST "$PIDGIN_URL/api/messages" \
-H "Authorization: Bearer $PIDGIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "question",
"title": "Pidgin setup complete",
"body": "Reply with ok to confirm the connection works.",
"priority": "normal",
"instance": {
"model": "manual-test",
"session_id": "setup-check",
"project": "pidgin-onboarding",
"source": "curl"
}
}'
Common issues
| Symptom | Likely cause | Fix |
|---|---|---|
| No push, curl returned ok | Device not registered, or APNs dev vs prod mismatch | Check /api/registry. If no devices, log into the app again. |
| curl returns 401 | PIDGIN_API_KEY not set or wrong |
Run echo $PIDGIN_API_KEY โ if empty, add to ~/.zshrc and reload |
| curl connection refused | PIDGIN_URL wrong or worker not deployed |
Try curl -sf $PIDGIN_URL/health. Check Cloudflare Worker dashboard. |
| Magic link doesn't open app | iOS universal links are finicky right after install โ the AASA must have been fetched, and links opened from inside some apps bypass it | Paste the link into Safari directly, or long-press it and choose "Open in Pidgin." The AASA appID in server/src/index.ts already matches the app's bundle ID (com.pidginroost.pidgin). |
/pidgin-setup can't find script |
Plugin not installed | Reinstall: /plugin install pidgin@pidgin (run /plugin marketplace add ashrocket/pidgin first if needed) |