Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d0ef6d8
feat(web-shell): support custom code block rendering
zhangxy-zju Jul 3, 2026
634772e
fix(web-shell): harden custom code block rendering
zhangxy-zju Jul 3, 2026
6d706dc
docs: add skill capability gating design
zhangxy-zju Jul 3, 2026
62dbb51
fix(web-shell): make chart skill host supplied
zhangxy-zju Jul 3, 2026
7daeebf
docs(web-shell): write chart skill in English
zhangxy-zju Jul 3, 2026
be64d78
docs(web-shell): document full-data chart payload
zhangxy-zju Jul 3, 2026
031e949
docs(web-shell): use dataset-backed chart payload
zhangxy-zju Jul 3, 2026
68bec83
feat(web-shell): add echarts full-data renderer
zhangxy-zju Jul 3, 2026
e6f228a
chore(web-shell): keep chart skill host supplied
zhangxy-zju Jul 3, 2026
a25192d
fix(web-shell): show loading for streaming chart blocks
zhangxy-zju Jul 3, 2026
bcf9c35
style(web-shell): polish echarts full-data renderer
zhangxy-zju Jul 3, 2026
eb0da5d
Merge remote-tracking branch 'origin/main' into feat/web-shell-code-b…
zhangxy-zju Jul 3, 2026
e689175
fix(web-shell): harden custom code block language parsing
zhangxy-zju Jul 3, 2026
dde6c54
fix(web-shell): harden echarts full-data renderer
zhangxy-zju Jul 3, 2026
a8dc8fb
fix(web-shell): polish echarts renderer followups
zhangxy-zju Jul 3, 2026
9464e11
fix(web-shell): reuse enhanced table for chart data
zhangxy-zju Jul 3, 2026
d43ca8f
fix(web-shell): recover chart renderer after errors
zhangxy-zju Jul 3, 2026
9e76749
Merge branch 'main' into feat/web-shell-code-block-renderer
zhangxy-zju Jul 3, 2026
56ed1d3
fix(web-shell): harden chart option handling
zhangxy-zju Jul 3, 2026
e98e20d
fix(web-shell): harden chart data rendering
zhangxy-zju Jul 3, 2026
925da8f
Merge branch 'main' into feat/web-shell-code-block-renderer
zhangxy-zju Jul 3, 2026
89ceb55
fix(web-shell): tighten chart renderer guardrails
zhangxy-zju Jul 3, 2026
66445e2
fix(web-shell): update chart fallback title
zhangxy-zju Jul 3, 2026
1c3f39c
fix(web-shell): polish chart renderer review fixes
zhangxy-zju Jul 3, 2026
52dd5cc
feat(web-shell): support compact echarts full data blocks
zhangxy-zju Jul 3, 2026
e25bc46
docs(web-shell): add chart skill template
zhangxy-zju Jul 3, 2026
ed482f9
fix(web-shell): address chart review suggestions
zhangxy-zju Jul 3, 2026
1514239
fix(web-shell): preserve punctuation language aliases
zhangxy-zju Jul 3, 2026
5e0f44e
fix(web-shell): address chart follow-up review
zhangxy-zju Jul 3, 2026
75202f3
fix(web-shell): harden chart ref resolution
zhangxy-zju Jul 4, 2026
4191476
fix(web-shell): cover chart sanitizer follow-ups
zhangxy-zju Jul 4, 2026
1dffa3b
fix(web-shell): address chart review follow-ups
zhangxy-zju Jul 4, 2026
976e0a5
fix(web-shell): address chart review leftovers
zhangxy-zju Jul 4, 2026
7ba76c3
fix(web-shell): close chart review gaps
zhangxy-zju Jul 4, 2026
31e05f7
fix(web-shell): handle latest chart review
zhangxy-zju Jul 4, 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
323 changes: 323 additions & 0 deletions docs/design/skill-required-capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
# Skill Required Capabilities Design

