* chore: format the 35 files CI had been silently rewriting
`scripts/lint.js --prettier` and the release workflow's `Format Project`
step both run `prettier --write`, which reformats in place and exits 0.
Neither is followed by a dirty-tree check, so the rewrites are discarded
when the job ends and these files have stayed unformatted on `main`.
This is the output of `prettier --write` over exactly those files, so the
next commit can turn the check into a real gate without failing on a
backlog. No behaviour change: every hunk is whitespace, quoting or
wrapping.
Verified with prettier 3.6.1, the version pinned in package-lock.json.
`prettier --check .` over the whole repo reports these 35 and nothing
else.
Refs #11109
* fix(ci): make the Prettier lane a real gate
`runPrettier()` ran `prettier --write .`. Prettier exits 0 after
reformatting, and no caller checks the tree afterwards, so the lane
passed on unformatted code and CI threw the rewrites away — the 35 files
in the previous commit are what it had been silently fixing and
discarding.
ESLint does not cover the gap: eslint.config.js loads
eslint-config-prettier, which disables formatting rules rather than
enforcing them. With this change the only enforcement point outside the
husky pre-commit hook actually enforces something.
`npm run lint:all` now reports unformatted files instead of fixing them;
`npm run format` is the fix. Prettier's own failure message says so.
Refs #11109
* fix(release): drop Format Project, it writes and discards
The step ran `npm run format` (`prettier --write .`) and nothing in
release.yml inspected the tree afterwards — no `git diff --exit-code`, no
`git status --porcelain` anywhere in the file. The rewrites died with the
job, so the only failure it could produce was Prettier crashing on an
unparsable file, which the Run Lint step reports anyway.
It cost 13m58s on a quiet host and 20m45s on a contended one, against a
30-minute cap that `quality_static` hit twice today (runs 33957952281 and
33963757913, both cancelled mid-lint with nothing failing). The remaining
steps are `npm ci` (1m44s) and `lint:ci` (~8m20s), so the job now has real
headroom instead of finishing 24 seconds over the wall.
Formatting is now gated where it belongs: the previous commit makes the
PR-CI Prettier lane `--check`.
Refs #11109
* fix(ci): keep prettier --check out of .qwen/ and the pre-paint theme script
Two things the `--write` → `--check` flip broke that `--write` had hidden.
`.qwen/` is gitignored as `.qwen/*` and holds machine-written state —
pending-skills/, auto-skill-*/, learned-skill-*/,
computer-use/installed.json. Prettier does not read .gitignore, so it was
walking in and silently reformatting whatever a contributor had there;
under `--check` that turns into a failed `npm run lint:all` on files git
does not even track. CI never saw it (fresh checkout, tracked files only),
which is exactly why it went unnoticed. Adding `.qwen/` to
.prettierignore also drops the one tracked file under it —
skills/find-simplifications/SKILL.md, force-added past .gitignore — from
the previous formatting commit, since a directory the gate should not
police should not be reformatted for it either.
The inline theme script in web-shell's index.html is restored to its
original single line behind `<!-- prettier-ignore -->`. It is a
render-blocking script in <head> that applies the stored theme before
first paint; the expanded form ships ~600 more bytes on the critical path
and buys no readability the comment above it does not already give. A
change about CI hygiene should not be reshaping that.
Refs #11109
* fix(ci): keep prettier --check out of vendored packages/mobile-mcp
eslint.config.js has ignored `packages/mobile-mcp/**` since it landed —
"vendored mobile-next/mobile-mcp; has own eslint config" — and
.prettierignore already carries its sibling `packages/cua-driver/`, listed
one line above with the same rationale. mobile-mcp was simply missed.
`--write` hid that: it reformatted the vendored package's own eslint
config to our house style every run and threw the result away. The
formatting commit in this PR would have made that permanent, widening the
diff against upstream on the next sync for a package this repo has already
decided not to lint. That file is reverted here and the directory is
ignored.
Same class as the .qwen/ fix in the previous commit: the gate reaching
somewhere the repo had already decided it should not.
Refs #11109
* fix(ci): mirror eslint's remaining global ignores in .prettierignore
`--check` makes .prettierignore load-bearing in a way `--write` never was:
under `--write` a file prettier should not touch was reformatted and the
result discarded, so nobody noticed; under `--check` it fails the lane.
These three are the rest of eslint.config.js's global ignores, added for
the reasons it already states. `scripts/codemod/fixtures/` is the one that
matters: those files are "intentionally non-idiomatic ink input/output",
so the obvious response to a `--check` failure there — reformat to house
style — would corrupt the fixtures the codemod tests assert against. The
trap is not live today (all three currently satisfy prettier), which is
precisely why it is worth closing before someone meets it.
Refs #11109
* chore: format converter.test.ts, which drifted onto main since this branch
This branch merged main 32 commits after its base and `prettier --check .`
found one new offender. It is the same gate failing the same way: nothing
enforces formatting, so `--write` reformatted this file on every CI run
since it landed and threw the result away.
Worth noting as evidence rather than noise — the backlog this PR fixes was
not a one-off from before someone got careless; it accrues continuously,
and it accrued again while the PR was open.
Refs #11109
* Revert "fix(release): drop Format Project, it writes and discards"
This reverts the release.yml half of this PR. #11195 removes that step on
its own, in one file and four lines, and two PRs racing on the same
deletion helps nobody.
The reasoning and the evidence are unchanged and now live on #11195: the
dry-run release dispatched from this branch with the step removed
(34022919438) went 18/18 green in 65m43s, quality_static finished in
7m00s against main's 8m57s, and Run Lint was 4m52s vs 4m43s — nothing
downstream ever read what the step produced.
Dropping release.yml from this PR also widens who can review it. It was
the only file here owned by @pomelo-nwu and @wenshao alone; what remains
under CODEOWNERS is /packages/core/, whose owner list is six people. The
Prettier gate no longer waits on the two maintainers who must sign off on
release workflow changes.
Refs #11109, #11195
* fix(ci): make the gate resolve the file set npm run format resolves
Two review findings, one root cause: the gate was checking a different set
of files than the tree it is supposed to police.
**The `.qwen/` ignore rested on a false premise (R1-1, @chiga0).** Prettier
3.6's `--ignore-path` already defaults to `[.gitignore, .prettierignore]`,
so every machine-written path that entry's comment named —
`pending-skills/`, `auto-skill-*/`, `learned-skill-*/` — was outside the
gate before it via `.gitignore:32`. What the entry actually excluded is the
corpus `.gitignore` deliberately re-includes: `.qwen/commands/**`,
`skills/**`, `agents/**`, `team-memory/**`, `review-context.json` — 57
tracked, hand-authored files. The gate then passed because the surface had
been narrowed, not because the tree was formatted, and contributors editing
those docs could ship them unformatted with both enforcement points silent.
The entry is dropped and the first commit's formatting of
`skills/find-simplifications/SKILL.md`, reverted alongside it, is re-landed.
**The gate and the remedy used different CLIs (R1-2).** `runPrettier()` ran
the classic `prettier --check .` while `npm run format` runs
`prettier --experimental-cli --write .`. The classic CLI reads only the
repo-root `.gitignore`; the experimental one also honours nested ones, and
this repo has 23 of those. Verified on a scratch tree: given
`pkg/.gitignore` containing `lib/`, classic reports `pkg/lib/nested.js` and
experimental skips it. So the lane could go red on a locally built package's
output that `npm run format` provably cannot clear. The gate now uses the
same CLI as the remedy it names.
Refs #11109
* fix(ci): let the pre-commit hook cover what the gate now checks, and pin it
**The hook was narrower than the gate (R1-5).** `lint-staged` formatted only
`*.{js,jsx,ts,tsx}` and `*.{json,md}`, but the gate checks every extension
Prettier has a parser for. Of the 35 files the first commit formatted, 29
(83%) are in classes the hook never touched — 13 `.yml`, 12 `.mjs`, 3
`.css`, 1 `.html`. Left alone, the backlog this PR just cleared would
re-accumulate, and now as a red CI step on someone else's PR rather than as
silent drift. `.mjs`, `.cjs`, `.yml`, `.yaml`, `.css` and `.html` join the
Prettier-only group; ESLint's globs are unchanged, since the gap is about
formatting coverage, not lint coverage.
**Nothing pinned the flag (R1-4).** `scripts/tests/lint.test.js` exercised
only the linter-directory helpers, and `ci-platform-lanes.test.js` asserts
that the `Run Prettier` step exists and is profile-gated, not what it runs.
A refactor, or a well-meant "make lint auto-fix again", could restore the
silent pass with every suite green. Two assertions now pin it: that
`runPrettier()` checks rather than writes, and that it uses the same
Prettier CLI as `npm run format`, so the two cannot drift apart again the
way R1-2 found them.
Refs #11109
* docs: correct the instructions and comments the --check flip falsified
**Three tracked instructions to automation agents now say the opposite of
what the code does (R1-9), and one is fed to a CI lane today** —
`.github/workflows/qwen-triage.yml` re-pins `verify-pr` from the base commit
and hands it to the verifying agent.
- `verify-pr/SKILL.md` told agents never to run `scripts/lint.js` with no
arguments because it would rewrite the working tree under their A/B
harness. That is no longer why. The prohibition is kept — it is still
right — but re-grounded in what the no-arg form actually does now
(`setupLinters()` wipes the linter temp dir and re-downloads three pinned
binaries), and `--prettier` joins the enumerated non-mutating checks it
was the only flag missing from.
- `find-simplifications/SKILL.md` and its `references/land.md` told the
simplification agent that a formatting diff "carries zero signal" because
CI runs `--write`. An agent believing that would skip `npm run format`
after a deletion changed line shape — on the very extensions the hook does
not cover — and go red on formatting it was told could not matter.
- `update-ecs-runner-qwen-workflow.test.js`'s comment justified parsing two
matrix layouts by "CI runs `prettier --write .` before this suite". CI no
longer rewrites anything; the two layouts are still worth parsing, so the
comment is re-grounded in the checked-in form versus older branches.
**The index.html rationale overstated its own number (R1-8, @chiga0).** It
claimed the expanded script ships "~600 more bytes"; measured against this
repo's Prettier 3.6.1 and its `tabWidth: 2`, it is +258 source and +8
gzipped here, +287/+20 by the reviewer's method — either way roughly half
what was claimed, and "~600" is what the same expansion costs at
`--tab-width 4`. Since the prose ships verbatim inside the built
`index.html`, the fix is to drop the contested figure and keep the comment
short. The `<!-- prettier-ignore -->` guard itself stays: it is load-bearing.
Refs #11109
* chore: format classify-profile.test.mjs, drifted again after commit 1
Third instance in this PR's lifetime, and the sharpest: commit `
|
||
|---|---|---|
| .github | ||
| .husky | ||
| .qwen | ||
| .vscode | ||
| docs | ||
| docs-site | ||
| eslint-rules | ||
| integration-tests | ||
| integrations | ||
| 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) | ✓ | — |
Qwen Code Evaluation
Evaluation Configuration
| Configuration | Value |
|---|---|
| Dataset | princeton-nlp/SWE-bench_Verified, 500 cases |
| Runs | 3 trials per version, 1,500 jobs per version; 7 Qwen Code versions |
| Model | Qwen 3.7 Max |
| Sampling | temperature=1, top_p=0.95 |
| Thinking / Reasoning | interleaved_thinking=true, thinking_type=adaptive, reasoning_effort=high |
| Context / Output Limits | context_1m=true, model_context_length=1,000,000, max_tokens=64,000, model_max_tokens=65,535 |
| Harness Limits | max_iterations=500, runtime_timeout_sec=7,200, agent_timeout_multiplier=3.0 |
Scores by Qwen Code Version
| Version | Avg Score | Pass Rate | pass@3 | pass^3 |
|---|---|---|---|---|
| 0.0.14 | 77.80% | 84.6% | 84.6% | 69.2% |
| 0.1.0 | 76.73% | 84.6% | 84.6% | 68.0% |
| 0.5.0 | 76.60% | 83.0% | 83.0% | 68.4% |
| 0.10.0 | 76.47% | 84.4% | 84.4% | 67.4% |
| 0.15.0 | 77.67% | 84.6% | 84.6% | 68.6% |
| 0.19.0 | 76.40% | 85.0% | 85.0% | 65.8% |
| 0.22.0 | 77.33% | 84.4% | 84.4% | 68.0% |
Avg Score Trend
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.
- Aliyun Model Studio CLI — Official CLI for Aliyun's AI platform (
bailian-cli). Extends Qwen Code with image/video generation, knowledge retrieval, app orchestration, and model deployment
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.
