Runyard Docs
Guides

Decisions and Telegram

Operate human checkpoints โ€” where decision cards appear, what each choice does, timed approvals, and the Telegram integration.

An approval is a declared question with a declared consequence. Cards carry an ask โ€” who is asked, what approving does, and why a human is needed โ€” and every surface renders that stored ask verbatim. A run held on a card sits in waiting_approval and is never failed or age-reaped for waiting.

Where decisions appear

SurfaceHow
TelegramPrimary PM decision surface. Cards are posted to the configured chat with inline buttons (see below).
Web appOptional audit/history surface. The Decisions view lists pending and resolved cards with their ask, consequences, and buttons.
MCPlist_pending_approvals (or list_approvals with a status filter), get_approval.
CLIrunyard approvals lists pending cards.
HTTPGET /api/approvals?status=pending, GET /api/approvals/{id}.

Resolving a card

Each card takes one of three decisions:

runyard approve <approval-id> -c "looks right"
runyard request-changes <approval-id> -c "narrow the scope to the checkout flow"
runyard reject <approval-id> -c "not this quarter"

HTTP: POST /api/approvals/{id}/approve|reject|request-changes. MCP: approve_run, reject_run, request_changes_run โ€” all take an approvalId, not a runId. These need a token with the api, mcp, or approvals scope (admin always qualifies).

What each decision does depends on the card's kind:

KindApproveRequest changesReject
Run hold (default / custom)The held run is released to the queue and executes.The run is cancelled; your note tells the requester what to change.The run is cancelled โ€” a human "no" is a decision, not a failure.
workflow_gate (mid-run engine gate)The decision is applied to the paused workflow on the runner and it resumes past the gate.Applied as a deny with your note attached; the workflow's own deny path decides what happens next.Applied as a deny; the workflow's deny path decides what happens next.
escalation (run already ended)Records your go-ahead on the card; the run is not restarted โ€” re-run it from the run page.Records that the workflow or input needs fixing; your note is the guidance.Records that the run should be left as it ended.
side_effectThe gated side effect is allowed to run.The side effect is skipped; your note explains what to change.The side effect is skipped; the run's completed work is unaffected.

Resolved cards keep the decision in their resolution field (approved, rejected, changes_requested) plus how it was decided (resolvedVia: human, fallback timer, engine, policy, or system).

Timed approvals and fallback

Approvals are blocking by default: with no timer configured, nothing happens until someone decides, and a linked run is held open indefinitely.

A creator can make a card timed by supplying timeoutMs or timeoutAt, optionally with a fallback decision (approve or reject) โ€” via POST /api/approvals or the create_approval MCP tool:

  • Timer + fallback โ€” if nobody decides before the deadline, the Hub applies the fallback decision on the human's behalf, fully audited (resolvedVia: fallback_timer).
  • Timer without fallback โ€” when the timer elapses the card is flagged fallback_required and stays pending: it is surfaced as urgent, but no decision is ever invented.

timeoutMs is clamped to between 1 second and 30 days.

Telegram integration

The Hub can post decision cards to a Telegram chat and accept decisions from the buttons on them.

Bot setup

Create a bot with Telegram's BotFather, then save TELEGRAM_BOT_TOKEN and the other Telegram values in Secrets. Settings shows whether Telegram is configured and which bot identity is in force; Secrets is the credential vault for the tokens themselves. Existing deployments can still provide the same names as environment variables; Settings-managed secrets take precedence and are the live source for decision sends, edits, button callbacks, replies, webhook verification, and Telegram WebApp approval login.

VariablePurpose
TELEGRAM_BOT_TOKENThe bot's API token.
TELEGRAM_APPROVAL_CHAT_IDChat (group or DM) where decision cards are posted.
TELEGRAM_APPROVAL_USER_IDSComma-separated Telegram user ids allowed to resolve approvals.
TELEGRAM_WEBHOOK_SECRETSecret Telegram echoes back so the Hub can verify webhook calls.
TELEGRAM_CHAT_ID / TELEGRAM_THREAD_IDOptional default chat/thread for non-approval notifications.

The Settings page shows whether the decision bot is sourced from Settings or the environment, plus the sanitized bot identity from a live validation of the selected bot token, so operators can confirm decisions are flowing through the exact connected bot without exposing TELEGRAM_BOT_TOKEN. Delivery health remains separate and reports queued, retried, failed, or delivered Telegram outbox work.

Webhook

Point the bot's webhook at the Hub:

curl -sS "https://api.telegram.org/bot<bot-token>/setWebhook" \
  -d "url=https://hub.example.com/api/telegram/webhook" \
  -d "secret_token=<webhook-secret>"

POST /api/telegram/webhook is the only Telegram-facing route. It is verified against the configured bot and webhook secret and is not a general API.

Decision cards with buttons

Each pending card is posted as a message carrying the ask (what approving does, why a human is needed), a sanitized input summary, and inline buttons: Approve & ship, Change scope, Not now/defer, Reject. Only the configured approval user ids can act; a button press resolves the card exactly like the web or API would, and the message is edited to show the durable state ("State: Resolved ยท approved") with the buttons removed.

After approval, normal implementation stays silent in Telegram. Shipping may edit or follow the original card with a concise shipped-state update that names the product outcome and release link, but product exceptions create new decision cards instead of reusing the old approval as a chat thread.

Telegram WebApp login

Cards can deep-link into the Hub as a Telegram WebApp. POST /api/auth/telegram-webapp exchanges the WebApp's signed init data for a browser session that is limited to the approvals scope โ€” a Telegram identity can review and resolve approval cards, and nothing else. Full app access always requires a real access token.

On this page