Status: discussion draft

## Context

Web Shell can render custom fenced code blocks through its markdown renderer. The
chart renderer proposal uses an `echarts-fulldata` fenced code block so the model
can return a complete ECharts option and dataset payload that Web Shell renders
as an interactive chart.

That output contract is only useful in clients that can render it. In the CLI,
ACP clients, or any other surface without a matching renderer, the same response
would appear as a large code block instead of a chart.

The current bundled `web-shell-charts` skill relies on wording to tell the model
that the format is for Web Shell. This is a soft guard. If the skill is exposed
in a non-Web-Shell session, the model can still choose an output format that the
client cannot render.

## Problem

Qwen Code needs a clear way to decide whether a host-specific skill should be
shown to the model and to users.

For `web-shell-charts`, the concrete question is:

- Should core support a generic `required-capabilities` skill metadata field?
- Or should `web-shell-charts` not be a core bundled skill at all, and instead be
supplied only by Web Shell clients that install or inject it?

## Goals

- Prevent renderer-specific skills from being exposed when the current client
cannot satisfy their output contract.
- Keep startup skill reminders, explicit skill activation, slash-command
discovery, and skill validation consistent.
- Avoid hardcoding `web-shell-charts` as a special case.
- Preserve existing skill behavior when no capability requirement is declared.
- Keep the design extensible for future host capabilities, not only ECharts.

## Non-goals

- Implementing the ECharts renderer itself.
- Redesigning all client/server capability negotiation.
- Changing the semantics of existing skill frontmatter.
- Solving multi-client shared-session capability changes in the first version.

## Current Related Mechanisms

The codebase already has several visibility controls, but none represent client
rendering capabilities:

- `disable-model-invocation`: prevents a skill from being auto-invoked by the
model.
- `user-invocable`: controls whether a bundled skill is available as a command.
- `paths`: scopes skill availability to matching workspace paths.
- `skills.disabled`: disables configured skills.
- `allowedTools`: currently used by bundled skill loading to hide cron-oriented
skills when cron tools are unavailable.
- Slash command `supportedModes`: filters commands by execution mode.
- Daemon and ACP capability objects: describe protocol or client support, but
are not currently connected to skill exposure.

There is no existing `required-capabilities` or equivalent skill frontmatter.
Adding it would be a new skill contract.

## Option A: Add `required-capabilities`

Add a generic skill frontmatter field:

```yaml
---
name: web-shell-charts
description: Render analytical charts in Web Shell using echarts-fulldata fenced code blocks.
required-capabilities:
- markdown.codeBlock.echarts-fulldata
---
```

When the current client/session does not advertise all listed capabilities, the
skill is treated as unavailable.

### Capability Naming

Use namespaced string capabilities:

```text
markdown.codeBlock.echarts-fulldata
```

This keeps the field generic while making the contract precise:

- `markdown`: the capability belongs to rendered markdown.
- `codeBlock`: the capability applies to fenced code block rendering.
- `echarts-fulldata`: the specific language/info string supported by the
renderer.

Future examples could be:

- `markdown.codeBlock.vega-lite`
- `markdown.codeBlock.mermaid-interactive`
- `artifact.openUrl`

### Skill Metadata

Add `requiredCapabilities?: string[]` to skill configuration after parsing the
frontmatter key `required-capabilities`.

Both skill parsing paths should understand the field:

- `packages/core/src/skills/skill-load.ts`
- `packages/core/src/skills/skill-manager.ts`

The field should be optional. Missing or empty means the skill has no client
capability requirement.

### Runtime Capability Source

Add client/session capabilities to the runtime config:

```ts
interface ConfigParameters {
clientCapabilitiesProvider?: () => ReadonlySet<string>;
}
```

Expose a helper on `Config`, for example:

```ts
config.getClientCapabilities(): ReadonlySet<string>
```

Then centralize the check:

