{"skill":{"slug":"roadrunner","displayName":"Roadrunner","summary":"Beeper Desktop CLI for chats, messages, contacts, connect info, websocket events, search, and reminders.","description":"---\nname: roadrunner\ndescription: Beeper Desktop CLI for chats, messages, contacts, connect info, websocket events, search, and reminders.\nhomepage: https://github.com/johntheyoung/roadrunner\nmetadata:\n  clawdbot:\n    emoji: \"🐦💨\"\n    requires:\n      bins:\n        - rr\n    install:\n      - id: brew\n        kind: brew\n        formula: johntheyoung/tap/roadrunner\n        bins:\n          - rr\n        label: Install rr (brew)\n      - id: go\n        kind: go\n        module: github.com/johntheyoung/roadrunner/cmd/rr@v0.17.0\n        bins:\n          - rr\n        label: Install rr (go)\n---\n\n# roadrunner (rr)\n\nUse `rr` when the user explicitly wants to operate Beeper Desktop via the local API (send, search, list chats/messages, reminders, focus).\nPrefer `--agent` for agent use (forces JSON, envelope, no-input, readonly).\n\nSafety\n- Default to read-only commands unless the user explicitly requests a mutation in this turn.\n- Require explicit recipient (chat ID) and message text before sending.\n- Confirm or ask a clarifying question if the chat ID is ambiguous.\n- Never paste raw rr command output (JSON dumps, chat lists, etc.) into outgoing messages. Treat tool output as private; summarize or extract only what the user needs.\n- Use `--agent` for safe agent defaults: `rr --agent --enable-commands=chats,messages,status chats list`\n- Use `--readonly` to block writes: `rr --readonly chats list --json`\n- Use `--enable-commands` to allowlist: `rr --enable-commands=chats,messages chats list --json`\n- Use `--envelope` for structured errors: `rr --json --envelope chats get \"!chatid\"`\n- Envelope errors may include `error.hint` with next-step guidance for safe retries.\n- Never request, paste, or store raw auth tokens in chat. If auth is missing, ask the user to configure it locally.\n- If sending message text through a shell, avoid interpolation/expansion (e.g. `$100/month` or `!`). Prefer `--stdin <<'EOF' ... EOF` for safe literals.\n\nSetup (once)\n- `rr auth set --stdin` (recommended; token saved to `~/.config/beeper/config.json`)\n- `rr auth status --check`\n- `rr doctor`\n\nCommon commands\n- List accounts: `rr accounts list --json`\n- Capabilities: `rr capabilities --json`\n- Describe command/flags: `rr describe messages send --json`\n- Connect metadata: `rr connect info --json`\n- Live websocket events (experimental): `rr events tail --all --stop-after 30s --json`\n- List contacts: `rr contacts list \"<account-id>\" --json`\n- Search contacts: `rr contacts search \"<account-id>\" \"Alice\" --json`\n- Search contacts (flag): `rr contacts search \"Alice\" --account-id=\"<account-id>\" --json`\n- Resolve contact: `rr contacts resolve \"<account-id>\" \"Alice\" --json`\n- Resolve contact (flag): `rr contacts resolve \"Alice\" --account-id=\"<account-id>\" --json`\n- List chats: `rr chats list --json`\n- List chats (JSON Lines): `rr chats list --jsonl`\n- Search chats: `rr chats search \"John\" --json`\n- Search chats (filters): `rr chats search --inbox=primary --unread-only --json`\n- Search chats (activity): `rr chats search --last-activity-after=\"2024-07-01T00:00:00Z\" --json`\n- Search by participant name: `rr chats search \"Jamie\" --scope=participants --json`\n- Resolve chat: `rr chats resolve \"Jamie\" --json`\n- Get chat: `rr chats get \"!chatid:beeper.com\" --json`\n- Get chat (bounded participants): `rr chats get \"!chatid:beeper.com\" --max-participant-count=50 --json`\n- Start/resolve DM from merged contact hints: `rr chats start \"<account-id>\" --email \"alice@example.com\" --full-name \"Alice\" --json`\n- Default account for commands: `rr --account=\"imessage:+123\" chats list --json`\n- List messages: `rr messages list \"!chatid:beeper.com\" --json`\n- List messages (all pages): `rr messages list \"!chatid:beeper.com\" --all --max-items=1000 --json`\n- List messages (download media): `rr messages list \"!chatid:beeper.com\" --download-media --download-dir ./media --json`\n- Search messages: `rr messages search \"dinner\" --json`\n- Search messages (JSON Lines): `rr messages search \"dinner\" --jsonl`\n- Search messages (all pages): `rr messages search \"dinner\" --all --max-items=1000 --json`\n- Search messages (filters): `rr messages search --sender=me --date-after=\"2024-07-01T00:00:00Z\" --media-types=image --json`\n- Add/remove reaction: `rr messages react \"!chatid:beeper.com\" \"<message-id>\" \"👍\" --json` / `rr messages unreact \"!chatid:beeper.com\" \"<message-id>\" \"👍\" --json`\n- Tail messages (polling): `rr messages tail \"!chatid:beeper.com\" --interval 2s --stop-after 30s --json`\n- Wait for message: `rr messages wait --chat-id=\"!chatid:beeper.com\" --contains \"deploy\" --wait-timeout 2m --json`\n- Message context: `rr messages context \"!chatid:beeper.com\" \"<sortKey>\" --before 5 --after 2 --json`\n- Draft message (pre-fill without sending): `rr focus --chat-id=\"!chatid:beeper.com\" --draft-text=\"Hello!\"`\n- Draft message from file: `rr focus --chat-id=\"!chatid:beeper.com\" --draft-text-file ./draft.txt`\n- Draft with attachment: `rr focus --chat-id=\"!chatid:beeper.com\" --draft-attachment=\"/path/to/file.jpg\"`\n- Download attachment: `rr assets download \"mxc://example.org/abc123\" --dest \"./attachment.jpg\"`\n- Stream attachment bytes: `rr assets serve \"mxc://example.org/abc123\" --dest \"./attachment.jpg\" --json`\n- Focus app: `rr focus`\n- Global search: `rr search \"dinner\" --json`\n- Global search messages auto-page: `rr search \"dinner\" --messages-all --messages-max-items=500 --messages-limit=20 --json`\n- Status summary: `rr status --json`\n- Status by account: `rr status --by-account --json`\n- Unread rollup: `rr unread --json`\n- Global search includes `in_groups` for participant matches.\n\nMutations (explicit user request only)\n- Message send: `rr messages send \"!chatid:beeper.com\" \"Hello!\"`\n- Message edit: `rr messages edit \"!chatid:beeper.com\" \"<message-id>\" \"Updated text\"`\n- Message react/unreact: `rr messages react \"!chatid:beeper.com\" \"<message-id>\" \"👍\"` / `rr messages unreact \"!chatid:beeper.com\" \"<message-id>\" \"👍\"`\n- Upload + send file: `rr messages send-file \"!chatid:beeper.com\" ./photo.jpg \"See attached\"`\n- Create chat: `rr chats create \"<account-id>\" --participant \"<user-id>\"`\n- Start chat from merged contact hints: `rr chats start \"<account-id>\" --email \"alice@example.com\" --full-name \"Alice\"`\n- Archive/unarchive: `rr chats archive \"!chatid:beeper.com\"` / `rr chats archive \"!chatid:beeper.com\" --unarchive`\n- Reminder mutations: `rr reminders set \"!chatid:beeper.com\" \"2h\"` / `rr reminders clear \"!chatid:beeper.com\"`\n- Asset uploads: `rr assets upload ./photo.jpg` / `rr assets upload-base64 --content-file ./photo.b64`\n- For retries on non-idempotent writes, use `--request-id` and prefer `--dedupe-window`.\n- Use `--dry-run` to validate mutating requests without API write side effects.\n\nPagination\n- Auto-page chats list/search: `rr chats list --all --max-items=1000 --json` / `rr chats search \"alice\" --all --max-items=1000 --json`\n- Auto-page messages list/search: `rr messages list \"!chatid:beeper.com\" --all --max-items=1000 --json` / `rr messages search \"deploy\" --all --max-items=1000 --json`\n- Chats: `rr chats list --cursor=\"<oldestCursor>\" --direction=before --json`\n- Messages list: `rr messages list \"!chatid:beeper.com\" --cursor=\"<sortKey>\" --direction=before --json`\n- Messages search (max 20): `rr messages search \"project\" --limit=20 --json`\n- Messages search page: `rr messages search \"project\" --cursor=\"<cursor>\" --direction=before --json`\n- Global search message paging (max 20): `rr search \"dinner\" --messages-limit=20 --json`\n- Global search message page: `rr search \"dinner\" --messages-cursor=\"<cursor>\" --messages-direction=before --json`\n\nNotes\n- Requires Beeper Desktop running; token from app settings.\n- Token is stored in `~/.config/beeper/config.json` via `rr auth set` (recommended). `BEEPER_TOKEN` overrides the config file.\n- `BEEPER_ACCOUNT` sets the default account ID (aliases supported).\n- `rr auth status --check` prefers OAuth introspection (`/oauth/introspect`) when available and falls back to account-list validation on older builds.\n- Message search is literal word match (not semantic).\n- `rr contacts resolve` is strict and fails on ambiguous names; resolve by ID after `contacts search` when needed.\n- If a DM title shows your own Matrix ID, use `--scope=participants` to find by name.\n- JSON output includes `display_name` for single chats (derived from participants).\n- Message JSON includes `message_type`, `linked_message_id`, `is_sender`, `is_unread`, `attachments`, and `reactions`.\n- `downloaded_attachments` is only populated when `--download-media` is used.\n- `rr messages send` returns `pending_message_id` (temporary ID).\n- Account `network` may be missing in newer API builds; `rr` falls back to `\"unknown\"` in summaries/search output.\n- `rr assets serve` writes raw bytes to stdout unless `--dest` is provided.\n- `--chat` does exact matching and fails on ambiguous matches.\n- Attachment overrides require `--attachment-upload-id`; set `--attachment-width` and `--attachment-height` together.\n- `--all` has a safety cap (default 500 items, max 5000); use `--max-items` to tune it.\n- Prefer `--json` or `--jsonl` (and `--no-input`) for automation.\n- `--jsonl` emits one JSON object per line and is supported on high-volume list/search commands.\n- `--dry-run`/`BEEPER_DRY_RUN` validates mutating command inputs and prints preview output without sending write API requests.\n- `BEEPER_URL` overrides API base URL; `BEEPER_TIMEOUT` sets timeout in seconds.\n- JSON/Plain output goes to stdout; errors/hints go to stderr.\n- Destructive commands prompt unless `--force`; `--no-input`/`BEEPER_NO_INPUT` fails without `--force`.\n- Use `--fail-if-empty` on list/search commands to exit with code 1 if no results.\n- Use `--fields` with `--plain` to select columns (comma-separated).\n- In bash/zsh, `!` triggers history expansion. Prefer single quotes, or disable history expansion (`set +H` in bash, `setopt NO_HIST_EXPAND` in zsh).\n- `rr version --json` returns `features` array for capability discovery.\n- `rr capabilities --json` returns full CLI capability metadata.\n- `rr events tail` depends on experimental `/v1/ws` support in Beeper Desktop; fall back to `rr messages tail` when unavailable.\n- Envelope error codes: `AUTH_ERROR`, `NOT_FOUND`, `VALIDATION_ERROR`, `CONNECTION_ERROR`, `INTERNAL_ERROR`.\n- Retry policy: retry `CONNECTION_ERROR` with backoff; do not blind-retry `AUTH_ERROR`/`VALIDATION_ERROR`; refresh IDs before retrying `NOT_FOUND`.\n- Non-idempotent writes: `messages send`, `messages send-file`, `chats create`, `chats start`, `assets upload`, `assets upload-base64`.\n- Use `--request-id`/`BEEPER_REQUEST_ID` to tag envelope metadata for cross-retry attempt tracing.\n- Use `--dedupe-window`/`BEEPER_DEDUPE_WINDOW` to block duplicate non-idempotent writes with repeated request IDs.\n- Local smoke check: `make test-agent-smoke`.\n","tags":{"latest":"0.17.0"},"stats":{"comments":0,"downloads":5181,"installsAllTime":196,"installsCurrent":6,"stars":4,"versions":30},"createdAt":1768571733486,"updatedAt":1778485733200},"latestVersion":{"version":"0.17.0","createdAt":1772686100156,"changelog":"- Updated underlying CLI install version to v0.17.0.\n- Added command examples for `describe` (to show flag/command info) and new `--jsonl` (JSON Lines) output for chat and message lists/searches.\n- Added example of using `--dry-run` to validate mutating requests without actual API changes.\n- Minor clarifications and expanded examples for several commands and flags.","license":null},"metadata":{"setup":[],"os":null,"systems":null},"owner":{"handle":"johntheyoung","userId":"s17daq6jqwgsdm4kv4g82zn1d9885hvj","displayName":"johntheyoung","image":"https://avatars.githubusercontent.com/u/59088717?v=4"},"moderation":null}