* fix(memory): scan uncapped when selecting forget candidates Recall moved to the uncapped scanner in #8716; forget did not. A document ranked past the 200-document cap could be recalled and injected into the prompt but never forgotten. Forget now scans uncapped, so its candidate universe matches recall's. The model-selection prompt renders every candidate, so it gets its own bound of 400: literal query matches first, then the most recently modified remainder. The heuristic fallback keeps scanning the full uncapped list. Indexer, status, and extraction stay capped on purpose, and the two design docs that recorded forget as capped now say otherwise. Refs: #9378 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(memory): give each scope its own share of the forget prompt Review round 1. The 400-candidate bound ranked both scopes into one recency budget, so a store whose project entries are all newer than its user entries seated no user memory at all. The capped scanners this replaced ran per scope, so each scope always had seats. That made an old user entry unselectable by the model while recall could still inject it, which is the same asymmetry the PR set out to close. Each scope now keeps a 200-candidate quota and whatever a smaller scope leaves is handed to the other. Within a scope, literal query matches rank first and both groups are ordered newest first, so truncation is deterministic instead of scan-order, and the bound logs when it drops candidates. Also from review: the query normalisation and match predicate are now shared with selectByHeuristic so the two cannot drift; the user scan gets the best-effort guard recall.ts and extractionAgentPlanner.ts already carry; and the docstring and design docs no longer claim an unconditional guarantee the bound does not provide. Three tests, each verified against the mutation it is meant to catch: global ranking drops the user ids, an ascending sort drops the newest filler, and handing the fallback the bounded list returns 400 of 450 matches. Refs: #9378 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(memory): bound the unconfirmed forget path and drop the silent scan guard Review round 2, all suggestions. MemoryManager.forget passed limit: MAX_SAFE_INTEGER and deletes without confirmation. With an uncapped scan and a heuristic fallback that substring matches the whole store, a one-character query matched nearly every entry in both scopes, where the capped scanners had held that same failure to one scan's worth of candidates. The limit is now the prompt bound, restoring the old ceiling. Round 1 added a best-effort catch on the user scan. That was wrong on two counts: scan.ts caps after reading and ordering the whole tree, so uncapping adds no read exposure to justify it, and swallowing the failure made forget report "no entries matched" for a scope it never read, then act on that answer by deleting. Reverted, with a comment saying why forget differs from recall here: a missed injection is recoverable, a missed deletion is not. normalizeForgetQuery now delegates to normalizeSummary so query matching and the post-selection re-match cannot drift apart, and one design-doc sentence no longer implies only semantic matches fall off the bound. Two tests, each verified against its mutation: the quota split is now exercised with both scopes over quota, where dropping it to 150 seats 250 project entries instead of 200; and the delete ceiling fails at 401 removals if the unbounded limit comes back. Refs: #9378 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(memory): split forget's deletion seats per scope, and decouple the ceiling Review round 3. The deletion ceiling added last round truncated the heuristic fallback in candidate order, and listIndexedForgetCandidates pushes every user entry ahead of every project entry. With 450 matching user entries and 50 matching project ones and the side query down, forget deleted 400 user entries, zero project ones, and reported success. That is the reachability asymmetry this PR exists to remove, moved into the delete path. The per-scope allocation the model prompt already used is now shared with the heuristic, so each scope keeps its share of the limit and a smaller scope's unused seats go to the other. The ceiling is also its own constant now rather than an alias of the prompt bound. Resizing the model prompt is a cost decision and resizing this is a blast-radius decision; sharing one constant let the first silently widen the second. Two tests, each checked against its mutation: the 450-user/50-project shape returns zero project matches under a plain slice, and oldest-first ranking inside a scope drops that scope's newest entry from the prompt. Refs: #9378 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(memory): pin the forget split at a small limit and the heuristic's own order Cross-review found both new tests mutation-survivable. Every case used a 400 limit, so hard-coding a 200 per-scope quota instead of deriving it from the budget still passed, and the recency case let the side query succeed, so it pinned the model prompt's ranking rather than selectByHeuristic's own comparator. One case at limit 5 with the side query failing covers both: it asserts the 3/2 split, which only holds if the quota comes from the budget, and that each scope contributes its newest entry, which fails if the comparator is reversed. Both mutants verified failing. Refs: #9378 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(memory): share the forget recency comparator and log a bound deletion Review round 4, both suggestions. The mtime comparator was the last thing the model path and the heuristic path each typed for themselves, after this branch had already hoisted the query normaliser, the match predicate and the per-scope allocator so the two could not drift. Each site has its own test, so a one-sided ordering change would have updated its own test, passed CI, and left the sibling stale. Now one definition. The deletion cap also bound silently. The prompt bound warns when it truncates; the path that actually deletes did not, so a forget that removed 400 of 500 matches reported success and left no record of why recall kept injecting the rest. It now says so. No test for the new warning: it is a debug log line, and asserting on it would pin the wording rather than the behaviour. Refs: #9378 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|---|---|---|
| .github | ||
| .husky | ||
| .qwen | ||
| .vscode | ||
| docs | ||
| docs-site | ||
| eslint-rules | ||
| integration-tests | ||
| integrations/external-context | ||
| 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.
- 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.
