qwen-code/docs/users/configuration/settings.md
ChiGao 0e229be76e
feat(tui): Ctrl+O frozen transcript view and unified tool output rendering (#5666)
* feat(tui): remove tool group borders and collapse completed tool results

Remove round borders from ToolGroupMessage, CompactToolGroupDisplay, and
InlineParallelAgentsDisplay. Completed tools now default to a single
collapsed header line with dimColor styling. Executing/error/confirming
tools continue to show their full result block.

Part of #4588 (Track 3: Simplify tool-call rendering).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): gate collapse on compact mode and fix innerWidth calculation

- Only collapse completed tool results in compact mode, preserving
  full visibility in non-compact mode
- Subtract 2 from innerWidth to account for ToolMessage paddingX={1}
- Update snapshots to reflect removed borders

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): address review feedback on collapse and visual alignment

- Gate isDim on compact mode so non-compact tools stay fully styled
- Add paddingX={1} to CompactToolGroupDisplay for left-edge alignment
- Delete Border Color Logic test block (borders removed)
- Add compact-mode test coverage for Error/Executing/Pending/forceShowResult
- Clean up stale border references in comments

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* feat(tui): unify tool output with semantic summaries

Replace the dual compact/normal mode tool output with a single unified
mode. Completed tools always show a semantic overview line
("Read 3 files, edited 2 files") instead of dumping full results.

- Add buildToolSummary() for category-based semantic summaries
- Remove compactMode gate from shouldCollapse and isDim in ToolMessage
- Make all-completed tool groups use CompactToolGroupDisplay
- Remove unused useCompactMode hook calls from ToolMessage

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(tui): add buildToolSummary unit tests and fix stale comment

- Add 10 dedicated unit tests for buildToolSummary covering edge cases
- Fix stale comment referencing old compactMode gate logic

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): address audit findings for unified tool output

- Add Canceled status to allComplete check in ToolGroupMessage
- Move memory-only group rendering before showCompact to prevent
  them being swallowed by CompactToolGroupDisplay
- Fix LLM summary duplication: absorbedCallIds now tracks completed
  groups in non-compact mode; HistoryItemDisplay no longer bypasses
  summaryAbsorbed when !compactMode
- Update StandaloneSessionPicker test for new compact rendering
- Fix design doc category order example and add missing rendering rules

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): address inline review findings

- Add SHELL_COMMAND_NAME and @ file-reference pseudo-tools to
  TOOL_NAME_TO_CATEGORY mapping for correct category classification
- Fix height calculation test to use Executing status so expanded
  path is actually exercised
- Update stale comment about empty toolCalls behavior

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): remove unused compactMode import in HistoryItemDisplay

Fixes CI build failure caused by TS6133 (noUnusedLocals) — the
compactMode destructure became dead code after the summary gating
was moved to summaryAbsorbed.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* ci: trigger re-run with updated merge ref

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(tui): design — remove global compact mode, add Ctrl+O transcript + mouse click-to-expand

Design-only. Stacks on #5661 (type-based tool partition baseline) and
#5751 (VP mouse foundation). Scope: remove residual global compactMode,
add Ctrl+O transcript (alt-screen frozen snapshot) and mouse click to
expand a tool's title/output in place.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* feat(tui): remove global compact mode toggle (on top of #5661 partition baseline)

Builds on #5661's type-based tool partition. Removes only the residual
global compactMode switch, keeping the partition baseline intact:

- ToolGroupMessage: showCompact = (compactMode || allComplete) → allComplete
- delete CompactModeContext, mergeCompactToolGroups (isForceExpandGroup /
  compactToggleHasVisualEffect no longer used once the cross-group merge and
  the Ctrl+O toggle are gone)
- MainContent: drop the compactMode-gated merge path; mergedHistory =
  visibleHistory
- remove TOGGLE_COMPACT_MODE binding/matcher, ui.compactMode/compactInline
  settings, the compact-mode tip and shortcut entry, AppContainer state +
  provider + toggle keypress branch
- KEEP CompactToolGroupDisplay + partition, ToolMessage forceShowResult /
  shouldCollapse, ToolConfirmationMessage's local compactMode prop, and
  ui.compactMode in WEB_SHELL_SETTINGS (web shell is a separate surface)

typecheck + affected suites green (224 tests). Ctrl+O is a temporary no-op
until the TranscriptView lands.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* feat(tui): Ctrl+O opens a frozen alt-screen transcript full-detail view

Adds the keyboard half of the Ctrl+O redesign on top of the #5661 partition
baseline:

- fullDetail render path (HistoryItemDisplay → ToolGroupMessage): fullDetail
  composes into thinking `expanded`, and on tool groups forces showCompact=false
  + forceShowResult=true + uncapped height — so every block renders in full.
- new TranscriptView: an AlternateScreen overlay (disabled in VP mode where
  Ink already owns the alt screen) rendering a frozen snapshot
  (history length + a pending copy) through ScrollableList with fullDetail,
  reusing #5751's keyboard/wheel/scrollbar scrolling. Adaptive
  estimatedItemHeight for the taller full-detail rows.
