Skip to content

Human-in-the-loop

executor: human pauses a pipeline until a person approves or rejects it, over whichever chat channel the run’s owning team is configured to use. This page covers the executor itself, all three approval channels, per-team routing, and where approvals surface in the UI.

executor: human — Human-in-the-Loop (Telegram, Slack, Microsoft Teams)

Section titled “executor: human — Human-in-the-Loop (Telegram, Slack, Microsoft Teams)”

executor: human sends an approval request and pauses the pipeline until the operator approves or rejects, or timeout_seconds elapses.

Outcome confidence proceed
Approved 1.0 true
Rejected 0.0 true — triggers on_low_confidence action
Timeout step marked failed

The prompt_template renders to the approval message text. Default timeout is 300s.

Which channel a run uses is resolved per-team, not per-pipeline. The same executor: human step works unchanged for every team — VectorStep looks up the run’s team (resolved from the webhook auth token, see Team attribution) against human_approval.teams in config.yaml, falling back to human_approval.default, falling back to the legacy Telegram-only config if human_approval is omitted entirely. This keeps team onboarding a config-only change (like issuing a token) rather than requiring a new executor or a pipeline fork per team.

- name: approve-remediation
executor: human
timeout_seconds: 600
confidence_threshold: 0.5
on_low_confidence: abort
on_abort: notify
prompt_template: |
<b>Approve remediation for {{labels.service}}?</b>
Proposed action: {{steps.investigation.next_step_context}}
human_approval:
ui_base_url: https://vectorstep.internal.example.com # required for the msteams channel — see below
default:
channel: telegram
teams:
team-a:
channel: slack
slack:
bot_token: ${SLACK_BOT_TOKEN_TEAMA}
app_token: ${SLACK_APP_TOKEN_TEAMA}
channel_id: C0123456
team-b:
channel: msteams
msteams:
webhook_url: ${TEAMS_WEBHOOK_URL_TEAMB}
Channel How the human responds Requires
telegram Inline-keyboard Approve/Reject buttons, resolved by the existing Telegram long-poll (notifications/telegram_poller.py). Requires a separate Telegram bot from OpenClaw (Telegram only allows one simultaneous getUpdates poller per bot token). human_approval.*.telegram.{bot_token,chat_id}, or falls back to notifications.telegram
slack Interactive Approve/Reject buttons via a Slack app’s Socket Mode connection (notifications/slack_poller.py) — no public HTTPS endpoint needed, free on any Slack plan. human_approval.*.slack.{bot_token,app_token,channel_id}
msteams One-way notification (via a Power Automate webhook flow) linking to a VectorStep web page (GET /ui/approvals/{token}) where the human clicks Approve/Reject. Real interactive Adaptive Card buttons in Teams need a registered Azure Bot with a public callback endpoint — this deployment doesn’t expose one, so Teams gets a notify-and-click-through flow instead. human_approval.*.msteams.webhook_url, human_approval.ui_base_url

If human_approval is omitted entirely, every human step behaves exactly as before this feature existed — the single global notifications.telegram bot/chat, no team awareness required.

Approval behaviour differs depending on the pipeline’s stage. See Pipeline stages for the full testing-vs-production model; the short version for executor: human and for human-type deterministic checks (see Grounding) is that in stage: testing, the external channel (Telegram/Slack/Teams) is not sent — the decision is made entirely via VectorStep’s own /ui/approvals — and a timeout auto-approves rather than failing the step. In production, the configured channel is used normally and a timeout marks the step failed as described above.

Page Route Description
Approvals /ui/approvals Every pending executor: human approval, regardless of channel — a universal fallback so a team isn’t stuck if their primary chat channel (Slack/Telegram) is unreachable. No standalone sidebar entry; reached via a pending-count badge next to Runs (only shown when the count is non-zero)
Approval decision /ui/approvals/{token} Standalone page (no sidebar) reached via a direct token link — used by the Teams approval channel, which posts this link instead of an in-chat button since Teams interactive cards need a public Bot Framework callback endpoint this deployment doesn’t expose (see executors/human.py’s TeamsApprovalChannel). Approve/Reject decision buttons post back to this same route
  • Team attribution — how a run’s team is resolved from its webhook auth token, which in turn drives the channel lookup above.
  • Pipeline stages — the full testing-vs-production behaviour matrix, including timeout and auto-approve differences.
  • Groundinghuman-type deterministic checks reuse this exact same approval subsystem.