Skip to content

Design: Skill Center — catalog source of truth, representation, assignment state, and sync #1221

Open

Description

@LUOSENGWA

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.spec is 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_uri with 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/skills reads 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 with updated_at); builtin entries additionally carry version/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) get 400 team scope required.
  • The team-scoped read (?team=) and the upload API (POST /skills scope=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 ActionList on the skills resource (no wildcard) stands.

7. Open questions for the community

  1. 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?
  2. Is the v1 source split right-sized (builtin + shared only; marketplace / remote → P2)?
  3. 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.
  4. Is list-on-read acceptable (vs. cache + TTL) at expected catalog sizes?
  5. 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)

  1. 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.
  2. 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 carry version and requirements (require_bins/require_envs/require_mcps, QwenPaw 2.2.x frontmatter semantics). Q2's size is deferred (MinIO directory entries are virtual 0-byte markers; real sizes need a recursive listing — v2), and uploaded_by needs a per-object stat (v2). Shared SKILL.md metadata (description/version/requires) remains a v2 candidate.
  3. Cross-runtime name variants. find-skills, mcporter, and file-sync ship 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.
  4. 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/ — catalog source="shared", value retained — plus the Manager seed skills in root-level skills//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 with agents/<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 gets scope=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 (v3 GET /nacos/v3/client/ai/skills, version/label-aware; the dashboard already lists custom | nacos | builtin sources) 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/mcps honored 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 copy teams/<t>/skills/ → agents/<w>/skills/ (one-shot copy, consistent with Q5's non-propagation semantics) → worker sync loop ≤ 5min. The team layer deliberately sits outside teams/<t>/shared/ (workers actively mirror shared/ — 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).
  5. Runtime consumption caveat. Not every runtime consumes MinIO-seeded or spec.skills-assigned skills — deepseek-harness preps 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.
  6. 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).
  7. 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 + redacted source_uri), inherit the team-scope view filter, and route credentials through the external_sources capability.
  8. 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.
  9. Audit. Catalog reads are unprivileged (no audit); assignment writes are audited via ActionSkillAssign per 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 直写 MinIO agents/global/skills/ 零 RBAC(无认证/无校验/无审计 = prompt 注入面)→ 必须改为走 controller API;dashboard POST /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 基建;⚠️ Manager 不参与团队技能任何路径)。

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 /skills scope=team/deployment)随 team-skills PR(§8.4)交付,不进 feat(controller): add read-only skill catalog endpoint for workbench #1211 v1
  • skills 资源显式 ActionList(无 wildcard)维持

§7 开放问题

  1. 凭据脱敏机制(无 token 时的 MinIO 读路径——STS 只读 list 已确认)
  2. builtin 模板版本化(catalog version 读 SKILL.md frontmatter,模板目录的版本化另议)
  3. 目录可见性:无参全局读 vs 团队 scope —— 已解决(9/11 干系人定案:authz scope 契约,见 Q4 定案表),等 maintainer 对定案契约表态

