Repository navigation
Design: Skill Center — catalog source of truth, representation, assignment state, and sync #1221
Description
Design: Skill Center — catalog source of truth, representation, assignment state, and sync
Background: The review of PR #1211 (Skill Center API, 2026-09-03) paused implementation until this design is agreed with the maintainers. This issue takes up the five discussion points raised in that review. The permission-side decisions (who can list / assign / reveal) are tracked in #1220; this issue covers the catalog architecture side.
Related: #1211 (implementation: v1 landed on branch 2026-09-11 — builtin + individual layer, L1-only authz,version/requirements/updated_at; team dimension + upload pending) · #1220 (L2 permission & capability model, cross-reference)
Proposed by: @LUOSENGWA (AgentTeams contributor) · 2026-09-03 · EN/ZH below (English is the primary text)
1. Question 1 — What is the authoritative public catalog, and which component owns it?
Proposal: the deployment-level shared skill store (MinIO), read by the controller.
- The catalog is the shared skill store of the deployment: skill objects uploaded through the upload path (as of 2026-09-11: the controller API, see §8.4), plus the built-in skill templates bundled with the worker image.
- Owner: the controller is the only component exposing catalog APIs; writes go through the existing upload path (controller-mediated, stored in MinIO).
Worker.specis not a source of truth for the catalog — it records per-worker assignment only (see Q3). - Rationale: the MinIO shared store is already the deployment's file truth source (team knowledge bases, shared artifacts). Making the skill catalog an object-level truth in the same store avoids a new storage path and keeps "list on read" simple (Q5).
(部署级 MinIO 共享 Skill 存储为权威目录,controller 是唯一读出口;写入走既有上传链路。Worker.spec 不是目录的 source of truth,只记 per-worker 分配。理由:MinIO 共享存储已是本部署的文件真相源,Skill 目录复用同一对象级真相,不新增存储路径。)
2. Question 2 — How are built-in, uploaded, marketplace, and remote registry skills represented?
Proposal: two first-class sources in v1; marketplace / remote registry deferred to P2.
| source | v1 representation | P2 |
|---|---|---|
| built-in | static template directory bundled in the worker image; listed with source: builtin, read-only metadata |
— |
| uploaded (deployment-shared) | skill objects in the MinIO shared store; metadata from the stored skill manifest (source: shared, version, uploaded_by, uploaded_at) |
— |
| marketplace | not in v1 | registry metadata + redacted source_uri; credential management via the external_sources capability defined in #1220 |
| remote registry | not in v1 | same as marketplace (a remote registry is a marketplace with a different endpoint) |
Each catalog entry carries: id, name, description, source, version, size, uploaded_by, uploaded_at — credentials are never part of catalog metadata (Q4). As of 2026-09-11: "uploaded" covers two scopes — team layer (teams/<t>/skills/, source: team) and individual layer (agents/global/skills/, source: shared retained); the source value set is builtin | shared | team (worker dimension P2). Implemented field set per #1211 v1: name/description/source/version/requirements/updated_at/agents/runtimes (§8.2).
(v1 一等来源:built-in(镜像内置模板目录)+ shared(MinIO 共享存储上传区);marketplace / remote registry 延后 P2,凭据管理挂 #1220 的 external_sources 能力。目录项含 source/version/元数据,永不含凭据。)
3. Question 3 — Boundary between catalog metadata, per-worker assignment state, and the worker's runtime copy
Three distinct layers, three owners:
| layer | answers | owner / storage | API |
|---|---|---|---|
| catalog metadata | what skills exist (global, redacted) | MinIO shared store + built-in templates; read by the controller | list / detail (visibility per Q4) |
| assignment state | which skills are active on which worker | Worker.spec.skills |
worker update API (ActionSkillAssign, #1220) |
| runtime copy | the files the worker process actually loads | worker-local mirror, synced by the worker's own sync loop | not exposed by the controller (out of scope) |
The catalog answers "what exists"; assignment answers "what is on this worker"; the runtime copy is a worker-internal detail. The controller never reads worker-local skill state.
(三层三主:目录元数据(全局、redacted,controller 读)/ 分配态(Worker.spec.skills,worker 更新 API)/ 运行时副本(worker 本地镜像、自同步,controller 不暴露不读取)。目录答"有什么",分配答"这个 worker 装了什么",运行时副本是 worker 内部细节。)
4. Question 4 — Team visibility, tenant isolation, credential redaction
Final (2026-09-11; supersedes the original 9/3 global-read proposal): scope is decided by authz, not by request shape.
| Request | Scope | Access |
|---|---|---|
GET /api/v1/skills (no team param) |
builtin + individual layer (agents/global/skills/) |
L1 only; L2 → 400 team scope required (self-explanatory) |
GET /api/v1/skills?team=T |
builtin + teams/T/skills/ |
L1 any / L2 own team; cross-team / unknown → 404 (anti-probing) |
Assignment stays team-scoped per #1220. L3 humans hold no team scope: they get the same 400 on the no-param read (their worker-scoped read path is unchanged).
- Credential redaction is unconditional: any
source_uriwith embedded credentials, and any registry auth block, is redacted at the store boundary (on upload) and in every API response. Redaction is a storage invariant, not a permission item. - Tenant isolation: v1 is single-tenant (one deployment = one trust domain); per-tenant catalogs (visibility labels or per-tenant store partitions) are P2, to be designed together with the multi-tenant roadmap.
(定案 2026-09-11,取代 9/3 全局读提案):scope 由 authz 决定,不由请求形态决定——无参 = builtin + 单独层(agents/global/skills/),仅 L1(L2 → 400 team scope required 自解释);?team=T = builtin + 团队层(teams/T/skills/),L1 任意 / L2 本团队 / 跨团队 404 防探测。L3 无团队 scope:无参读同 L2 得 400(其 worker scope 读路径不变)。分配仍按 #1220 team-scoped。凭据 redaction 是无条件存储不变量(上传时 + 每个 API 响应),不是权限项。多租户隔离 = P2,跟多租户路线图一起设计。)
5. Question 5 — How does the catalog update when skills are added, updated, or deleted?
Proposal: object-level operations + list on read (no cache in v1).
- Add = upload a skill object to the shared store → the next catalog list includes it.
- Update = overwrite the object (new version) → the catalog reflects the new metadata.
- Delete = remove the object → the catalog drops it; already-assigned workers keep their runtime copy and their assignment (no cascade un-assign) — the operator decides whether to un-assign.
- Built-in skills change only with a worker image release.
- No catalog cache in v1: list on read from the store. (P2: TTL cache if listing latency becomes an issue at larger catalog sizes.)
(对象级操作 + list-on-read(无缓存):新增=上传对象、更新=覆盖、删除=移除对象(已分配 worker 保留运行时副本与分配,不级联解绑——由操作者决定)。built-in 随镜像版本变。P2 视规模加 TTL 缓存。)
6. Effect on #1211 (implementation)
- feat(controller): add read-only skill catalog endpoint for workbench #1211 v1 is implemented on the branch (2026-09-11, review pending):
GET /api/v1/skillsreads builtin (template scan, per-runtime availability derived from the deployer's own template-selection function so the catalog never drifts) + individual layer (agents/global/skills/listing withupdated_at); builtin entries additionally carryversion/requirements(QwenPaw 2.2.x frontmatter semantics). Authz: L1 (admin) only for the no-param read; non-admin callers (L2 humans, team leaders, workers, manager) get400 team scope required. - The team-scoped read (
?team=) and the upload API (POST /skillsscope=team/deployment) ship with the team-skills PR (this issue's §8.4), not with feat(controller): add read-only skill catalog endpoint for workbench #1211 v1. - The explicit
ActionListon the skills resource (no wildcard) stands.
7. Open questions for the community
- Is the MinIO shared store acceptable as the v1 catalog owner (vs. a controller-managed CRD), given it is already the deployment's file truth source?
- Is the v1 source split right-sized (builtin + shared only; marketplace / remote → P2)?
Is global catalog read for all authenticated roles acceptable in v1 (vs. team-filtered)— Resolved 2026-09-11 (stakeholder): the authz-scope contract (no-param = L1 only;?team== team scope, L2 own teams — Q4 final table). Open for maintainer comment on the final contract.- Is list-on-read acceptable (vs. cache + TTL) at expected catalog sizes?
- On delete, is "keep runtime copy, keep assignment" the right default (vs. cascade un-assign)?
8. Follow-ups (2026-09-11, recorded post-#1211-v1)
- Update propagation is explicit non-propagation. "Update" overwrites the catalog object and its metadata only — it does not reach already-assigned workers' runtime copies. Assignment is a one-shot copy, not a subscription (the Q5 delete semantics confirm the same boundary). Propagating a new version to assigned workers (materialized-version reporting + an explicit resync action) is a v2 item, building on the per-worker availability endpoint.
- Entry metadata as implemented in feat(controller): add read-only skill catalog endpoint for workbench #1211 (2026-09-11). Shared entries carry
name+updated_at(the listing timestamp, RFC3339 UTC, omitted when the backend cannot provide one). Builtin entries additionally carryversionandrequirements(require_bins/require_envs/require_mcps, QwenPaw 2.2.x frontmatter semantics). Q2'ssizeis deferred (MinIO directory entries are virtual 0-byte markers; real sizes need a recursive listing — v2), anduploaded_byneeds a per-object stat (v2). Shared SKILL.md metadata (description/version/requires) remains a v2 candidate. - Cross-runtime name variants.
find-skills,mcporter, andfile-syncship differing content per runtime template (verified by diff). The name-keyed catalog reports one representative entry (first-scanned template variant — accurate for 4 of the 6 runtimes; hermes/copaw-legacy values are representative). Per-runtime variant metadata is a v2 schema candidate. - Four-layer skill model (final, 2026-09-11 — supersedes the earlier two-layer sketch and "publish = admin only"). Skills (and MCP, as a design principle) live in four layers: builtin (code-bundled template directories) · individual (
agents/global/skills/— catalogsource="shared", value retained — plus the Manager seed skills in root-levelskills//skills-alpha/; the Manager/admin's individual assets, managed by L1 (admin) only; the Manager agent is the managed object of this layer, not a manager of it) · team (teams/<team>/skills/— team-space root, symmetric withagents/<worker>/skills/; the existing worker team STS policy already covers the prefix, zero new authz infrastructure) · worker (agents/<worker>/skills/— the materialized copy layer, the only layer that becomes prompt content). The Manager agent does not participate in any team-skill path (explicit declaration, to prevent future designs treating the Manager as a team-skill manager). Publish (humans): L2 default-uploads into their own team (role AND scope — Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220's capability value set unchanged) with a compensation package (upload scan best-effort + mandatory scan at materialize-at-assign = the real gate + team scope + audit +source/uploader marking + warn-to-admin); L1 additionally getsscope=deployment→ individual layer. Uploads must go through the controller API (authz + security scan + audit in one chokepoint; L2 humans hold no MinIO STS, so this is their only write path) — the dashboard's direct-MinIO write pattern (POST /packages) carries no RBAC and is scheduled for deletion (F5 cutover: new API live → dashboard + plugin switch → route deleted). External sources (P2): skills may also be pulled from the Nacos AI registry (v3GET /nacos/v3/client/ai/skills, version/label-aware; the dashboard already listscustom | nacos | builtinsources) or the ClawHub marketplace (clawhub.ai, a native QwenPaw hub origin); a controller-side ClawHub fetcher (fetch → security scan → MinIO → catalog metadata) is required for the MinIO-based materialization path. Security gate: QwenPaw ships a content scanner (security/skill_scanner, 8 signature categories: command injection, data exfiltration, hardcoded secrets, obfuscation, prompt injection, social engineering, supply chain, unauthorized tool use; block/warn/off modes); no other runtime has an equivalent (verified in-tree). The gate design is a two-layer scan: upload-time scan (best-effort fast feedback at the controller chokepoint, executed in a QwenPaw runtime container via the existing executor pattern) + mandatory scan at materialize-at-assign (block = not copied + reported; covers every write path, including direct MinIO writes by workers/manager that the existing project pattern already permits). Per-runtime enablement gating stays as-is (require_bins/envs/mcpshonored on QwenPaw 2.2.x; other runtimes have no equivalent gate — unknown = unverified). Assign (leader agent, not human): the team's leader agent assigns via the controller worker-update API (PUT /workers {skills}— live since feat(controller): allow L2 humans to update worker skills within their teams #1212, plus the leader's existing write surface, zero new endpoints; the non-sensitive skills/MCP allowlist per Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220 §5, leaders never hold capabilities). Assignment materializes as a controller copyteams/<t>/skills/→agents/<w>/skills/(one-shot copy, consistent with Q5's non-propagation semantics) → worker sync loop ≤ 5min. The team layer deliberately sits outsideteams/<t>/shared/(workers actively mirrorshared/— inside it, skills would materialize to the whole team with no per-skill gate; the controller copy is the only materialization path and the only gate point). Catalog (feat(controller): add read-only skill catalog endpoint for workbench #1211): no-param read = L1 only (builtin + individual layer, L2 → 400);?team=T= builtin + team layer (L1 any / L2 own team / cross-team 404);source∈ {builtin, shared, team} (worker dimension P2). - Runtime consumption caveat. Not every runtime consumes MinIO-seeded or
spec.skills-assigned skills —deepseek-harnesspreps skills from its in-image plugin manifest (assignment no-ops until it consumes them). Q3's "worker sync loop" assumption holds for the other runtimes. - Visibility cross-reference (updated 2026-09-11, supersedes the 9/5 global-read state). The API-level read contract is now the authz-scope table in Q4 above (no-param = L1 only, L2 → 400;
?team== team scope). The workbench view keeps the team picker: the Worker×skill matrix is filtered to the selected team's workers, and a per-team "skill assets" view aggregates the team workers'spec.skills. Tracked in Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220 §13 Q4 (final). - P2 schema constraint (recorded now to avoid rework). When marketplace/remote registry support lands, remote entries must reuse the same catalog schema (
name/description/source/version/requirements/runtimes+ redactedsource_uri), inherit the team-scope view filter, and route credentials through theexternal_sourcescapability. - Trust boundary (final, 2026-09-11 — supersedes "v1 boundary = admin upload surface"). A skill is prompt content injected into worker context. Since L2 can upload to their own team by default (item 4), the boundary is the two-layer scan gate: upload scan (best-effort fast feedback) + mandatory scan at materialize-at-assign (the only path by which team skills become prompt content; block = not copied + reported). Structure validation (frontmatter lint, name/dir consistency) + audit + uploader marking + warn-to-admin form the compensation package. Multi-tenancy remains P2.
- Audit. Catalog reads are unprivileged (no audit); assignment writes are audited via
ActionSkillAssignper Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220 §8–9; publishing (team or deployment scope) is audited at the controller chokepoint (v1 = structured log line; the durable MinIO JSONL layer ships with PR-A per Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220 §8).
Q1 权威目录
部署级 MinIO 共享 Skill 存储(对象级,controller 直接读,只读 list + 元数据)= 唯一权威源;Worker.spec.skills / spec.remoteSkills 只是分配状态,不是目录来源;dashboard 插件不消费分配/副本状态(Q3 脚注)。
9/11 源码补充实查:
- 目录无团队维度(
oss.Client的ListObjects不支持子前缀过滤 →?team=/?worker=需扩展接口) - 技能无安全扫描(上传走 dashboard 自己的私有 OSS 端点,controller 侧无 scanner)
- dashboard
POST /packages直写 MinIOagents/global/skills/零 RBAC(无认证/无校验/无审计 = prompt 注入面)→ 必须改为走 controller API;dashboardPOST /skills上传链路同样零 RBAC,F5 一并替换 - MinIO STS 策略只读 list 已确认(无 PutObject)
F1/F2(GET /packages 零 RBAC 只读 list;MinIO 无服务端 filter)保持 open。
F3 团队/worker 技能路径(2026-09-11 定案):teams/<team>/skills/(team 空间根下,与 agents/<worker>/skills/ 对称;agents/teams/<team>/skills/ 候选已废——deployer.go:899 用裸 team 名、worker_env.go:43 带 agents/ 前缀,同前缀会解析碰撞;既有 worker team STS 已覆盖该路径,零新 authz 基建;
Q2 表示
source: builtin | shared + version/uploaded_by/uploaded_at;凭据永不进 metadata(Q4)。
2026-09-11 起:"uploaded" 覆盖两个 scope——团队层(teams/<t>/skills/,source: team)与单独层(agents/global/skills/,source: shared 值保留);source 值集 builtin | shared | team(worker 维度 P2)。#1211 v1 落地字段集:name/description/source/version/requirements/updated_at/agents/runtimes(§8.2)。marketplace / remote registry → P2(凭据走 #1220 external_sources 能力)。
Q3 三层边界
- 目录元数据(redacted)
- 分配态(
Worker.spec.skills,既有 worker 更新 API 管) - 运行时副本(worker 内部,controller 不碰)
分配是单向拷贝——assign 时从权威源拷进 worker 前缀,之后不自动传播(传播是 P2 的显式功能,不是意外);worker sync loop ≤5min 是同步机制;dashboard 插件不消费分配/副本状态;P2 远程半侧复用同 schema + 团队 scope 过滤 + external_sources 溯源。
Q4 可见性(9/11 定案,取代 9/3 全局读提案)
scope 由 authz 决定,不由请求形态决定。
| 请求 | scope | 访问 |
|---|---|---|
GET /api/v1/skills(无 team 参数) |
builtin + 单独层(agents/global/skills/) |
仅 L1;L2 → 400 team scope required(自解释) |
GET /api/v1/skills?team=T |
builtin + teams/T/skills/ |
L1 任意 / L2 本团队;跨团队/未知 T → 404(防探测) |
分配仍按 #1220 team-scoped。L3 无团队 scope:无参读同 L2 得 400(其 worker scope 读路径不变)。凭据 redaction 是无条件存储不变量(上传时 + 每个 API 响应),不是权限项。多租户隔离 = P2,跟多租户路线图一起设计。
Q5 共享语义
技能 = 不可变版本对象,不随团队共享自动传播;per-worker 副本是运行时事实;"团队共享技能" = 一次 assign 动作 = 一次性拷贝(不订阅/不自动同步——传播是 P2 的显式功能);v1 = 对象级操作 + list-on-read(无缓存),删除不级联解绑;团队层刻意放在 teams/<t>/shared/ 之外(worker 主动镜像同步 shared/,放里面会无门控物化到全团队;controller 拷贝是唯一物化路径 = 唯一门控点)。
§6 对 #1211 的影响(实现)
#1211 v1 分支已实现(2026-09-11,待 review):
GET /api/v1/skills读 builtin(模板扫描,per-runtime 可用性取自 deployer 自己的模板选择函数,目录与实际下发的内置技能永不漂移)+ 单独层(agents/global/skills/列表 +updated_at)- builtin 条目另含
version/requirements(QwenPaw 2.2.x frontmatter 语义) - 鉴权:无参读仅 L1(admin);非 admin(L2 人类 / 团队 Leader / Worker / Manager)→
400 team scope required - 团队范围读(
?team=)与上传 API(POST /skillsscope=team/deployment)随 team-skills PR(§8.4)交付,不进 feat(controller): add read-only skill catalog endpoint for workbench #1211 v1 - skills 资源显式
ActionList(无 wildcard)维持
§7 开放问题
- 凭据脱敏机制(无 token 时的 MinIO 读路径——STS 只读 list 已确认)
- builtin 模板版本化(catalog
version读 SKILL.md frontmatter,模板目录的版本化另议) 目录可见性:无参全局读 vs 团队 scope—— 已解决(9/11 干系人定案:authz scope 契约,见 Q4 定案表),等 maintainer 对定案契约表态
§8 Follow-ups(2026-09-11,#1211-v1 落地后记录)
- 更新 = 显式不传播:只覆写 catalog 对象与元数据,不到已分配 worker 的运行时副本;assign 是单次拷贝不是订阅;版本传播(物化版本上报 + 显式 resync)= v2,基于 per-worker 可用端点。
- feat(controller): add read-only skill catalog endpoint for workbench #1211 实现的元数据:shared =
name+updated_at(列表时间戳,RFC3339 UTC,后端不提供则省略);builtin 另含version/requirements(QwenPaw 2.2.x frontmatter 语义);size(目录条目是虚拟 0 字节标记,真实大小需递归列读)与uploaded_by(需逐对象 stat)延后 v2;shared SKILL.md 元数据仍是 v2 候选。 - 跨运行时同名变体:
find-skills/mcporter/file-sync各运行时模板内容不同(diff 实证);name-keyed 目录报一个代表条目(首个扫到的模板变体——对 6 个运行时中的 4 个精确,hermes/copaw-legacy 为代表性值);per-runtime 变体元数据 = v2 schema 候选。 - 技能四层模型(9/11 定案,取代双层草图与"publish=admin only"):
- builtin——代码捆绑模板目录
- 单独层——
agents/global/skills/(目录source="shared"值保留)+ 根级skills//skills-alpha/Manager 种子;Manager/管理员的单独资产,仅 L1(admin)管理(技能 + MCP;MCP 半留在既有 manager 配置面);Manager agent 是被管理对象而非管理者 - 团队层——
teams/<team>/skills/(team 空间根,与agents/<worker>/skills/对称;既有 worker team STS 已覆盖前缀,零新 authz 基建;L1 全部 / L2 本团队);Manager agent 不参与任何团队技能路径(显式声明,防未来设计把 Manager 当团队技能管理员) - worker 层——
agents/<worker>/skills/物化副本层,唯一变成 prompt 内容的层 - MCP 同理为设计原则
- 发布(人类):L2 默认上传本团队(role AND scope——Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220 能力值集不变)+ 补偿包(上传扫描 best-effort + assign 拷贝强制扫描 = 真门 + 团队 scope + 审计 +
source/uploader 标记 + warn admin);L1 另有scope=deployment→ 单独层 - 必须走 controller API(authz + 安全扫描 + 审计三合一 chokepoint;L2 无 MinIO STS,controller API 是其唯一写路径);dashboard 直写
POST /packages零 RBAC = 已定删除(F5 切流:新 API live → dashboard + 插件切换 → 删路由) - 外部源(P2):Nacos AI 注册表(v3
GET /nacos/v3/client/ai/skills,version/label-aware;dashboard 已列custom | nacos | builtin三源)+ ClawHub(clawhub.ai,QwenPaw 原生 hub origin);MinIO 物化路径需 controller fetcher(fetch → 安全扫描 → MinIO → 目录元数据) - 安全门:QwenPaw 自带内容扫描器(
security/skill_scanner,8 类签名:命令注入/数据外泄/硬编码密钥/混淆/prompt 注入/社会工程/供应链/未授权工具使用;block/warn/off 三档);其他运行时均无同等设施(树内实查)。门 = 双层扫描:上传时扫描(best-effort 快速反馈,controller chokepoint,经既有 executor 模式在 QwenPaw 运行时容器执行)+ 物化-at-assign 强制扫描(block = 不拷 + 上报;覆盖所有写路径,含既有项目模式已允许的 worker/manager 直写 MinIO)。per-runtime 启用门控维持现状(require_bins/envs/mcps仅 QwenPaw 2.2.x 生效;其他运行时未知 = 未验证) - assign(Leader agent,非人类):经 controller worker 更新 API(
PUT /workers {skills}——feat(controller): allow L2 humans to update worker skills within their teams #1212 已 live + leader 既有写面,零新端点;Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220 §5 非敏感白名单,leader 永不持有能力)物化为 controller 拷贝teams/<t>/skills/→agents/<w>/skills/(一次性拷贝,与 Q5 非传播语义一致)→ worker sync loop ≤5min;团队层刻意在teams/<t>/shared/之外(controller 拷贝 = 唯一物化路径 = 唯一门控点) - 目录(feat(controller): add read-only skill catalog endpoint for workbench #1211):无参读 = 仅 L1(builtin + 单独层,L2 → 400);
?team=T= builtin + 团队层(L1 任意 / L2 本团队 / 跨团队 404);source∈ {builtin, shared, team}(worker 维度 P2)
- 运行时消费注意事项:并非所有运行时都消费 MinIO 种子或
spec.skills分配的技能——deepseek-harness从镜像内插件清单准备技能(分配 no-op 直到它开始消费);Q3 的"worker sync loop"假设对其余运行时成立。 - 可见性交叉引用(9/11 更新,取代 9/5 全局读状态):API 层读契约 = 上文 Q4 的 authz scope 表(无参 = 仅 L1,L2 → 400;
?team== 团队 scope);工作台视图保留团队选择器(Worker×技能矩阵按选中团队过滤;"团队技能资产"视图聚合团队 Worker 的spec.skills)。跟踪于 Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220 §13 Q4(定案)。 - P2 schema 约束(现在记录,避免返工):marketplace/远程注册表落地时,远程条目必须复用同一目录 schema(
name/description/source/version/requirements/runtimes+ 脱敏source_uri),继承团队 scope 视图过滤,凭据走external_sources能力。 - 信任边界(9/11 定案,取代"v1 边界 = admin 上传面"):技能 = 注入 worker 上下文的 prompt 内容;L2 默认可上传本团队后(第 4 条),边界 = 双层扫描门:上传扫描(best-effort 快速反馈)+ 物化-at-assign 强制扫描(团队技能变成 prompt 内容的唯一路径;block = 不拷 + 上报);结构校验(frontmatter lint、name/dir 一致性)+ 审计 + uploader 标记 + warn-to-admin 构成补偿包;多租户仍 P2。
- 审计:目录读无特权(免审计);assign 写经
ActionSkillAssign审计(Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220 §8–9);publish(team 或 deployment scope)在 controller chokepoint 审计(v1 = 结构化日志行;持久化 MinIO JSONL 层随 Design: L2 permission & capability model (worker config, channels, approval, skill catalog) #1220 §8 的 PR-A 交付)。
关联:#1211(实现:v1 分支已落地——builtin + 单独层、L1-only 鉴权、version/requirements/updated_at;团队维度 + 上传待定)· #1220(L2 权限与能力模型,交叉引用)。权限面在 #1220(ActionSkillAssign / 目录 scope 契约等),本 issue 管架构面。
Activity
oss-maintainer commentedon Sep 3, 2026
Issue Evaluation
Category:
enhancement(design proposal) | Status: Evaluated — pending maintainer discussionFeasibility: needs-discussion — the five open questions (catalog owner, v1 source split, visibility, list-on-read, delete semantics) need maintainer decisions before #1211 implementation resumes.
Scope: controller catalog API (read path over the MinIO shared store), MinIO object layout for skill manifests,
Worker.spec.skillsassignment semantics, and the #1211 data-source rework. The worker runtime copy is explicitly out of controller scope.Compatibility: no CRD schema change is required for the catalog itself (assignment reuses
Worker.spec.skills); "delete keeps assignment + runtime copy (no cascade un-assign)" is an operator-visible behavior decision worth calling out in docs.Brief assessment:
Worker.spec(which could leak cross-team registry details).This is a design discussion; implementation in #1211 is paused pending maintainer agreement. No automated code action will be taken on this issue.
Automated evaluation by github-manager-bot
shiyiyue1102 commentedon Sep 5, 2026
整体设计方向没有问题,五个问题的边界也基本清楚。v1 可以按 MinIO 作为部署级共享 catalog、仅支持 builtin + shared、对已认证角色全局只读、list-on-read,以及删除时不级联解绑已有 Worker 的方案推进;请在 API 和文档中明确删除后的保留语义,并确保 catalog metadata 不持久化或返回凭据信息。
可以基于这个结论继续调整 #1211;marketplace/remote registry、多租户隔离和缓存后续再单独设计。
LUOSENGWA commentedon Sep 5, 2026
@shiyiyue1102 The issue body has been updated to the final contract (2026-09-11). What changed:
agents/global/skills/, catalogsource="shared"retained, plus Manager seed skills; L1-only management) · team (teams/<team>/skills/— team-space root, symmetric withagents/<worker>/skills/; the existing team STS covers the prefix, zero new authz infrastructure) · worker (the materialized copy layer). The Manager agent does not participate in any team-skill path (explicit declaration).400 team scope required);?team=T= team scope (cross-team / unknown →404). L3 humans hold no team scope (same 400 on the no-param read).scope=deployment; the dashboard's direct-MinIO write (POST /packages) is scheduled for deletion (F5 cutover: new API live → dashboard + plugin switch → route deleted).version/requirements/updated_at); the team-scoped read + upload API ship with the team-skills PR.@shiyiyue1102 issue body 已更新为终态契约(2026-09-11)。变更点:
agents/global/skills/,目录source="shared"值保留 + Manager 种子技能;仅 L1 管理)· 团队层(teams/<team>/skills/——team 空间根,与agents/<worker>/skills/对称;既有 team STS 已覆盖前缀,零新 authz 基建)· worker 层(物化副本层)。Manager agent 不参与团队技能任何路径(显式声明)。400 team scope required);?team=T= 团队 scope(跨团队/未知 →404)。L3 无团队 scope(无参读同 400)。scope=deployment;dashboard 直写 MinIO(POST /packages)已定删除(F5 切流:新 API live → dashboard + 插件切换 → 删路由)。version/requirements/updated_at);团队范围读 + 上传 API 随 team-skills PR 交付。LUOSENGWA commentedon Sep 15, 2026
Q1 addendum — plugin-provided skills as a third catalog source
The current proposal covers two catalog sources: skills uploaded through the
controller upload path, and the built-in skill templates bundled with the
worker image. A third source is missing: skills shipped inside a plugin
package (e.g. the TeamHarness plugin bundles its own skills; on current
QwenPaw runtimes they surface in the worker's skill pool alongside
builtin/uploaded skills).
Observed gap: those plugin skills are invisible to the Skill Center — they
appear neither in the template layer, the global/shared layer, nor the spec
assignment view — while they are live in the workers that carry the plugin.
The catalog therefore under-reports what a worker can actually do.
Proposal:
(
source: "plugin"), discovered from the plugin package's skill manifest(the runtime's skill pool metadata), not scraped from worker state.
{ name, description, source: "plugin", plugin: <plugin name>, version }; no per-worker assignment field (visibility follows theplugin's deployment — a plugin skill is available to a worker iff the
worker has the plugin; the assignment matrix shows that derivation).
Skill Center; their lifecycle belongs to the plugin package).
This keeps #1221's core decision intact (controller-owned catalog, MinIO
shared store for uploads, Worker.spec for assignment) and adds one read-only
source.
Q1 增补——插件自带技能作为第三目录源
当前提案覆盖两个目录源:经 Controller 上传路径上传的技能,以及随 worker
镜像内置的技能模板。缺第三个源:随插件包分发的技能(如 TeamHarness
插件自带技能;现役 QwenPaw 运行时里它们出现在 worker 的 skill pool 中,
与 builtin/上传技能并列)。
观察到的缺口:这些插件技能对 Skill Center 不可见——template 层、
global/shared 层、spec 分配视图里都没有——但装着插件的 worker 里它们是
活的。目录因此少报了 worker 实际能做的事。
提案:
source: "plugin"),从插件包的 skill清单(运行时的 skill pool 元数据)发现,不从 worker 状态抓取。
{ name, description, source: "plugin", plugin: <插件名>, version };无 per-worker 分配字段(可见性跟随插件部署——worker 有插件即有插件技能;分配矩阵展示这个推导)。
此增补不动 #1221 的核心决策(Controller 持有目录、MinIO 共享库存上传、
Worker.spec 记分配),只加一个只读源。