Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1596751
feat(skills): add auto-skill curator
DragonnZhang Jul 27, 2026
d70df62
fix(i18n): translate /curator command descriptions for zh and zh-TW
claude Jul 27, 2026
91699bf
fix(i18n): add English source keys for /curator command
claude Jul 27, 2026
fc10834
fix(skills): align curator lifecycle safeguards
DragonnZhang Jul 28, 2026
d5a1c70
fix(skills): harden curator trust and name guards
DragonnZhang Jul 28, 2026
a0c943a
fix(skills): guard curator mutations by workspace trust
DragonnZhang Jul 28, 2026
2f8b325
test(skills): cover curator stale-to-active reactivation path
claude Jul 28, 2026
6ca1eb9
Merge branch 'main' into dragon/auto-skill-curator
claude Jul 28, 2026
70d1395
test(skills): cover curator rollback and restore-collision paths
claude Jul 28, 2026
f35f0fe
test(cli): cover curator command errors and stacked auto-skill usage
claude Jul 28, 2026
171ac3f
fix(skills): reject control-byte auto-skill directory names
claude Jul 28, 2026
1c3c030
fix(skills): guard curator state reads and clarify restore errors
claude Jul 28, 2026
4915a72
fix(skills): close curator TOCTOU reads and preserve seeding baseline
claude Jul 28, 2026
2bf5324
Merge branch 'main' into dragon/auto-skill-curator
qwen-code-dev-bot Jul 28, 2026
c95980b
Merge branch 'main' into dragon/auto-skill-curator
qwen-code-dev-bot Jul 28, 2026
f3814a1
fix(core): harden auto-skill curator per review feedback (#7846)
qwen-code-dev-bot Jul 28, 2026
8d4b0a4
test(core): cover curator restore rollback and re-read guard (#7846)
qwen-code-dev-bot Jul 28, 2026
f7e2178
fix(core): record auto-skill usage on re-invocation (#7846)
qwen-code-dev-bot Jul 29, 2026
ddfac38
Merge branch 'main' into dragon/auto-skill-curator
qwen-code-dev-bot Jul 29, 2026
536f3a6
Merge branch 'main' into dragon/auto-skill-curator
qwen-code-dev-bot Jul 29, 2026
1a3c632
Merge branch 'main' into dragon/auto-skill-curator
wenshao Jul 29, 2026
86f63a4
Merge branch 'main' into dragon/auto-skill-curator
qwen-code-dev-bot Jul 29, 2026
83e3854
fix(skills): preserve curator read failures
DragonnZhang Jul 29, 2026
2d6c8f9
fix(skills): harden curator lifecycle guards
DragonnZhang Jul 30, 2026
3b8d733
test(skills): cover curator safety paths
DragonnZhang Jul 30, 2026
1bd2238
fix(skills): address curator review findings (#7846)
Jul 30, 2026
b753a50
fix(cli): localize curator messages
DragonnZhang Jul 31, 2026
fec3a19
Merge branch 'main' into dragon/auto-skill-curator
Aug 1, 2026
1829624
test(skills): cover curator usage safeguards
DragonnZhang Aug 1, 2026
77f11c0
fix(skills): address curator review feedback (#7846)
qwen-code-ci-bot Aug 1, 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
117 changes: 117 additions & 0 deletions docs/design/2026-07-27-auto-skill-curator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Auto-Skill Curator

## Problem

Qwen Code can extract reusable project skills from tool-heavy conversations,
but accepted auto-skills only accumulate. The existing review agent can create
or update `source: auto-skill` skills and is explicitly forbidden from deleting
them. Path gating and `skills.disabled` reduce prompt noise but do not maintain
the on-disk library.

## Scope

Add a small, deterministic lifecycle manager for project auto-skills:

- Track successful invocations of project skills whose directory starts with
`auto-skill-` and whose frontmatter contains `source: auto-skill`.
- Mark a managed skill stale after 30 days without activity.
- Archive it after 90 days without activity by moving its whole directory out
of `.qwen/skills/` into `.qwen/archived-skills/`.
- Allow individual managed skills to be pinned out of automatic transitions.
- Run the deterministic pass at most once every 7 days during configuration
initialization when Auto Skill is enabled and the workspace is trusted.
- Expose `/curator`, `/curator status`, `/curator run [--dry-run]`, and
`/curator pin|unpin|restore <directory>` in interactive, non-interactive,
and ACP command surfaces.

This first version does not use an LLM, consolidate overlapping skills, manage
personal/bundled/extension/learned/hand-authored skills, permanently delete
anything, or introduce configurable thresholds.

## Ownership and persistence

The curator is resolved only from `Config.getProjectRoot()`. Its state lives at
`<project>/.qwen/skill-curator.json`, and archived packages live at
`<project>/.qwen/archived-skills/`. There is no fallback to the process's
primary workspace, home directory, or another active session. This keeps
daemon and multi-workspace sessions isolated.

State is keyed by the auto-skill directory name because that is the unit moved
to and from the archive. Each record stores the frontmatter skill name,
first-seen time, last successful use, use count, lifecycle state, pin state,
and optional archive time. Writes are serialized with a cross-process lock and
committed atomically.

Corrupt state is a hard, non-mutating failure. The curator must not infer that
missing usage means inactivity when its persisted evidence cannot be read.

## Eligibility and safety

A directory is curator-managed only when every condition holds:

1. It is a direct, non-symlink directory under the project skills root.
2. Its name starts with `auto-skill-`.
3. It contains a regular, non-symlink `SKILL.md`.
4. The opening YAML frontmatter contains exactly `source: auto-skill`.

This double marker prevents the curator from moving hand-authored, learned,
extension, bundled, personal, malformed, or symlinked content. Archive and
restore never overwrite an existing skill. A destination collision skips only
that package so unrelated maintenance can continue. Archived directory names
are shown as reserved in the review prompt and rejected by its write permission
guard, while confirmation staging still snapshots active skills only.
If state persistence fails after moves, the pass attempts to move every package
back before surfacing the error.

Read-only status and dry-run previews remain available in safe mode and
untrusted workspaces. Applying a maintenance pass, pinning, unpinning, and
restoring require a trusted workspace outside safe mode.

## Activity and transitions

A successful Skill tool or direct skill slash-command invocation updates an
eligible auto-skill record best-effort, even while automatic skill generation
is disabled. This keeps observed activity independent from the switch that
controls generation and scheduled maintenance. Failed, skill-disabled, or
hook-blocked invocations do not count.

For a live skill, activity is the newest of:

- the persisted last successful invocation;
- the persisted first-seen time;
- the persisted restore time; and
- the skill manifest modification time.

Including modification time prevents a recently improved skill from being
archived merely because it has not yet been invoked again.

The first observation of each eligible skill seeds `firstSeenAt = now` rather
than inferring inactivity from an old filesystem timestamp. The first automatic
observation also seeds `lastRunAt`, then waits a full 7-day interval. Explicit
`/curator run` bypasses the interval but preserves per-skill first-sight grace;
`--dry-run` reports the same seeding and transition candidates without moving
directories or changing state. Pinned records bypass stale and archive
transitions until explicitly unpinned.

## Integration points

- `Config.initialize`: performs the due deterministic pass before
`SkillManager` scans the filesystem.
- `SkillTool`: records a successful managed-skill invocation.
- `SkillCommandLoader` and the interactive/non-interactive command processors:
record successful direct slash-command invocations; ACP reuses the
non-interactive processor.
- `SkillManager`: its existing refresh path is used after manual archive or
restore so the model and slash-command surfaces immediately match disk.
- `BuiltinCommandLoader`: publishes the new `/curator` command.

No other consumer should write curator state or move managed skill packages.

## Verification

Unit tests cover eligibility, first-run seeding, stale/archive thresholds,
dry-run non-mutation, recent-use protection, recently-modified protection,
corrupt-state fail-closed behavior, collision handling, restoration, and the
command surface. Existing Skill tool tests verify that only successful loads
record usage. Build and typecheck cover the cross-package export and command
registration.
1 change: 1 addition & 0 deletions docs/users/features/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Commands for managing AI tools and models.
| `/import-config` | Import MCP servers from Claude configs | `/import-config all`, `/import-config claude-code`, `/import-config claude-desktop --scope user\|project` |
| `/tools` | Display currently available tool list | `/tools`, `/tools desc` |
| `/skills` | Open the Skills panel to browse, search, toggle, and launch skills | `/skills`, `/<skill-name>` |
| `/curator` | Inspect, pin, archive, or restore inactive project auto-skills | `/curator`, `/curator run --dry-run`, `/curator pin <directory>`, `/curator restore <directory>` |
| `/plan` | Switch to plan mode or exit plan mode | `/plan`, `/plan <task>`, `/plan exit` |
| `/approval-mode` | Change the tool-approval mode (current session only) | `/approval-mode`, `/approval-mode auto-edit` |
| → `plan` | Analysis only, no execution (secure review) | `/approval-mode plan` |
Expand Down
14 changes: 14 additions & 0 deletions docs/users/features/skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ Use project Skills for:

Project Skills can be checked into git and automatically become available to teammates.

### Maintain auto-generated project Skills

Qwen Code tracks successful uses of generated project Skills locally, including while new Auto Skill generation is disabled, so re-enabling maintenance cannot mistake a recently used skill for an inactive one. When **Auto Skill** is enabled, it periodically moves inactive generated Skills out of the active library. Only directories named `.qwen/skills/auto-skill-*` whose `SKILL.md` frontmatter contains `source: auto-skill` are managed; personal, extension, bundled, and hand-authored Skills are never selected.

- After 30 days without a successful use or `SKILL.md` edit, an auto-skill is marked stale.
- After 90 days, its complete directory is moved to `.qwen/archived-skills/`. Nothing is permanently deleted.
- Automatic maintenance runs at most once every 7 days in trusted workspaces. Each newly observed auto-skill gets a full grace period before maintenance begins.
- A pinned auto-skill is excluded from automatic stale and archive transitions until it is unpinned.
- Archived directory names remain reserved, and an existing archive destination skips only that collision rather than stopping maintenance for other skills.

Use `/curator` to see active, stale, archived, and pinned auto-skills. Run `/curator run --dry-run` to preview a maintenance pass, `/curator run` to apply it immediately, `/curator pin <directory>` or `/curator unpin <directory>` to control per-skill maintenance, or `/curator restore <directory>` to move an archived auto-skill back into the active library.

Status and dry-run previews are available in safe mode and untrusted workspaces. Applying maintenance, changing pins, and restoring archived auto-skills require a trusted workspace outside safe mode.

## Write `SKILL.md`

Create a `SKILL.md` file with YAML frontmatter and Markdown content:
Expand Down
59 changes: 59 additions & 0 deletions packages/cli/src/i18n/locales/ca.js
Original file line number Diff line number Diff line change
Expand Up @@ -2758,4 +2758,63 @@ export default {
'Executant aquesta tasca programada en una sessió nova: {{link}}',
'This scheduled run could not be started: {{error}}':
"Aquesta execució programada no s'ha pogut iniciar: {{error}}",

// ==========================================================================
// Auto-skill curator (/curator command)
// ==========================================================================
'Maintain project auto-skills based on recent use.':
"Gestiona les habilitats automàtiques del projecte segons l'ús recent.",
'Show project auto-skill lifecycle status.':
'Mostra l’estat del cicle de vida de les habilitats automàtiques del projecte.',
'Run project auto-skill lifecycle maintenance.':
'Executa el manteniment del cicle de vida de les habilitats automàtiques del projecte.',
'Restore an archived project auto-skill.':
'Restaura una habilitat automàtica del projecte arxivada.',
'Auto-skill curator': "Gestor d'habilitats automàtiques",
'Last run: {{time}}': 'Última execució: {{time}}',
'Active: {{count}}': 'Actives: {{count}}',
'Stale: {{count}}': 'Obsoletes: {{count}}',
'Archived: {{count}}': 'Arxivades: {{count}}',
'Stale skills:': 'Habilitats obsoletes:',
'Pinned skills:': 'Habilitats fixades:',
'Archived skills:': 'Habilitats arxivades:',
'Dry run complete.': 'Simulació completada.',
'Curator run complete.': 'Execució del gestor completada.',
'Checked: {{count}}': 'Comprovades: {{count}}',
'First observed: {{count}}': 'Observades per primera vegada: {{count}}',
'Marked stale: {{count}}': 'Marcades com a obsoletes: {{count}}',
'Reactivated: {{count}}': 'Reactivades: {{count}}',
'Skipped archive collisions: {{count}}':
"Col·lisions d'arxivament omeses: {{count}}",
'Archive candidates:': "Candidates a l'arxivament:",
'Skipped archive collisions:': "Col·lisions d'arxivament omeses:",
'Skipped rename errors: {{count}}':
'Errors de canvi de nom omesos: {{count}}',
'Skipped rename errors:': 'Errors de canvi de nom omesos:',
'{{verb}}: {{count}}': '{{verb}}: {{count}}',
'Would archive': "S'arxivarien",
Archived: 'Arxivades',
'Failed to read auto-skill curator status: {{message}}':
"No s'ha pogut llegir l'estat del gestor d'habilitats automàtiques: {{message}}",
'Usage: /curator run [--dry-run]': 'Ús: /curator run [--dry-run]',
'Failed to run auto-skill curator: {{message}}':
"No s'ha pogut executar el gestor d'habilitats automàtiques: {{message}}",
'Usage: /curator restore <directory>': 'Ús: /curator restore <directori>',
'Restored auto-skill: {{name}}': 'Habilitat automàtica restaurada: {{name}}',
'Failed to restore auto-skill: {{message}}':
"No s'ha pogut restaurar l'habilitat automàtica: {{message}}",
'Exclude an auto-skill from automatic maintenance.':
'Exclou una habilitat automàtica del manteniment automàtic.',
'Return a pinned auto-skill to automatic maintenance.':
'Retorna una habilitat automàtica fixada al manteniment automàtic.',
'Usage: /curator pin <directory>': 'Ús: /curator pin <directori>',
'Usage: /curator unpin <directory>': 'Ús: /curator unpin <directori>',
'Pinned auto-skill: {{name}}': 'Habilitat automàtica fixada: {{name}}',
'Unpinned auto-skill: {{name}}': 'Habilitat automàtica desfixada: {{name}}',
'Failed to update auto-skill pin: {{message}}':
"No s'ha pogut actualitzar la fixació de l'habilitat automàtica: {{message}}",
'Auto-skill curator changes are disabled in safe mode.':
"Els canvis del gestor d'habilitats automàtiques estan desactivats en mode segur.",
'Auto-skill curator changes are only available in trusted workspaces. Trust this folder via `/trust` and try again.':
"Els canvis del gestor d'habilitats automàtiques només estan disponibles en espais de treball de confiança. Marca aquesta carpeta com a fiable amb `/trust` i torna-ho a provar.",
};
61 changes: 61 additions & 0 deletions packages/cli/src/i18n/locales/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -2238,4 +2238,65 @@ export default {
'Die Sitzungsaufzeichnung wurde nach einem Schreibfehler beendet. Neue Nachrichten der betroffenen Sitzung werden nicht gespeichert. Prüfen Sie Speicherplatz und Berechtigungen und starten Sie anschließend eine neue Sitzung, um die Aufzeichnung fortzusetzen. Weitere Details finden Sie im Debug-Protokoll.',
'Session recording stopped after a write failure. New messages for the affected session will not be saved. Check disk space and permissions, then run `/clear` to start a new recorded session. See the debug log for details.':
'Die Sitzungsaufzeichnung wurde nach einem Schreibfehler beendet. Neue Nachrichten der betroffenen Sitzung werden nicht gespeichert. Prüfen Sie Speicherplatz und Berechtigungen und führen Sie anschließend `/clear` aus, um eine neue aufgezeichnete Sitzung zu starten. Weitere Details finden Sie im Debug-Protokoll.',

// ==========================================================================
// Auto-skill curator (/curator command)
// ==========================================================================
'Maintain project auto-skills based on recent use.':
'Projekt-Auto-Skills anhand der letzten Nutzung verwalten.',
'Show project auto-skill lifecycle status.':
'Lebenszyklusstatus der Projekt-Auto-Skills anzeigen.',
'Run project auto-skill lifecycle maintenance.':
'Lebenszykluswartung der Projekt-Auto-Skills ausführen.',
'Restore an archived project auto-skill.':
'Einen archivierten Projekt-Auto-Skill wiederherstellen.',
'Auto-skill curator': 'Auto-Skill-Kurator',
'Last run: {{time}}': 'Letzter Durchlauf: {{time}}',
'Active: {{count}}': 'Aktiv: {{count}}',
'Stale: {{count}}': 'Veraltet: {{count}}',
'Archived: {{count}}': 'Archiviert: {{count}}',
'Stale skills:': 'Veraltete Skills:',
'Pinned skills:': 'Fixierte Skills:',
'Archived skills:': 'Archivierte Skills:',
'Dry run complete.': 'Testlauf abgeschlossen.',
'Curator run complete.': 'Kurator-Durchlauf abgeschlossen.',
'Checked: {{count}}': 'Geprüft: {{count}}',
'First observed: {{count}}': 'Erstmals erfasst: {{count}}',
'Marked stale: {{count}}': 'Als veraltet markiert: {{count}}',
'Reactivated: {{count}}': 'Reaktiviert: {{count}}',
'Skipped archive collisions: {{count}}':
'Übersprungene Archivierungskonflikte: {{count}}',
'Archive candidates:': 'Archivierungskandidaten:',
'Skipped archive collisions:': 'Übersprungene Archivierungskonflikte:',
'Skipped rename errors: {{count}}':
'Übersprungene Umbenennungsfehler: {{count}}',
'Skipped rename errors:': 'Übersprungene Umbenennungsfehler:',
'{{verb}}: {{count}}': '{{verb}}: {{count}}',
'Would archive': 'Würde archivieren',
Archived: 'Archiviert',
'Failed to read auto-skill curator status: {{message}}':
'Status des Auto-Skill-Kurators konnte nicht gelesen werden: {{message}}',
'Usage: /curator run [--dry-run]': 'Verwendung: /curator run [--dry-run]',
'Failed to run auto-skill curator: {{message}}':
'Auto-Skill-Kurator konnte nicht ausgeführt werden: {{message}}',
'Usage: /curator restore <directory>':
'Verwendung: /curator restore <Verzeichnis>',
'Restored auto-skill: {{name}}': 'Auto-Skill wiederhergestellt: {{name}}',
'Failed to restore auto-skill: {{message}}':
'Auto-Skill konnte nicht wiederhergestellt werden: {{message}}',
'Exclude an auto-skill from automatic maintenance.':
'Einen Auto-Skill von der automatischen Wartung ausschließen.',
'Return a pinned auto-skill to automatic maintenance.':
'Einen fixierten Auto-Skill wieder automatisch warten.',
'Usage: /curator pin <directory>': 'Verwendung: /curator pin <Verzeichnis>',
'Usage: /curator unpin <directory>':
'Verwendung: /curator unpin <Verzeichnis>',
'Pinned auto-skill: {{name}}': 'Auto-Skill fixiert: {{name}}',
'Unpinned auto-skill: {{name}}': 'Fixierung aufgehoben: {{name}}',
'Failed to update auto-skill pin: {{message}}':
'Fixierung des Auto-Skills konnte nicht aktualisiert werden: {{message}}',
'Auto-skill curator changes are disabled in safe mode.':
'Änderungen durch den Auto-Skill-Kurator sind im Sicherheitsmodus deaktiviert.',
'Auto-skill curator changes are only available in trusted workspaces. Trust this folder via `/trust` and try again.':
'Änderungen durch den Auto-Skill-Kurator sind nur in vertrauenswürdigen Arbeitsbereichen verfügbar. Stufen Sie diesen Ordner mit `/trust` als vertrauenswürdig ein und versuchen Sie es erneut.',
};
Loading
Loading