* ci(shepherd): add Fleet Shepherd — automated unblocking of the bot-PR fleet
A scheduled janitor that applies, per open bot PR, the smallest lever that
unblocks it — each lever was validated by hand across the fleet before being
automated here:
- conflict → dispatch the autofix loop for that PR (its --conflict path
merges base and resolves), deduped per conflicted head SHA via a marker
comment, with a bilingual notice on the PR
- stale base → update-branch when ≥25 commits behind main (fresh CI signal
and propagates workflow/skill fixes to the branch tree; self-limiting
because behind_by resets to zero after the sync), never while checks run
- known-flake red → rerun failed jobs only when EVERY failing test parsed
from the job log matches .github/known-flakes.txt (one unknown failure
blocks the rerun), only after the run fully concluded, max 2 attempts per
run id; the registry seeds the three repeatedly-observed flakes
- scan liveness → if no autofix full scan ran in 60 minutes and none is in
flight, dispatch one (GitHub cron was observed silent for 16h on a */10
schedule)
A single "Fleet Shepherd Dashboard" issue is edited in place each tick for
observability. Safety rails: bot-authored in-repo main-targeting PRs only,
per-tick action caps (3 syncs / 2 dispatches), dry-run dispatch input,
FLEET_SHEPHERD_DISABLED repository-variable kill switch, PAT identity
verified before any write; dispatches/reruns ride the workflow token while
comments/update-branch/dashboard use the bot PAT so synced branches still
trigger CI. Contract test (8 cases) pins triggers, scoping, credential
split, idempotency markers, caps, liveness, dashboard, and validates every
registry line as a compiling test-file regex.
* ci(shepherd): review fixes — gate reruns across ALL failed jobs, behavioral tests
Addresses the /review findings:
- The flake gate now enumerates EVERY failed job of the run via the jobs API
and parses failing tests from all their logs before deciding — matching the
header's "every failing test" promise, since `gh run rerun --failed` reruns
them all. A flaky Ubuntu test can no longer green-light a run that also has
a genuine Windows failure. Failed jobs exposing no parseable failing tests
(e.g. a coverage comment failing downstream of the test job) neither allow
nor block on their own — documented tradeoff. This also removes the URL
job-id parse entirely, mooting the /job-vs-/jobs concern (for the record:
statusCheckRollup detailsUrl is the web URL and uses singular /job/, as the
campaign's live extractions confirmed — but not parsing URLs is better).
- Behavioral tests: the log parser and the flake-gate pipeline are extracted
VERBATIM from the workflow (the test fails if either drifts) and executed
under bash — parser fixture → exact file list; gate matrix all-known→RERUN,
mixed→BLOCK, unknown→BLOCK, empty→SKIP. 10/10.
* ci(shepherd): review round 2 — atomic markers, dashboard lookup fix, hardened plumbing
Two criticals and the standing suggestions from review:
- act() now propagates the wrapped command's real exit status (still set -e
safe at the if-wrapped call sites), and every dedup marker is posted ONLY
when its primary action succeeded — a transient dispatch/rerun failure no
longer plants a marker that freezes the PR at that head or burns phantom
rerun attempts.
- Dashboard lookup used `--jq --arg`, which gh does not support (single
expression only) — DASH_NUM was always empty, creating a new dashboard
issue every tick. Fixed to an exact-title search with a plain expression.
- Scan-liveness signal now counts SCHEDULE runs plus the shepherd's own
liveness dispatches (recorded as a watermark in the dashboard body), so a
conflict dispatch — also a workflow_dispatch — can no longer satisfy the
watchdog and silently starve full scans; one run-list call now feeds both
the age and in-flight computations.
- Fleet metadata comes from ONE gh pr list call (no N+1 pr view loop);
actions reads (run state, jobs, logs) ride the workflow token whose
actions scope is guaranteed; update-branch passes expected_head_sha as a
compare-and-swap against races with the loop's own pushes; PENDING now
counts WAITING/REQUESTED; RUN_ID extraction is pipefail-guarded; the
registry filter is a trichotomy — rc≥2 (invalid pattern) BLOCKS reruns
instead of falling through to the rerun branch.
- Behavioral replay extended: invalid-ERE registry → ERRBLOCK (fail-safe
direction proven under bash). 10/10.
* ci(shepherd): review round 3 — cede rerun ownership to CI Failure Patrol; consumer-parity gates
The decisive review finding (raised independently by two reviewers): the
flake-rerun lever created a SECOND scheduled owner for the same failed CI
runs, unserialized against the existing Qwen CI Failure Patrol
(qwen-ci-flaky-rerun.yml) — exactly the rerun-vs-rerun race class observed
live during the fleet campaign. Single-owner principle applied: the lever,
its registry (.github/known-flakes.txt), and its tests are removed; the
shepherd now only REPORTS red CI on the dashboard, and the header documents
the non-goal. This also moots the sibling findings against the lever's
internals (stale first-FAILURE selection, unparseable-job neutrality, missing
fleet-wide rerun budget).
Remaining findings fixed:
- Conflict dispatch now mirrors its consumer's predicate: the autofix scan
skips PRs with checks in flight, so the shepherd defers the dispatch (and
its dedup marker) until checks are quiet instead of wasting the dispatch
and freezing the head behind a marker for a scan that never ran.
- A failed marker read now SKIPS the PR for the tick — an empty comment
history must never masquerade as "no markers" and double-fire actions.
- New behavioral test: act() is extracted verbatim from the workflow and run
under bash, proving a failing primary action returns nonzero (marker
skipped) and a succeeding one returns zero (marker posted). 9/9.
* ci(shepherd): honest budget accounting on marker failure; dry-run behavioral proof
Review round 4 (two suggestions):
- A successful dispatch now counts against MAX_DISPATCHES_PER_TICK the moment
it happens, with the marker posted afterwards; if the marker post fails the
note says so honestly and the possible next-tick re-dispatch is absorbed by
downstream dedup (the autofix scan's busy-PR skip and nothing-new gate).
The reviewer's ordering — counting only after a successful marker — would
let a marker outage overspend the per-tick dispatch budget.
- The act() behavioral replay now also proves the dry-run branch: with
DRY_RUN=true and `false` as the primary command, act() returns 0 without
executing it (DRY-OK), so an inverted condition or dropped return can no
longer pass on string presence alone. 9/9.
* ci(shepherd): scope-named conflict cap, wider liveness window, no empty-fleet overwrite
Review body-level confirms addressed:
- MAX_DISPATCHES_PER_TICK renamed to MAX_CONFLICT_DISPATCHES_PER_TICK: the
cap budgets conflict dispatches only, BY DESIGN — the liveness dispatch is
separately self-limited (dashboard watermark + 60-minute age + in-flight
gate ⇒ at most one per tick and usually one per hour), and sharing one
budget would let a liveness fire starve conflict handling. The name now
states the scope instead of inviting the bypass reading.
- Liveness run-list window widened to 50 so a review-event storm can't push
schedule runs or an in-flight scan out of view; the residual worst case
(one unnecessary dispatch) stays bounded by the watermark and the autofix
scan's own busy/nothing-new gates.
- A failed fleet enumeration now skips the walk AND the dashboard update —
the previous dashboard body is preserved instead of being overwritten with
a misleading empty table. 9/9.
* test(shepherd): rename to qwen-fleet-shepherd-workflow.test.js per convention
Every other workflow contract test in scripts/tests/ carries the -workflow
suffix; match it so workflow-test globs include this file.
* ci(shepherd): if-wrap every act(), exact-title dashboard, drop vestigial checkout
Review round 7:
- act() propagates real exit codes, so under the runner's set -eo pipefail a
BARE failing call aborts the whole tick — the reviewer's sharpened framing
of the marker-call issue (that call was already if-wrapped in the previous
round; the residue was the two dashboard writes). Both are now if-wrapped
with retry-next-tick warnings, and the test asserts no bare act call
remains anywhere.
- Dashboard lookup: exact-title equality via standalone jq --arg (in:title is
a substring search — a bystander issue merely containing the title must
never be hijacked and overwritten), and a FAILED lookup now skips the
dashboard for the tick instead of minting a duplicate via create-on-failure
(same fail-closed rule as the fleet and marker reads).
- Removed the vestigial checkout step: with the rerun lever ceded to the
Patrol, the run step reads no repo files — every read goes through the API.
10/10.
* ci(shepherd): fail-closed run snapshot, liveness-scoped in-flight, shepherd-own busy-set
Review round: three Criticals against the run-snapshot section.
- A failed autofix run-list read sets SCAN_RUNS_OK=false and skips the
liveness lever AND every conflict dispatch for the tick, instead of
falling back to '[]' — an empty snapshot both zeroed the in-flight
count and blanked the schedule signal, so the watchdog could stack a
duplicate scan on top of a live one.
- SCAN_INFLIGHT counts only SCHEDULE runs plus workflow_dispatch runs
whose createdAt sits within 180s of our recorded liveness watermark.
Forced conflict dispatches can hold a run in progress for up to two
hours; counting them starved the watchdog and froze full scans exactly
when the fleet was busiest.
- The shepherd builds its OWN busy-set from live runs' review-address
matrix jobs and defers a conflict dispatch while one is live or
queued (unknown snapshot => every dispatch deferred). The
marker-failure retry note claimed 'downstream dedup' that lives in an
unmerged PR; the dedup now travels with this workflow.
Contract tests: 11/11, including a verbatim-extracted jq replay proving
a foreign forced dispatch (created far from the liveness watermark)
neither satisfies nor starves the watchdog.
* ci(shepherd): declare set -eo pipefail explicitly
The act() contract, every if-wrapper, and the behavioral replay all
assume strict-mode semantics. Actions' default bash gives -e (bash -e
{0}) but NOT pipefail — declare both so production matches the tested
contract and a future bare act() call fails loudly instead of silently
posting its marker. The one real pipeline in the tick (the liveness
watermark grep) already carries || true.
* ci(shepherd): platform-blind CI-red on the dashboard; document first-tick edge
Review notes (non-blocking, adopted): the dashboard's ci-red state
matched only 'Test (ubuntu' — a Windows- or macOS-only regression
stayed invisible on the health view. Widen to any Test platform
(reruns stay with the Patrol either way) and pin it. Also record the
first-tick liveness edge at the in-flight computation: with no
watermark yet a manual dispatch in flight is not counted and one
duplicate scan may go out; the scan's own busy/nothing-new gates
absorb it, and every later tick has the watermark.
* ci(shepherd): unknown watermark and partial busy-set fail closed
Review round: two remote-read failure paths still turned unknown state
into actionable empty state.
- The liveness watermark lives in the dashboard body, so a failed body
read (not just a failed lookup) now flips DASH_LOOKUP_OK: the
dashboard is not overwritten (that would destroy the stored
watermark) and the liveness lever is skipped — otherwise, with cron
already stale, a PAT outage would dispatch a duplicate full scan
every tick for its duration. The lever now requires known watermark
state, a good run snapshot, expired age, and zero in-flight.
- Every busy-set jobs read is tracked: BUSY_OK inherits SCAN_RUNS_OK
and flips false on the first failed gh run view or jq parse, because
a partial enumeration is unknown busy-state, not a smaller busy-set
(a gh failure inside process substitution never trips the parent
shell). Conflict dispatches now gate on BUSY_OK.
New behavioral replay (PATH-stubbed gh over the verbatim-extracted
walk): failed jobs read → BUSY_OK=false with an empty set; successful
read → the queued review-address PR lands in the busy-set; no live
runs → known-empty set with dispatches enabled. 12/12.
* ci(shepherd): fetch markers only for conflicting PRs
Review suggestion, adopted: MY_MARKS was fetched (paginated) for every
PR in the fleet but consumed only by the conflict lever's dedup —
~100 wasted comments fetches per tick on a 50-PR fleet — and a failed
fetch on a NON-conflicting PR dropped the PR from the dashboard,
stale-base sync, and CI-red reporting via the shared continue. The
read now lives inside the CONFLICTING branch behind MARKS_OK: a failed
read defers just the conflict dispatch (empty history still never
masquerades as no markers), and every other lever keeps working.
* ci(shepherd): link the dashboard ci-red state to the failing job
Review suggestion, adopted: FAILED_TEST_URL was extracted per PR and
then only tested for non-emptiness — the dashboard said 'ci red' with
no way to reach the failure, forcing exactly the per-PR navigation the
dashboard exists to eliminate. The state cell is now a markdown link
to the failing Test job.
* ci(shepherd): attribute in-flight liveness by run id, not timestamp proximity
Review round: the ±180s attribution window necessarily miscounted a
conflict dispatch fired later in the SAME tick — created seconds from
the liveness watermark, its two-hour address run then suppressed the
age>=60m dispatch on every later tick, the exact starvation the header
claims to prevent. And the behavioral test only exercised a foreign
dispatch 40 minutes outside the window, masking the reachable case.
The liveness dispatch now records its run id: captured right after the
dispatch (a correlation window in which no other dispatch can exist —
conflict dispatches fire later in the walk), persisted in the
dashboard marker as 'run=<id>', and matched by id equality next tick.
No proximity window exists at all. Unknown id (capture failure or a
pre-id marker) attributes nothing, so the failure mode is one absorbed
duplicate scan — never starvation. The replay now proves the
reviewer's in-window case: a conflict dispatch created 5s after the
watermark counts 0, and our completed run plus that live conflict run
also counts 0. 12/12.
---------
Co-authored-by: wenshao <wenshao@example.com>
|
||
|---|---|---|
| .github | ||
| .husky | ||
| .qwen | ||
| .vscode | ||
| docs | ||
| docs-site | ||
| eslint-rules | ||
| integration-tests | ||
| packages | ||
| patches | ||
| scripts | ||
| .dockerignore | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| .npmrc | ||
| .nvmrc | ||
| .prettierignore | ||
| .prettierrc.json | ||
| .yamllint.yml | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| Dockerfile | ||
| esbuild.config.js | ||
| eslint.config.js | ||
| eslint.legacy-filenames.mjs | ||
| LICENSE | ||
| Makefile | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| SECURITY.md | ||
| tsconfig.json | ||
| vitest.config.ts | ||
The open-source AI coding agent that lives in your terminal.
中文 | Deutsch | français | 日本語 | Русский | Português (Brasil)
Why Qwen Code?
- Agentic out of the box — Auto-Memory, Auto-Skills, SubAgents, Agent Teams, and MCP. Dynamic workflows, zero setup.
- Open-source, inside and out — The framework and the Qwen models are open-source. They evolve together. No vendor lock-in.
- Multi-protocol — Supports OpenAI, Anthropic, Gemini, and Qwen APIs. Any third-party provider or local model (Ollama / vLLM). Switch at runtime.
- Beyond the terminal — IDE plugins, Desktop app, daemon mode, SDKs, and IM bots (Telegram / DingTalk / WeChat / Feishu).
Tip
Qwen Code is actively iterating on itself — using its own agent and models to file issues, submit PRs, review code, and run tests. Powered by the community, driven by AI.
Installation
Linux / macOS:
curl -fsSL https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.sh | bash
Windows:
irm https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.ps1 | iex
Restart your terminal after installation to ensure environment variables take effect.
NPM / Homebrew
NPM (requires Node.js 22+):
npm install -g @qwen-code/qwen-code@latest
Homebrew (macOS / Linux):
brew install qwen-code
Quick Start
qwen # Launch interactive terminal UI
# Inside the session:
/auth # Configure your provider and API key
See the Authentication Guide and Settings Reference for detailed setup.
How to Use Qwen Code
| Mode | Command | Use Case |
|---|---|---|
| Interactive | qwen |
Terminal UI with rich rendering, @file references, slash commands |
| Headless | qwen -p "..." |
Scripts, CI/CD, batch processing — no UI |
| IDE | — | VS Code, Zed, JetBrains |
| Desktop | — | Qwen Code Desktop — GUI for macOS, Windows, Linux |
| Daemon | qwen serve |
Shared agent session over HTTP+SSE (ACP). Multiple clients, one agent. (experimental) Docs |
| SDK | — | TypeScript, Python, Java |
| IM Bot | qwen channel |
Connect to Telegram, DingTalk, WeChat, or Feishu |
SDK example (Python)
import asyncio
from qwen_code_sdk import is_sdk_result_message, query
async def main() -> None:
result = query(
"Summarize the repository layout.",
{
"cwd": "/path/to/project",
"path_to_qwen_executable": "qwen",
},
)
async for message in result:
if is_sdk_result_message(message):
print(message["result"])
asyncio.run(main())
Capabilities
If you know Claude Code, you already know Qwen Code — and then some. We've put significant effort into bringing Qwen Code to feature parity with Claude Code, improving both breadth and reliability across the board.
| Feature | Qwen Code | Claude Code |
|---|---|---|
| SubAgents, Agent Teams, Dynamic Workflows | ✓ | ✓ |
| Auto-Memory, Auto-Skills, Hooks | ✓ | ✓ |
| Built-in Skills (/review, /batch, /loop, /bugfix…) | ✓ | ✓ |
| MCP, Plan Mode, LSP Integration | ✓ | ✓ |
| Auto Mode, Sandbox, Git Worktrees | ✓ | ✓ |
| Computer Use (desktop automation) | ✓ | ✓ |
| IDE Plugins (VS Code / JetBrains / Zed) | ✓ | ✓ |
| SDK | ✓ | ✓ |
| Headless Mode, Session Management | ✓ | ✓ |
| Open-source — model and framework | ✓ | — |
| Multi-protocol (OpenAI / Anthropic / Gemini / Qwen + any provider) | ✓ | — |
| Agent Arena (multi-model head-to-head on same task) | ✓ | — |
Daemon Mode — qwen serve (multi-client shared agent) |
✓ | — |
| IM Channels (Telegram / DingTalk / WeChat / Feishu) | ✓ | — |
Ecosystem
-
Qwen Code Desktop — Official desktop app for macOS, Windows, and Linux
-
AionUi — A modern GUI for command-line AI tools including Qwen Code
-
Gemini CLI Desktop — A cross-platform desktop/web/mobile UI for Qwen Code
-
🦞 Qwen Code Claw — Let other agents (Claude, Codex, etc.) delegate coding tasks to Qwen Code via ACP. Paste this prompt into your agent:
Use Qwen Code as a coding agent. First, fetch and read this skill reference:
https://raw.githubusercontent.com/QwenLM/qwen-code/refs/heads/main/.qwen/skills/qwen-code-claw/SKILL.md
Then follow the instructions inside to install, authenticate, and use Qwen Code via acpx for all coding tasks.
Contributing
Contributions are welcome! See CONTRIBUTING.md for guidelines.
Acknowledgments
This project was originally based on Google Gemini CLI v0.8.2. We gratefully acknowledge the Gemini CLI team's excellent work. Starting from Qwen Code v0.1, we stopped syncing with upstream and began independent development as a multi-protocol, multi-platform agent framework with deep integrations for Qwen models and beyond.
