Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 30 additions & 1 deletion docs/declarative-agents-port.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,36 @@ coordinating with the workflow port in issue [#4721][i4721] / PR [#4732][p4732].
[i4721]: https://github.com/QwenLM/qwen-code/issues/4721
[p4732]: https://github.com/QwenLM/qwen-code/pull/4732

**Implementation status:** PR [#4842](https://github.com/QwenLM/qwen-code/pull/4842) ships `permissionMode`, `maxTurns`, and a tightened `color` allowlist. The other fields documented below are reference material for follow-up PRs once their prerequisite infra exists (`effort` → model-layer param; `mcpServers`/`hooks` → nested YAML parser; `memory` → scoped memory subsystem; `isolation` → workflow PR #4732; `initialPrompt` → `--agent` flag; `skills` → SkillManager wiring).
## Implementation status (vertical-sliced)

PR [#4842][p4842] shipped the fields with an end-to-end runtime path at the
time. PR [#4870][p4870] then replaced the YAML parser to support block
scalars. This follow-up PR builds on both: it replaces the YAML
**stringifier** (PR #4870 left it hand-rolled — see
`docs/yaml-parser-replacement.md`), surfaces `mcpServers` + `hooks` on
`SubagentConfig`, and wires them to the runtime so per-agent MCP servers
and hooks actually fire when a subagent runs.

| Field | Status | Notes |
| ----------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `permissionMode` | **shipped (#4842)** | bridges to existing qwen `approvalMode` at parse time |
| `maxTurns` | **shipped (#4842)** | wired into existing `runConfig.max_turns` runtime path |
| `color` allowlist | **shipped (#4842)** | tightens existing field to CC's `_Y` set + `auto` legacy sentinel handling |
| `mcpServers` | **shipped (follow-up)** | nested YAML round-trip safe via eemeli/`yaml` stringify; runtime override merges session + agent servers via subagent Config wrapper + forced tool-registry rebuild |
| `hooks` | **shipped (follow-up)** | ephemeral HookRegistry entries registered at subagent spawn, removed via `onStop`; v1 fires globally (no agent-scope filter) |
| `effort` | deferred | no model-layer `effort` parameter exists yet in qwen providers |
| `memory` | deferred | qwen's auto-memory has no `user`/`project`/`local` scope distinction yet |
| `isolation` | deferred | workflow PR #4732 owns the runtime; per-agent default lands when that lands |
| `initialPrompt` | deferred | requires `--agent` CLI flag (no main-session-agent infra in qwen) |
| `skills` | deferred | requires SkillManager consumption of `config.skills` |

The full reverse-engineering record below is retained as the design reference
for the deferred fields — schema constants, DL7/Ig5 semantics, error
messages, and the coordination matrix with workflow are still load-bearing
for that work.

[p4842]: https://github.com/QwenLM/qwen-code/pull/4842
[p4870]: https://github.com/QwenLM/qwen-code/pull/4870

---

Expand Down
43 changes: 32 additions & 11 deletions docs/users/features/sub-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,15 @@ can drop a CC agent file into `.qwen/agents/` and have the supported fields
parse identically. Optional fields with invalid values are silently dropped
at parse time rather than rejected — the same lenient posture CC uses.

| Field | Type | Notes |
| ---------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `permissionMode` | enum string | `acceptEdits`, `auto`, `bypassPermissions`, `default`, `dontAsk`, `plan`. Mapped to `approvalMode` at parse time; when both are set, the explicit `approvalMode` wins. |
| `maxTurns` | positive integer | Caps the agent's turn budget. Wired into `runConfig.max_turns` at runtime; when both are set, the top-level field wins. |
| `color` | enum string | Display color. Allowlist: `red`, `blue`, `green`, `yellow`, `purple`, `orange`, `pink`, `cyan` (mirrors CC's `_Y`). The legacy qwen sentinel `auto` is also preserved for backward compatibility. Other values are silently dropped on parse. |
| Field | Type | Notes |
| ---------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `permissionMode` | enum string | `acceptEdits`, `auto`, `bypassPermissions`, `default`, `dontAsk`, `plan`. Mapped to `approvalMode` at parse time; when both are set, the explicit `approvalMode` wins. |
| `maxTurns` | positive integer | Caps the agent's turn budget. Wired into `runConfig.max_turns` at runtime; when both are set, the top-level field wins. The legacy nested value is pruned from the on-disk file on save to avoid two sources of truth. |
| `color` | enum string | Display color. Allowlist: `red`, `blue`, `green`, `yellow`, `purple`, `orange`, `pink`, `cyan` (mirrors CC's `_Y`). The legacy qwen sentinel `auto` is preserved for backward compatibility. Other values are silently dropped on parse. |
| `mcpServers` | record of specs | Per-agent MCP server overrides. Merged with the session-level MCP server set when the agent spawns; on key collision the agent's spec wins (matching CC's `scope: 'agent'` semantics). Malformed entries are dropped per-key with a warning rather than failing the whole agent. |
| `hooks` | record of arrays | Per-agent hooks. Keys are CC hook event names (`PreToolUse`, `PostToolUse`, `UserPromptSubmit`, …); values are arrays of `{ matcher?, hooks: [...] }` definitions in the same shape as `settings.json`'s `hooks` field. Registered while the agent runs, removed when it stops. |

Example:
Example with all of the above:

```
---
Expand All @@ -301,18 +303,37 @@ tools:
- read_file
- grep_search
- glob
mcpServers:
filesystem:
type: stdio
command: node
args: [/usr/local/lib/mcp-fs/server.js]
hooks:
PreToolUse:
- matcher: Bash
hooks:
- type: command
command: echo "review-agent about to run a shell command"
---

You are a code reviewer. Analyze the code thoroughly and report findings
ordered by severity.
```

The remaining CC frontmatter fields — `effort`, `skills`, `initialPrompt`,
`memory`, `isolation`, `mcpServers`, `hooks` — are documented in the
declarative-agent design doc and land in follow-up PRs once the prerequisite
infrastructure exists (`effort` needs a model-layer parameter; `memory`
needs a scoped memory subsystem; `mcpServers` / `hooks` need a nested-aware
YAML parser; `--agent` CLI flag enables `initialPrompt`; etc.).
`memory`, `isolation` — are documented in the declarative-agent design doc
and land in follow-up PRs once the prerequisite infrastructure exists
(`effort` needs a model-layer parameter; `memory` needs a scoped memory
subsystem; `--agent` CLI flag enables `initialPrompt`; etc.).

> **`hooks` v1 limitation.** While a subagent declaring `hooks` is running,
> its hook entries fire for every matching event in the session, not only
> for that subagent's own tool calls. If two subagents with different
> per-agent hook sets run concurrently, both sets fire for both agents.
> Per-agent scope filtering at hook-firing time is left to a follow-up;
> for v1, prefer per-agent hooks that are safe to fire globally for the
> duration of the agent's run (e.g. logging) over hooks that mutate
> behavior.

#### Example Usage

Expand Down
Loading
Loading