Challenge Gate
Detect bot walls and escalate CAPTCHA to a human.
Skill metadata
| Source | Bundled (installed by default) |
| Path | skills/research/challenge-gate |
| Version | 1.0.0 |
| Author | VibeOS |
| License | MIT |
| Platforms | linux, macos, windows |
| Tags | research, browser, captcha, bot-wall, human-in-the-loop |
| Related skills | choose-interaction-surface, professional-research, analysis-orchestration, ru-public-sources |
Reference: full SKILL.md
The following is the complete skill definition that VibeOS loads when this skill is triggered. This is what the agent sees as instructions when the skill is active.
Challenge Gate Skill
Handle CAPTCHA / Cloudflare / Turnstile / login walls without thrashing. Prefer avoid → one provider assist → human handoff → honest partial brief. Never invent page content behind a wall.
When to Use
browser_navigatereturnsbot_detection_warningorchallenge.- Title/snapshot shows captcha, “Just a moment”, Turnstile, “are you a robot”.
- Extract/search fails because the target is behind a challenge.
- Research skills hit a blocked source mid-gather.
Do not use to crack CAPTCHAs, farm solvers, or bypass paywalls silently.
Prerequisites
- Browser tools and/or
web_search+web_extract. clarifyfor human handoff (CLI / gateway / desktop).- Optional: Browserbase proxies/stealth, CDP
/browser connect, warm Camofox profile. - Config (defaults in
config.yamlunderbrowser.challenge):
| Key | Default | Meaning |
|---|---|---|
prefer_human | true | Prefer L3 over solver thrash |
max_auto_attempts | 1 | Max L1/L2 cycles before L3 |
human_timeout_seconds | 600 | Then L4 partial |
allow_provider_solve | true | Use provider assist when available |
record_artifacts | true | Write challenge.md |
Skills that forbid bypass (ru-public-sources, etc.): skip L2, go Detect → optional Human → L4.
How to Run
On any challenge signal, run layers in order. Stop when the page is clear or L4 applies.
L0 Detect → L1 Avoid → L2 Provider assist → L3 Human handoff → L4 Partial continue
Quick Reference
| Layer | Action | Tools |
|---|---|---|
| L0 | Classify type/severity | challenge field, browser_vision |
| L1 | Prefer search/extract/MCP; one gentle retry | web_search, web_extract, MCP |
| L2 | One provider assist if configured | Browserbase stealth/proxies |
| L3 | Ask human; wait for готово/done | clarify, screenshot |
| L4 | Mark blocked; continue other sources | sources.json, challenge.md |
Procedure
L0 — Detect
- If response has
challenge, use it. Else classify from title/body. - Types:
cloudflare_iuam,turnstile,hcaptcha,recaptcha_v2,login_wall,paywall,custom,unknown. - Severity:
soft|hard|human_only. - Do not click randomly. Announce: “ChallengeGate L0 on <url>”.
L1 — Avoid (max max_auto_attempts)
Prefer facts without the wall:
web_search+web_extractfor the same facts.- MCP/OAuth for SaaS instead of login UI.
- Warm profile / CDP user Chrome if already trusted for that site.
- One slowed re-navigate (hub → target) only for
softseverity.
Forbidden: endless reload; computer_use on the browser window as first choice.
L2 — Provider assist (once, opt-in)
Only if allow_provider_solve and backend supports it (e.g. Browserbase proxies/stealth already configured). One attempt. Still blocked → L3.
L3 — Human handoff
Call clarify with:
- Screenshot (
browser_vision/ MEDIA path). - Ask from
templates/human-handoff.md(RU/EN): replyготово/doneorskip. - If
challenge_gate.live_view_urlis present on the last navigate response, paste that URL verbatim into the clarify question (labeledLive View:). Desktop will offer Open live browser so the user solves in the same Browserbase session (cookies preserved whenBROWSERBASE_KEEP_ALIVEis on). - Note timeout → partial brief.
Surfaces (prefer first available): CDP user Chrome → headed/local or Browserbase Live View → computer_use only if browser tools cannot see a native WebView.
On готово/done: browser_snapshot again in the same session (do not
browser_close first). Still challenged → ask once more, then L4.
Navigate payloads expose the resume contract under challenge_gate:
preserve_session, resume_after_human: browser_snapshot_same_session, and a
forbid list that includes close-before-resume. Prefer CDP user Chrome or
Browserbase keep-alive so cookies warm the next navigate to the same host
(Scenario E). Detect-only warm-up:
CHALLENGE_GATE_KEEP_SESSION=1 RUN_LIVE_CHALLENGE_DETECT=1 \
CHALLENGE_GATE_LIVE_URL='https://…' \
scripts/smoke-challenge-gate-live-detect.sh
Desktop: when the clarify question matches CAPTCHA/ChallengeGate copy, the UI
shows Open live browser (when a Browserbase URL is in the question),
Done / Skip page / Research Pro (answers: done / skip).
Durable kanban research jobs: block with kind=challenge (status stays
blocked) so cron does not thrash overnight retries. Unblock after human clear
or skip the source and continue.
Cron recipe (do not thrash)
When a scheduled research job hits a wall:
- Append
challenge.md/ markaccess: blocked_by_challenge. kanban_block/vibeos kanban block <id> --kind challenge --reason "…".- Deliver a partial brief or alert — do not schedule tight retries on the same URL overnight.
- Human unblocks after clearing CAPTCHA (or closes the source as skipped).
- If unblock↔re-block loops, expect escalation to
triage(BLOCK_RECURRENCE_LIMIT).
Operator manual E2E: docs/ops/challenge-gate-manual-e2e.md.
Offline smoke: scripts/smoke-challenge-gate.sh.
L4 — Partial continue
- Append/update
challenge.mdin the research workspace (template below). - In
sources.jsonset that URLaccesstoblocked_by_challenge(orpartialif some facts came from snippets). - Continue with alternate public sources.
- Brief must state what was unreachable. Never fabricate wall content.
- If this was a kanban task:
kanban_block/ CLI withkind=challenge(or leave blocked until human resumes).
Artifact: challenge.md
Prefer the helper (from this skill directory):
python3 scripts/append_challenge_log.py --path challenge.md --also-sources sources.json <<'EOF'
{"url":"https://…","type":"cloudflare_iuam","severity":"hard","detected_by":"title","layer_reached":"L4","resolved":"no","human_handoff":"yes","notes":"skipped"}
EOF
Or append manually:
# Challenge log
## Entry
- url: <URL>
- type: <challenge.type>
- severity: <soft|hard|human_only>
- detected_by: <title|snapshot|vision|provider>
- layer_reached: <L0|L1|L2|L3|L4>
- resolved: <yes|no|partial>
- human_handoff: <yes|no>
- notes: <one line>
sources.json field
{
"url": "https://example.com/page",
"title": "...",
"access": "ok | challenge | blocked_by_challenge | partial",
"challenge_type": "cloudflare_iuam"
}
Pitfalls
- Do not spam
browser_clickon CAPTCHA widgets. - Do not treat CAPTCHA clear as permission to purchase or create accounts.
- Do not use captcha-farm APIs unless the user explicitly configured an external solver (off by default; not in-tree).
- Do not drive Chrome via
computer_usewhenbrowser_*works. - Keep prompt-cache safe: do not swap toolsets mid-session to “enable solver”.
Verification
- Challenge classified within two tool turns of detection.
- Auto attempts ≤
max_auto_attempts. - Hard wall →
clarifyor documented L4 skip. -
challenge.mdwritten whenrecord_artifactsis true. - Brief does not claim facts only available behind an unresolved wall.