```ts
function skillMeetsRequiredCapabilities(skill: Skill, config: Config): boolean {
return skill.config.requiredCapabilities.every((capability) =>
config.getClientCapabilities().has(capability),
);
}
```

### Filtering Points

The capability filter should be applied before skills are exposed to either the
model or the user:

- `collectAvailableSkillEntries` in `packages/core/src/tools/skill-utils.ts`
should skip skills whose required capabilities are missing. This keeps startup
skill reminders, delta reminders, `SkillTool` validation, and model-invocable
activation aligned.
- `BundledSkillLoader` should skip unavailable bundled skills when creating
user-facing commands.
- `SkillCommandLoader` should skip unavailable file-system skills when creating
user-facing commands.

The important invariant is that a skill hidden from the model should not still
appear as an invocable command unless the project intentionally supports a
manual override.

### Web Shell Registration

Web Shell should advertise renderer support explicitly rather than relying on
the presence of an opaque `renderCodeBlock` callback.

For example:

```tsx
<WebShell
customization={{
markdown: {
renderableCodeBlockLanguages: ['echarts-fulldata'],
renderCodeBlock(info) {
// render custom blocks
},
},
}}
/>
```

The Web Shell client can map that to:

```text
markdown.codeBlock.echarts-fulldata
```

This makes the capability declaration stable even if the renderer callback
contains custom logic, fallbacks, or multiple supported languages.

### Daemon and ACP Propagation

For hosted or daemon-based sessions, the client capability set needs to reach
core before skills are loaded or listed. A minimal version can pass capabilities
when creating a session:

```ts
interface CreateSessionRequest {
clientCapabilities?: string[];
}
```

The daemon bridge, SDK, and ACP session creation flow can store this as
session-scoped config.

For the first version, capabilities can be session-scoped. If multiple clients
attach to the same session, the behavior should be documented as using the
capabilities from session creation time.

### Pros

- Keeps `web-shell-charts` as one canonical bundled skill.
- Prevents host-specific output contracts from leaking into unsupported
clients.
- Creates a reusable mechanism for future renderer-specific or host-specific
skills.
- Makes the dependency explicit and testable.

### Cons

- Adds a new cross-cutting skill metadata field.
- Requires client/session capability plumbing across Web Shell, daemon, SDK, and
ACP surfaces.
- Needs careful documentation for shared-session behavior.
- May be more machinery than needed if `web-shell-charts` is the only expected
capability-gated skill.

## Option B: Client-Supplied Skill

Do not add a generic `required-capabilities` field. Instead, avoid bundling
`web-shell-charts` in core. The Web Shell client, or any client that supports
the renderer, supplies the skill itself.

Possible distribution models:

- The Web Shell host installs `.qwen/skills/web-shell-charts/SKILL.md`.
- The Web Shell integration ships an extension skill package.
- The Web Shell integration injects equivalent model instructions only when its
chart renderer is enabled.

In this model, the skill is available only because the rendering client chose to
provide it.

### Pros

- Minimal core change.
- No new global skill metadata contract.
- Capability availability is naturally owned by the client that implements the
renderer.
- Avoids daemon or ACP plumbing unless the client already has a skill injection
mechanism.

### Cons

- No canonical bundled skill unless all clients copy the same content.
- More burden on each Web Shell integrator.
- Users moving between clients may see inconsistent skill availability.
- Does not create a general safeguard for future host-specific skills.
- Harder to test in core because availability depends on external installation
or injection.

## Recommendation

Discuss this as a product/API boundary decision.

Choose Option A if maintainers expect Qwen Code to support more client-rendered
output contracts over time. In that case, `required-capabilities` is a small
general contract that keeps skill exposure honest across CLI, Web Shell, ACP,
and future clients.

Choose Option B if `web-shell-charts` is expected to remain a Web-Shell-only
extension and maintainers do not want core skills to depend on client rendering
features. In that case, the current bundled skill should be removed from core
and supplied by Web Shell clients that support `echarts-fulldata`.