§8 Follow-ups(2026-09-11,#1211-v1 落地后记录)

  1. 更新 = 显式不传播:只覆写 catalog 对象与元数据,不到已分配 worker 的运行时副本;assign 是单次拷贝不是订阅;版本传播(物化版本上报 + 显式 resync)= v2,基于 per-worker 可用端点。
  2. 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 候选。
  3. 跨运行时同名变体:find-skills/mcporter/file-sync 各运行时模板内容不同(diff 实证);name-keyed 目录报一个代表条目(首个扫到的模板变体——对 6 个运行时中的 4 个精确,hermes/copaw-legacy 为代表性值);per-runtime 变体元数据 = v2 schema 候选。
  4. 技能四层模型(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)
  5. 运行时消费注意事项:并非所有运行时都消费 MinIO 种子或 spec.skills 分配的技能——deepseek-harness 从镜像内插件清单准备技能(分配 no-op 直到它开始消费);Q3 的"worker sync loop"假设对其余运行时成立。
  6. 可见性交叉引用(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(定案)。
  7. P2 schema 约束(现在记录,避免返工):marketplace/远程注册表落地时,远程条目必须复用同一目录 schema(name/description/source/version/requirements/runtimes + 脱敏 source_uri),继承团队 scope 视图过滤,凭据走 external_sources 能力。
  8. 信任边界(9/11 定案,取代"v1 边界 = admin 上传面"):技能 = 注入 worker 上下文的 prompt 内容;L2 默认可上传本团队后(第 4 条),边界 = 双层扫描门:上传扫描(best-effort 快速反馈)+ 物化-at-assign 强制扫描(团队技能变成 prompt 内容的唯一路径;block = 不拷 + 上报);结构校验(frontmatter lint、name/dir 一致性)+ 审计 + uploader 标记 + warn-to-admin 构成补偿包;多租户仍 P2。
  9. 审计:目录读无特权(免审计);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

  1. oss-maintainer commented on Sep 3, 2026

    @oss-maintainer

    Issue Evaluation

    Category: enhancement (design proposal) | Status: Evaluated — pending maintainer discussion

    Feasibility: 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.skills assignment 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:

    • Reusing the MinIO shared store as catalog truth is consistent with the deployment's existing file truth source and avoids a new storage path; controller-only-read keeps the API surface small.
    • Making credential redaction an unconditional storage invariant (at upload + in every API response) rather than a permission item matches the project's credential-isolation requirements.
    • The three-layer split (catalog metadata / assignment state / runtime copy) cleanly separates "what exists" from "what is assigned", and avoids reconstructing the catalog from Worker.spec (which could leak cross-team registry details).
    • List-on-read without cache is reasonable at v1 catalog sizes; the noted P2 TTL cache is the right escalation path if listing latency grows.

    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

  2. shiyiyue1102 commented on Sep 5, 2026

    @shiyiyue1102
    Collaborator

    整体设计方向没有问题,五个问题的边界也基本清楚。v1 可以按 MinIO 作为部署级共享 catalog、仅支持 builtin + shared、对已认证角色全局只读、list-on-read,以及删除时不级联解绑已有 Worker 的方案推进;请在 API 和文档中明确删除后的保留语义,并确保 catalog metadata 不持久化或返回凭据信息。

    可以基于这个结论继续调整 #1211;marketplace/remote registry、多租户隔离和缓存后续再单独设计。

  3. LUOSENGWA commented on Sep 5, 2026

    @LUOSENGWA
    CollaboratorAuthor

    @shiyiyue1102 The issue body has been updated to the final contract (2026-09-11). What changed:

    • §8.4 — four-layer model (final), supersedes the two-layer sketch: builtin · individual (agents/global/skills/, catalog source="shared" retained, plus Manager seed skills; L1-only management) · team (teams/<team>/skills/ — team-space root, symmetric with agents/<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).
    • Q4 (final): the 9/3 global-read proposal is superseded by the authz-scope contract — no param = L1 only (L2 → 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).
    • Trust boundary (§8.8): since L2 can upload to their own team by default, the boundary is the two-layer scan gate (upload scan best-effort + mandatory scan at materialize-at-assign = the real gate, block = not copied + reported).
    • Publish: L2 default = own team (role AND scope + compensation package); L1-only scope=deployment; the dashboard's direct-MinIO write (POST /packages) is scheduled for deletion (F5 cutover: new API live → dashboard + plugin switch → route deleted).
    • §6: feat(controller): add read-only skill catalog endpoint for workbench #1211 v1 is implemented on the branch (builtin + individual layer, L1-only authz, version/requirements/updated_at); the team-scoped read + upload API ship with the team-skills PR.

    @shiyiyue1102 issue body 已更新为终态契约(2026-09-11)。变更点:

    • §8.4——四层模型(定案,取代双层草图):builtin · 单独层(agents/global/skills/,目录 source="shared" 值保留 + Manager 种子技能;仅 L1 管理)· 团队层(teams/<team>/skills/——team 空间根,与 agents/<worker>/skills/ 对称;既有 team STS 已覆盖前缀,零新 authz 基建)· worker 层(物化副本层)。Manager agent 不参与团队技能任何路径(显式声明)。
    • Q4(定案):9/3 全局读提案被 authz scope 契约取代——无参 = 仅 L1(L2 → 400 team scope required);?team=T = 团队 scope(跨团队/未知 → 404)。L3 无团队 scope(无参读同 400)。
    • 信任边界(§8.8):L2 默认可上传本团队后,边界 = 双层扫描门(上传扫描 best-effort + 物化-at-assign 强制扫描 = 真门,block = 不拷 + 上报)。
    • 发布:L2 默认 = 本团队(role AND scope + 补偿包);L1-only scope=deployment;dashboard 直写 MinIO(POST /packages)已定删除(F5 切流:新 API live → dashboard + 插件切换 → 删路由)。
    • §6:feat(controller): add read-only skill catalog endpoint for workbench #1211 v1 分支已实现(builtin + 单独层,L1-only 鉴权,version/requirements/updated_at);团队范围读 + 上传 API 随 team-skills PR 交付。
  4. LUOSENGWA commented on Sep 15, 2026

    @LUOSENGWA
    CollaboratorAuthor

    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:

    • Treat plugin-provided skills as a first-class catalog source
      (source: "plugin"), discovered from the plugin package's skill manifest
      (the runtime's skill pool metadata), not scraped from worker state.
    • Catalog entry: { name, description, source: "plugin", plugin: <plugin name>, version }; no per-worker assignment field (visibility follows the
      plugin's deployment — a plugin skill is available to a worker iff the
      worker has the plugin; the assignment matrix shows that derivation).
    • Read-only in the catalog (plugin skills cannot be uploaded/edited via the
      Skill Center; their lifecycle belongs to the plugin package).
    • Authz: same L1/L2 rules as the other sources.

    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 有插件
      即有插件技能;分配矩阵展示这个推导)。
    • 目录中只读(插件技能不经 Skill Center 上传/编辑;其生命周期归插件包)。
    • 鉴权:与其他源同一套 L1/L2 规则。

    此增补不动 #1221 的核心决策(Controller 持有目录、MinIO 共享库存上传、
    Worker.spec 记分配),只加一个只读源。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions