README
¶
💬 Beeper CLI — Messaging in your terminal.
Manage chats, send messages, and control Beeper Desktop from the command line.
Features
- Authentication - browser-based login with secure keyring storage
- Chat management - list, search, archive, and organize conversations
- Desktop control - focus Beeper window, navigate to chats, pre-fill drafts
- Messaging - send messages, search history, and view conversations
- Local-first - everything stays on your device via Beeper Desktop’s local API
- Multi-network support - WhatsApp, Signal, Telegram, Discord, Google Messages, Google Chat, Google Voice, Slack, X (Twitter DMs), LinkedIn, Instagram, Messenger (Facebook Messenger)
- Upcoming networks - LINE, Hinge, Snapchat (coming soon)
- Reminders - set and clear chat reminders
Supported Networks
Currently supported chat networks:
- Signal
- Telegram
- Discord
- Google Messages
- Google Chat
- Google Voice
- Slack
- X (Twitter DMs)
- Messenger (Facebook Messenger)
Installation
Homebrew
brew install salmonumbrella/tap/beeper-cli
Go Install
go install github.com/salmonumbrella/beeper-cli/cmd/beeper@latest
Build from Source
git clone https://github.com/salmonumbrella/beeper-cli
cd beeper-cli
make build && make install
Quick Start
1. Enable Local API
Open Beeper Desktop → Settings → Developers → Enable Local API
2. Authenticate
beeper auth login
This opens your browser to authenticate with Beeper and securely stores the token in your system keyring.
Prefer to paste a token directly?
beeper auth add --token "<token>"
3. Test Connection
beeper auth test
4. Start Using
beeper accounts # List connected networks
beeper chats list # Show recent chats
beeper messages search "hi" # Search message history
beeper c ls # Short alias: chats list
beeper m s "hi" # Short alias: messages search
Agent Mode
Beeper CLI is optimized for automation. The following features are designed to reduce agent friction:
beeper schema [command path]- JSON schema for commands/flagsbeeper schema --show-key-map- Include machine-readable light short-key mapbeeper examples- Canonical usage examplesbeeper agent guidelines- Store local agent instructionsbeeper agent smoke- Read-only smoke plan for key flowsbeeper agent state- Inspect/clear persisted handle state--handles/BEEPER_AGENT_HANDLES=1- Emit handle tokens like@chat:1and@msg:2beeper agent tools list|run- Run user-defined tool definitionsbeeper agent tools schema|validate- Tool definition schema + validation
Handle tokens persist to a local state file (see Environment Variables) so agents can reference @chat:1 later.
Message commands support --include-chat to bundle chat metadata in JSON output.
Default agent files live under the Beeper CLI config directory:
- Agent state:
agent-state.json(oragent-state.<profile>.json) - Agent trace:
agent-trace.jsonl
Configuration
Account Filtering
Filter commands by specific chat networks:
# Via flag
beeper chats list --account whatsapp
# Multiple networks
beeper messages search "invoice" --account whatsapp,telegram
Get account IDs from beeper accounts.
Profile Selection
If you have multiple auth tokens saved, select one with --profile:
beeper --profile personal chats list
You can set a default profile with BEEPER_PROFILE.
Aliases
Create shortcuts for frequently used chat IDs:
beeper alias add work "!abc123:beeper.local"
beeper alias add family "!xyz789:beeper.local"
beeper alias list
Use aliases anywhere a chat name or ID is accepted:
beeper messages send --to work --text "Shipping now"
beeper focus --chat family --draft "On my way"
Reserved keywords are also supported:
beeper messages send --to myself --text "Remember to follow up"
Environment Variables
BEEPER_OUTPUT- Output format:agent(default),text,json,json-pretty, orjsonlBEEPER_COLOR- Color mode:auto(default),always, orneverNO_COLOR- Set to any value to disable colors (standard convention)BEEPER_PROFILE- Default auth profile nameBEEPER_BASE_URL- Override API base URL (default:http://localhost:23373)BEEPER_SOURCE- Backend source:api(default),db, orautoBEEPER_DB- Path to Beeperindex.db(implies--source db)BEEPER_AGENT_HANDLES- Emit handle tokens like@chat:1/@msg:2BEEPER_AGENT_STATE- Override the agent state file pathBEEPER_AGENT_TRACE- Enable trace logging (set to a path or truthy value)BEEPER_AGENT_TOOLS_DIR- Override the agent tools directory
DB Backend (Read-Only)
For faster local search, you can use the DB backend which reads Beeper’s local SQLite database directly. This is read-only and does not support sending or modifying data.
Requirements
- CGO-enabled Go toolchain
- SQLite3 library available on your system
Usage
# Use DB backend explicitly
beeper --source db messages search "invoice"
# Or point directly at the database (implies db backend)
beeper --db ~/Library/Application\ Support/BeeperTexts/index.db messages search "invoice"
# Include context around search hits
beeper --source db messages search "invoice" --context 2 --window 30m
# Auto mode (API first, DB fallback for search)
beeper --source auto messages search "invoice"
Security
Credential Storage
Tokens are stored securely in your system's keychain:
- macOS: Keychain Access
- Linux: Secret Service (GNOME Keyring, KWallet)
- Windows: Credential Manager
Commands
Authentication
beeper auth login # Authenticate via browser (opens browser)
beeper auth add # Add a token (interactive or --token)
beeper auth add --token "<token>"
beeper auth add work # Add a token with a profile name
beeper auth list # List configured tokens
beeper auth remove <name> # Remove a token
beeper auth test # Test current token
beeper auth test work # Test a named token
Aliases
beeper alias list
beeper alias add <name> <chat-id>
beeper alias show <name>
beeper alias remove <name>
Accounts
beeper accounts # List connected chat networks
Chats
beeper chats list # List recent chats
beeper chats list --unread # Only unread chats
beeper chats list --all # List ALL chats (pagination via search)
beeper chats list --all --include-muted # Include muted chats
beeper chats list --pinned # Only pinned chats
beeper chats list --muted # Only muted chats
beeper chats list --archived # Only archived chats
beeper chats list --inbox primary # Filter by inbox
beeper chats list --inbox archive # Show archived chats
beeper chats list --account whatsapp # Filter by network
beeper chats list --type dm # Filter by chat type (dm or group)
beeper chats list --cursor <cursor> # Paginate (recent or all)
beeper chats list --direction before # Paginate direction
beeper --source db chats list # List chats via local DB (read-only)
beeper chats get <chat-id> # Get chat details
beeper chats search <query> # Search for chats by name
beeper chats search <query> --limit 50 # Limit search results
beeper chats archive <chat-id> # Archive a chat
beeper chats archive --chat "John" # Archive by name
beeper chats archive --unarchive <chat-id> # Unarchive
beeper chats archive-read # Archive all read chats
beeper chats archive-read --dry-run # Preview what would be archived
beeper chats archive-read --yes # Skip confirmation prompt
Messages
beeper messages list <chat-id> # List messages in a chat
beeper messages list --chat "John" # List by chat name
beeper messages list <chat-id> --limit 50 # Limit results
beeper messages list --unread # Only unread messages
beeper messages list --cursor <cursor> # Paginate from cursor
beeper messages list --direction before # Paginate direction
beeper messages search <query> # Search all messages
beeper messages search "invoice" --account telegram
beeper messages search "invoice" --after 2024-01-01
beeper messages search "invoice" --after "2h ago"
beeper messages search "invoice" --chat <chat-id>
beeper messages search "invoice" --limit 50
beeper messages send <chat-id> --text "Hello!"
beeper messages send --to "John" --text "Meeting at 3pm"
beeper messages send --to "John" --stdin
beeper messages send --to "John" --file ./message.txt
beeper messages send --to "John" --reply-to <message-id>
beeper messages tail <chat-id> # Follow new messages
beeper messages tail --chat "John" # Follow by chat name
beeper messages tail --interval 2s # Polling interval
beeper messages tail --limit 20 # Show last N before following
beeper messages delete <message-id> --chat "John"
beeper messages delete <message-id> --chat-id <chat-id> --yes
beeper messages read --chat "John"
beeper messages read --chat-id <chat-id>
beeper messages react <message-id> --chat "John" --emoji "👍"
beeper messages react <message-id> --chat-id <chat-id> --emoji "👍"
beeper messages get <message-id> --chat "John" --context 3
beeper messages get <message-id> --chat-id <chat-id>
Shortcuts (Verb-First)
These are shortcuts for common flows (same flags/behavior as the canonical commands):
beeper send|snd ... # = beeper messages send ...
beeper tail|tl ... # = beeper messages tail ...
beeper search|s ... # = beeper messages search ...
beeper reply|r ... # reply to a message (infers chat via handle state / DB)
beeper open|o ... # = beeper focus ... (with extra copy/paste affordances)
beeper unread|ib # = beeper inbox
Short Aliases
For token savings, common resource and subcommand aliases are available:
beeper c ls # chats list
beeper c s "team" # chats search
beeper m ls --chat "Team" # messages list
beeper m g "$msg123" --chat "Team" # messages get
beeper ct s "alex" # contacts search
DB backend search options:
beeper --source db messages search "invoice" --days 7
beeper --source db messages search "invoice" --context 2 --window 30m
beeper --source db messages search "invoice" --message-format plain
beeper --source db messages search "invoice" --media image,video
Contacts
beeper contacts list # List DM contacts
beeper contacts list --limit 50 # Limit results
beeper contacts search <query> # Search contacts by name
beeper contacts search <query> --limit 50 # Limit search results
Search Capabilities
Both contacts search and chats search use fuzzy matching with smart ranking:
- Fuzzy matching - tolerates typos and approximate spelling
beeper contacts search "damnznd" # Finds "Damnzand" beeper chats search "boxing" # Finds "Boxing Club" etc. - Multi-term search - multiple words use AND logic (all terms must match)
beeper contacts search "john signal" # Matches contacts named John on Signal - Field-weighted scoring - exact name matches rank higher than participant matches
- Activity sorting - when scores are tied, most recently active results appear first
- Group sender hints - when no DM contacts match, matching participants in group chats are shown on stderr
beeper contacts search "alex" # stderr: hint: "Alex" found as sender in group "Team Chat"
Inbox
beeper inbox # Show unread messages
beeper inbox --limit 10 # Limit chats shown
beeper inbox --dm # Only DM conversations
beeper inbox --since 1h # Messages since duration
beeper inbox --watch --interval 3s # Stream new messages
Reminders
beeper reminders set <chat-id> --at "2024-12-25 10:00"
beeper reminders set --chat "John" --at "2024-12-25 10:00"
beeper reminders set --chat "John" --at "30m"
beeper reminders clear <chat-id>
Agent
beeper agent guidelines # Show current agent guidelines
beeper agent guidelines --init # Create a starter guidelines file
beeper agent guidelines --path # Print the guidelines file path
Guidelines are stored in your config directory. When using --profile, a profile-specific guidelines file is used.
Focus (Desktop Control)
beeper focus # Bring Beeper to foreground
beeper focus --chat "John" # Open specific chat
beeper focus --chat-id <chat-id> # Open specific chat by ID
beeper focus --chat "John" --draft "Hi!" # Open with pre-filled draft
beeper focus --chat "John" --message <id> # Jump to a message
beeper focus --chat "John" --attachment /path/to/file
Version
beeper version # Print version info
beeper version --check # Check for updates
Doctor
beeper doctor # Run diagnostics
Completion
beeper completion [bash|zsh|fish|powershell]
Output Formats
Text
Human-readable tables with colors and formatting:
$ beeper chats list
ID NAME NETWORK UNREAD LAST ACTIVITY
!abc123... John Smith WhatsApp 3:42 PM
!def456... Team Chat Telegram 5 2:15 PM
!ghi789... Mom iMessage 2 Yesterday
Agent
Compact, ID-embedded output for automation:
$ beeper chats list -o agent
[chat:!abc123] Team Chat (slack) - 2 unread [group]
[chat:!def456] Alice (whatsapp)
$ beeper messages list --chat "Team Chat" -o agent
[chat:!abc123] Team Chat
10:23 Alex: Standup in 5 [id:$msg1]
10:25 → You: On it [id:$msg2]
JSON
Machine-readable output:
$ beeper chats list -o json
{
"items": [
{
"id": "!abc123...",
"title": "John Smith",
"network": "WhatsApp",
"unreadCount": 0,
"lastActivity": "2024-12-25T15:42:00Z"
}
],
"total": 1,
"hasMore": false
}
Data goes to stdout, errors and progress to stderr for clean piping.
When using -o json, -o jsonl, or -o json-pretty, errors are also emitted as a single JSON object on stderr.
If you want only the array for piping to tools like jq, use --results-only:
beeper chats list -o json --results-only | jq '.[0]'
Pretty JSON
Readable JSON formatting:
beeper chats list -o json-pretty
Template Output
Customize text output with Go templates (applies per item for list commands):
beeper chats list --format '{{.Title}}\t{{.Network}}'
JSON Lines (JSONL)
Streaming commands emit one JSON object per line when -o json or -o jsonl is set.
For list outputs, -o jsonl emits one object per line:
# Follow a chat and stream JSON events
beeper messages tail --chat "Team" -o jsonl | jq -c .
# Watch inbox updates as JSON lines
beeper inbox --watch -o jsonl
# List chats as JSON lines
beeper chats list -o jsonl
Sample event payloads:
{"chatID":"!abc123:beeper.com","chatTitle":"Team","network":"Slack","chatType":"group","message":"Standup in 5","sender":"Alex","timestamp":"2025-01-12T10:15:00Z"}
{"id":"$event:1","chatID":"!abc123:beeper.com","accountID":"acct1","senderID":"@alex:beeper.com","sender":"Alex","senderName":"Alex","text":"Hello","timestamp":"2025-01-12T10:15:00Z","isMe":false}
Fields by stream:
beeper inbox --watch -o jsonchatID,chatTitle,network,chatType,message,sender,timestamp
beeper messages tail -o jsonid,chatID,accountID,senderID,sender,senderName,text,timestamp,isMe,attachments,reactions,replyTo
Streaming filters:
# Print only message text from a live stream
beeper messages tail --chat "Team" -o json | jq -r '.text'
# Print inbox sender + message
beeper inbox --watch -o json | jq -r '"\(.sender): \(.message)"'
List output schema (JSON):
beeper chats list -o jsonitems[]with chat fields (id,title,network,unreadCount,lastActivity,type,accountID,isArchived,isMuted,isPinned,preview)total,hasMore,cursor,newestCursor,oldestCursor
beeper messages list -o jsonitems[]with message fields (id,chatID,accountID,senderID,sender,senderName,text,timestamp,isMe,attachments,reactions,replyTo)
beeper messages search -o jsonmessages[]with message fields,chats{}lookup,hasMore,cursor
beeper inbox -o jsonchatID,chatTitle,network,chatType,message,sender,timestamp
beeper contacts list -o jsonid,title,network,lastActivity
beeper contacts search -o jsonitems[]with chat fields (DMs),hasMore,cursor
beeper accounts -o jsonid,network,user
beeper reminders set/clear -o jsonstatus,chat_id,reminder_at(forset)
beeper focus -o jsonstatus,chat_id,draft
Examples
Archive all read chats
# Preview first
beeper chats archive-read --dry-run
# Then execute
beeper chats archive-read
Send a quick message
beeper messages send --to "John" --text "Running 5 mins late!"
Follow a chat
beeper messages tail --chat "Team" --interval 2s
Search messages across networks
beeper messages search "pdf" --account whatsapp -o json | jq '.messages[]'
Search with relative dates (DB or API)
beeper messages search "invoice" --after "yesterday"
Search attachments (DB backend)
beeper --source db messages search "invoice" --media file
Use aliases and "myself"
beeper alias add work "!abc123:beeper.local"
beeper messages send --to work --text "Shipped"
beeper messages send --to myself --text "Follow up tomorrow"
Focus chat with draft from clipboard
beeper focus --chat "Team" --draft "$(pbpaste)"
Disambiguate chat names
beeper messages send --to "Project" --exact --text "Shipping now"
beeper chats archive --chat "Family" --first
beeper reminders set --chat "Alex" --dm --at "2024-12-25 10:00"
Automation
Use -o json for scripting and --dry-run to preview changes:
# Count unread chats
beeper chats list -o json | jq '[.items[] | select(.unreadCount > 0)] | length'
# Get all Telegram chat IDs
beeper chats list --account telegram -o json --query '.items[].id'
# Notify on unread count
unread=$(beeper chats list -o json | jq '[.items[] | select(.unreadCount > 0)] | length')
[ "$unread" -gt 10 ] && osascript -e "display notification \"$unread unread\" with title \"Beeper\""
Debug Mode
Enable verbose output for troubleshooting:
beeper --debug chats list
# Shows: api request method=GET url=http://localhost:9988/...
# Shows: api response status=200 content_length=1234
JQ Filtering
Filter JSON output with JQ expressions:
# Get only unread chats
beeper chats list -o json --query '.items[] | select(.unreadCount > 0)'
# Extract chat IDs
beeper chats list -o json --query '.items[].id'
# Get chats from specific network
beeper chats list -o json --query '.items[] | select(.network == "Telegram")'
Global Flags
All commands support these flags:
--account <id>- Filter by account/network ID--profile <name>- Auth profile name (frombeeper auth list)--base-url <url>- Override API base URL-o, --output <format>- Output format:agent,text,json,json-pretty, orjsonl(default: agent)--color <mode>- Color mode:auto,always, ornever(default: auto)--debug- Enable debug output (shows API requests/responses)--query <expr>- JQ filter expression for JSON output--results-only- For JSON output, return only the results array (strip envelope)--compact-json,--cj- Prefer compact JSON in JSON modes (forces single-line output forjson-pretty)--format <template>- Go template for text output (applies per item for lists)--source <api|db|auto>- Backend source (db is read-only)--db <path>- Path to Beeper index.db (implies db backend)--help- Show help for any command--version- Show version information
Commands that support local --light (--li) auto-switch to -o json when output was not explicitly set, and default --compact-json to true unless --compact-json/--cj was explicitly provided.
In light mode, JSON payloads use short field keys to reduce token usage. Key map:
- chats:
id,ti(title),nw(network),ty(type),ur(unread),ts(last activity),pv(preview) - messages:
id,ch(chat id),sn(sender),tx(text),ts(timestamp),me(is me) - chats messages: same key map as messages (uses MessageLight)
- inbox:
ch(chat id),ti(chat title),sn(sender),tx(message),ts(timestamp)
For programmatic discovery, run:
beeper schema --show-key-map -o json --query '.lightKeyMap'
API Limitations
The Beeper Desktop local API does not currently expose endpoints for:
- Muting, pinning, or renaming chats
- Editing messages
- Real-time event streams (this CLI uses polling for
messages tail)
If these endpoints are added in the future, the CLI can expand to support them.
API Limits
Some endpoints have server-side limits:
| Endpoint | Max --limit |
Notes |
|---|---|---|
messages search |
20 | Use --cursor to paginate for more results |
chats search |
20 | Use --cursor to paginate for more results |
contacts search |
20 | Use --cursor to paginate for more results |
The DB backend (--source db) does not have these limits.
Shell Quoting
Chat IDs start with ! which has special meaning in bash/zsh (history expansion). Prefer single quotes around chat IDs:
# Correct
beeper messages list '!abc123:beeper.local'
beeper chats get '!abc123:beeper.local'
# Also correct (escaped)
beeper messages list "\\!abc123:beeper.local"
beeper chats get "\\!abc123:beeper.local"
# Wrong - may fail or behave unexpectedly
beeper messages list "!abc123:beeper.local"
beeper messages list !abc123:beeper.local
Copy/Paste Tokens (Agent Output)
In addition to raw IDs, most commands accept identifiers copied directly from output:
- Chat tokens:
[chat:!abc123] ...orchat:!abc123 - Message tokens:
... [id:$msg123] ...,id:$msg123, or↩$msg123 - Handle refs (when enabled):
@chat:1,@msg:2(also works as[@chat:1]/[@msg:2])
When piping to jq, avoid != which can trigger history expansion. Use jq's truthy check instead:
# Correct - jq treats null as falsy
beeper messages list "!chat:id" -o json | jq '.items[] | select(.text)'
# Problematic in some shells
beeper messages list "!chat:id" -o json | jq '.items[] | select(.text != null)'
Shell Completions
Generate shell completions for your preferred shell:
Bash
# macOS (Homebrew):
beeper completion bash > $(brew --prefix)/etc/bash_completion.d/beeper
# Linux:
beeper completion bash > /etc/bash_completion.d/beeper
# Or source directly:
source <(beeper completion bash)
Zsh
beeper completion zsh > "${fpath[1]}/_beeper"
Fish
beeper completion fish > ~/.config/fish/completions/beeper.fish
PowerShell
beeper completion powershell | Out-String | Invoke-Expression
Development
After cloning, install git hooks:
make setup
This installs lefthook pre-commit and pre-push hooks for linting and testing.
Manual Checks
beeper doctor
beeper alias add work "!abc123:beeper.local"
beeper alias list
beeper messages send --to myself --text "ping"
beeper messages search "invoice" --after "2h ago"
beeper --source db messages search "invoice" --media image
License
MIT