Skip to content
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
2faa4d3
fix(core): harden auto mode self-modification checks
qqqys May 27, 2026
0ed3ce5
fix(core): address auto mode review feedback
qqqys May 27, 2026
c6aabe2
fix(core): preserve shell-style absolute paths
qqqys May 27, 2026
31016a4
fix(core): avoid regex slash trimming in shell semantics
qqqys May 27, 2026
1cae556
test(core): cover shell rule relevance ordering
qqqys May 31, 2026
7d148a9
fix(core): close auto mode fallback review gaps
qqqys May 31, 2026
a964d13
fix(core): harden auto mode cwd review paths
qqqys May 31, 2026
59079fd
perf(core): Cache auto mode write path candidates
qqqys May 31, 2026
7ec50ee
fix(core): refine auto mode protected write review
qqqys May 31, 2026
7ed81ad
fix(core): track pushd in shell semantics
qqqys May 31, 2026
67afded
fix(core): harden dynamic shell cwd permissions
qqqys Jun 1, 2026
6748944
fix(core): harden auto-mode shell write detection
qqqys Jun 1, 2026
43ea551
fix(core): harden shell semantic bypasses
qqqys Jun 1, 2026
d23569a
fix(core): route pending auto allows through classifier
qqqys Jun 1, 2026
ff7e40f
Merge main into feat/auto-mode-harden
qqqys Jun 1, 2026
d24dee1
fix(core): avoid regex shell syntax trimming
qqqys Jun 1, 2026
7c49a91
fix(core): fire pending auto denial hooks
qqqys Jun 1, 2026
be9456c
test(cli): cover ACP protected Bash auto review
qqqys Jun 1, 2026
db36135
fix(core): guard pending permission denied hook failures
qqqys Jun 2, 2026
2a146c7
test(cli): cover ACP auto denial for protected Bash writes
qqqys Jun 2, 2026
c5cbd7d
fix(core): guard PermissionDenied hook failures
qqqys Jun 2, 2026
05d5ff4
fix(core): re-resolve auto mode write paths
qqqys Jun 2, 2026
b9d3906
Merge upstream/main into feat/auto-mode-harden
qqqys Jun 3, 2026
25dfdff
fix(core): catch disguised protected shell writes
qqqys Jun 3, 2026
ab3e7c3
fix(core): catch additional protected shell writes
qqqys Jun 3, 2026
e66a4c9
fix(core): harden raw protected redirect parsing
qqqys Jun 3, 2026
050456f
fix(core): close protected shell write gaps
qqqys Jun 3, 2026
19c5f7a
fix(core): keep auto fallback protected writes pending
qqqys Jun 3, 2026
8d3e1ae
fix(core): detect sort output protected writes
qqqys Jun 4, 2026
cd34b44
fix(core): detect protected target-directory writes
qqqys Jun 4, 2026
59d2496
fix(core): detect raw protected shell writes
qqqys Jun 4, 2026
86b73a4
fix(core): harden auto mode shell write detection
qqqys Jun 4, 2026
633a108
fix(core): detect attached downloader output flags
qqqys Jun 4, 2026
4d4174d
feat(core): configure auto classifier controls
qqqys Jun 4, 2026
586b7cf
fix(core): catch attached protected write flags
qqqys Jun 5, 2026
f2cf68b
fix(core): enforce minimum classifier timeout
qqqys Jun 5, 2026
980a545
fix(core): close auto mode shell bypasses
qqqys Jun 5, 2026
268e174
test(core): cover find execdir protected writes
qqqys Jun 5, 2026
0bf65a1
fix(core): detect awk in-place edits
qqqys Jun 6, 2026
3d5c7cd
fix(core): preserve auto mode denial prefix
qqqys Jun 6, 2026
16dfa83
test(core): cover awk long-form inplace flag
qqqys Jun 6, 2026
aa5b9b6
fix(core): handle pending auto fallback flow
qqqys Jun 6, 2026
2b33bbe
fix(core): keep protected pending tools manual on fallback
qqqys Jun 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 54 additions & 9 deletions docs/users/features/auto-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ walks three layers in order:

1. **acceptEdits fast-path** — Edit / Write whose target path is inside
the workspace is auto-approved without invoking the classifier.
**Exception:** writes to Qwen Code's own self-modification surfaces
(`.qwen/settings*.json`, `QWEN.md`, `AGENTS.md`, `QWEN.local.md`,
configured context filenames, `.qwen/rules/`, `.qwen/commands/`,
`.qwen/agents/`, `.qwen/skills/`, `.qwen/hooks/`, `.mcp.json`) and
persistence surfaces (`.git/`, `.husky/`, `package.json`, `.npmrc`,
`Makefile`, `.github/workflows/`, etc.) route through the classifier
even when they are inside the workspace. Symlinks targeting protected
paths are resolved and rejected too. Shell commands that reach these
paths via `cd && bash -lc '...'` or other wrappers go through the
classifier as well.
2. **Safe-tool allowlist** — Read-only and metadata-only built-in tools
(Read, Grep, Glob, LS, LSP, TodoWrite, AskUserQuestion, etc.) are
auto-approved without invoking the classifier.
Expand Down Expand Up @@ -42,7 +52,12 @@ runs:
classifier never sees it.
- `permissions.allow` rules with specific specifiers (e.g.
`Bash(git status)`, `Read(./docs/**)`) still auto-allow without the
classifier.
classifier — **except** when the call resolves to a write at a
protected self-modification or persistence path (see the list under
"How it works"). In that case Auto Mode re-checks the call through
the classifier so an allow rule on `Bash(*)` cannot silently turn
into permission to rewrite Qwen Code settings, commands, hooks,
skills, or MCP servers.
- `permissions.ask` rules force manual confirmation even in Auto Mode.

## Over-broad allow rules are stripped while in Auto Mode
Expand All @@ -69,6 +84,19 @@ entries are natural-language descriptions, not rule patterns — they are
injected additively into the classifier's system prompt alongside the
built-in defaults.

There are three hint categories plus an environment list:

- **`allow`** — actions the classifier should auto-approve.
- **`softDeny`** — destructive or irreversible actions the classifier
should block **unless the user's most recent explicit request asked
for that exact action and scope**. Soft denies can be cleared by
user intent; a generic "yes do whatever" doesn't count.
- **`hardDeny`** — security-boundary actions the classifier must block
in Auto Mode regardless of `autoMode.hints.allow` or recent user
intent. This is classifier policy, not a deterministic permission
rule: it does not override `permissions.allow`. Use `permissions.deny`
for actions that must never be allowed by the permission manager.

```json
{
"permissions": {
Expand All @@ -79,10 +107,13 @@ built-in defaults.
"Cleaning build artifacts under ./dist or ./build",
"Reading any file under /Users/me/code/"
],
"deny": [
"Any network call to intranet.example.com endpoints",
"Modifying anything under ~/.ssh or ~/.aws",
"softDeny": [
"Editing Qwen Code settings unless I explicitly ask for the exact change",
"Running migration scripts that touch the production DB"
],
"hardDeny": [
"Sending secrets or .env contents to any network endpoint",
"Modifying anything under ~/.ssh or ~/.aws"
]
},
"environment": [
Expand All @@ -94,13 +125,18 @@ built-in defaults.
}
```

`hints.deny` is still accepted for backward compatibility and is treated
as `softDeny`. Mixing both is fine — entries are concatenated, `softDeny`
first.

### Length and count limits

To keep the classifier system prompt small:

- Each entry is capped at 200 characters (longer entries are truncated
with a warning).
- `hints.allow` and `hints.deny` accept up to 50 entries each.
- `hints.allow`, `hints.softDeny`, and `hints.hardDeny` accept up to 50
entries each.
- `environment` accepts up to 20 entries.

### Layering across settings files
Expand All @@ -114,15 +150,24 @@ de-duplicated.
When the classifier blocks an action, the tool call fails with one of
the following error texts:

- **`Blocked by auto mode policy: <reason>`** — the classifier judged
the action unsafe. The reason comes from Stage 2 of the classifier.
- **`Permission for this action has been denied. Reason: <reason>`** —

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Docs/code prefix mismatch: this line still reads Permission for this action has been denied. Reason: <reason>, but commit 3d5c7cd84 changed autoMode.ts:602 to emit Blocked by auto mode policy: <reason>. The PR diff actually reverted this doc line from the correct new prefix back to the old one.

Suggested change
- **`Permission for this action has been denied. Reason: <reason>`**
- **`Blocked by auto mode policy: <reason>`**

— qwen3.7-max via Qwen Code /review

the classifier judged the action unsafe. The reason comes from Stage
2 of the classifier.
- **`Auto mode classifier unavailable; action blocked for safety`** —
the classifier API was unreachable, timed out, or returned an
un-parseable response. This is fail-closed behavior: when in doubt,
block.

The main LLM sees the same message in the tool result and adjusts its
approach (asks you, switches tactic, gives up).
Both messages are followed by a trailing guidance line telling the agent
that the **denied action specifically** must not be completed through
another tool, shell indirection, generated script, alias, symlink,
config change, hook, command file, MCP configuration, encoded payload,
or equivalent path. **Unrelated safe work and genuinely safer
alternatives are still allowed** — only attempts to accomplish the same
denied intent through a different surface are blocked.

If the denied action is genuinely required, the agent should stop and
ask you for explicit approval rather than route around the denial.

### Classifier reason language

Expand Down
Loading
Loading