qwen-code/docs/users/configuration/settings.md
Shaojin Wen 162213e9da
feat(review): adopt a round-aware convergence posture for posted findings (#9118)
* feat(review): adopt a round-aware convergence posture for posted findings

Re-reviews of the same PR regenerate non-Critical feedback at zero marginal
cost after every push: the review files findings on code the previous round
just added, the next push implements them, and the diff widens — which
allocates more agents, which file more findings. Measured from the outside:
one managed PR reached +13k lines across 8 review rounds with its per-round
Critical count flat and was closed unmerged; on two others 78-86% of the
growth was test lines. Every existing brake lives in the calling workflow
and covers only bot-managed PRs; a human contributor answering a
push-triggered review round by round rides the same loop with no brake at
all. Convergence therefore has to be a property of /review itself, not of
any orchestration around it.

Teach the reviewer to raise its POSTING bar as rounds accumulate — finding,
verification, the terminal report and the findings artifact are untouched:

- The convergence posture (Step 6): with no flag, Suggestions post through
  round 5; from round 6 only Criticals post, and non-Critical findings are
  recorded, not requested — one line each into the new `deferredSuggestions`
  compose state, which compose-review renders as a disclosed, non-capping
  list on every event (nothing is silently dropped, and a deferral never
  withholds the incremental anchor). A Critical is never deferred, at any
  round under any floor. An APPROVE over a non-empty deferral list opens
  "No blocking issues" instead of "No issues found", and the round number
  in the clause comes from the same side-file read the ledger marker
  stamps, so the two cannot disagree.

- The code-age rule (rounds 2-5): a NEW non-Critical finding anchored on
  code unchanged since the previous round's reviewed head defers the same
  way — that code was read last round and not flagged, so filing a nit on
  it now is re-derivation churn. The age reference is the previous review's
  own commit_id, which pr-context now recovers into the prev-ledger side
  file: unlike the ledger sha (a range certification, withheld on
  fail-closed rounds on purpose) it exists on every posted round, so the
  fail-closed full-range re-review — the common case in a bot loop — can
  still apply the rule. Validation and the newly-reachable exception mirror
  the anchor check; an absent or invalid reference skips the rule, never
  the review.

- `--severity-floor <critical|suggestion>` and `review.severityFloor` make
  the posture an explicit knob in both directions: `critical` applies it
  from round 1, `suggestion` turns it off, and `auto` — the default — is
  the round-adaptive rule. Grammar, deferred warnings, non-PR gating and
  operator-scope resolution all mirror `--effort`/`--comment`.

* chore(review): regenerate settings.schema.json for review.severityFloor

* fix(review): close the round-1 review findings on the convergence posture

Five verified findings from the PR's own reviews, each with its mechanism:

- The verdict surface now carries the deferrals. A deferrals-only APPROVE
  set lowSignal, so verdictLine printed "none of the N review agents
  reported a finding" while the same body listed the findings two
  paragraphs down — on exactly the posture's canonical end state. lowSignal
  is skipped when deferrals exist, ComposeReviewResult gains deferredCount,
  and the verdict line names the deferrals instead.
- Deferred findings count toward the verifier-delivery floor. They publish
  in the body as the deferral list, and an unverified claim does not become
  publishable by being deferred — a deferrals-only run owes a verifier
  exactly as a posting run does.
- The deferrable set is narrowed to high-confidence Suggestions that would
  otherwise post. Low-confidence and Nice-to-have findings stay
  terminal-only: routing them through the deferral list would publish what
  the review contract keeps off the PR.
- The code-age rule is hardened on both operands and both premises: the
  documented command quotes the PR-controlled path and passes
  --literal-pathspecs (an unquoted name executes shell; a glob name ages
  the finding against a sibling file's hunks), and age suppression is
  skipped for findings in scope the previous round disclosed as not
  reviewed — "the previous round saw this code" is false there.
- One side-file read per compose: the deferral clause and the ledger marker
  take the same prevRound value, so a mid-compose update can no longer
  publish two different round numbers in one review. The deferral list also
  caps each entry at 240 chars (twenty 4,000-char entries would push the
  body past GitHub's 65,536 rejection line), and the disclosed 20×240 cap
  is now stated in the prose the list's survival promise lives in.

Smaller closures from the same rounds: two invalid flag values are two
typos, not a target and a tiebreak (neither becomes a file target); the
--severity-floor warning arms invalid-eq and kept-as-target gain the tests
whose absence a mutation probe demonstrated; the commitId fixture gains a
newer marker-less review so a latest-review-wins mutant fails; the
severityFloor setting joins the settings-dialog membership assertion and
the configured-floor wiring tests; and the /review argument-hint now
advertises the flag.

* fix(review): carry deferredCount through the persisted verdict

The save-artifact validator constructs the persisted verdict from the
composed JSON and gained the field with absent-means-zero semantics: a
composed file written by a build predating the posture must not fail a
save over a count that only affects display, while a present value of
the wrong shape is refused like every other field.

* test(review): pin deferredCount passthrough and the pre-posture default in the saved artifact

* fix(review): close the round-2 findings — deterministic deferrals and the truthful verdict line

- The verifier-delivery floor now excludes deterministic [build]/[test]/
  [probe] deferrals by their source tag, the same exclusion body Criticals
  get: a pre-confirmed finding never produces a verifier delivery, so
  counting it demanded a delivery that cannot exist — the cap never lifted,
  the anchor was withheld every round, and the posture's own enforcement
  regenerated the full-range re-review loop it exists to end. The deferral
  entry format now carries the source tag (SKILL prose + a pin), and the
  determinism regex is one shared constant for both scans.
- verdictLine's "(listed in the body)" turns cap-aware past the 20-line
  render cap, so a verdict counting 21 no longer certifies a body listing
  20; the line caps are module-scoped for the two readers.
- The mutation-demonstrated assertion gaps are closed: deferredCount is
  asserted on the REQUEST_CHANGES and COMMENT return sites, and
  save-artifact's refuse arm has its wrong-shape cases ('two', -1, 1.5).

* fix(review): close the round-3 findings — source-position tags, a Critical tripwire, and honest age-reference lifecycle

- Deterministic classification of a deferral reads the SOURCE position only
  (tag immediately after the entry's first em-dash): a whole-entry scan
  classified a finding deterministic off a title that mentioned [test] and
  skipped the verifier floor for an unverified claim (probe-confirmed).
- A deferral carrying a Critical marker is refused outright: the channel is
  model-written free text that casts no vote on C, and a Critical routed
  there composed an APPROVE over a blocker in a probe. Marker forms only,
  so prose like "critical-path" passes; artifact-level reconciliation stays
  a structural follow-up.
- The prev-ledger side file now carries the winning review's own id, and a
  run that recovers no ledger strips a stale file's commitId/reviewId while
  keeping the round counter: an age reference the PR's current reviews no
  longer vouch for can wrongly defer a finding on code changed-and-reverted
  since the true previous round — snapshot diffs are not monotonic over
  intervals, which refutes the earlier keep-it-it's-conservative ruling.
  The write/strip logic is an extracted, filesystem-tested helper, closing
  the serialization blind spot two rounds of review asked about.
- Prose repairs: the code-age rule is auto-only (an explicit suggestion
  floor turns it off, as the resolve-floor paragraph already promised); the
  fallback names the commitId, not the ledger sha; the not-reviewed check
  binds to the review the side file's reviewId names; and the
  context-unavailable state skips the age rule (the side file may be a
  previous run's). save-artifact's null-deferredCount reads as zero — the
  same absence semantics compose-review's toCount gives the field's
  siblings — now stated and tested rather than accidental.

* fix(review): close the round-4 findings — licence the deferral channel, harden the side file, age aggregates per location

Code:
- The deferral channel gains its licence check: the resolved severityFloor
  rides the compose state, and a non-empty deferral under an explicit
  suggestion floor (posture off) or on round 1 of auto (no posture, no age
  reference) is refused — the one channel that removes findings from
  posting now gets the same deterministic treatment as the counts. Rounds
  2-5 under auto stay licensed: the code-age rule defers there, which the
  reviewer's proposed round<6 condition would have wrongly outlawed.
- Ledger recovery skips PENDING drafts (the API serves the caller's own
  unsubmitted reviews; a crashed run's draft is not a previous round), and
  the side file's lifecycle is three-way honest: recovered → written whole
  (atomically, temp+rename — a mid-write failure must never leave a
  truncated file that parses as no round); reviews read but no ledger for
  this account → file REMOVED (another account's round counter must not
  stamp this account's first review round N+1); recovery threw → round
  counter kept, age-sensitive commitId/reviewId stripped.
- Disposal rule v3: an invalid flag value survives by what it could BE — a
  PR-shaped token survives unless a typed target exists (an unrelated typo
  must not change WHICH codebase is reviewed), a file-shaped token only as
  the sole kept token.
- The per-entry cap backs off a split surrogate pair (zh titles ride the
  deferral list untranslated; unit 240 on a high surrogate shipped U+FFFD).

Prose (SKILL):
- Pattern aggregates age per location: ANY changed location posts the
  aggregate; deferral only when every location is unchanged and covered.
- The reviewId body is consulted only after fetching a truncated tail (the
  8,000-char render cap can hide the very "Not reviewed" disclosure the
  age rule depends on); an unreadable body skips the rule.
- context-unavailable resolves the auto floor as round 1: no posture, full
  posting, said in the terminal — a posting bar in doubt fails open.
- Deferred findings number under D<round>-<n>, never consuming an R id the
  ledger's buildLedger would reassign to a posted sibling.
- The Step 8 record sentence now states exactly what survives where, and
  the state contract documents severityFloor.

Tests pin all of it, including the mutation-shown gaps: the marker/clause
round agreement, the exactly-20 verdict-line boundary, the submit-seam
deferral passthrough, and sha survival through the side-file rewrites.
Structural remainders are filed instead of grown: #9176 (typed deferral
channel derived from the findings artifact), #9177 (whole-body byte budget).

* fix(review): close the round-5 findings — carry the floor unresolved, cap unlicensed deferrals, guard the counter

The round-5 reviews caught a shipped design contradiction: the SKILL told
Step 6 to carry the RESOLVED floor into the compose state, so a legal
rounds-2-5 age-rule deferral arrived as the string 'suggestion' — which
the licence check reads as the operator's explicit posture-off override —
and the compose threw, losing the entire round, Criticals included. Two
fixes, one per side of the contract:

- The state carries the verdict's floor UNRESOLVED: auto stays the literal
  'auto', and the module licenses it by the round it derives itself. A
  SKILL pin makes the sentence load-bearing, and an end-to-end test pins
  the legal round-3 shape (side file at round 2, auto floor, deferral →
  clean APPROVE naming round 3).
- Unlicensed deferrals CAP instead of throwing: prevRound is a best-effort
  side-file read whose every failure mode returns 0, so a missing file at
  a true round 6 must degrade to a disclosed, capped, anchor-withheld
  verdict — never to no verdict at all. The findings render under a
  warning clause; the Critical-marker tripwire stays a refusal (a Critical
  rendered as "recorded, not requested" would be the worse outcome).

Adjacent round-5 closures: the tripwire is separator-agnostic (an ASCII
hyphen where the format prescribes an em dash was the cheapest real miss);
side-file removal is gated on a POSITIVELY read non-empty reviews list
(ghApiAll flattens error envelopes to [], and an empty list must not
delete a live round counter and its anchor); the atomic temp name is
per-process so concurrent same-PR fetches cannot rename each other's
bytes, with debris unlinked on a failed rename; two PR-shaped invalid flag
values are refused as ambiguous instead of first-wins; the apostrophe
escaping clause and the unresolved-carry sentence gain SKILL pins; and
review.severityFloor joins the user-facing settings reference.

Declined, recorded on the PR: requiring per-file coverage evidence for the
age rule — the anchor chain already encodes it (an incremental round's
anchor certifies the preceding full coverage; broken links are fail-closed
rounds whose disclosures the rule consults).

* fix(review): close the round-6 Criticals — relocate stray Criticals, license by evidence at hand, one separator grammar

Round 6 tripled the finding count and aimed almost entirely at rounds 4-5's
hardening code — the expansion signal this PR's own posture exists to
answer — so this round lands only the confirmed Criticals and defers the
Suggestion tail on the record:

- A Critical-marked deferral is RELOCATED into the body Criticals instead
  of thrown: it counts toward C, the event blocks, and the round posts —
  the same doctrine the round-5 fix applied to the licence check, closing
  the last channel where one bad entry could cost a composed round (with
  real drafted Criticals attached). A lookbehind spares hyphenated
  compounds — the SKILL's own "non-Critical findings" phrasing was a
  realistic false positive that would have blocked over a nit.
- The two deferral regexes share one separator grammar: the deterministic
  classifier now accepts hyphen/en/em like the tripwire, so two spellings
  of one [test] finding no longer produce opposite verdicts (the unmatched
  form demanded a verifier that cannot exist — the self-inflicted cap).
- The licence closes its evidence gaps: an ABSENT severityFloor beside a
  non-empty deferral list is unlicensed (the field ships with the channel;
  omission must not silently re-license what an explicit suggestion floor
  forbade), auto in the context-unavailable state is unlicensed (the round
  is unknowable), and the unlicensed cap now joins the certification
  ladder so "Reviewed — no blockers." cannot open a body whose own warning
  says findings may be under-posted.
- Deferred entries render Markdown-neutralized (mdField, the budget-gap
  rule — model text reaching a public body), carry a truncation ellipsis
  when the per-entry cap cut them, and --severity-floor accepts the
  documented `auto` spelling while quoted-empty flag values are consumed
  as missing instead of becoming empty file targets.
- Prose: the age rule's deferrable set names the same high-confidence
  otherwise-postable Suggestions as the floor paragraph (never
  low-confidence/NTH); a reviewId body absent because it matched the
  canonical LGTM filter is disclosure-free by definition, not unreadable;
  and the posture round is the side file's — the cache scopes the diff but
  never decides the posture.

The Suggestion tail and the two structural families are recorded, not
grown: #9176 gains the age-evidence and id-timing bullets; #9177 already
carries the whole-body budget. Declines stand where argued (R2-2/R2-15
anchor-chain; sole-file-shaped promotion keeps the forgot-the-level use).

* fix(review): close the round-7 findings — kebab paths, the equals-form ambiguity hole, and the relocated blocker's ledger seat

Round 7 caught a regression the round-6 fix itself introduced, plus one
genuine hole in the round-5/6 ambiguity guard:

- The deterministic classifier anchors on the first WHITESPACE-FLANKED
  separator after the leading file:line token. The round-6 negated-class
  walk stopped at the first hyphen INSIDE a kebab-case path — this repo's
  enforced .ts convention — so the common spelling of a [test] deferral was
  misclassified non-deterministic and demanded a verifier that cannot
  exist: the permanent self-cap loop, on exactly the entries the exclusion
  exists for. Kebab, [build] and [probe] cases pin all three tags on both
  separators.
- The PR-target ambiguity pool counts BOTH flag spellings: an equals-form
  invalid value never enters the disposal set, so which of two PR numbers
  got reviewed depended on which syntax was typed. All four spelling
  combinations now land on the same loud refusal, pinned.
- A relocated Critical rides the machine ledger: the split moved into a
  shared helper that the body composer and the marker builder both call,
  so a mis-routed blocker keeps its id continuity ("the findings always
  ride" includes the mis-routed ones).
- The age rule's two diff-output doubt states fail open like every other
  arm: a non-matching pathspec (prove it with tree-relative cat-file before
  reading the diff's silence) is about the path, not the code, and a
  zero-hunk non-empty diff — a PR-controlled .gitattributes binary mark —
  is a file-level change; both post. Commands pinned to the worktree root.
- The mutation-shown pin and test gaps are closed: explicit auto override,
  quoted-empty consumption on both flags, the invalid-configured-floor
  handler seam, the SKILL's validation commands, round-source and
  context-unavailable clauses, and the aggregate age clause.

The four re-asserted body Criticals remain tracked (#9176/#9177 and the
two serialization-ordering threads) — their standing disposition is the
round-6 batch record, and their final resolution is the maintainer's
merge decision.

* fix(review): close the round-8 Criticals — one entry grammar, one rescue rule, deletion only on proven absence

Round 8 landed three genuine Criticals, all on rounds 6-7's hardening code,
plus a fourth from a local lane sharing the first's mechanism:

- The deterministic classifier's entry grammar tolerates the shapes the
  SKILL itself prescribes: the aggregate `(+N locations)` suffix between
  the anchor and the separator, a leading space (entries are trimmed before
  the scan; the filter trimmed only for emptiness), and an en dash. Every
  one classified a pre-confirmed [test] deferral non-deterministic and
  demanded a verifier that cannot exist — the permanent self-cap on the
  posture's own stop signal, probe-demonstrated three ways.
- A relocated Critical is classified by that same position-anchored rule,
  not the whole-entry tag scan the model's own body Criticals get: a
  title-borne [test] in a relocated unverified claim exempted it from the
  floor and posted it as a blocking Request changes with no verifier. The
  split helper reports the deterministic count and the body composer keeps
  the two provenances apart.
- The equals-form PR-shaped invalid value joins the disposal pool exactly
  as the spaced form does — the round-7 fix wired it into refusal only, so
  `--severity-floor=6711` reviewed the local tree while `--severity-floor
  6711` rescued PR 6711. Every spelling converges; the ambiguity pool counts
  distinct values, so two spellings of one PR are one candidate.
- Side-file deletion requires PROVEN absence — a walked review list with no
  submitted review by this account — never "recovery returned null": an own
  review whose marker fails to parse (edited or damaged bot body, marker-
  less follow-up) is a persistent state, and deleting there stamped the next
  round "round 1" mid-PR and reset the posture clock. Recovery is
  three-valued; the middle state strips conservatively.

Adjacent closures: an unrecognised severityFloor (model-transcribed drift
like "Critical" or "auto ") is the unknown state — unlicensed with a list,
inert without one — instead of a refusal that lost zero-deferral rounds
over a field that changed no output; the interface doc says UNRESOLVED
where it said RESOLVED (the round-5 regression's own wording); the
deferrable-set description at four sites names the real set
(otherwise-postable high-confidence Suggestions; low-confidence and NTH
stay terminal-only) and the rounds-2-5 age deferrals; and the mutation-
shown gaps are pinned — pure deferrals stay out of the ledger, a
relocation-only run incurs no licence cap, an invalid configured floor is
silent on non-PR targets, and a 64-hex commit id survives recovery.

* feat(review): type the deferral channel — carry the fields, stop re-parsing prose

Every genuine Critical in review rounds 5-8 lived in one place: the
deferral channel was free text re-parsed for provenance it did not carry.
A separator regex classified deterministic source, a marker regex caught
mis-routed Criticals, and each round's probe found the spelling the last
fix excluded — kebab paths, the SKILL's own aggregate suffix, an en dash, a
title-borne [test], (Critical), a fullwidth colon. A whole-module
self-audit (with reproduced witnesses) found eight more shapes and named
the class: the fourth, fifth and sixth rounds of the same enumeration
trap this repo's own review doctrine (#9095) says to close structurally.

So the entry is typed. `deferredSuggestions` is an array of
`{file, line?, source, severity, title, locations?}` copied from the
findings artifact the model already wrote in Step 6: deterministic derives
from `source` (build/test/probe), relocation from `severity === Critical`
(counts toward C, blocks, rides the ledger, classified by its FIELD — a
title mentioning [test] no longer exempts an unverified claim), a
`Nice to have` or malformed or free-text entry is refused at the boundary
like a NaN count (the channel that un-posts findings is not guessed at),
and the human line `file:line — [source] title (+N locations)` is RENDERED
by compose-review — nothing downstream parses it back. Both regexes and
the split helper's string grammar are gone; the SKILL contract, the state
bullet, the submit seam test and the whole deferral describe block are
rewritten for the typed shape (no test probes a spelling any more).

The self-audit's side-file findings land in the same commit: the recovered
write never lowers the round (a stale walked list — a concurrent lane, or a
paginated fetch that came back short — overwrote round 7 with round 2 and
dropped the anchor sha; compare on round, reviewId as tiebreak), and login
comparison is case-insensitive per GitHub (a case mismatch read "own
review exists" as proven absence and deleted the counter). Both pinned.

This pulls the structural half of #9176 into the PR; the issue keeps its
remaining bullets (structured `deferred` artifact marker, age-evidence arm,
R/D-id timing).

* fix(review): bound the relocation exit and dedupe rescued targets by identity

Round-9 findings on the pre-typed head, the halves that survive typing:

- The relocation exit applies the same per-entry bound as the deferred
  exit — newline collapse, the 240-char cap without splitting a surrogate
  pair, the ellipsis on a trim, and Markdown neutralization — through one
  shared helper. Relocated titles were spliced into the body verbatim, an
  unbounded feed the deferred exit's cap was added precisely to prevent.
- Rescued PR-shaped flag values dedupe by RESOLVED TARGET (number, plus
  host/owner/repo for a URL), not by raw string: a bare number and a
  same-number URL are one PR, and a raw-token Set read them as two and
  silently fell back to the local tree. Of several spellings of one rescued
  PR exactly one becomes the target; the restatements no longer surface as
  "Ignoring extra argument(s)" on the invocation the dedupe blesses.
- The persist test's debris check asserts on the directory listing rather
  than a temp name no code path writes (the temp is per-process).

The round's other two findings — the whole-entry Critical tripwire and its
title-borne false positives — no longer have an input form: the channel is
typed (6118109118) and severity is a field.
2026-08-15 17:09:43 +00:00

246 KiB
Raw Blame History

Qwen Code Configuration

Tip

Authentication / API keys: Authentication (API Key, Alibaba Cloud Coding Plan) and auth-related environment variables (like OPENAI_API_KEY) are documented in Authentication.

Note

Note on New Configuration Format: The format of the settings.json file has been updated to a new, more organized structure. The old format will be migrated automatically. Qwen Code offers several ways to configure its behavior, including environment variables, command-line arguments, and settings files. This document outlines the different configuration methods and available settings.

Configuration layers

Configuration is applied in the following order of precedence (lower numbers are overridden by higher numbers):

Level Configuration Source Description
1 Default values Hardcoded defaults within the application
2 System defaults file System-wide default settings that can be overridden by other settings files
3 User settings file Global settings for the current user
4 Project settings file Project-specific settings
5 System settings file System-wide settings that override all other settings files
6 Environment variables System-wide or session-specific variables, potentially loaded from .env files
7 Command-line arguments Values passed when launching the CLI

Settings files

Qwen Code uses JSON settings files for persistent configuration. There are four locations for these files:

File Type Location Scope
System defaults file Linux: /etc/qwen-code/system-defaults.json
Windows: C:\ProgramData\qwen-code\system-defaults.json
macOS: /Library/Application Support/QwenCode/system-defaults.json
The path can be overridden using the QWEN_CODE_SYSTEM_DEFAULTS_PATH environment variable.
Provides a base layer of system-wide default settings. These settings have the lowest precedence and are intended to be overridden by user, project, or system override settings.
User settings file ~/.qwen/settings.json (where ~ is your home directory). Applies to all Qwen Code sessions for the current user.
Project settings file .qwen/settings.json within your project's root directory. Applies only when running Qwen Code from that specific project. Project settings override user settings.
System settings file Linux /etc/qwen-code/settings.json
Windows: C:\ProgramData\qwen-code\settings.json
macOS: /Library/Application Support/QwenCode/settings.json
The path can be overridden using the QWEN_CODE_SYSTEM_SETTINGS_PATH environment variable.
Applies to all Qwen Code sessions on the system, for all users. System settings override user and project settings. May be useful for system administrators at enterprises to have controls over users' Qwen Code setups.

Note

Note on environment variables in settings: String values within your settings.json files can reference environment variables using either $VAR_NAME or ${VAR_NAME} syntax. These variables will be automatically resolved when the settings are loaded. For example, if you have an environment variable MY_API_TOKEN, you could use it in settings.json like this: "apiKey": "$MY_API_TOKEN".

The .qwen directory in your project

In addition to a project settings file, a project's .qwen directory can contain other project-specific files related to Qwen Code's operation, such as:

Configuration migration

Qwen Code automatically migrates legacy configuration settings to the new format. Old settings files are backed up before migration. The following settings have been renamed from negative (disable*) to positive (enable*) naming:

Old Setting New Setting Notes
disableAutoUpdate + disableUpdateNag general.enableAutoUpdate Consolidated into a single setting
disableLoadingPhrases ui.accessibility.enableLoadingPhrases
disableFuzzySearch context.fileFiltering.enableFuzzySearch
disableCacheControl model.generationConfig.enableCacheControl

Note

Boolean value inversion: When migrating, boolean values are inverted (e.g., disableAutoUpdate: true becomes enableAutoUpdate: false).

Consolidation policy for disableAutoUpdate and disableUpdateNag

When both legacy settings are present with different values, the migration follows this policy: if either disableAutoUpdate or disableUpdateNag is true, then enableAutoUpdate becomes false:

disableAutoUpdate disableUpdateNag Migrated enableAutoUpdate
false false true
false true false
true false false
true true false

Available settings in settings.json

Settings are organized into categories. Most settings should be placed within their corresponding top-level category object in your settings.json file. A few top-level settings like proxy and plansDirectory remain direct root keys for compatibility.

general

Setting Type Description Default
general.preferredEditor string The preferred editor to open files in. undefined
general.vimMode boolean Enable Vim keybindings. false
general.enableAutoUpdate boolean Enable automatic update checks and installations on startup. true
general.showSessionRecap boolean Auto-show a one-line "where you left off" recap when returning to the terminal after being away. Off by default. Use /recap to trigger manually regardless of this setting. false
general.sessionRecapAwayThresholdMinutes number Minutes the terminal must be blurred before an auto-recap fires on focus-in. Only used when showSessionRecap is enabled. 5
general.gitCoAuthor.commit boolean Add a Co-authored-by trailer to git commit messages AND attach a per-file AI-attribution git note (refs/notes/ai-attribution) for commits made through Qwen Code. Disabling skips both. true
general.gitCoAuthor.pr boolean Append a Qwen Code attribution line to pull request descriptions when running gh pr create. true
general.defaultFileEncoding enum Default encoding for new files. Use "utf-8" (default) for UTF-8 without BOM, or "utf-8-bom" for UTF-8 with BOM. Only change this if your project specifically requires BOM. "utf-8"
general.voice.enabled boolean Enable voice dictation in the prompt input. Also toggleable with the /voice command. Requires a transcription model (voiceModel) to be configured. false
general.voice.mode enum How push-to-talk behaves: "hold" to talk while the key is held, or "tap" to start and tap (or pause) to stop and submit. "hold"
general.voice.language string Preferred spoken language for voice transcription (e.g. "english", "chinese"). Leave empty to auto-detect. ""
general.voice.keytermsFile string Path to a custom keyterms file (one term per line, # for comments) that biases voice transcription toward domain-specific terms. Relative paths resolve from the workspace root; defaults to .qwen/voice-keyterms.txt when present. Read only in trusted workspaces. Only applies to Qwen ASR models (qwen3-asr-*). ""
general.voice.refineTranscript boolean Clean up voice transcripts with the fast model before inserting them — removes filler words and fixes recognition errors while preserving meaning. Falls back to the raw transcript on failure, and is skipped when no fast model is configured. true
general.cleanupPeriodDays number Days to retain ~/.qwen/file-history/ session backups used by /rewind. Backups older than this are removed by a background pass that runs at most once per day. 0 = minimum retention (~1 hour): keeps sessions touched in the last hour plus the currently active one. Changes take effect after restart. 30
general.language enum Language for the user interface. Use "auto" to detect from system settings, or a language code (e.g. "zh-CN", "fr"). Custom codes can be added by placing JS locale files in ~/.qwen/locales/. See i18n. Requires restart. "auto"
general.outputLanguage string Language for model output. Use "auto" to detect from system settings, or set a specific language. Requires restart. "auto"
general.dynamicCommandTranslation boolean Enable AI translation of dynamic slash-command descriptions. When disabled, dynamic commands keep their original descriptions and skip translation model calls. false
general.terminalBell boolean Play a terminal bell sound when a response completes or needs approval. true
general.preventSystemSleep boolean Prevent the system from sleeping while Qwen Code is streaming a model response or executing tools. Idle prompt time and permission prompts do not inhibit sleep. Read once at startup, so changes take effect after restart. true
general.chatRecording boolean Save chat history to disk. Disabling this also prevents --continue and --resume from working. Requires restart. true

output

Setting Type Description Default Possible Values
output.format string The format of the CLI output. "text" "text", "json"
output.showTimestamps boolean Show an [HH:MM:SS] timestamp before each assistant response. false

review

Setting Type Description Default
review.attribution boolean Append the attribution footer naming the model and CLI version (e.g. _— qwen3-coder via Qwen Code /review (v0.21.2)_) to review bodies and inline comments posted by /review. Disable to post reviews without AI attribution. With the footer off, presubmit duplicate detection still recognizes earlier posts by the same GitHub account, but footer-less posts from other accounts escape it. true
review.effort enum Default effort for /review when --effort is not given: "low", "medium", "high", or "auto" (the built-in rule: high for PRs, medium for local changes). An explicit --effort wins; an effective --comment still forces high and --fix still floors at medium. "auto"
review.comment boolean Treat every PR /review as if --comment was passed: findings are posted to the pull request without the flag. The post still binds to the PR named in the invocation. Enable only if you always want reviews published. false
review.severityFloor enum The lowest severity a PR /review posts when --severity-floor is not given: "auto" (the round-adaptive default — Suggestions post through round 5, only Criticals from round 6, with otherwise-postable high-confidence Suggestions recorded and deferred, and rounds 25 deferring new Suggestions on code unchanged since the previous round; low-confidence and Nice-to-have findings stay terminal-only), "critical" (that posture from round 1), or "suggestion" (Suggestions post at every round; turns the convergence posture off). Non-PR targets have no rounds and ignore this. "auto"

These settings are read from operator scopes only (User, System, and SystemDefaults); values in a workspace .qwen/settings.json are ignored, so a repository cannot set review policy for its reviewers.

ui

Setting Type Description Default
ui.theme string The color theme for the UI. See Themes for available options. "Qwen Dark"
ui.customThemes object Custom theme definitions. {}
ui.statusLine object Custom status line configuration. Supports command, refreshInterval, respectUserColors, and hideContextIndicator options. See Status Line. undefined
ui.hideWindowTitle boolean Hide the window title bar. false
ui.hideTips boolean Hide all tips (startup and post-response) in the UI. See Contextual Tips. false
ui.hideBanner boolean Hide the startup ASCII logo and info panel. Tips and chat input still render unless ui.hideTips is also set. false
ui.customBannerTitle string Replace the default >_ Qwen Code title in the banner info panel. The (vX.Y.Z) version suffix is always appended; auth, model, and path lines are not affected. Sanitized; capped at 80 characters. ""
ui.customBannerSubtitle string Optional subtitle line rendered between the banner title and the auth/model line, in place of the blank spacer row. Sanitized; capped at 160 characters. Empty (default) keeps the original blank spacer. ""
ui.customAsciiArt string | object Replace the QWEN ASCII logo in the banner. Accepts an inline string (used for both width tiers), { "path": "./brand.txt" } (relative paths resolve against the owning settings file's directory; read once at startup with O_NOFOLLOW on POSIX, capped at 64 KB), or { "small": ..., "large": ... } for width-aware selection. Sanitized; capped at 200 lines × 200 columns per tier. undefined
ui.showLineNumbers boolean Show line numbers in code blocks in the CLI output. true
ui.renderMode string Default Markdown display mode. Use "render" for rich visual previews or "raw" to show source-oriented Markdown by default. Toggle during a session with Alt/Option+M; on macOS the terminal must send Option as Meta. See Markdown Rendering. "render"
ui.showCitations boolean Show citations for generated text in the chat. false
ui.history.collapseOnResume boolean Whether to collapse history by default when resuming a session. Can be toggled via /history collapse-on-resume and /history expand-on-resume. false
ui.history.collapsePreviewCount number Number of most recent user turns to keep visible when ui.history.collapseOnResume is enabled. 0 collapses all restored history by default; -1 shows all restored history. 0
ui.compactMode boolean Retired in the terminal UI. The CLI now always shows the compact, type-based tool view in the main transcript; press Ctrl+O to toggle expanded detail mode (expand or collapse all thinking blocks and tool outputs inline) instead of toggling a mode. Still honored by the web shell. false
ui.shellOutputMaxLines number Max number of shell output lines shown inline. Set to 0 to disable the cap and show full output. Hidden lines are surfaced via the +N lines indicator. Errors, !-prefix user-initiated commands, confirming tools, and focused embedded shells always show full output. 5
ui.enableWelcomeBack boolean Show welcome back dialog when returning to a project with conversation history. When enabled, Qwen Code will automatically detect if you're returning to a project with a previously generated project summary (.qwen/PROJECT_SUMMARY.md) and show a dialog allowing you to continue your previous conversation or start fresh. If you choose Start new chat session, that choice is remembered for the current project until the project summary changes. This feature integrates with the /summary command and quit confirmation dialog. true
ui.accessibility.enableLoadingPhrases boolean Enable loading phrases (disable for accessibility). true
ui.accessibility.screenReader boolean Enables screen reader mode, which adjusts the TUI for better compatibility with screen readers. false
ui.customWittyPhrases array of strings A list of custom phrases to display during loading states. When provided, the CLI will cycle through these phrases instead of the default ones. []
ui.showResponseTokensPerSecond boolean Show a live tokens/sec estimate next to the response token counter while the model is streaming. This is a generation-speed hint, not an ETA or completion percentage. Takes effect in the next session. false
ui.enableFollowupSuggestions boolean Enable followup suggestions that predict what you want to type next after the model responds. Suggestions appear as placeholder text and are accepted with Tab, Enter, or Right Arrow (which fill the input — they do not auto-submit). On by default; set to false to opt out. true
ui.enableCacheSharing boolean Use cache-aware forked queries for suggestion generation. Reduces cost on providers that support prefix caching (experimental). true
ui.enableSpeculation boolean Speculatively execute accepted suggestions before submission. Results appear instantly when you accept (experimental). false
ui.showStatusInTitle boolean Show the Qwen Code session name and status in the terminal window title. true
ui.disableWorkflowKeywordTrigger boolean When true, mentioning the word workflow in a prompt no longer softly steers the turn toward the Workflow tool (and the Footer workflow active indicator is suppressed). Only applies when workflows are enabled. false
ui.enableUserFeedback boolean Show an optional feedback dialog after conversations to help improve Qwen performance. true
ui.compactInline boolean Compact tool display within each group instead of merging across groups. Requires ui.compactMode to be enabled. Requires restart. false
ui.useTerminalBuffer boolean Render conversation history in an in-app scrollable viewport instead of the terminal scrollback buffer. Enabled by default in compatible interactive terminals to avoid flicker, scroll-storm, and interface freeze on long sessions. Scroll with Shift+↑/↓ (line), PgUp/PgDn (page), Ctrl+Home/End (top/bottom), or the mouse wheel. Does not use the host terminal scrollback while enabled; drag to select text (double/triple click selects a word/line), or hold Shift (or Option on macOS) while dragging for the terminal's own selection. Mouse interactions (wheel, drag-select, click, hover) require ui.mouseTracking (on by default). true
ui.showScrollbar boolean Show the auto-hiding scrollbar in the in-app scrollable viewport (Virtualized History). The bar appears while scrolling and fades out when idle. Disable to hide it entirely. Only applies in the interactive terminal UI. true
ui.mouseTracking boolean Enable in-app SGR mouse tracking for text selection, click-to-position in text inputs, row hover, history-item toggling, and viewport scrolling. While enabled, the terminal forwards all mouse events to the app, so native right-click context menus and OSC 8 hyperlink clicks are unavailable. Disable to restore native right-click and clickable URL links; this turns off all in-app mouse interaction, and in Virtualized History the wheel no longer scrolls the transcript — use Shift+↑/↓, PgUp/PgDn, or Ctrl+Home/End instead (pair with ui.useTerminalBuffer: false to restore native terminal scrollback). Only applies in the interactive terminal UI. true
ui.hideBuiltinWorktreeIndicator boolean Hide the built-in ⎇ worktree-<branch> (<slug>) line in the Footer. The worktree state is still passed to custom statusline scripts via the stdin payload. Keep at the default unless your custom statusline renders the worktree itself. false

ide

Setting Type Description Default
ide.enabled boolean Enable IDE integration mode. false
ide.hasSeenNudge boolean Whether the user has seen the IDE integration nudge. false

privacy

Setting Type Description Default
privacy.usageStatisticsEnabled boolean Enable collection of usage statistics. true

model

Setting Type Description Default
model.name string The Qwen model to use for conversations. undefined
model.reasoningEffort enum How hard reasoning-capable models think, applied across all providers. Set with the /effort command (low, medium, high, xhigh, max). Each provider maps and clamps this to what the active model supports (e.g. Gemini caps at high; Anthropic clamps tiers a model lacks). Leave unset to use the model/provider default. undefined
model.baseUrl string Persisted automatically by the model picker to disambiguate when multiple modelProviders entries share the same model id. Not intended to be set by hand — use the /model picker or a modelProviders entry instead; a stale hand-edited value can silently route requests to a different same-id provider. undefined
model.sessionTokenLimit number Maximum recorded prompt token count allowed before sending the next message. -1 means unlimited; 0 is also treated as unlimited (unlike model.maxToolCalls, where 0 disallows all calls). When the recorded prompt count exceeds the limit, the next send is dropped (the session is not aborted). -1
model.maxSessionTurns integer Maximum number of user/model/tool turns to keep in a session. -1 means unlimited. -1
model.maxWallTimeSeconds number Wall-clock budget for headless / unattended runs, in seconds. -1 means unlimited. Overridable per-invocation via --max-wall-time, which requires a positive duration (90, 30s, 5m, 1h, 1.5h); the minimum is 1 second — sub-second values (500ms, 0.5) are rejected as typos. Omit the flag to fall back to this setting. Aborts with exit code 55 when exceeded. -1
model.maxToolCalls number Cumulative tool-call budget for a run (counts every executed tool, success or failure; structured_output under --json-schema is exempt). -1 means unlimited; 0 means "no tool calls allowed". Capped at 1,000,000 to catch typos. Overridable via --max-tool-calls. Aborts with exit code 55 when exceeded. -1
model.maxSubagentDepth number Maximum sub-agent nesting depth (1-based levels: a top-level sub-agent is level 1). 1 keeps sub-agents available but disables nesting — the pre-nesting behavior. Values clamp to the range 1100; non-finite values fall back to the default. Teammates, forks, and workflow-spawned agents never nest regardless of this setting. Overridable via --max-subagent-depth. 5
model.generationConfig object Advanced overrides passed to the underlying content generator. Supports request controls such as timeout, maxRetries, retryInitialDelayMs, retryMaxDelayMs, enableCacheControl, splitToolMedia (default true; splits tool-returned media — including images read by the built-in read_file — into a follow-up user message instead of the spec-violating role: "tool" message, so strict OpenAI-compatible servers like doubao / new-api / LM Studio can see it; set false to restore the legacy embed-in-tool behavior), toolResultContentFormat (default "parts"; set "string" only for legacy OpenAI-compatible runtimes whose tool templates ignore text content parts), contextWindowSize (override model's context window size), modalities (override auto-detected input modalities), customHeaders (custom HTTP headers for API requests), and extra_body (additional body parameters for OpenAI-compatible API requests only), along with fine-tuning knobs under samplingParams (for example temperature, top_p, max_tokens). Leave unset to rely on provider defaults. undefined
model.chatCompression.contextPercentageThreshold number REMOVED. Replaced by context.autoCompactThreshold (see #### context section below). Auto-compaction now uses a three-tier threshold ladder (warn / auto / hard) computed internally from the model's context window via the computeThresholds() function. The old setting is silently ignored (no startup warning). See PR #4345 / docs/design/auto-compaction-threshold-redesign.md for the redesign rationale. N/A
model.chatCompression.maxRecentFilesToRetain number Number of most-recently-touched files whose current content is restored (embedded if small, otherwise referenced by path) into history after auto-compaction. 0 restores none. Env override: QWEN_COMPACT_MAX_RECENT_FILES. 5
model.chatCompression.maxRecentImagesToRetain number Number of most-recent images (tool screenshots / user pastes) restored into history after auto-compaction. 0 restores none. Env override: QWEN_COMPACT_MAX_RECENT_IMAGES. 3
model.chatCompression.enableScreenshotTrigger boolean When true, auto-compaction also fires once the number of tool-returned images accumulated in history reaches screenshotTriggerThreshold, independent of token usage — aimed at computer-use sessions where frequent screenshots dilute model attention. Counts only images returned inside tool results, not user-pasted images. Env override: QWEN_COMPACT_SCREENSHOT_TRIGGER (1/true/0/false). true
model.chatCompression.screenshotTriggerThreshold number Tool-returned image count at or above which the screenshot trigger fires (only when enableScreenshotTrigger). Compaction resets the count — surviving images are re-embedded as top-level parts, which the trigger doesn't count — so it won't immediately re-fire. Env override: QWEN_COMPACT_SCREENSHOT_THRESHOLD. 20
model.skipNextSpeakerCheck boolean Skip the next speaker check. true
model.skipLoopDetection boolean Disables streaming loop detection checks. Defaults to true (loop detection is skipped) to avoid false positives interrupting legitimate workflows. Set to false to re-enable streaming loop detection — useful as a guardrail in headless / non-interactive runs where stuck repetition can otherwise waste budget. In daemon/ACP sessions, which run none of the other streaming detectors, re-enabling also activates a global-duplicate tool-call halt; the always-on per-turn tool-call cap and an invalid-tool-params stagnation guard run there regardless of this setting. true
model.maxToolCallsPerTurn integer Per-turn tool-call cap (one model turn plus its tool-result continuations; blocking Stop-hook continuations such as /goal iterations start a fresh budget). When set explicitly, this value is a hard cap: the turn halts on the next tool call after it is reached (the released behavior). When left unset (default 100), the cap is adaptive: once the turn exceeds 100 it halts only when the model keeps repeating the same call (a stuck loop); a productive turn (diverse calls) continues up to a hard backstop of 1000, which always halts. The adaptive default applies to the interactive TUI, non-interactive (-p / JSON / stream-JSON) core-client runs, and daemon/ACP sessions alike. Daemon/ACP sessions evaluate the cap once per tool batch, before execution: a batch that would cross an explicit cap or the hard backstop is skipped whole, so a turn never executes past either (it can halt up to one batch short), while the adaptive soft cap is exceeded by design, up to the backstop. They also have no in-session disable. Always-on circuit breaker against runaway turns, independent of model.skipLoopDetection. Set to 0 or a negative value to disable the cap. Choosing "Disable loop detection for this session" in the loop-detected dialog also suppresses it for the rest of the session. 100
model.skipStartupContext boolean Skips sending the startup workspace context (environment summary and acknowledgement) at the beginning of each session. Enable this if you prefer to provide context manually or want to save tokens on startup. false
model.enableOpenAILogging boolean Enables logging of OpenAI API calls for debugging and analysis. When enabled, API requests and responses are logged to JSON files. false
model.openAILoggingDir string Custom directory path for OpenAI API logs. If not specified, defaults to logs/openai in the current working directory. Supports absolute paths, relative paths (resolved from current working directory), and ~ expansion (home directory). undefined
model.openAILogRetentionDays number Days to retain OpenAI API log files written when model.enableOpenAILogging is on. Completed background housekeeping passes run at most once per day in interactive, headless, stream-json SDK, and ACP sessions. Short-lived non-interactive processes make best-effort progress, while persistent processes scan to completion. 0 = minimum retention (~1 hour). For a custom model.openAILoggingDir, configure retention at user or system scope; workspace-scoped retention is skipped because one custom directory can be shared by multiple workspaces. Changes take effect after restart. 7

Example model.generationConfig:

{
  "model": {
    "generationConfig": {
      "timeout": 60000,
      "contextWindowSize": 128000,
      "modalities": {
        "image": true
      },
      "enableCacheControl": true,
      "toolResultContentFormat": "parts",
      "customHeaders": {
        "X-Client-Request-ID": "req-123"
      },
      "extra_body": {
        "enable_thinking": true
      },
      "samplingParams": {
        "temperature": 0.2,
        "top_p": 0.8,
        "max_tokens": 1024
      }
    }
  }
}

timeout (request timeout):

timeout is the per-request timeout in milliseconds (default 120000). Set it to 0 to disable the request timeout — matching the QWEN_STREAM_IDLE_TIMEOUT_MS=0 convention — rather than aborting the request. It can also be set via the QWEN_CODE_API_TIMEOUT_MS environment variable. This is distinct from the two stream guards below.

stream guards (OpenAI-compatible providers only):

Two guards bound a streaming response, each accepting 0 to disable. Neither is implemented by the Anthropic/Gemini generators, which leave the drip-fed shape below unbounded.

  • QWEN_STREAM_IDLE_TIMEOUT_MS (default 240000) bounds inactivity between streamed chunks: a stream that goes silent for this long is aborted as a retryable ETIMEDOUT.
  • QWEN_STREAM_MAX_LIFETIME_MS (default 900000) caps the total upstream-wait time of one streaming response regardless of chunk flow — the bound a drip-fed stream that never completes cannot reset.

These are environment variables (or, for embedders, ContentGeneratorConfig.streamIdleTimeoutMs / streamMaxLifetimeMs) only — there is no settings.json key; writing "streamMaxLifetimeMs" into settings.json has no effect. Upgrade notes: a deployment that previously set QWEN_STREAM_IDLE_TIMEOUT_MS=0 — or passed streamIdleTimeoutMs: 0 in ContentGeneratorConfig — to opt out of stream aborts now also needs QWEN_STREAM_MAX_LIFETIME_MS=0 (or streamMaxLifetimeMs: 0) to keep that; and the 15-minute lifetime cap bounds even a stream whose idle timeout you raised above it (e.g. QWEN_STREAM_IDLE_TIMEOUT_MS=1800000) — raise the cap likewise, or set it to 0, if you rely on a longer window.

max_tokens (output token limit):

When neither samplingParams.max_tokens nor QWEN_CODE_MAX_OUTPUT_TOKENS is set, Qwen Code generally uses the selected model's declared output limit as the request's default output limit. If the response still hits that limit, Qwen Code may retry with an escalated limit (using a 64K floor) and then recover across continuation turns.

For OpenAI-compatible providers, samplingParams is also a wire-shape escape hatch: when it is set, its keys are passed through verbatim and Qwen Code does not synthesize a max_tokens default. Use this for provider-specific parameters such as max_completion_tokens.

To force a fixed output limit, set samplingParams.max_tokens in your settings or use the QWEN_CODE_MAX_OUTPUT_TOKENS environment variable. Explicit limits disable automatic output-token escalation.

toolResultContentFormat:

Controls how text-only tool results are serialized in OpenAI-compatible requests. The default "parts" keeps the standard content-part array shape. Set "string" only for legacy OpenAI-compatible runtimes whose tool templates ignore text content parts, such as older GLM-5.1 vLLM/SGLang templates. Tool-returned media is still controlled by splitToolMedia.

contextWindowSize:

Overrides the default context window size for the selected model. Qwen Code determines the context window using built-in defaults based on model name matching, with a constant fallback value. Use this setting when a provider's effective context limit differs from Qwen Code's default. This value defines the model's assumed maximum context capacity, not a per-request token limit.

When the selected model is defined in modelProviders, set contextWindowSize in that provider entry's generationConfig instead of the top-level model.generationConfig. Provider model entries are sealed, so top-level generation settings do not fill missing provider fields.

modalities:

Overrides the auto-detected input modalities for the selected model. Qwen Code automatically detects supported modalities (image, PDF, audio, video) based on model name pattern matching. Use this setting when the auto-detection is incorrect — for example, to enable pdf for a model that supports it but isn't recognized. Format: { "image": true, "pdf": true, "audio": true, "video": true }. Omit a key or set it to false for unsupported types.

customHeaders:

Allows you to add custom HTTP headers to all API requests. This is useful for request tracing, monitoring, API gateway routing, or when different models require different headers. For provider models, define customHeaders in modelProviders[].generationConfig.customHeaders. For runtime models without a matching provider entry, define it in model.generationConfig.customHeaders. No merging occurs between the two levels.

The extra_body field allows you to add custom parameters to the request body sent to the API. This is useful for provider-specific options that are not covered by the standard configuration fields. Note: This field is only supported for OpenAI-compatible providers (openai, qwen-oauth). It is ignored for Anthropic and Gemini providers. For provider models, define extra_body in modelProviders[].generationConfig.extra_body. For runtime models without a matching provider entry, define it in model.generationConfig.extra_body.

model.openAILoggingDir examples:

  • "~/qwen-logs" - Logs to ~/qwen-logs directory
  • "./custom-logs" - Logs to ./custom-logs relative to current directory
  • "/tmp/openai-logs" - Logs to absolute path /tmp/openai-logs

fastModel

Setting Type Description Default
fastModel string Model used for generating prompt suggestions and speculative execution. Leave empty to use the main model. A smaller/faster model (e.g., qwen3-coder-flash) reduces latency and cost. Can also be set via /model --fast. ""

visionModel

Setting Type Description Default
visionModel string Image-capable model used as the vision bridge: when a text-only main model receives an image, or read_file needs the bounded PDF visual fallback, it is transcribed by this model first. Setting this explicitly authorizes bridge calls to that model even when it uses another provider; the tool display discloses the endpoint. Leave empty to auto-pick a same-provider vision model. Can also be set via /model --vision. ""

compactionModel

Setting Type Description Default
compactionModel string Model used for chat compression (auto-compaction). Leave empty to fall back to the main model. A smaller or faster model can reduce compression latency and cost. Can also be set or cleared via /model --compaction. ""

imageModel

Setting Type Description Default
imageModel string Model used by the built-in image_gen tool. The selected model must have imageOnly: true, an HTTPS baseUrl, and envKey in modelProviders. Leave empty to keep the tool unavailable. Can also be set via /model --image. ""

visionBridgeTimeoutMs

Setting Type Description Default
visionBridgeTimeoutMs integer Per-attempt timeout in milliseconds for the vision bridge image transcription call (positive integer up to 2147483647; the bridge retries a timed-out attempt once with a fresh timeout). Unset uses the built-in 30s. Raise for slow or proxied vision endpoints. unset

voiceModel

Setting Type Description Default
voiceModel string Model used for voice transcription. Leave empty to keep voice dictation disabled until a voice model is selected. Can also be set via /model --voice. ""

modelFallbacks

Setting Type Description Default
modelFallbacks string Ordered list of fallback model IDs (comma-separated, max 3) to try when the primary model hits capacity errors (429/503/529). Example: "qwen-plus,qwen-turbo". Can also be set via the --fallback-model CLI flag. Requires restart. ""

modelPricing

Setting Type Description Default
modelPricing object Optional per-model pricing for cost estimation in /stats model. Example: { "qwen3-coder": { "inputPerMillionTokens": 0.30, "outputPerMillionTokens": 1.20 } }. undefined

context

Setting Type Description Default
context.fileName string or array of strings The name of the context file(s). undefined
context.autoCompactThreshold number Target fraction of the context window at which auto-compaction triggers. Must be greater than 0 and at most 1. Default is 0.85 (85%). Acts as a ceiling on the trigger: on large windows it is the effective trigger (~85%), while on smaller windows compaction may fire earlier to leave room to summarize. Replaces the old model.chatCompression.contextPercentageThreshold. undefined (uses internal 0.85)
context.importFormat string The format to use when importing memory. undefined
context.includeDirectories array Additional directories to include in the workspace context. Specifies an array of additional absolute or relative paths to include in the workspace context. Missing directories will be skipped with a warning by default. Paths can use ~ to refer to the user's home directory. This setting can be combined with the --include-directories command-line flag. []
context.loadFromIncludeDirectories boolean Controls the behavior of the /memory refresh command. If set to true, QWEN.md files should be loaded from all directories that are added. If set to false, QWEN.md should only be loaded from the current directory. false
context.fileFiltering.respectGitIgnore boolean Respect .gitignore files when searching. true
context.fileFiltering.respectQwenIgnore boolean Respect .qwenignore and configured custom ignore files when searching. true
context.fileFiltering.customIgnoreFiles array Project-root-relative ignore files to use instead of the default compatibility files (.agentignore, .aiignore) when respectQwenIgnore is enabled. .qwenignore is always included. [".agentignore", ".aiignore"]
context.fileFiltering.enableRecursiveFileSearch boolean Whether to enable searching recursively for filenames under the current tree when completing @ prefixes in the prompt. true
context.fileFiltering.enableFuzzySearch boolean When true, enables fuzzy search capabilities when searching for files. Set to false to improve performance on projects with a large number of files. true
context.clearContextOnIdle.toolResultsThresholdMinutes number Minutes of inactivity before clearing old tool result content. Use -1 to disable the idle trigger. 60
context.clearContextOnIdle.toolResultsNumToKeep integer Integer number of most-recent compactable tool results to preserve when clearing. Values below 1 are floored to 1. 5
context.clearContextOnIdle.toolResultsTotalCharsThreshold number Total compactable tool result output characters allowed in history before clearing oldest results. When exceeded, oldest results are cleared down to half this threshold (best effort) so later turns keep reusing the provider prompt cache instead of rewriting history every turn. Use -1 to disable the size trigger. This is a soft threshold: protected recent tool results may keep the total above it. 500000

Troubleshooting File Search Performance

If you are experiencing performance issues with file searching (e.g., with @ completions), especially in projects with a very large number of files, here are a few things you can try in order of recommendation:

  1. Use an ignore file: Create a .qwenignore or configured custom ignore file in your project root to exclude directories that contain a large number of files that you don't need to reference (e.g., build artifacts, logs, node_modules). Reducing the total number of files crawled is the most effective way to improve performance.
  2. Disable Fuzzy Search: If ignoring files is not enough, you can disable fuzzy search by setting enableFuzzySearch to false in your settings.json file. This will use a simpler, non-fuzzy matching algorithm, which can be faster.
  3. Disable Recursive File Search: As a last resort, you can disable recursive file search entirely by setting enableRecursiveFileSearch to false. This will be the fastest option as it avoids a recursive crawl of your project. However, it means you will need to type the full path to files when using @ completions.

tools

Setting Type Description Default Notes
tools.sandbox boolean or string Sandbox execution environment (can be a boolean or a path string). undefined
tools.sandboxImage string Sandbox image URI used by Docker/Podman when --sandbox-image and QWEN_SANDBOX_IMAGE are not set. undefined
tools.shell.enableInteractiveShell boolean Use node-pty for an interactive shell experience. Fallback to child_process still applies. true
tools.shell.defaultTimeoutMs number Default timeout, in milliseconds, for foreground shell commands started by the agent. A per-call timeout on the shell tool overrides this. When unset, foreground commands time out after 120000 ms (2 minutes). Set to 0 to disable the timeout. undefined
tools.shell.heartbeatIntervalMs number Interval, in milliseconds, between liveness heartbeats emitted while a foreground shell command produces no output. Heartbeats are forwarded to ACP clients and stream-json consumers so they can tell a silent command from a dead session. When unset, heartbeats fire every 10000 ms (10 seconds). Set to 0 to disable heartbeats. undefined
tools.core array of strings Deprecated. Will be removed in next version. Use permissions.allow + permissions.deny instead. Restricts built-in tools to an allowlist. All tools not in the list are disabled. undefined
tools.exclude array of strings Deprecated. Use permissions.deny instead. Tool names to exclude from discovery. Automatically migrated to the permissions format on first load. undefined
tools.disabled array of strings Tool names hidden from the registry entirely. Unlike permissions.deny (which blocks calls at runtime), disabled tools are never registered, so they do not appear in /tools and cannot be discovered or called by the model. For example, ["enter_plan_mode"] prevents the model from switching into plan mode on its own. Merged as a union across scopes. undefined
tools.visible array of strings Deferred tool names made visible at startup without requiring tool_search. Listed tools appear alongside core tools in the initial session. Merged as a union across scopes. undefined
tools.allowed array of strings Deprecated. Use permissions.allow instead. Tool names that bypass the confirmation dialog. Automatically migrated to the permissions format on first load. undefined
tools.approvalMode string Sets the default approval mode for tool usage. auto Possible values: plan (analyze only, do not modify files or execute commands), default (require approval before file edits or shell commands run), auto-edit (automatically approve file edits), auto (LLM classifier auto-approves safe actions, blocks risky ones), yolo (automatically approve all tool calls)
tools.discoveryCommand string Command to run for tool discovery. undefined
tools.callCommand string Defines a custom shell command for calling a specific tool that was discovered using tools.discoveryCommand. The shell command must meet the following criteria: It must take function name (exactly as in function declaration) as first command line argument. It must read function arguments as JSON on stdin, analogous to functionCall.args. It must return function output as JSON on stdout, analogous to functionResponse.response.content. undefined
tools.useRipgrep boolean Use ripgrep for file content search instead of the fallback implementation. Provides faster search performance. true
tools.useBuiltinRipgrep boolean Use the bundled ripgrep binary. When set to false, the system-level rg command will be used instead. This setting is only effective when tools.useRipgrep is true. true
tools.truncateToolOutputThreshold number Truncate tool output if it is larger than this many characters. Applies to Shell, Grep, Glob, ReadFile and ReadManyFiles tools. 25000 Requires restart: Yes
tools.truncateToolOutputLines number Maximum lines or entries kept when truncating tool output. Applies to Shell, Grep, Glob, ReadFile and ReadManyFiles tools. 1000 Requires restart: Yes
tools.computerUse.enabled boolean Enable the built-in Computer Use tools (cua-driver native desktop automation). When true (default), the computer_use__* tools are registered as deferred built-ins; the first invocation downloads the pinned, signed cua-driver binary into ~/.qwen/computer-use/ and walks through macOS Accessibility / Screen Recording permissions. true Requires restart: Yes
tools.computerUse.maxImageDimension number Longest-edge pixel cap applied to cua-driver screenshots (via set_config's max_image_dimension). -1 (default) keeps cua-driver's built-in default (1568); 0 disables resizing (full resolution); a positive value caps the longest edge. Lower caps cut vision-token cost at the expense of fine detail. -1 Requires restart: Yes. Env override: QWEN_COMPUTER_USE_MAX_IMAGE_DIMENSION (a non-negative integer; takes precedence over this setting)
tools.computerUse.idleTimeoutMs number Milliseconds to keep the cua-driver process alive after the last computer_use__* call. The default is 300000 (5 minutes). Set to 0 to keep it running until Qwen Code exits. 300000 Requires restart: Yes
tools.toolSearch.enabled boolean Load MCP tools on demand via ToolSearch to reduce prompt size. Disable this for models that rely on prefix-based KV caching (e.g. DeepSeek) to keep the prompt prefix stable and maximize cache hit rates. true Requires restart: Yes
tools.toolSearch.threshold number Context-window percentage used as the session-start budget for preloading deferred tools (bundled built-ins and MCP alike). When the combined schemas of every deferred tool fit within this budget, they are all declared upfront instead of loaded on demand via ToolSearch — a stable declaration list keeps prefix KV caches valid for the whole session. Set 0 to always load deferred tools on demand. 10 Requires restart: Yes

Note

Migrating from tools.core / tools.exclude / tools.allowed: These legacy settings are deprecated and automatically migrated to the new permissions format on first load. Prefer configuring permissions.allow / permissions.deny directly. Use /permissions to manage rules interactively.

memory

Setting Type Description Default
memory.enableManagedAutoMemory boolean Enable background extraction of memories from conversations. true
memory.enableManagedAutoDream boolean Enable automatic consolidation (deduplication and cleanup) of collected memories. true
memory.enableAutoSkill boolean Enable background review for reusable project skills after tool-heavy sessions. true
memory.autoSkillConfirm boolean Ask for confirmation before auto-generated skills are added to the skill library. When off, auto-skills are saved immediately. true
memory.enableTeamMemory boolean Enable a project memory tier shared with collaborators via the git-tracked .qwen/team-memory/ directory. Writes to it are secret-scanned and reviewable in the git diff. false
memory.enableTeamMemorySync boolean When team memory is enabled, automatically commit, fast-forward-pull, and push the .qwen/team-memory/ directory at session start so collaborators stay in sync. Requires a configured git upstream. false
memory.agentTimeoutMinutes number Max runtime in minutes for background memory agents (extraction, dream, remember, skill review). Unset uses each agent's built-in default (25 minutes); 0 disables the time limit. unset
memory.agentMaxTurns number Max turns for background memory agents (extraction, dream, remember, skill review). Unset uses each agent's built-in default (58); 0 disables the turn limit. unset

See Memory for details on how auto-memory works and how to use the /memory, /remember, and /dream commands.

agents

Setting Type Description Default
agents.builtin.exploreModel string Model selector for the built-in Explore subagent. Use inherit for the main session model, fast for fastModel, a model ID, or an authType:model-id selector. A custom same-name Explore agent keeps its own model configuration. Requires restart. inherit
agents.modelGrades object Maps semantic grade names exposed to the Agent tool to model selectors. Requires restart. undefined
agents.allowedGrades array of strings Optional whitelist of configured model grades the Agent tool may use. Requires restart. undefined

permissions

The permissions system provides fine-grained control over which tools can run, which require confirmation, and which are blocked.

Decision priority (highest first): deny > ask > allow > (default/interactive mode)

The first matching rule wins. Rules use the format "ToolName" or "ToolName(specifier)".

Setting Type Description Default
permissions.allow array of strings Rules for auto-approved tool calls (no confirmation needed). Merged across all scopes (user + project + system). undefined
permissions.ask array of strings Rules for tool calls that always require user confirmation. Takes priority over allow. undefined
permissions.deny array of strings Rules for blocked tool calls. Highest priority — overrides both allow and ask. undefined

Tool name aliases (any of these work in rules):

Alias Canonical tool Notes
Bash, Shell run_shell_command
Read, ReadFile read_file Meta-category — see below
Edit, EditFile edit Meta-category — see below
Write, WriteFile write_file
NotebookEdit notebook_edit
NotebookEditTool notebook_edit
Grep, SearchFiles grep_search
Glob, FindFiles glob
ListFiles list_directory
WebFetch web_fetch
Agent task
Skill skill

Meta-categories:

Some rule names automatically cover multiple tools:

Rule name Tools covered
Read read_file, grep_search, glob, list_directory
Edit edit, write_file, notebook_edit

Important

Read(/path/**) matches all four read tools (file read, grep, glob, and directory listing). To restrict only file reading, use ReadFile(/path/**) or read_file(/path/**).

Rule syntax examples:

Rule Meaning
"Bash" All shell commands
"Bash(git *)" Shell commands starting with git (word boundary: NOT gitk)
"Bash(git push *)" Shell commands like git push origin main
"Bash(npm run *)" Any npm run script
"Read" All file read operations (read, grep, glob, list)
"Read(./secrets/**)" Read any file under ./secrets/ recursively
"Edit(/src/**/*.ts)" Edit TypeScript files under project root /src/
"WebFetch(api.example.com)" Fetch from api.example.com and all its subdomains
"mcp__puppeteer" All tools from the puppeteer MCP server

Path pattern prefixes:

Prefix Meaning Example
// Absolute path from filesystem root //etc/passwd
~/ Relative to home directory ~/Documents/*.pdf
/ Relative to project root /src/**/*.ts
./ Relative to current working directory ./secrets/**
(none) Same as ./ secrets/**

Shell command bypass prevention:

Permission rules for Read, Edit, and WebFetch are also enforced when the agent runs equivalent shell commands. For example, if Read(./.env) is in deny, the agent cannot bypass it via cat .env in a shell command. Supported shell commands include cat, grep, curl, wget, cp, mv, rm, chmod, and many more. Unknown/safe commands (e.g. git) are unaffected by file/network rules.

Migrating from legacy settings:

Legacy setting Equivalent permissions rule Notes
tools.allowed permissions.allow Auto-migrated on first load
tools.exclude permissions.deny Auto-migrated on first load
tools.core permissions.allow (allowlist) Auto-migrated; unlisted tools are disabled at registry level

Example configuration:

{
  "permissions": {
    "allow": ["Bash(git *)", "Bash(npm run *)", "Read(//Users/alice/code/**)"],
    "ask": ["Bash(git push *)", "Edit"],
    "deny": ["Bash(rm -rf *)", "Read(.env)", "WebFetch(malicious.com)"]
  }
}

Tip

Use /permissions in the interactive CLI to view, add, and remove rules without editing settings.json directly.

slashCommands

Controls which slash commands are available in the CLI. Useful for locking down the command surface in multi-tenant or enterprise deployments.

Setting Type Description Default
slashCommands.disabled array of strings Slash command names to hide and refuse to execute. Matched case-insensitively against the final command name (for extension commands this is the disambiguated form, e.g. myext.deploy). Merged as a union across scopes, so workspace settings can add to but not remove entries defined in user or system settings. undefined

The same denylist can also be provided via the --disabled-slash-commands CLI flag (comma-separated or repeated) and the QWEN_DISABLED_SLASH_COMMANDS environment variable; values from all three sources are unioned together.

Example — lock down built-ins for a sandboxed deployment:

{
  "slashCommands": {
    "disabled": ["auth", "mcp", "extensions", "ide", "quit"]
  }
}

With these values in a system-level settings.json (/etc/qwen-code/settings.json or QWEN_CODE_SYSTEM_SETTINGS_PATH), users cannot shrink the denylist from their own scope, and the disabled commands will not appear in autocomplete or execute when typed.

Note

This setting only gates slash commands (e.g. /auth, /mcp). It does not affect tool permissions — see permissions.deny for that. It also does not intercept keyboard shortcuts such as Ctrl+C or Esc.

skills

Controls which Skills are exposed to the model.

Setting Type Description Default
skills.disabledLevels array of strings Skill discovery levels to skip entirely. Supported values are project, user, extension, and bundled. Merged as a union across settings scopes. Use ["bundled"] to hide every bundled skill while retaining host-provided skills. Note: skills.directories entries are discovered at the user level, so ["user"] hides those too. undefined
skills.disabled array of strings Hard-disabled skill names. Matched case-insensitively and merged as a union across settings scopes, so project settings cannot override a user or system entry. Hidden skills do not appear in <available_skills> or as /<name> slash commands. undefined
skills.defaultDisabled array of strings Skill names that start disabled but can be opted into through skills.enabled. Matched case-insensitively and merged as a union across settings scopes. undefined
skills.enabled array of strings Explicit opt-ins that override matching skills.defaultDisabled entries. Matched case-insensitively and merged as a union across settings scopes. This setting cannot override skills.disabled or re-enable skills from a skills.disabledLevels-excluded level. undefined

The precedence is skills.disabled > skills.enabled > skills.defaultDisabled. For example, a user can put a skill in defaultDisabled and a project can add the same name to enabled; a hard disabled entry at any scope still wins.

mcp

Setting Type Description Default
mcp.serverCommand string Command to start an MCP server. undefined
mcp.allowed array of strings An allowlist of MCP servers to allow. Allows you to specify a list of MCP server names that should be made available to the model. This can be used to restrict the set of MCP servers to connect to. Supports glob patterns (* matches any sequence, ? matches a single character — e.g. "*puppeteer*"); entries without glob characters are matched exactly. Note that this will be ignored if --allowed-mcp-server-names is set. undefined
mcp.excluded array of strings A denylist of MCP servers to exclude. A server listed in both mcp.excluded and mcp.allowed is excluded. Supports glob patterns (*, ?) the same way as mcp.allowed. Note that this will be ignored if --allowed-mcp-server-names is set. undefined
mcp.toolIdleTimeoutMs number Idle timeout in milliseconds for MCP tool calls. If the MCP server does not produce any response or progress update within this time, the call is aborted. Must be between 10000 and 3600000. Can be overridden via the QWEN_CODE_MCP_TOOL_IDLE_TIMEOUT_MS environment variable. 300000

Note

Security Note for MCP servers: These settings use simple string matching on MCP server names, which can be modified. If you're a system administrator looking to prevent users from bypassing this, consider configuring the mcpServers at the system settings level such that the user will not be able to configure any MCP servers of their own. This should not be used as an airtight security mechanism.

lsp

Warning

Experimental Feature: LSP support is currently experimental and disabled by default. Enable it using the --experimental-lsp command line flag.

Language Server Protocol (LSP) provides code intelligence features like go-to-definition, find references, and diagnostics.

LSP server configuration is done through .lsp.json files in your project root directory, not through settings.json. See the LSP documentation for configuration details and examples.

security

Setting Type Description Default
security.folderTrust.enabled boolean Setting to track whether Folder trust is enabled. false
security.auth.selectedType string The currently selected authentication type. undefined
security.auth.enforcedType string The required auth type (useful for enterprises). undefined
security.auth.useExternal boolean Whether to use an external authentication flow. undefined
security.auth.apiKey string Deprecated. API key for OpenAI-compatible authentication. Migrate to modelProviders with envKey instead — see Model Providers. undefined
security.auth.baseUrl string Deprecated. Base URL for the OpenAI-compatible API. Migrate to modelProviders instead — see Model Providers. undefined
security.allowedInsecureVoiceBaseUrls array of strings Complete voice provider base URLs that may use HTTP or resolve to private-network addresses. Each entry must include an explicit http:// or https:// scheme and the full path (for example, /v1); only URL serialization and trailing slashes are normalized. Wildcards are not supported; metadata, link-local, local-use NAT64, 6to4, and Teredo addresses remain blocked even when listed, as do hostnames that resolve to loopback; IPv4-mapped, IPv4-compatible, and well-known NAT64 (64:ff9b::/96) literals are classified by their embedded IPv4 address. Only User, System, and SystemDefaults scopes are honored. Use only for trusted endpoints in managed private networks. Cleartext HTTP also exposes the provider API key transmitted in the Authorization header. An allowlisted hostname is only as trustworthy as its DNS; prefer IP-literal entries when the gateway address is stable. The exact match covers the batch request URL; streaming transports connect to a WebSocket URL derived from it (same scheme, host, and port, /api-ws/v1/... path), not to the allowlisted path itself. []

serve

Persistent sub-session concurrency settings for qwen serve. Changes require restarting the daemon. Non-positive or non-integer concurrency limits produce a warning and fall back to their built-in defaults.

Setting Type Description Default
serve.maxConcurrentSubSessionsPerCaller integer Maximum number of in-flight sub-sessions that one caller session can create through create_sub_session. Must be at least 1. 16
serve.maxConcurrentSubSessionsTotal integer Maximum number of in-flight sub-sessions across all callers in one workspace. Must be an integer from 1 through 1024. Values above 1024 are clamped to 1024 without a warning. 24

advanced

Setting Type Description Default
advanced.autoConfigureMemory boolean Automatically configure Node.js memory limits. false
advanced.dnsResolutionOrder string The DNS resolution order. undefined
advanced.excludedEnvVars array of strings Environment variables to exclude from project context. Specifies environment variables that should be excluded from being loaded from project .env files. This prevents project-specific environment variables (like DEBUG=true) from interfering with the CLI behavior. Variables from .qwen/.env files are never excluded by this list; loader-affecting variables are always rejected from every .env scope (see below). ["DEBUG","DEBUG_MODE"]
advanced.bugCommand object Configuration for the bug report command. Overrides the default URL for the /bug command. Properties: urlTemplate (string): A URL that can contain {title} and {info} placeholders. Example: "bugCommand": { "urlTemplate": "https://bug.example.com/new?title={title}&info={info}" } undefined
plansDirectory string Custom directory for approved Plan Mode files. Relative paths are resolved from the project root, and the resolved path must stay within the project root. If unset, plan files are stored in ~/.qwen/plans. Requires restart. If the directory is inside the project root, add it to .gitignore to avoid committing plan files. undefined

experimental

Warning

Experimental features. These toggles gate in-development capabilities and may change or be removed in future releases.

Setting Type Description Default
experimental.cron boolean Enable in-session cron/loop tools (cron_create, cron_list, cron_delete) so the model can create recurring prompts. Can be disabled via the QWEN_CODE_DISABLE_CRON=1 environment variable. Requires restart. true
experimental.todoStopGuard boolean Allow daemon and ACP sessions to continue after a natural model stop when the current work chain successfully wrote an unfinished top-level Todo list. Adds at most two consecutive primary-model calls without new user input; mid-turn user input starts a fresh two-attempt stage. It is not restored after process restart and is forced off in safe, bare, and Approval plan modes. Requires restart. false
experimental.sessionWriterLease boolean Enable cross-process write fencing for persisted ACP and daemon sessions. The value is frozen when the ACP or daemon process starts. All concurrent ACP writers must enable the setting; mixed versions or configurations remain unsafe. Interactive and headless recorders are unaffected. Requires process restart. false
experimental.cronRecurringMaxAgeDays number Days a recurring cron/loop job lives before auto-expiring (it fires one final time, then is deleted). Set to 0 to disable expiry so jobs run until deleted — useful for long-running daemon deployments. Can be overridden via the QWEN_CODE_CRON_MAX_AGE_DAYS environment variable. Requires restart. 7
experimental.agentTeam boolean Enable agent-team collaboration tools (team_create, task_create, task_update, send_message, etc.) for multi-agent coordination. Can also be enabled via QWEN_CODE_ENABLE_AGENT_TEAM=1. Requires restart. false
experimental.artifact boolean Enable artifact tools. Enabled by default. In interactive, non-SDK sessions, the model can publish a self-contained HTML page as an interactive Artifact and open it in the browser. Non-SDK daemon sessions can use metadata-only record_artifact. Set this to false or use QWEN_CODE_DISABLE_ARTIFACT=1 to disable both. Requires restart. true
experimental.emitToolUseSummaries boolean Generate a short LLM-based label after each tool-call batch completes. See Tool-Use Summaries. Requires a fast model to be configured (fastModel); silently skipped otherwise. Can be overridden per-session with QWEN_CODE_EMIT_TOOL_USE_SUMMARIES=0 or =1. true

mcpServers

Configures connections to one or more Model-Context Protocol (MCP) servers for discovering and using custom tools. Qwen Code attempts to connect to each configured MCP server to discover available tools. If multiple MCP servers expose a tool with the same name, the tool names will be prefixed with the server alias you defined in the configuration (e.g., serverAlias__actualToolName) to avoid conflicts. Note that the system might strip certain schema properties from MCP tool definitions for compatibility. At least one of command, url, or httpUrl must be provided. If multiple are specified, the order of precedence is httpUrl, then url, then command.

Property Type Description Optional
mcpServers.<SERVER_NAME>.command string The command to execute to start the MCP server via standard I/O. Yes
mcpServers.<SERVER_NAME>.args array of strings Arguments to pass to the command. Yes
mcpServers.<SERVER_NAME>.env object Environment variables to set for the server process. Yes
mcpServers.<SERVER_NAME>.cwd string The working directory in which to start the server. Yes
mcpServers.<SERVER_NAME>.url string The URL of an MCP server that uses Server-Sent Events (SSE) for communication. Yes
mcpServers.<SERVER_NAME>.httpUrl string The URL of an MCP server that uses streamable HTTP for communication. Yes
mcpServers.<SERVER_NAME>.headers object A map of HTTP headers to send with requests to url or httpUrl. Yes
mcpServers.<SERVER_NAME>.timeout number Timeout in milliseconds for requests to this MCP server. Yes
mcpServers.<SERVER_NAME>.trust boolean Trust this server and bypass its tool call confirmations in a trusted workspace. Yes
mcpServers.<SERVER_NAME>.description string A brief description of the server, which may be used for display purposes. Yes
mcpServers.<SERVER_NAME>.includeTools array of strings List of tool names to include from this MCP server. When specified, only the tools listed here will be available from this server (allowlist behavior). If not specified, all tools from the server are enabled by default. Yes
mcpServers.<SERVER_NAME>.excludeTools array of strings List of tool names to exclude from this MCP server. Tools listed here will not be available to the model, even if they are exposed by the server. Note: excludeTools takes precedence over includeTools - if a tool is in both lists, it will be excluded. Yes

telemetry

Configures logging and metrics collection for Qwen Code. For more information, see telemetry.

Setting Type Description Default
telemetry.enabled boolean Whether or not telemetry is enabled.
telemetry.target string Informational label for the telemetry destination (local or gcp). Does not control exporter routing; set telemetry.otlpEndpoint or telemetry.outfile to configure where data is sent.
telemetry.otlpEndpoint string The endpoint for the OTLP Exporter.
telemetry.otlpProtocol string The protocol for the OTLP Exporter (grpc or http).
telemetry.logPrompts boolean Whether or not to include the content of user prompts in the logs.
telemetry.userId string Stable end-user identifier written to GenAI spans as the ARMS extension gen_ai.user.id. Prefer a pseudonymous value. Do not set a process-wide value for a shared multi-user daemon or channel instance.
telemetry.includeSensitiveSpanAttributes boolean When enabled, attaches verbatim user prompts, system prompts, tool inputs/outputs, and model responses to native OTel span attributes (in addition to log-to-span bridge spans). ⚠️ Streams sensitive data — file contents, shell commands, conversation history — to your OTLP backend. false
telemetry.sensitiveSpanAttributeMaxLength number Maximum JavaScript string length for each sensitive native OTel span attribute content payload. Must be between 1 and 104857600 (100 MiB). Set lower if your collector or backend rejects large attributes. 1048576
telemetry.outfile string Path to write telemetry to a file. When set, overrides OTLP export.

Example settings.json

Here is an example of a settings.json file with the nested structure, new as of v0.3.0:

{
  "proxy": "http://localhost:7890",
  "plansDirectory": "./.qwen/plans",
  "general": {
    "vimMode": true,
    "preferredEditor": "code"
  },
  "ui": {
    "theme": "GitHub",
    "hideTips": false,
    "customWittyPhrases": [
      "You forget a thousand things every day. Make sure this is one of 'em",
      "Connecting to AGI"
    ]
  },
  "tools": {
    "approvalMode": "yolo",
    "sandbox": "docker",
    "sandboxImage": "ghcr.io/qwenlm/qwen-code:0.14.1",
    "discoveryCommand": "bin/get_tools",
    "callCommand": "bin/call_tool",
    "exclude": ["write_file"]
  },
  "mcpServers": {
    "mainServer": {
      "command": "bin/mcp_server.py"
    },
    "anotherServer": {
      "command": "node",
      "args": ["mcp_server.js", "--verbose"]
    }
  },
  "telemetry": {
    "enabled": true,
    "target": "local",
    "otlpEndpoint": "http://localhost:4317",
    "logPrompts": true,
    "userId": "user-079458",
    "includeSensitiveSpanAttributes": false,
    "sensitiveSpanAttributeMaxLength": 1048576
  },
  "privacy": {
    "usageStatisticsEnabled": true
  },
  "model": {
    "name": "qwen3-coder-plus",
    "maxSessionTurns": 10,
    "enableOpenAILogging": false,
    "openAILoggingDir": "~/qwen-logs",
  },
  "context": {
    "fileName": ["CONTEXT.md", "QWEN.md"],
    "includeDirectories": ["path/to/dir1", "~/path/to/dir2", "../path/to/dir3"],
    "loadFromIncludeDirectories": true,
    "fileFiltering": {
      "respectGitIgnore": false
    }
  },
  "advanced": {
    "excludedEnvVars": ["DEBUG", "DEBUG_MODE", "NODE_ENV"]
  }
}

Shell History

The CLI keeps a history of shell commands you run. To avoid conflicts between different projects, this history is stored in a project-specific directory within your user's home folder.

  • Location: ~/.qwen/tmp/<project_hash>/shell_history
    • <project_hash> is a unique identifier generated from your project's root path.
    • The history is stored in a file named shell_history.

Environment Variables & .env Files

Environment variables are a common way to configure applications, especially for sensitive information (like tokens) or for settings that might change between environments.

Qwen Code can automatically load environment variables from .env files. For authentication-related variables (like OPENAI_*) and the recommended .qwen/.env approach, see Authentication.

Tip

Environment Variable Exclusion: Some environment variables (like DEBUG and DEBUG_MODE) are automatically excluded from project .env files by default to prevent interference with the CLI behavior. Variables from .qwen/.env files are never excluded by this default list. You can customize this behavior using the advanced.excludedEnvVarssetting in your settings.json file.

Warning

Loader-affecting variables are always rejected: Variables that make a spawned Node.js process or OS loader execute an attacker-chosen file — NODE_OPTIONS, npm_config_node_options (and npm's config-file redirects npm_config_userconfig, npm_config_globalconfig, npm_config_script_shell, npm_config_prefix), NODE_PATH, OPENSSL_CONF (dlopens an attacker OpenSSL engine at startup), NODE_REPL_EXTERNAL_MODULE, npm_config_node_gyp, npm_config_init_module, LD_PRELOAD, LD_AUDIT, DYLD_INSERT_LIBRARIES, BASH_ENV, ZDOTDIR, and exported bash function definitions (BASH_FUNC_*) — are never loaded from .env files (any scope, including .qwen/.env and user-level files) or from the top-level settings.json env section. A workspace-controlled value there could hijack module resolution for every subprocess Qwen Code spawns, so Qwen Code prints a warning when it rejects such a key (once per process, per key and source — in a multi-workspace daemon each workspace's rejection is reported separately). To use one of these variables, export it in the environment you launch Qwen Code from; sessions hosted by a qwen serve daemon deliberately do not inherit them, while direct editor (ACP) sessions and the plain CLI keep the exported value. Library search paths (LD_LIBRARY_PATH, DYLD_LIBRARY_PATH) and the interactive-shell-only ENV are intentionally not on this list — rejecting them breaks mainstream toolchains (ENV=production, conda/CUDA library dirs) — but a project .env still cannot apply them on reload. This rejection applies to the top-level env section only: per-server mcpServers[].env and per-hook hooks[].env are intentionally scoped to that server or hook and still apply (both surfaces are gated by folder trust for workspace-provided configs). Separately, a project .env can never set QWEN_CLI_ENTRY (the daemon's session-process entrypoint), QWEN_CDP_MCP_COMMAND (the command the daemon spawns as the browser-automation MCP adapter), QWEN_SERVE_CDP_TUNNEL_OVER_WS (switches that tunnel surface on), DEV (the dev-harness launch marker), the TLS trust-anchor variables (NODE_EXTRA_CA_CERTS, SSL_CERT_FILE, SSL_CERT_DIR, CURL_CA_BUNDLE, REQUESTS_CA_BUNDLE, GIT_SSL_CAINFO, GIT_SSL_CAPATH, npm_config_cafile, npm_config_ca, npm_config_strict_ssl, PIP_CERT — an attacker CA there, or npm_config_strict_ssl=false, would enable MITM of the token-bearing traffic a session's git/npm/pip/curl calls make), the git command-execution variables (GIT_SSH_COMMAND, GIT_SSH, GIT_EXEC_PATH, GIT_TEMPLATE_DIR, GIT_ASKPASS, GIT_PROXY_COMMAND, GIT_EDITOR, GIT_SEQUENCE_EDITOR, GIT_EXTERNAL_DIFF, GIT_CONFIG_GLOBAL, GIT_CONFIG_SYSTEM, GIT_CONFIG_COUNT, GIT_CONFIG_PARAMETERS and the numbered GIT_CONFIG_KEY_<n>/GIT_CONFIG_VALUE_<n> pairs — git runs these on any session git invocation — and XDG_CONFIG_HOME, which redirects the $XDG_CONFIG_HOME/git/config git merges with ~/.gitconfig), the curl/wget rc-file redirects (CURL_HOME, WGETRC — their rc files can install an attacker proxy or CA), PIP_CONFIG_FILE (redirects all of pip's configuration — index-url, trusted-host, proxy, or cert settings in an attacker file send session pip traffic or credentials to attacker infrastructure), SSH_ASKPASS (git/ssh execute it as the fallback passphrase-prompt program on an auth challenge), LESSOPEN and LESSCLOSE (less executes them as input preprocessors on every file a session views), the node-gyp interpreter-selection variables (NODE_GYP_FORCE_PYTHON, npm_config_python, PYTHON — run as the build Python during native-addon installs — and npm_config_git, run as npm's git binary), the editor and startup hooks (VISUAL, EDITOR — git's editor fallback chain, also spawned by the CLI's own external-editor flows — and PYTHONSTARTUP, which CPython executes at interactive startup), or BROWSER (the CLI execs it via the secure browser launcher). Those stay settable from the shell environment or a user-level .env; unlike the loader list above they are rejected from project files only, so a value you export yourself is preserved. They are also frozen at boot from a user-level .env: a settings reload does not apply edits to them there — or their removal — until the process restarts. Upgrade note: before this denylist existed, some of these keys could load from .env files or settings.json env on some paths; they are now rejected everywhere with a warning, and a qwen serve daemon no longer passes inherited values of them to session subprocesses.

Environment Variables Table

Variable Description Notes
QWEN_HOME Customizes the global configuration directory (default: ~/.qwen). Accepts an absolute or relative path (relative paths are resolved from the current working directory). Leading ~ is expanded to the user's home directory. Stores credentials, settings, memory, skills, and other global state. When set, project-level .qwen/ directories are unaffected. An empty string is treated as unset.
QWEN_RUNTIME_DIR Overrides the runtime output directory (conversations, logs, todos). When unset, defaults to the QWEN_HOME directory. Use this to separate ephemeral runtime data from persistent config. Useful when QWEN_HOME is on a shared/slow filesystem.
QWEN_USAGE_STATISTICS_ENABLED Set to true or 1 to enable usage statistics. Any other value is treated as disabling them. Overrides the privacy.usageStatisticsEnabled setting. Defaults to enabled when neither is configured.
QWEN_TELEMETRY_ENABLED Set to true or 1 to enable telemetry. Any other value is treated as disabling it. Overrides the telemetry.enabled setting.
QWEN_TELEMETRY_TARGET Sets an informational label for the telemetry destination (local or gcp). Does not control routing; use QWEN_TELEMETRY_OTLP_ENDPOINT or QWEN_TELEMETRY_OUTFILE to configure where data is sent. Overrides the telemetry.target setting.
QWEN_TELEMETRY_OTLP_ENDPOINT Sets the OTLP endpoint for telemetry. Overrides the telemetry.otlpEndpoint setting.
QWEN_TELEMETRY_OTLP_PROTOCOL Sets the OTLP protocol (grpc or http). Overrides the telemetry.otlpProtocol setting.
QWEN_TELEMETRY_LOG_PROMPTS Set to true or 1 to enable or disable logging of user prompts. Any other value is treated as disabling it. Overrides the telemetry.logPrompts setting.
QWEN_TELEMETRY_USER_ID Sets a stable end-user identifier on interaction, LLM, Tool, and Agent spans as gen_ai.user.id. Prefer a pseudonymous value. Overrides telemetry.userId after trimming. A blank value falls back to settings. This is process-wide and must not be used as per-request identity in a shared multi-user process.
QWEN_TELEMETRY_INCLUDE_SENSITIVE_SPAN_ATTRIBUTES Set to true or 1 to attach verbatim user prompts, system prompts, tool I/O, and model responses to native OTel span attributes (and keep prompt / function_args / response_text on log-to-span bridge spans). Any other value disables it. Overrides the telemetry.includeSensitiveSpanAttributes setting. ⚠️ Streams sensitive data to your OTLP backend.
QWEN_TELEMETRY_SENSITIVE_SPAN_ATTRIBUTE_MAX_LENGTH Sets the maximum JavaScript string length for each sensitive native OTel span attribute content payload. Must be a positive integer no greater than 104857600 (100 MiB). Overrides the telemetry.sensitiveSpanAttributeMaxLength setting. Default is 1048576 (1 MiB); lower it if your collector or backend rejects large span attributes.
QWEN_TELEMETRY_OUTFILE Sets the file path to write telemetry to. When set, overrides OTLP export. Overrides the telemetry.outfile setting.
QWEN_SANDBOX Alternative to the sandbox setting in settings.json. Accepts true, false, docker, podman, or a custom command string.
QWEN_SANDBOX_IMAGE Overrides sandbox image selection for Docker/Podman. Takes precedence over tools.sandboxImage.
SEATBELT_PROFILE (macOS specific) Switches the Seatbelt (sandbox-exec) profile on macOS. permissive-open: (Default) Restricts writes to the project folder (and a few other folders, see packages/cli/src/utils/sandbox-macos-permissive-open.sb) but allows other operations. strict: Uses a strict profile that declines operations by default. <profile_name>: Uses a custom profile. To define a custom profile, create a file named sandbox-macos-<profile_name>.sb in your project's .qwen/ directory (e.g., my-project/.qwen/sandbox-macos-custom.sb).
DEBUG or DEBUG_MODE (often used by underlying libraries or the CLI itself) Set to true or 1 to enable verbose debug logging, which can be helpful for troubleshooting. Note: These variables are automatically excluded from project .env files by default to prevent interference with the CLI behavior. Use .qwen/.env files if you need to set these for Qwen Code specifically.
NO_COLOR Set to any value to disable all color output in the CLI.
FORCE_HYPERLINK Override the OSC 8 clickable-link detection in the markdown renderer. Set to 1 (or any non-zero integer, or empty string) to force-enable; set to 0 or a non-numeric value such as false / off to force-disable. Honors NO_COLOR / QWEN_DISABLE_HYPERLINKS opt-outs above it. Use this to opt into OSC 8 inside tmux / GNU screen (auto-detection refuses by default because the host terminal's capabilities are hidden behind the multiplexer). Requires set -g allow-passthrough on on tmux 3.3+. Also enables Hyper, which isn't auto-detected.
QWEN_DISABLE_HYPERLINKS Set to 1 to hard-disable OSC 8 clickable hyperlinks in the markdown renderer even on terminals that auto-detect as capable. Useful when a terminal advertises support but breaks on long URLs, or when piping output through an intermediary that mangles escape sequences. The renderer falls back to plain label (url) rendering.
CLI_TITLE Set to a string to customize the title of the CLI.
CODE_ASSIST_ENDPOINT Specifies the endpoint for the code assist server. This is useful for development and testing.
QWEN_CODE_MAX_OUTPUT_TOKENS Overrides the default maximum output tokens per response. When not set, Qwen Code defaults to the model's declared output limit and, if a response is truncated, automatically escalates (64K floor) and recovers across turns. Set this to a specific value (e.g., 16000) to use a fixed limit instead — useful for capacity-constrained self-hosted backends that want a lower per-request slot reservation. Takes precedence over the model-limit default but is overridden by samplingParams.max_tokens in settings. Disables automatic escalation when set. Example: export QWEN_CODE_MAX_OUTPUT_TOKENS=16000
QWEN_CODE_UNATTENDED_RETRY Set to true or 1 to enable persistent retry mode. When enabled, transient API capacity errors (HTTP 429 Rate Limit and 529 Overloaded) are retried indefinitely with exponential backoff (capped at 5 minutes per retry) and heartbeat keepalives every 30 seconds on stderr. Designed for CI/CD pipelines and background automation where long-running tasks should survive temporary API outages. Must be set explicitly — CI=true alone does not activate this mode. See Headless Mode for details. Example: export QWEN_CODE_UNATTENDED_RETRY=1
QWEN_CODE_ACP_REPEATED_TOOL_FAILURE_GUARD Operator rollout mode for ACP repeated tool-execution failure protection. Accepts off, shadow, warn, or enforce; missing or invalid values default to shadow. Applies only to interactive foreground ACP prompts; channel-driven and automatic routes remain off. Project and workspace environment files cannot set this operator policy. Shadow leaves model continuation and messages unchanged but adds the queued-prompt watch flag to craft/drainMidTurnQueue; every non-off mode requires reliable queued-prompt state. Non-empty invalid values emit a diagnostic; export the variable in the process environment or a user-level file.
QWEN_CODE_PROFILE_STARTUP Set to 1 to enable startup performance profiling. Writes a JSON timing report to ~/.qwen/startup-perf/ with per-phase durations. Only active inside the sandbox child process (or with QWEN_CODE_PROFILE_STARTUP_OUTER=1). Zero overhead when not set. Example: export QWEN_CODE_PROFILE_STARTUP=1
QWEN_CODE_PROFILE_STARTUP_OUTER Set to 1 together with QWEN_CODE_PROFILE_STARTUP=1 to also collect a startup profile in the outer (pre-sandbox) process. Outer-process reports get an outer- filename prefix to keep them distinct from the sandbox child's report. Off by default — only the sandbox child collects, to avoid duplicate reports. Useful for local development where the cli isn't relaunched into a sandbox.
QWEN_CODE_PROFILE_STARTUP_NO_HEAP Set to 1 together with QWEN_CODE_PROFILE_STARTUP=1 to skip the per-checkpoint process.memoryUsage() snapshots. Useful when measuring the profiler's own Heisenberg overhead. Off by default. Heap snapshots cost ~50 µs each (well below 1% of total startup) so most users should leave this alone.
QWEN_CODE_LEGACY_MCP_BLOCKING Set to 1 to restore the pre-progressive-MCP behavior where Config.initialize() waits synchronously for every configured MCP server's discover handshake before returning. Off by default. Modern qwen-code lets MCP servers come online in the background while the UI is already interactive; the model sees each batch of new tools within ~16 ms of the server settling. This flag is kept as a rollback escape hatch for ≥ 1 release. Example: export QWEN_CODE_LEGACY_MCP_BLOCKING=1

When both user-level .env files define the same variable, the Qwen-specific file wins: <QWEN_HOME>/.env (or ~/.qwen/.env when QWEN_HOME is unset) is loaded before ~/.env, and existing environment values are not overwritten.

Command-Line Arguments

Arguments passed directly when running the CLI can override other configurations for that specific session.

For sandbox image selection, precedence is: --sandbox-image > QWEN_SANDBOX_IMAGE > tools.sandboxImage > built-in default image.

Command-Line Arguments Table

Argument Alias Description Possible Values Notes
--model -m Specifies the Qwen model to use for this session. Model name Example: npm start -- --model qwen3-coder-plus
--prompt -p Used to pass a prompt directly to the command. This invokes Qwen Code in a non-interactive mode. Your prompt text For scripting examples, use the --output-format json flag to get structured output.
--prompt-interactive -i Starts an interactive session with the provided prompt as the initial input. Your prompt text The prompt is processed within the interactive session, not before it. Cannot be used when piping input from stdin. Example: qwen -i "explain this code"
--system-prompt Overrides the built-in main session system prompt for this run. Your prompt text Loaded context files such as QWEN.md are still appended after this override. Can be combined with --append-system-prompt.
--append-system-prompt Appends extra instructions to the main session system prompt for this run. Your prompt text Applied after the built-in prompt and loaded context files. Can be combined with --system-prompt. See Headless Mode for examples.
--output-format -o Specifies the format of the CLI output for non-interactive mode. text, json, stream-json text: (Default) The standard human-readable output. json: A machine-readable JSON output emitted at the end of execution. stream-json: Streaming JSON messages emitted as they occur during execution. For structured output and scripting, use the --output-format json or --output-format stream-json flag. See Headless Mode for detailed information.
--input-format Specifies the format consumed from standard input. text, stream-json text: (Default) Standard text input from stdin or command-line arguments. stream-json: JSON message protocol via stdin for bidirectional communication. Requirement: --input-format stream-json requires --output-format stream-json to be set. When using stream-json, stdin is reserved for protocol messages. See Headless Mode for detailed information.
--include-partial-messages Include partial assistant messages when using stream-json output format. When enabled, emits stream events (message_start, content_block_delta, etc.) as they occur during streaming. Default: false. Requirement: Requires --output-format stream-json to be set. See Headless Mode for detailed information about stream events.
--sandbox -s Enables sandbox mode for this session.
--sandbox-image Sets the sandbox image URI.
--debug -d Enables debug mode for this session, providing more verbose output.
--help -h Displays help information about command-line arguments.
--yolo Enables YOLO mode, which automatically approves all tool calls.
--approval-mode Sets the approval mode for tool calls. plan, default, auto-edit, auto, yolo Supported modes: plan: Analyze only—do not modify files or execute commands. default: Require approval for file edits or shell commands (default behavior). auto-edit: Automatically approve edit tools (edit, write_file, notebook_edit) while prompting for others. auto: LLM classifier auto-approves safe actions and blocks risky ones. yolo: Automatically approve all tool calls (equivalent to --yolo). Cannot be used together with --yolo. Use --approval-mode=yolo instead of --yolo for the new unified approach. Example: qwen --approval-mode auto-edit
See more about Approval Mode.
--allowed-tools A comma-separated list of tool names that will bypass the confirmation dialog. Tool names Example: qwen --allowed-tools "Shell(git status)"
--disabled-slash-commands Slash command names to hide/disable (comma-separated or repeated). Unioned with the slashCommands.disabled setting and the QWEN_DISABLED_SLASH_COMMANDS environment variable. Matched case-insensitively against the final command name. Command names Example: qwen --disabled-slash-commands "auth,mcp,extensions"
--telemetry Enables telemetry.
--telemetry-target Sets the telemetry target. See telemetry for more information.
--telemetry-otlp-endpoint Sets the OTLP endpoint for telemetry. See telemetry for more information.
--telemetry-otlp-protocol Sets the OTLP protocol for telemetry (grpc or http). Defaults to grpc. See telemetry for more information.
--telemetry-log-prompts Enables logging of prompts for telemetry. See telemetry for more information.
--acp Enables ACP mode (Agent Client Protocol). Useful for IDE/editor integrations like Zed. Stable. Replaces the deprecated --experimental-acp flag.
--experimental-lsp Enables experimental LSP (Language Server Protocol) feature for code intelligence (go-to-definition, find references, diagnostics, etc.). Experimental. Requires language servers to be installed.
--extensions -e Specifies a list of extensions to use for the session. Extension names If not provided, all available extensions are used. Use the special term qwen -e none to disable all extensions. Example: qwen -e my-extension -e my-other-extension
--list-extensions -l Lists all available extensions and exits.
--proxy Sets the proxy for the CLI. Proxy URL Example: --proxy http://localhost:7890.
--include-directories Includes additional directories in the workspace for multi-directory support. Directory paths Can be specified multiple times or as comma-separated values. Example: --include-directories /path/to/project1,/path/to/project2 or --include-directories /path/to/project1 --include-directories /path/to/project2
--screen-reader Enables screen reader mode, which adjusts the TUI for better compatibility with screen readers.
--version Displays the version of the CLI.
--openai-logging Enables logging of OpenAI API calls for debugging and analysis. This flag overrides the enableOpenAILogging setting in settings.json.
--openai-logging-dir Sets a custom directory path for OpenAI API logs. Directory path This flag overrides the openAILoggingDir setting in settings.json. Supports absolute paths, relative paths, and ~ expansion. Example: qwen --openai-logging-dir "~/qwen-logs" --openai-logging

Context Files (Hierarchical Instructional Context)

While not strictly configuration for the CLI's behavior, context files (defaulting to QWEN.md but configurable via the context.fileName setting) are crucial for configuring the instructional context (also referred to as "memory"). This powerful feature allows you to give project-specific instructions, coding style guides, or any relevant background information to the AI, making its responses more tailored and accurate to your needs. The CLI includes UI elements, such as an indicator in the footer showing the number of loaded context files, to keep you informed about the active context.

  • Purpose: These Markdown files contain instructions, guidelines, or context that you want the Qwen model to be aware of during your interactions. The system is designed to manage this instructional context hierarchically.

Example Context File Content (e.g. QWEN.md)

Here's a conceptual example of what a context file at the root of a TypeScript project might contain:

# Project: My Awesome TypeScript Library

## General Instructions:
- When generating new TypeScript code, please follow the existing coding style.
- Ensure all new functions and classes have JSDoc comments.
- Prefer functional programming paradigms where appropriate.
- All code should be compatible with TypeScript 5.0 and Node.js 22+.

## Coding Style:
- Use 2 spaces for indentation.
- Interface names should be prefixed with `I` (e.g., `IUserService`).
- Private class members should be prefixed with an underscore (`_`).
- Always use strict equality (`===` and `!==`).

## Specific Component: `src/api/client.ts`
- This file handles all outbound API requests.
- When adding new API call functions, ensure they include robust error handling and logging.
- Use the existing `fetchWithRetry` utility for all GET requests.

## Regarding Dependencies:
- Avoid introducing new external dependencies unless absolutely necessary.
- If a new dependency is required, please state the reason.

This example demonstrates how you can provide general project context, specific coding conventions, and even notes about particular files or components. The more relevant and precise your context files are, the better the AI can assist you. Project-specific context files are highly encouraged to establish conventions and context.

  • Hierarchical Loading and Precedence: The CLI implements a hierarchical memory system by loading context files (e.g., QWEN.md) from several locations. Content from files lower in this list (more specific) typically overrides or supplements content from files higher up (more general). The exact concatenation order and final context can be inspected from the /memory dialog. The typical loading order is:
    1. Global Context File:
      • Location: ~/.qwen/<configured-context-filename> (e.g., ~/.qwen/QWEN.md in your user home directory).
      • Scope: Provides default instructions for all your projects.
    2. Project Root & Ancestors Context Files:
      • Location: The CLI searches for the configured context file in the current working directory and then in each parent directory up to either the project root (identified by a .git folder) or your home directory.
      • Scope: Provides context relevant to the entire project or a significant portion of it.
  • Concatenation & UI Indication: The contents of all found context files are concatenated (with separators indicating their origin and path) and provided as part of the system prompt. The CLI footer displays the count of loaded context files, giving you a quick visual cue about the active instructional context.
  • Importing Content: You can modularize your context files by importing other Markdown files using the @path/to/file.md syntax. For more details, see the Memory documentation.
  • Commands for Memory Management:
    • Use /memory to open the memory management dialog.
    • Refresh memory from the dialog to re-scan and reload context files from all configured locations.
    • See the Commands documentation for full details on the /memory command.

By understanding and utilizing these configuration layers and the hierarchical nature of context files, you can effectively manage the AI's memory and tailor Qwen Code's responses to your specific needs and projects.

Sandbox

Qwen Code can execute potentially unsafe operations (like shell commands and file modifications) within a sandboxed environment to protect your system.

Sandbox is disabled by default, but you can enable it in a few ways:

  • Using --sandbox or -s flag.
  • Setting QWEN_SANDBOX environment variable.
  • Setting tools.sandbox in settings.

⚠️ --yolo does not automatically enable a sandbox. YOLO mode only auto-approves tool calls; sandboxing must still be opted into via --sandbox, QWEN_SANDBOX, or tools.sandbox. In headless / non-interactive runs with --yolo (or --approval-mode=yolo) and no sandbox, the model can execute shell, write, and edit tools at the current process's privilege level — Qwen Code prints a warning to stderr in that case. Suppress with QWEN_CODE_SUPPRESS_YOLO_WARNING=1 once you've reviewed the trade-off.

By default, it uses a pre-built qwen-code-sandbox Docker image.

For project-specific sandboxing needs, you can create a custom Dockerfile at .qwen/sandbox.Dockerfile in your project's root directory. This Dockerfile can be based on the base sandbox image:

FROM qwen-code-sandbox
# Add your custom dependencies or configurations here
# For example:
# RUN apt-get update && apt-get install -y some-package
# COPY ./my-config /app/my-config

When .qwen/sandbox.Dockerfile exists, you can use BUILD_SANDBOX environment variable when running Qwen Code to automatically build the custom sandbox image:

BUILD_SANDBOX=1 qwen -s

Usage Statistics

To help us improve Qwen Code, we collect anonymized usage statistics. This data helps us understand how the CLI is used, identify common issues, and prioritize new features.

What we collect:

  • Tool Calls: We log the names and categories (native or MCP) of the tools that are called, their terminal status (success, error, or cancelled), and how long they take to execute. We do not collect the arguments passed to the tools or any data returned by them.
  • API Requests: We log the model used for each request, the duration of the request, and whether it was successful. We do not collect the content of the prompts or responses.
  • Session Information: We collect information about the configuration of the CLI, such as the enabled tools and the approval mode.

What we DON'T collect:

  • Personally Identifiable Information (PII): We do not collect any personal information, such as your name, email address, or API keys.
  • Prompt and Response Content: We do not log the content of your prompts or the responses from the model.
  • File Content: We do not log the content of any files that are read or written by the CLI.

How to opt out:

You can opt out of usage statistics collection at any time by setting the usageStatisticsEnabled property to false under the privacy category in your settings.json file:

{
  "privacy": {
    "usageStatisticsEnabled": false
  }
}

Alternatively, set QWEN_USAGE_STATISTICS_ENABLED=false (or 0) in the environment. The environment variable takes precedence over the setting. Restart Qwen Code after changing either value.

Note

When usage statistics are enabled, events are sent to an Alibaba Cloud RUM collection endpoint.