The recommended default is Option A only if maintainers are comfortable making
client/session capabilities part of the skill system. Otherwise, keep the chart
skill client-owned.

## Open Questions

- Should capabilities be session-scoped, request-scoped, or client-scoped?
- Should missing capabilities hide user-invocable commands, or only hide
model-invocable skill activation?
- Should capability names be free-form strings or validated against a known
registry?
- Should unavailable skills be hidden entirely from `/skills`, or shown as
disabled with a reason?
- Should there be a manual override for users who intentionally want to emit raw
`echarts-fulldata` blocks in unsupported clients?
- Should the field name be `required-capabilities`, `requires-capabilities`, or
`client-capabilities`?

## Validation Plan

If Option A is implemented, add tests for:

- Frontmatter parsing in both skill parsing paths.
- `collectAvailableSkillEntries` hiding a skill when capabilities are missing.
- The same skill appearing when capabilities are present.
- Interaction with `paths`, `skills.disabled`, and `disable-model-invocation`.
- `BundledSkillLoader` and `SkillCommandLoader` command visibility.
- Web Shell mapping from supported code block languages to client capabilities.
- Daemon or ACP session creation preserving the capability set.
- Existing bundled skill integration tests, to ensure skills without
`required-capabilities` are unchanged.

## Migration

Existing skills require no migration because the new field is optional.

If Option A is accepted, add:

```yaml
required-capabilities:
- markdown.codeBlock.echarts-fulldata
```

to `web-shell-charts`.

If Option B is accepted, remove `web-shell-charts` from core bundled skills and
document how Web Shell clients can install or inject it when they register an
`echarts-fulldata` renderer.
55 changes: 55 additions & 0 deletions packages/core/src/skills/bundled/web-shell-charts/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: web-shell-charts
description: Produce Qwen Code Web Shell renderable ECharts code blocks using the echarts-fulldata fenced-code format. Use when the user asks for charts or visual data output that should render directly in Web Shell.
Comment thread
zhangxy-zju marked this conversation as resolved.
Resolved
when_to_use: When the user asks to create, show, render, or visualize a chart in Qwen Code Web Shell, especially with ECharts or the echarts-fulldata fenced-code format.
---

# Web Shell Charts

Use this skill to emit charts that a Web Shell host can render from Markdown
code blocks.

## Output Contract

Emit a fenced code block with the language tag `echarts-fulldata`:

```echarts-fulldata
const option = {
title: { text: 'Weekly orders' },
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'] },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: [120, 200, 150, 80, 240] }],
};
```

The code block body must define `option` as an Apache ECharts option object.
Comment thread
zhangxy-zju marked this conversation as resolved.
Resolved
The renderer decides how to load ECharts and execute the block.

## Rules

- Put all chart data inside the code block. Use `dataset.source`, `series.data`,
or other inline option fields. Do not reference local files, URLs, DOM nodes,
global app state, or network requests.
- Keep the block deterministic and side-effect free. Do not use `fetch`,
`import`, timers, random data, `document`, `window`, or filesystem access.
- Prefer plain object/array data. Avoid functions in the option unless the user
explicitly needs custom ECharts callbacks and the host is known to allow them.
- Close the Markdown fence normally so the Web Shell can render after the fence
closes or streaming finishes.
- Use the simplest chart that answers the question. Include clear titles, axis
labels, units, and readable number formats.
- If the data is too large, aggregate or sample it before producing the chart
and explain that reduction outside the code block.
- If a chart cannot be produced safely, explain the reason in normal Markdown
and do not emit an `echarts-fulldata` block.

## Response Shape

For chart answers, use this order:

1. One short takeaway sentence.
2. One `echarts-fulldata` fenced code block containing the complete option.
3. Optional notes about data reduction, assumptions, or how to read the chart.

Do not wrap the chart block in another Markdown container.
Loading
Loading