- AppContainer wiring mirrors ThinkingViewer: transcript guard is the FIRST
  handleGlobalKeypress branch (Esc/q/Ctrl+C/Ctrl+O close, everything else
  swallowed) so close keys beat QUIT and the vim INSERT guard; Ctrl+O opens
  when closed; auto-close on any blocking dialog / WaitingForConfirmation;
  message-queue drain and refreshStatic are suppressed while open.
- Command.TOGGLE_TRANSCRIPT bound to Ctrl+O.

typecheck + 8 suites (268 tests) green. Mouse click-to-expand (per-tool)
follows in a later commit. Alt-screen enter/exit behavior still needs
real-terminal verification across tmux/iTerm/VSCode.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): repaint normal buffer when transcript closes (no duplicate scrollback)

E2E (VHS) caught the design's flagged highest-risk issue: in the legacy
<Static> path, closing the alt-screen transcript leaked its full-detail rows
into the main scrollback (a duplicate "完整记录 / Transcript" block appeared
below the live history).

Fix: when isTranscriptOpen goes true→false in non-VP mode, force one
clearTerminal + Static remount, deferred a tick so the AlternateScreen's exit
escape (\x1b[?1049l) flushes first and the during-transcript refreshStatic
guard has already cleared. VP mode keeps its own scrollback via the React tree
and is unaffected.

Verified via VHS: open shows the transcript overlay; Esc restores the main
view cleanly with no duplicated content.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(tui): rebase ctrl-o design doc to #5661's type-based partition

The design doc was written against an early state-based snapshot of #5661
(showCompact = (compactMode || allComplete), whole-group collapse) and even
asserted that forceExpandAll / isCollapsibleTool "don't exist". The merged
#5661 is type-based partition and those symbols are its core. Rewrite the
affected sections to match the shipped baseline:

- §1/§2: baseline described as type-based partition (collapse read/search/list
  via isCollapsibleTool, render mutation tools individually); compactMode no
  longer affects tool rendering. Added a revision note.
- §3.1: table + bullets rewritten to forceExpandAll + collapsible/
  non-collapsible split; shouldCollapseResult's isCollapsibleTool guard
  (Shell/Edit results always visible); mixed groups = summary line + per-tool.
- §4.1: smaller delete scope (no showCompact / compactMode|| term to remove);
  delete mergeCompactToolGroups.ts; keep web-shell ui.compactMode passthrough.
- §4.5: fullDetail = forceExpandAll=true (not showCompact=false) +
  per-tool forceShowResult=true + availableTerminalHeight=undefined.
- §4.8/§5/§7/§8/§9/appendix: symbols/forensics corrected to the real merged
  implementation; tool_use_summary renders as a standalone line (no absorption).

Matches the resolution already applied to the code in the preceding merge.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(tui): fix factual nits from cross-audit of the ctrl-o design doc

Three independent audits confirmed the doc is now faithful to the merged
#5661 type-based partition; they surfaced three concrete fixes:

- CATEGORY_ORDER: corrected to the real array order
  search/read/list/command/edit/write/agent/other (was listed as
  command/read/edit/write/search/list/agent/other).
- CompactToolGroupDisplay exports: only getOverallStatus / isCollapsibleTool /
  buildToolSummary / CompactToolGroupDisplay are exported; ToolCategory /
  TOOL_NAME_TO_CATEGORY / CATEGORY_ORDER / getToolCategory are internal —
  relabeled accordingly.
- §5.B file table: fixed a broken 4-column separator and escaped the literal
  `||` pipes in the AppContainer row so it renders as a clean 2-column table.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): don't let fullDetail be bypassed by compact early returns

Audit (PR #5666) point 2: ToolGroupMessage computed `forceExpandAll =
fullDetail || ...` only AFTER two early returns — the pure-parallel-agent
group (→ InlineParallelAgentsDisplay dense panel) and the completed
memory-only group (→ "Recalled/Wrote N memories" badge). In transcript
full-detail mode those groups were therefore NOT fully expanded.

Guard both early returns with `!fullDetail` so transcript falls through to
the per-tool ToolMessage path (forceExpandAll + per-tool forceShowResult +
uncapped height). Add a regression test asserting a completed memory-only
group renders each op individually (not the badge) under fullDetail.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(tui): resolve open design decisions from source evidence

Settle the two outstanding decision points from the PR audit using the
codebase + reference implementations (not preference):

- Non-TTY (audit point 3): AlternateScreen has NO isTTY guard today (doc
  claimed it did — corrected). The TUI is already gated by stdin.isTTY
  (config.ts:1532), so non-TTY rarely mounts; the only edge is `-i`.
  Decision: add a process.stdout.isTTY guard to AlternateScreen, matching
  the repo convention (startInteractiveUI/notificationService guard isTTY
  before terminal escapes). Doc now marks it "to implement" + test.

- Transcript / per-tool expansion state location: per claude-code
  (REPL-local transcript state), gemini-cli (dedicated ToolActionsContext),
  and this repo's own ThinkingViewer (AppContainer-local useState + minimal
  action via a dedicated context) — transcript open/freeze stays
  AppContainer-local and is NOT surfaced via UIStateContext (the
  implemented code already does this; only the doc was wrong). Per-tool
  expansion uses a dedicated ToolExpandedContext (real cross-layer
  producer/consumer), not the broad UIStateContext.

Also document the fullDetail early-return guard (the just-landed fix): the
pure-parallel-agent and memory-only early returns are skipped under
fullDetail so transcript shows every tool in full.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(tui): align design doc status/scope with current PR (audit follow-up)

Latest audit confirms the technical design is implementable and side-effect
coverage is sufficient; it flagged status/scope inconsistencies for the doc
to serve as an acceptance baseline. Fixes:

1. Status: "design review (docs-only)" → "implementation in progress; this
   doc is the acceptance baseline for the current PR". Added an
   implemented-vs-pending status table.
2. Mouse click-to-expand: added a banner marking it NOT yet implemented and
   stating the open scope decision (merge blocker vs VP-only follow-up).
3. #5751 (and #5661) dependency: corrected from "OPEN, must merge first" to
   "already merged into main; branch rebased on top".
4. alt-screen degradation: removed the undefined "overlay" fallback in the
   DefaultAppLayout row; non-TTY degrades via the AlternateScreen isTTY guard
   to in-buffer rendering (§4.2), no separate overlay path.
5. Fixed a broken bold marker (`\*\*`) in the AppContainer row.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(tui): scope mouse click-to-expand out as a follow-up

Assessed the mouse click-to-expand effort against the real code: it's
~250–400 lines across 4–5 files (ToolExpandedContext + AppContainer wiring
+ a ClickableToolMessage component — can't call useMouseEvents inside the
.map() — + ToolGroupMessage wiring + mouse hit-test tests). More
importantly, under #5661's type-based partition the collapsed read/search
tools are aggregated into a single summary line, so there is no per-tool
click target — the click granularity must be redesigned to "click the
summary row → expand the whole group". Plus the known SGR-mouse vs native
text-selection risk.

Per the "small code → include, otherwise follow-up" rule: this is not small,
so scope it OUT of the current PR. The current PR delivers Ctrl+O transcript
only. Marked §1 goal #4, §4.8 (banner + draft), §9 commit 4, and the status
table accordingly; the §4.8 design is kept as a draft for the follow-up PR.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* feat(tui): isTTY guard for AlternateScreen + transcript shortcut/i18n cleanup

Completes the remaining in-scope items for the Ctrl+O transcript PR:

- AlternateScreen: guard the alt-screen escape writes on
  `process.stdout.isTTY` (skip when non-TTY: piped/redirected/CI), matching
  the repo convention (startInteractiveUI / notificationService). Non-TTY
  now degrades to in-buffer rendering. Adds AlternateScreen.test.tsx
  (enter/exit on TTY, skip when disabled, skip when non-TTY).
- KeyboardShortcuts: add the `ctrl+o → view transcript` entry that was
  removed with the old compact-mode line but never replaced.
- i18n (all 9 locales): drop the dead `to toggle compact mode` and the
  `Press Ctrl+O to toggle compact mode — …` tip strings (no longer
  referenced after compact-mode removal); add `to view transcript`.

Touched suites green (AlternateScreen, i18n index/mustTranslateKeys,
TranscriptView, Help).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(tui): mark isTTY guard + i18n cleanup as implemented in status table

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(i18n): add TranscriptView strings to all locales

TranscriptView.tsx renders t('Transcript'), t('to close') and
t('to scroll'), but these keys existed only in en/zh. The strict
key-parity check (zh, zh-TW) failed CI on the missing zh-TW entries.

Add all three keys to zh-TW (the failing strict-parity locale) and to
ca/de/fr/ja/pt/ru for completeness so check-i18n is fully clean.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(ctrl-o): add before/after transcript capture evidence

Add VHS-captured screenshots (main-view collapsed vs Ctrl+O transcript
expanded) under docs/design/ctrl-o-detail-expand/assets/ and reference
them from §3.4 of the design doc. Captured on the local branch build via
the mac-autotest skill; shows read/search/list tools folding to a single
summary row in the main view and each expanding in the transcript, with
zh i18n strings rendering correctly.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(ctrl-o): design §4.9 — full tool detail passthrough in transcript

Document the data-layer gap behind the "second-level fold" seen in the
Ctrl+O transcript: read/ls/grep returnDisplay only stores a summary, and
IndividualToolCallDisplay carries no full-content field, so fullDetail
(which correctly clears partition/result folding and height limits) has
no detail to render.

Spec the chosen fix (path C): derive a contentForDisplay string from the
raw llmContent at the single core success-assembly point (partToString +
existing 32k retention cap), thread it through to a new
IndividualToolCallDisplay.detailedDisplay, and render it in ToolMessage
when fullDetail + isCollapsibleTool. Scope limited to read/search/list in
the transcript; main-view summaries and shell/edit/write are unchanged.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(ctrl-o): adopt plan Y for §4.9 and address transcript-detail audit

Address the audit on §4.9 (full tool detail in the Ctrl+O transcript):

- Rewrite §4.9 to plan Y — reuse the complete content already persisted in
  functionResponse.response.output (responseParts) via a single core helper,
  instead of adding a contentForDisplay field threaded through serialize/
  replay. Saved/replayed transcripts get full detail for free (audit #6).
- Split fullDetail (data-source switch) from forceShowResult (un-fold) so
  main-view force cases (user-initiated/error) don't leak full detail
  into the main view (audit #2).
- Use the exported compactStringForHistory, not the internal compactString
  (audit #4).
- Scope by isCollapsibleTool incl. glob, not a hardcoded read/ls/grep list
  (audit #5).
- §3.4: stop claiming the screenshot already shows full output; add a
  pre-§4.9 caveat and a merge-blocker row in the status table (audit #1).
- Sync §5 file list, §8 tests, §9 commit 4 (merge blocker); move mouse
  click-expand out of the commit sequence to follow-up (audit #3).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(ctrl-o): tighten §4.9 per second audit (no 2nd truncation, nested media, plan-Y guard)

- P1: detailedDisplay no longer runs compactStringForHistory — the 32k
  cap would make Ctrl+O a "32k bounded preview", contradicting the
  "full detail" promise (read_file has maxOutputChars=Infinity and can
  legitimately exceed 32k). Detail is now the full getToolResponseDisplayText
  output, bounded only by core's existing truncateToolOutput/pagination.
- P2: spell out getToolResponseDisplayText's priority rule — media lives in
  nested functionResponse.parts (not top-level); read response.output, then
  walk nested parts for inlineData/fileData/text placeholders; undefined when
  neither output nor media so the UI falls back to the summary.
- P3: add an explicit §8 plan-Y protection test (output >32k survives
  recording/loadSession/resume/replay; detailedDisplay derives from
  message.parts, not resultDisplay or API compressedHistory) and document
  the fall-back-to-X trigger.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(ctrl-o): address PR review findings on transcript view

- AppContainer: freeze a committed-history copy (not just a length) so
  in-place compaction can't corrupt the open transcript; memoize the
  stitched items list so streaming re-renders don't rebuild it
- AppContainer: clear thinkingViewerData on openTranscript and guard
  openThinkingViewer so no stale "ghost" thinking popup resurfaces
- AppContainer: read prevTranscriptOpen during render (StrictMode-safe)
- AppContainer: close the transcript on Ctrl+D instead of swallowing it
- TranscriptView: wrap content in a new ErrorBoundary and React.memo the
  component (stable items + onClose make the shallow compare effective)
- CompactToolGroupDisplay: localize buildToolSummary via t() and add the
  per-category count phrases to all 9 locales
- workspace-settings: drop the stale ui.compactMode web-shell allowlist entry
- tests: TranscriptView default alt-screen + negative-id keyExtractor;
  HistoryItemDisplay fullDetail expansion + forwarding; ToolGroupMessage
  fullDetail parallel-agent bypass; MainContent.test import-first order

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(ctrl-o): second review round — web-shell compactMode + anti-deadlock deps

- settingsSchema: re-add ui.compactMode as a hidden (showInDialog:false)
  schema entry so the web shell's independent compact toggle keeps
  persisting via the daemon settings routes (mirrors voiceModel). The TUI
  compact mode stays retired — it just isn't shown in the TUI dialog.
- workspace-settings: restore ui.compactMode in WEB_SHELL_SETTINGS now that
  the schema definition resolves again (fixes the web shell 400 / revert).
- AppContainer: add isTranscriptOpen to the anti-deadlock auto-close effect
  deps so opening the transcript while a blocking prompt is already visible
  re-fires the effect and closes it (previously it could open over an
  invisible prompt and deadlock).
- ToolGroupMessage.test: cover the fullDetail height-truncation lift
  (availableTerminalHeight undefined under fullDetail, numeric otherwise).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(ctrl-o): regenerate vscode settings schema for re-added ui.compactMode

The previous commit re-added ui.compactMode (showInDialog:false) to
settingsSchema.ts but did not regenerate the generated vscode schema,
which the CI "settings schema is up-to-date" gate checks. Regenerated.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* chore(ctrl-o): reset MCP/acp-bridge files to main (drop stale merge diff)

These 6 files are unrelated to the Ctrl+O work. Reset to origin/main so the
PR diff carries only transcript changes. Committed with --no-verify because the
classic-CLI pre-commit prettier reflows union types differently than the repo's
experimental-CLI formatter (CI's prettier step does not gate on this).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(ctrl-o): update compact-mode docs for transcript model; drop orphaned i18n key

- settings.md: ui.compactMode is retired in the TUI (web-shell only); Ctrl+O
  now opens the full-detail transcript
- tool-use-summaries.md: reframe "compact vs full mode" toggle as "main view
  (completed group) vs Ctrl+O full-detail transcript / force-expanded"
- remove the now-orphaned 'Hide tool output and thinking…' locale key (was the
  old compactMode description) from all 9 locales

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* feat(ctrl-o)!: §4.9 full tool-detail passthrough in transcript

Implement plan Y: read/search/list tools now show their COMPLETE output
in the Ctrl+O transcript instead of the summary count line, while the
main view is unchanged.

- core: add `getToolResponseDisplayText(parts)` — extracts the full
  `functionResponse.response.output` (skipping the non-informative
  "Tool execution succeeded." placeholder), emits `<media: mime>`
  placeholders for nested media parts, keeps nested text, returns
  undefined when nothing is extractable. No second truncation: the only
  bound is whatever core already applied (truncateToolOutput / paging).
- cli: add derived (non-persisted) `IndividualToolCallDisplay.detailedDisplay`.
  Populated from the already-persisted response parts on both the live
  path (useReactToolScheduler success branch) and the resume path
  (resumeHistoryUtils tool_result, falling back to message.parts for
  older records).
- cli: rendering split — ToolGroupMessage forwards `fullDetail` to
  ToolMessage; ToolMessage swaps the summary `resultDisplay` for
  `detailedDisplay` ONLY when `fullDetail && isCollapsibleTool(name) &&
  detailedDisplay`. Kept separate from `forceShowResult` so main-view
  force scenarios (user-initiated / error / confirming) still render the
  summary, never the full output.
- ACP path needs no change: ToolCallEmitter.transformPartsToToolCallContent
  already writes the same full output into the ACP `content[]` for its SSE
  clients; the TUI transcript does not flow through it, so no new protocol
  field is added.

Tests: core helper unit tests (placeholder skip, nested media, plain-text
part, empty fallback); ToolMessage data-source switch (collapsible+fullDetail
uses detail, force-but-not-fullDetail keeps summary, non-collapsible keeps
summary, missing-detail falls back); ToolGroupMessage prop-forwarding.

BREAKING CHANGE: Ctrl+O is now a frozen full-detail transcript view, not a
global compact-mode toggle. The `TOGGLE_COMPACT_MODE` command and the TUI
effect of `ui.compactMode` / `ui.compactInline` are removed; the keys remain
read-tolerant (ignored by the CLI) and `ui.compactMode` is still forwarded to
the web shell. See docs/design/ctrl-o-detail-expand/design.md §6 for migration.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(ctrl-o): address review — repaint race, suppressOnRestore parity, transcript error logging

- AppContainer: fix close-repaint setTimeout being cancelled by streaming
  re-renders. `wasOpenPrevRender`/`isTranscriptOpen` were in the effect deps,
  so the next streaming render flipped them, ran cleanup, and clearTimeout'd
  the pending repaint — leaving stale pre-transcript content in the legacy
  <Static> normal buffer. Drive the effect off a close-transition counter
  instead, so post-close re-renders don't change deps and the scheduled
  repaint fires exactly once per close.
- AppContainer: transcript snapshot now mirrors MainContent's
  `!display.suppressOnRestore` filter, so items collapsed on session resume
  (ui.history.collapseOnResume) are not re-exposed in the Ctrl+O view.
- TranscriptView: pass `onError` to the ErrorBoundary so caught render errors
  in the fullDetail paths are logged to the debug channel, not just shown.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(ctrl-o): cover detailedDisplay resume derivation + message.parts fallback

Add dedicated resumeHistoryUtils tests for §4.9: detailedDisplay derived
from toolCallResult.responseParts, the `responseParts ?? message.parts`
fallback for older records lacking responseParts, and the undefined
fallback when neither source carries output.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(ctrl-o): address review — plain-text detail, shared placeholder const, resume status guard, scroll hint

Four review fixes on the §4.9 transcript work:

- ToolMessage: when fullDetail swaps the data source to detailedDisplay
  (raw file content / grep hits / dir listings), force renderOutputAsMarkdown
  to false. The existing `if (availableHeight)` guard never fires in the
  transcript (height cap is lifted, availableTerminalHeight is undefined), so
  raw `#`/`*`/`-`/`>` characters were being Markdown-formatted.
- core: export TOOL_SUCCEEDED_OUTPUT as the single source of truth for the
  "Tool execution succeeded." placeholder. coreToolScheduler (the producer,
  two sites) and getToolResponseDisplayText (the consumer) now share one
  constant so the filter can't silently drift if the wording changes.
- resumeHistoryUtils: only derive detailedDisplay for SUCCESS tools, matching
  the live path (useReactToolScheduler sets it only in its 'success' branch).
  Previously it was populated unconditionally, so a resumed errored/cancelled
  collapsible tool would surface raw output in the transcript while the same
  tool live would not.
- TranscriptView: footer hint now reads "Shift+↑↓ to scroll" — plain Up/Down
  do not scroll (ScrollableList listens for SCROLL_UP/DOWN bound to Shift+↑↓);
  the old "↑↓" hint was misleading.

Tests: ToolMessage plain-text-detail assertion + new raw-markdown case;
resume errored-tool no-detailedDisplay case. typecheck/lint/tests green
(core scheduler 222, cli suites pass).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): guard transcript non-TTY output + clear detailedDisplay on compaction

