# Blocking IO Guard

Checks async backend code for event loop blocking and keeps runtime tests in place.

- Repository: https://github.com/bytedance/deer-flow (84840 stars)
- Category: Testing
- License: MIT
- Last updated: 2026-11-01
- Runs scripts: yes, review before use

## Install

Claude Code: `npx skills add bytedance/deer-flow --skill blocking-io-guard -g -a claude-code -y`
Codex: `npx skills add bytedance/deer-flow --skill blocking-io-guard -g -a codex -y`
Cursor: `npx skills add bytedance/deer-flow --skill blocking-io-guard -g -a cursor -y`
Gemini CLI: `npx skills add bytedance/deer-flow --skill blocking-io-guard -g -a gemini-cli -y`

## Description

Ensure async-path backend code that could block the asyncio event loop is protected by a teeth-verified runtime anchor in tests/blocking_io/. Use when changing backend Python under app/, packages/harness/deerflow/, or scripts/, when running a blocking-IO triage round over the whole repo, or when a reviewer/CI asks for blocking-IO coverage. Runs a deterministic scan (changed-lines or full-repo), routes each candidate, drafts/extends an anchor, and proves it fails when the blocking IO regresses.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Blocking-IO Guard Skill

Help a contributor ship backend async changes together with the runtime anchor
that lets DeerFlow's blocking-IO CI gate actually see the new code. The dynamic
detector only catches blocking IO on paths a test executes, this skill closes
that gap, either for your own diff or for a repo-wide triage round.

Read `references/good-anchor-rules.md` before writing any anchor.
Only read `references/sop-skeleton.md` when generalizing this SOP to another
detector domain, it is not needed to execute the steps below.

## When to use

- Your change touches Python under `backend/app/`,
  `backend/packages/harness/deerflow/`, or `backend/scripts/` and may run on
  the async event loop (Mode A). If unsure, run Step 0, it answers
  deterministically.
- You are doing a maintenance triage round over the existing codebase
  (Mode B).

## SOP (router)

### Step 0, Scope (deterministic)

**Mode A, your own diff** (default, pre-PR). From repo root:

```bash
uv run --project backend python scripts/scan_changed_blocking_io.py --base origin/main
```

Lists blocking-IO candidates your change introduces: findings on lines the
diff added, **plus** findings that are new versus the merge base, the latter
catches a new async caller exposing an old sync helper whose blocking line is
not in the diff. The diff is `<base>...HEAD`, so **commit your work first**, uncommitted lines are not selected.

If the list is empty, this change introduces no blocking-IO surface *that the
static detector can see in the changed files*. One residual blind spot
remains: reachability is same-file only, so a new async caller of a sync
helper **defined in another file** is invisible to both selections. If your
diff adds an async call into a helper that lives elsewhere, check that helper
manually (codegraph or `git grep`) before stopping.

**Mode B, full-repo triage round.** From repo root:

```bash
make detect-blocking-io
```

The rest: https://github.com/bytedance/deer-flow/blob/HEAD/.agent/skills/blocking-io-guard/SKILL.md
