Skip to main content

hitl-escalate

Escalate blocked runs to a human via configured channel or fallback to BLOCKED.md and exit the loop. Use when the loop hits an ambiguous spec, a missing credential, a destructive action needing approval, or 3+ consecutive verify failures on the same task.

Source facts

Repository
Archive228/loopkit
Last source activity
July 14, 2026 at 21:06
Detected SKILL.md language
English
Stars
757
Forks
124

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
hitl-escalate
description
Escalate blocked runs to a human via configured channel or fallback to BLOCKED.md and exit the loop. Use when the loop hits an ambiguous spec, a missing credential, a destructive action needing approval, or 3+ consecutive verify failures on the same task.
when_to_use
the loop hit an ambiguous spec, a missing credential, a destructive action needing approval, or 3+ consecutive verify failures on same task
# Human-in-the-Loop Escalate Long-running agent loops fail in a specific way when they meet a question they can't answer: they guess. The guess ships, the next session builds on it, and by the time a human looks the divergence is three commits deep. This skill is the release valve — when the agent is stuck, it stops and asks, cleanly, in a shape the human can act on. ## Trigger — escalate when any of these are true - **Ambiguous spec.** `PROMPT.md` admits two implementations and the choice changes user-visible behavior. - **Missing credential.** A required env var, API key, or config file is absent, and there is no sanctioned way for the agent to create one. - **Destructive action needing approval.** Dropping a table, force-pushing, deleting user data, spending money, sending mail to real recipients. - **3+ consecutive `/verify` failures on the same task.** The loop is thrashing. Stop and get a human eye before the fourth attempt. - **External dependency down.** A third-party service the feature needs is unreachable and no offline path exists. If none of the above hold, do not escalate. Guessing is bad; escalating on a solvable problem is also bad (it trains humans to ignore the channel). ## Primary action — call the human via the configured channel Read `LOOPKIT_HITL_CHANNEL`. Supported values: | Value | Shape | |---|---| | `telegram` | POST to `https://api.telegram.org/bot$LOOPKIT_HITL_TELEGRAM_TOKEN/sendMessage` with `chat_id=$LOOPKIT_HITL_TELEGRAM_CHAT`, `text=<question + repo + short context>`. | | `slack` | POST JSON `{"text": "..."}` to `$LOOPKIT_HITL_SLACK_WEBHOOK` (incoming-webhook URL). | | `dial` | Run `$LOOPKIT_HITL_DIAL_CMD` with the message on stdin. Whatever the operator wired up — SMS gateway, ntfy, phone call, pager. | | `none` (or unset) | Skip the primary action. Go straight to fallback. | Message body — always these five lines, in this order: ``` [loopkit] blocked in <repo-name> on <ISO timestamp> Q: <one-line question> Context: <one-line what you were doing> Attempted: <one-line what you tried> Choices: <A | B | C> ``` Non-2xx from the channel is a soft failure. Log it, then fall through to the fallback so the loop still exits cleanly. ## Fallback — write BLOCKED.md and exit Whether the primary succeeds or fails, always write `./BLOCKED.md` at the repo root with exactly four sections: ```markdown # Blocked ## Question: <one sentence, answerable with a short reply> ## Context: <what feature, which file, which commit, why now — 3-6 lines> ## Attempted: <bulleted list of what you tried and why each fell short> ## Choices: - A) <option> — <consequence> - B) <option> — <consequence> - C) <option> — <consequence> ``` Then `exit 2`. The loop runner (`run.sh`) checks for `BLOCKED.md` at the head of each iteration and exits with code 2 if it exists — that stops the loop until a human clears it. ## Human unblocks The human reads `BLOCKED.md`, edits `PROMPT.md` / drops the credential / approves the destructive step, then `rm BLOCKED.md` and restarts `run.sh`. The deleted `BLOCKED.md` is the unblock signal. ## Anti-patterns — do not do these - **Do not fabricate an answer.** "I'll assume the user meant X" is how divergence starts. Assume nothing under ambiguity — escalate. - **Do not loop endlessly.** After the third consecutive `/verify` failure on the same task, escalate. The fourth attempt is not going to succeed by the same reasoning that failed thrice. - **Do not silently swallow the missing credential.** Do not commit a placeholder, do not disable the feature, do not "TODO" the auth. Ask. - **Do not escalate for questions the repo already answers.** Read `AGENTS.md`, `PROMPT.md`, and the last three commits first. Escalation is expensive human attention — spend it on real ambiguity. - **Do not skip writing `BLOCKED.md` because the primary channel succeeded.** The file is the loop's exit contract. Without it, `run.sh` keeps spinning. ## Pairs with - `adversarial-verify` — the source of the 3-verify-failure trigger. - `shift-notes` — after escalating, note the block in `IMPLEMENTATION_PLAN.md` so the next session (post-unblock) has full context. - `spec-first` — an ambiguous `PROMPT.md` is a spec-first failure; the human's unblock should tighten the spec, not just answer the one-off.
View on GitHub