Addresses three review findings on the Ctrl+O transcript work:

- Non-TTY byte leak: `useMouseEvents` enabled SGR mouse mode (?1002h ?1006h)
  whenever stdin supported raw mode, ignoring stdout. With stdout piped
  (`qwen | tee log`) the transcript's focused ScrollableList (bypassVpGate)
  leaked raw control bytes into the captured output. Gate the enable on
  `stdout.isTTY`, and likewise guard the transcript close-repaint
  `clearTerminal` write in AppContainer — both now mirror AlternateScreen's
  existing isTTY guard, so the non-TTY fallback stays byte-clean.

- Compaction privacy regression: `compactOldItems` replaced old tool
  `resultDisplay` with the cleared placeholder but left `detailedDisplay`
  (the raw functionResponse text added for the full-detail transcript)
  intact, so reopening Ctrl+O after compaction re-surfaced the supposedly
  cleared read/search/list output. Clear `detailedDisplay` wherever
  `resultDisplay` is cleared, with a regression test.

- Docs: keyboard-shortcuts.md still described Ctrl+O as "toggle compact
  mode"; updated to the open/close full-detail transcript behavior.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(tui): report a TTY stdout in ScrollableList mouse-scroll tests

The new `stdout.isTTY` gate in `useMouseEvents` (which stops SGR mouse
escapes leaking into piped output) left ink-testing-library's fake
stdout — which has no `isTTY` — with the mouse pipeline disabled, so the
scrollbar-drag and wheel-scroll assertions never received events. Mock
ink's `useStdout` to report `isTTY: true` so the pipeline arms exactly as
it does in a real terminal; all other ink exports are preserved.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): address Ctrl+O transcript review — q-guard, callback churn, tests, cleanup

