Access & permissions
Nobody talks to your agent without your say-so.
The inbound gate
The gate decides on the sender, never the chat: a stranger in an allowed group is still dropped.
| Policy | Behavior |
|---|---|
pairing (default) | Unknown DM sender gets a pairing code; you approve or deny from the terminal |
allowlist | Only listed user IDs are delivered; everyone else is silent |
disabled | No DMs at all |
Pairing
The first message from an unknown sender returns a 6-hex pairing code. Codes expire after 24 hours. Approve or reject from your terminal:
hotline pair <code>
hotline deny <code>
Approval happens only from your terminal. Claude never approves a pairing or edits access because a chat message asked it to. That request is exactly what a prompt injection looks like.
Groups
Groups are opt-in per group ID, with optional requireMention (deliver only when the bot is mentioned, replied to, or a mentionPatterns regex matches) and an optional per-group sender allowlist.
access.json
Configuration lives in ~/.claude/channels/tele-go/access.json and is re-read on every inbound message, so edits take effect live:
{
"dmPolicy": "pairing", // pairing (default) | allowlist | disabled
"allowFrom": ["412587349"], // numeric user IDs
"groups": {
"-1001234567890": { "requireMention": true, "allowFrom": [] }
},
"mentionPatterns": ["^hey claude"],
"ackReaction": "👀", // emoji reaction on receipt ("" disables)
"replyToMode": "first", // first | all | off
"textChunkLimit": 4096,
"chunkMode": "newline", // newline | length
"bubbleMode": "paced" // paced | instant
}
Each provider keeps its own access.json in its own state directory. On Signal the allowlist holds phone numbers (E.164) and group ids look like group:<id>; on Discord, guild channels gate as groups keyed by channel ID.
Outbound is gated too
Every tool call checks the target chat against the same rules before touching the provider API, so Claude can only message chats that could message it. The channel also refuses to attach its own state files, and sanitizes uploader-controlled filenames before they enter the message metadata. Button-tap authorization mirrors the inbound gate.
The permission relay
When a token is configured, hotline declares the claude/channel/permission capability. Claude Code's permission prompts are relayed to allowlisted DMs (never groups) with See more / Allow / Deny buttons. You can also answer by text with yes <code> or no <code>; those replies are intercepted and converted to a verdict instead of being relayed as chat.
This is the piece that makes leaving the terminal viable. The session doesn't stall on a permission prompt nobody is looking at; it asks your pocket. On transports without buttons (Signal), the relay is text-only.
The transcript
Every message in both directions is appended to <stateDir>/transcript.jsonl. Telegram has no history API and Claude Code sessions compact or restart, so the transcript is how the assistant recalls the thread across resets. It's written 0600 and currently unbounded.