Telegram Human Gateway¶
Telegram is an async triage and control gate for the Beekeeper: push notifications plus a short set of mutations from the phone. It is not a remote IDE and does not relay PTY / bee chat into chat.
Mutations reuse the same packages as CLI and Queen Console (agentId: telegram). Accepting an invite starts an interactive session on the machine running the gate.
Design record: specs/010-telegram-human-gateway.md. Vocabulary: glossary (Human Gateway).
Prerequisites¶
- Colony already initialized (
paseka init) with a resolved slug - NATS URL in
~/.config/paseka/<slug>/config.yaml(gate will not start without it) - A Telegram bot token from @BotFather
- Your Telegram user id and the chat id where you want pushes (private chat with the bot, or a group/supergroup)
paseka run is optional for the gate itself. AFK progress after /task still needs a live reactor; /status shows whether the reactor is alive.
1. Create the bot and find ids¶
- Message BotFather →
/newbot→ copy the token. - Start a chat with your bot (or add it to a group and send a message).
- Resolve ids (pick one approach):
# After messaging the bot, inspect getUpdates (replace <TOKEN>)
curl -s "https://api.telegram.org/bot<TOKEN>/getUpdates" | jq .
# message.from.id → allow_from
# message.chat.id → chat_ids
Or use a helper bot such as @userinfobot for your user id. Group/supergroup chat ids are typically negative (e.g. -100…).
2. Machine-local config¶
Create ~/.config/paseka/<slug>/telegram.yaml. It is not created by paseka init and must never live under committed .paseka/.
enabled: true
bot_token: "123456:ABC…" # or omit and set PASEKA_TELEGRAM_BOT_TOKEN
mode: longpoll # webhook is not implemented yet
allow_from:
- 123456789 # Telegram user id(s) allowed to run commands
chat_ids:
- 123456789 # push destinations (private chat id often equals user id)
# - -1001234567890 # and/or a group
notify:
invites: sound
blocked: sound
failed: sound
review_required: sound # waiting_review + review: required (soft HITL)
review_final: sound # waiting_review + review: final / _review (merge gate)
commit_gate: off # waiting_review without review gate (AFK defer)
completed: silent # VERIFICATION/task.completed (live bus only)
# waiting_review: true # legacy: maps to review_required + review_final
commands:
task_autorun: true # Confirm on /task also publishes task.ready
default_bee: builder
default_intent: general # task intent for default_bee (see bee intents)
default_review: none
custom:
feature:
description: "Intake idea/bug via Scout"
cue: feature # preferred — loads .paseka/cues/feature.yaml
legacy:
description: "Inline emit (still supported)"
emit: signal
type: SIGNAL
kind: feature.requested
static:
priority: medium
console_base_url: "" # optional; e.g. Tailscale URL to Queen Console
| Field | Required | Notes |
|---|---|---|
enabled |
yes | Must be true or the gate exits |
bot_token |
yes* | *Or env PASEKA_TELEGRAM_BOT_TOKEN (env wins) |
allow_from |
yes | Non-empty; inbound commands from others are silently ignored |
chat_ids |
yes | Non-empty; pushes go here; commands from chats outside this list are also ignored |
mode |
no | Default longpoll. webhook is rejected at runtime until V2 |
notify.* |
no | Per-category push mode: off, silent (no sound), or sound (default for most). Legacy waiting_review maps to review_required + review_final. See example above. |
commands.* |
no | Defaults: bee builder, intent general, review none, autorun true |
commands.custom.<name> |
no | Custom slash commands — cue: <id> (preferred) or inline emit: signal. See below. |
console_base_url |
no | When set, cards may include a Console deep-link |
Custom commands (cue: or inline emit)¶
Use commands.custom for colony choreography entry points. Each command maps to /name <text> in Telegram (preview + Confirm, like /task). AFK dispatch needs paseka run (see bee routing §4).
Preferred — Forage Cue (cue: <id>): loads .paseka/cues/<id>.yaml from the colony repo. One definition shared with paseka cue and Queen Console Run cue. See Forage Cues.
| Field | Required | Notes |
|---|---|---|
description |
yes* | Shown in /help and preview (*optional when cue is set — falls back to cue description) |
cue |
yes* | Cue id (alternative to inline emit below) |
emit |
yes* | Must be signal when not using cue |
type |
yes* | Must be SIGNAL when inline |
kind |
yes* | payload.kind (e.g. feature.requested) when inline |
static |
no | Extra string fields merged into payload (inline only) |
Legacy — inline emit: signal: same behavior as before 016; migration to cue: is optional.
Reserved names: start, status, help, invites, traces, energy, task.
Runtime notify dedup state: ~/.config/paseka/<slug>/telegram-notify-state.json (created automatically).
3. Run the gate¶
From inside the colony repo (or pass -C):
# Typical: reactor + gate as separate processes
paseka run # AFK hive consumer (optional for notify/commands alone)
paseka gate telegram # long-poll + notify + commands
# optional: paseka console # heavy HITL (diffs, topology, browser PTY)
Stop with Ctrl-C (SIGINT / SIGTERM). Telegram network failures do not take down paseka run because the gate is a separate process.
One bot token = one colony slug for MVP. Wrong-hive mutations are worse than managing a second BotFather token.
On startup the gate best-effort clears and re-registers the Telegram command menu (deleteMyCommands + setMyCommands for default, private-chat, and allowlisted chat scopes — no-arg built-ins only), refreshes a compact reply keyboard in each allowlisted chat_id, and sends a short welcome with minimal colony status (reactor, live bees, pending invites). Failures are logged only; long-poll and notify keep running.
4. Commands and buttons¶
Message the bot from an allowlisted user and chat:
| Command | Behavior |
|---|---|
/status |
Reactor alive?, slug, subject prefix, live bees, pending invites; Refresh button |
/energy <traceId> |
Honey remaining/budget |
/energy add <traceId> <n> |
Top up honey (SIGNAL/energy.add) |
/task <text> |
Preview card → Confirm/Cancel → task.plan (+ task.ready if autorun) |
/feature <text> (example custom) |
Preview → Confirm → SIGNAL/feature.requested on new trace (when configured) |
/invites |
Pending invites with Accept / Reject / Defer |
/traces |
Recent colony traces (activity + status hints; optional Console links) |
/help |
Command list |
The reply keyboard (refreshed on gate startup) offers one-tap /status, /help, and /invites. The Telegram command menu (tap / in the composer) lists the same no-arg built-ins. Parameterized commands (/energy, /task, custom emit commands) are available via /help and typed manually.
Invite Accept / Reject and proposal Approve / Reject use a two-step Confirm. Defer is immediate.
On blocked / insufficient-honey replies: +1 / +5 / +12 energy buttons (no confirm).
Proposal policy: Reject always allowed. Approve allowed only for soft/mid review gates — not final-merge (review: final / _review). Final-merge cards offer Reject + “approve in Console/CLI only”.
On invite Accept, the gate starts a detached local session and replies that the PTY is on the gate host (not in Telegram). Attach with paseka session attach or Queen Console — see interactive sessions.
5. What gets pushed¶
Allowlisted chat_ids receive short cards (with buttons where applicable) when:
| Condition | Typical buttons |
|---|---|
Pending session.invite |
Accept / Reject / Defer |
Task → waiting_review |
Reject; Approve if not final-merge |
Task → blocked (incl. honey exhausted) |
Energy +1 / +5 / +12 when energy-blocked |
Task → failed |
Summary only |
On startup the gate reconciles pending invites and waiting_review / blocked / failed tasks, using machine-local dedup so restart does not spam.
6. Troubleshooting¶
| Symptom | Check |
|---|---|
missing …/telegram.yaml |
Create the file under the colony’s slug home |
disabled in telegram.yaml |
Set enabled: true |
bot_token is required |
Set bot_token or PASEKA_TELEGRAM_BOT_TOKEN |
nats url not configured |
Set nats.url in home config.yaml |
webhook mode is not implemented |
Use mode: longpoll |
| Bot ignores messages | User must be in allow_from and chat in chat_ids (silent ignore otherwise) |
/task confirms but AFK never runs |
Start paseka run on the same colony |
| Invite accept “PTY on this machine” | Expected — attach locally; optional console_base_url for a Console link |
Related documentation¶
| Doc | Topic |
|---|---|
| CLI | paseka gate telegram in the command tree |
| Colony layout | Slug and machine-local secrets |
| Interactive sessions | Local PTY after invite accept |
| Task ledger | Energy, waiting_review, review policies |
| specs/010-telegram-human-gateway.md | Full MVP design |
| specs/006-human-gateway-invites.md | Invite lifecycle |