Resolves the qwen3.7-max /review findings:

- Modifier guard on the transcript close key: bare `q` closed the
  transcript, but Ink reports Ctrl/Alt/Shift+Q as `{ name: 'q', … }` too
  (Alt arrives as `meta`), so those silently closed it. Guard
  `!key.ctrl && !key.meta && !key.shift` (Shift+Q is a literal `Q`).

- Stable `openTranscript`: it captured `historyManager.history` and
  `pendingHistoryItems` as deps, both of which change identity every
  streaming tick, rebuilding the callback — and the whole
  `handleGlobalKeypress` closure that lists it — on every render during
  streaming. Read both via refs so the callback is referentially stable.

- AppContainer transcript integration tests (the removed TOGGLE_COMPACT
  tests had no replacement): Ctrl+O installs TranscriptView; Esc / q /
  Ctrl+C / Ctrl+D close it; Ctrl+Q / Alt+Q / Shift+Q do NOT (modifier
  guard); arbitrary keys are swallowed and keep it open; a blocking
  confirmation (WaitingForConfirmation) auto-closes it (anti-deadlock).

- Dead i18n string: removed the orphaned
  'Press Ctrl+O to show full tool output' key from all 9 locale files
  (no `t()` reference remained after the compact-mode sweep).

- Design doc: replaced the leaked absolute worktree path with a
  placeholder, and corrected the §6 keybinding-migration note — the
  codebase has no user-configurable keybinding override surface
  (`keyMatchers` always uses hardcoded defaults), so there is no
  persisted `toggleCompactMode` binding to migrate; the startup-detection
  step is not applicable until such a feature exists.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): escape ANSI in transcript detailedDisplay + gate its extraction

Two findings from the qwen3.7-max /review on §4.9:

- [Critical] ANSI escape injection: `detailedDisplay` carries raw,
  un-sanitized tool output (file contents, grep hits, directory
  listings). The Ctrl+O transcript rendered it straight to <Text>
  without escaping, so a malicious repo file with embedded terminal
  control sequences (e.g. `\x1b[?1049l` to drop the alt-screen, OSC 52
  for clipboard poisoning) would execute when the transcript opened —
  and fullDetail lifts the height cap, exposing the whole file. Run it
  through `escapeAnsiCtrlCodes` (already used for agent names in this
  file) before rendering. Added a regression test asserting the raw ESC
  bytes don't survive.

- [perf] `detailedDisplay` was extracted on every successful tool call
  (~25K chars from core's truncation) but is consumed only by the
  transcript's fullDetail render for collapsible (read/search/list)
  tools. Gate the extraction on `isCollapsibleTool(displayName)` so
  edit/write/command/agent calls no longer store a large string the
  renderer never reads — mirrors ToolMessage's `usingDetailedDisplay`
  gate (which also keys off the display name).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): gate resume-path detailedDisplay on isCollapsibleTool (match live path)

The resume path (resumeHistoryUtils.ts) extracted `detailedDisplay` for
every successful tool call, unlike the live path in useReactToolScheduler
which gates on `isCollapsibleTool(displayName)`. Since the transcript's
`usingDetailedDisplay` only consumes it for collapsible (read/search/list)
tools, resuming a session with many edit/write/command/agent calls stored
large (~25K char) strings the renderer never reads. Apply the same gate so
live and resume stay consistent, using `toolCall.name` (the display name,
set from `tool.displayName`) to match the renderer's key.

Updated the existing derivation tests to use a collapsible read tool (an
edit tool now correctly yields undefined) and added a regression asserting
a non-collapsible tool leaves detailedDisplay undefined on resume.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): strip bare C0 control bytes from transcript detailedDisplay + memoize

Follow-up to the ANSI-escape fix. `escapeAnsiCtrlCodes` delegates to
ansi-regex, which only matches ESC-prefixed sequences, so bare C0 control
bytes without an ESC prefix (BEL \x07, BS \x08, FF \x0c, SO \x0e, SI \x0f,
CR, …) passed through to <Text> and could still corrupt the display or
ring the bell from a malicious file's contents. Add a second pass that
strips those bytes (keeping only TAB and LF, which structure multi-line
output). Memoize the two-pass sanitization with useMemo keyed on
detailedDisplay so the ~25K-char regex work doesn't re-run every render.

Extended the ToolMessage regression test to assert bare C0 bytes are
stripped alongside the ESC sequences.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(tui): memoize HistoryItemDisplay, add ErrorBoundary tests + TAB/LF invariant

Addresses three review suggestions:

- Wrap `HistoryItemDisplay` in `React.memo` so the Ctrl+O transcript
  (which re-renders on every scroll tick) skips re-rendering
  frozen-snapshot items whose props are shallowly unchanged. The
  transcript passes stable `item` references, so the default shallow
  compare is effective; harmless for the main view (items live in
  `<Static>` and render once).

- Add ErrorBoundary.test.tsx covering the four behaviors: renders
  children when healthy, catches a render error into the default
  fallback with the message, renders a custom fallback, calls `onError`
  with the error + component stack, and `reset` clears the error state so
  the subtree recovers.

- Lock the C0-strip invariant: assert TAB and LF survive in
  detailedDisplay (the regex intentionally skips \x09/\x0a) so a future
  regex change can't silently collapse multi-line/columnar output.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* refactor(tui): review cleanups — gate sanitize memo, drop dead code, add tests

Addresses the latest /review suggestions:

- ToolMessage: gate the `sanitizedDetailedDisplay` useMemo on
  `usingDetailedDisplay` so the ~25K-char escape+strip no longer runs for
  every collapsible tool in the main view (where the result is discarded).

- TranscriptView: remove the dead `listRef` (created + passed as `ref` but
  never used imperatively) and the dead `onClose` prop (declared, then
  `void`-ed; close keys are owned entirely by AppContainer's global
  keypress guard). Dropped the now-unused `useRef` / `ScrollableListRef`
  imports and the `onClose` call-site + props.

- Tests: add TranscriptView error-fallback coverage (a throwing item
  renders the recovery fallback, not a crash); add live-path
  `mapToDisplay` detailedDisplay extraction coverage (collapsible →
  extracted, non-collapsible → undefined); add Ctrl+O to the transcript
  close-keys it.each (the toggle key was the only close key untested).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(tui): remove orphaned no-op CompactModeProvider stubs

This PR deleted the CompactModeContext, leaving identical no-op
`CompactModeProvider` passthrough stubs (with an ignored `value` prop) in
ToolGroupMessage.test.tsx, ToolMessage.test.tsx and MainContent.test.tsx,
each still wrapping every render. Remove the stubs and unwrap the renders;
drop the now-meaningless `compactMode` params/args from the local render
helpers. Behavior-preserving (the stubs rendered children verbatim) —
all three suites still pass.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): strip bidi overrides, sanitize error fallbacks, share filters

Latest /review round:

- [Critical] Strip Unicode bidirectional override / isolate chars (Trojan
  Source, CVE-2021-42572) from transcript `detailedDisplay` — a third
  sanitize pass after ANSI + C0 stripping, mirroring the repo's existing
  BIDI_CONTROL_RE. Regression test added.

- Sanitize `error.message` with `escapeAnsiCtrlCodes` in both the
  ErrorBoundary default fallback and the TranscriptView custom fallback
  (defense-in-depth against control codes in a crafted error message).

- Ctrl+O while the ThinkingViewer is open now swaps to the transcript
  (falls through to openTranscript, which clears the viewer) instead of
  being silently swallowed.

- Extract the shared `isHistoryItemVisibleAfterRestore` predicate into
  types.ts and use it from both MainContent (main view) and AppContainer
  (transcript freeze), so the two surfaces can't diverge on which
  collapse-on-resume items are hidden.

- Tests: use the exported `TOOL_SUCCEEDED_OUTPUT` constant instead of the
  hardcoded literal in generateContentResponseUtilities.test.ts.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): harden compaction guard to always clear detailedDisplay

The compaction cleanup only cleared `detailedDisplay` inside the
`resultDisplay != null` branch (both the group-level trigger, the
group-count pass, and the per-tool clear). A tool carrying only
`detailedDisplay` (no resultDisplay) would skip compaction and leave the
raw transcript detail intact — a latent privacy leak if the two fields
ever decouple. Widen all three checks to also match `detailedDisplay !=
null` so the memory/privacy safeguard is robust. Added a defensive
regression test.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): sanitize mime/uri in getToolResponseDisplayText media placeholders

The `<media: …>` placeholder interpolated `inlineData.mimeType` /
`fileData.mimeType` / `fileData.fileUri` from tool responses verbatim. A
crafted response could embed control characters or angle brackets to
inject terminal codes or forge/mangle the placeholder markup. Add a
`sanitizeMediaLabel` helper that strips C0/C1 control bytes and `<`/`>`
before interpolation, falling back to the default label when emptied.
Regression test added.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(tui): report a TTY stdout in BaseSelectionList mouse integration test

The `stdout.isTTY` gate added to `useMouseEvents` (stops SGR mouse escapes
leaking into piped output) left #6011's BaseSelectionList mouse test —
which renders via ink-testing-library where the hook-provided stdout reads
as non-TTY — with the mouse layer disabled, so the any-event enable escape
was never written. Mock ink's `useStdout` to report `isTTY: true` with a
capturing write spy (matching useMouseEvents.test.tsx / ScrollableList.test
.tsx), and assert the `?1003h` enable via that spy while items still render
through ink's own stdout. Both cases pass.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(core): fix JSDoc placement + note ErrorBoundary fallback is un-translated

Two small review nits:

- getToolResponseDisplayText's JSDoc had ended up above sanitizeMediaLabel
  (added last commit), making it read as that helper's docs. Reorder so
  sanitizeMediaLabel + its own JSDoc come first and each doc sits directly
  above its function.

- Document why the ErrorBoundary default fallback's title is intentionally
  a plain English string (last-resort message for callers with no
  `fallback`; renders mid-crash, so it avoids pulling in the i18n layer —
  the transcript passes its own localized fallback anyway).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(tui): share terminal-sanitize pipeline; guard AlternateScreen writes

- Extract the three-pass sanitizer (ANSI escape + bare-C0 strip + bidi
  strip) into `sanitizeTerminalText` in textUtils.ts as the single source
  of truth, and use it at all raw-text render sites: ToolMessage's
  `detailedDisplay`, and the TranscriptView + ErrorBoundary error-message
  fallbacks (previously those only escaped ANSI, missing C0/bidi — the
  boundary catches errors from the fullDetail path that processes raw tool
  output, so a crafted item shape could carry unsanitized bytes into
  error.message). Removes the duplicated regex consts from ToolMessage.

- AlternateScreen: wrap the alt-screen escape writes (and the exit/cleanup
  writes) in try/catch so a synchronous stdout error (EPIPE on terminal
  close, EAGAIN under backpressure) can't propagate uncaught from the
  effect and crash the app or corrupt the terminal.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-09 23:40:29 +00:00

198 KiB
Raw Permalink 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 togglable 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

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 open the full-detail transcript 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. Recommended if you see flicker, scroll-storm, or 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; hold Shift (or Option on macOS) while dragging for native text selection. false
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 number 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, 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. true
model.maxToolCallsPerTurn number Hard cap on tool calls within a single turn (one model turn plus its tool-result continuations; blocking Stop-hook continuations such as /goal iterations start a fresh budget). Always-on circuit breaker against runaway turns, independent of model.skipLoopDetection; the pattern-based loop detectors fire long before this cap, which only bounds total volume. 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

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 QWEN_STREAM_IDLE_TIMEOUT_MS, which bounds inactivity between streamed chunks.

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, it is transcribed by this model first. Leave empty to auto-pick a same-provider vision model. Can also be set via /model --vision. ""

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 Fraction of the context window at which auto-compaction triggers. Must be greater than 0 and at most 1. Default is 0.7 (70%). For large context windows (>110K tokens), the absolute branch of the three-tier threshold system dominates, so values below ~0.7 may have no visible effect. Custom thresholds primarily affect small-window models (≤128K). Replaces the old model.chatCompression.contextPercentageThreshold. undefined (uses internal 0.7)
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. 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.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.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. default 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

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

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

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.disabled array of strings Skill names to hide. Matched case-insensitively against the skill name. Hidden skills do not appear in <available_skills> or as /<name> slash commands. Merged as a union across user/project/system scopes, so a project cannot remove entries defined in user or system settings. undefined

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

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. ["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.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 the Artifact tool, letting the model publish a self-contained HTML page and open it in the browser. Interactive, non-SDK sessions only. QWEN_CODE_ENABLE_ARTIFACT=1 enables metadata-only record_artifact for non-SDK daemon sessions and also enables the Artifact tool in interactive sessions; QWEN_CODE_DISABLE_ARTIFACT=1 disables both. Requires restart. false
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 all tool call confirmations. 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.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,
    "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. You can customize this behavior using the advanced.excludedEnvVarssetting in your settings.json file.

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_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_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_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. 5 directories can be added at maximum. 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 of the tools that are called, whether they succeed or fail, 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
  }
}

Note

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