☰
IronClaw Product Command Train:角色门控、WebUI 命令面板与原生 Slack 斜杠命令的设计与实践
2026/9/25 2:30:06 网站建设 项目流程
  • 人工智能
  • AI 应用
  • 交互助手
  • AI Agent

【免费下载链接】ironclaw

IronClaw is an Agent OS focused on privacy, security and extensibility

项目地址:https://gitcode.com/gh_mirrors/iro/ironclaw
点击查看免费下载

本指南深入解析 IronClaw 中"产品命令列车"(Product Command Train)的完整设计——它统一了 Slack、Telegram、WebUI 三端的命令输入,补齐了命令表面的三大缺口,并堵住了/model set等租户级控制命令无角色校验的安全漏洞。读完本文,你将掌握 IronClaw 命令系统的共享管线架构、CommandAudience角色门控模型、WebUI 命令面板的服务端驱动实现,以及 Slack 原生/ironclaw斜杠命令的传输层归一化方案,并能直接对照仓库源码定位每一处落点。

背景:命令表面上的三个缺口与一个安全漏洞

设计文档 2026-07-29-product-command-train-design.md 开篇列出了在规划命令表面时发现的四个问题,前三个是体验缺口,第四个是安全漏洞:

  1. Slack 体验缺口:命令必须以带前导空格的形式(/status)输入才能生效。因为 Slack 客户端会拦截裸/text用于自己的斜杠命令系统,未注册的命令会在客户端侧直接报错,永远到不了应用。
  2. WebUI 体验缺口:Web 聊天输入框完全没有命令支持——在 web 聊天里输入/status会作为一条普通 LLM 轮次提交。
  3. 管理员后门(安全):/model set与/model set-provider会执行LlmConfigService::set_active,这是一次全租户范围的 LLM provider/model 热切换,但命令路径上没有角色检查(reborn_services.rs::execute_product_model_command→invoke_llm_active_set)。同理,十个生命周期命令(extension_configure、skill_install等)也是租户级操作,却合法出现在任意渠道 manifest 的commands = [...]声明中(validate_declared_product_command接受整个注册表)。内置的 Slack/Telegram 清单今天只声明了["status"],所以漏洞在第一方渠道上是潜伏的——但任何第三方扩展 manifest 都可能把租户级控制暴露给配对的 DM 用户。

在深入各 PR 之前,先建立"当前状态"基线(文档标注于 main 分支 2026-07-29):通用骨干已经落地(对应 PR #6816 及其邻接提交):

  • 分类:ironclaw_extension_host::extension_ingress在每条归一化渠道消息上运行classify_channel_inbound_text(定义于ironclaw_host_api::product_adapter::inbound),/cmd args变为携带归一化InboundCommandPayload的ChannelInboundClassification::Command;
  • 准入:ironclaw_assistant::DirectConversationCommandAdmission——仅限直接会话 + 渠道 manifest 声明的命令集合,失败即关闭(fail-closed),拒绝帮助只列出已声明命令;
  • 分发:类型化的ProductCommand→ProductSurface::invoke操作(product.model.command、product.status.command、product.lifecycle.command),绑定解析提供binding.actor_user_id(workflow.rs::dispatch_product_command);
  • 结果:CommandResultView(title/fields/lines)由RunDeliveryObserver作为渠道消息投递,帮助文本通过with_enabled_commands限定范围;
  • 注册表:ironclaw_assistant::commands——描述符只带名称 + 别名(无 title/description/usage);清单一度是model、status(别名progress)+ 十个生命周期命令。

设计文档同时记录了一个前置 PR#6678(分支alpine-fight,OPEN、CONFLICTING),它早于已落地的骨干,仍包含本列车上需要的未落地切片:描述符元数据、GET/POSTWebUI 命令路由、以及 composer 斜杠菜单。

决策总览:八项关键取舍

设计文档用一张决策表固定了八项取舍,它们是后续所有实现细节的锚点:

#决策选择
1#6678 的去向Rebase到 main 作为 PR-2 载体;冲突一律以 main 已落地的形态为准。
2Slack 原生命名单一/ironclaw分发器(/ironclaw status、/ironclaw model set …)。Slack 命令命名空间是 workspace 全局的,内置/status无法覆盖,生态惯例是应用命名分发器(/github …、/jira …)。不注册别名;未来新命令无需任何 Slack 应用改动。仅限 Slack:Telegram 命令命名空间是 per-bot 的(bot DM 中/status无歧义;群聊用/status@BotName原生消歧),所以 Telegram 保留直连命令——分发器只是 Slack 的呈现层,不是管线词汇。
3管理命令现在做角色门控(product 决策 remove-vs-gate 待定;选 gate 使两个结果都可达)。按动作粒度:/model裸读是 User;set/set-provider及生命周期族是 Admin。
4可见性处处按角色过滤:WebUI 清单按调用者角色过滤;Slack 只原生注册面向用户的命令;渠道帮助文本统一过滤为用户受众命令(对所有角色一致;按角色过滤是 WebUI 面板的职责,准入是兜底)。准入拒绝是最终防线——隐藏从来不是控制手段。
5列车顺序Gate → Palette → Slack(PR-1 → PR-2 → PR-3,堆叠推进)。不存在浏览器或 manifest 暴露未门控租户控制的窗口期。
6WebUI 结果临时system-notice 气泡(类 Slack,沿用 #6678 的形态)。按事件规则明确为临时事件,不是持久时间线事件;持久渲染留待未来决策。
7内置清单声明["model", "status"](在 PR-1 中与门控同批)。生命周期命令在内置渠道上保持未声明;管理员从 WebUI 管理扩展。第三方 manifest 可以声明它们,由准入把关。
8别名PR-1 中删除。progress是注册表唯一别名且处处无效(声明是精确 token,无人声明它)。整个机制随之移除:aliases描述符字段、别名匹配分支、别名不隐式启用校验规则及其 pins、#6678 的前端别名匹配。如日后真出现同义词需求,可从 git 复活。

值得注意:仓库现状已经超越了这张表的部分内容——/new、/stop、/interrupt三个命令现已随注册表 + audience 模型落地(见 commands.rs 的COMMAND_SPECS),Slack 清单也已声明["model", "status", "new", "stop", "interrupt"]。这与文档"Delivered follow-up"一节的规划一致。

共享管线:一个中心,薄边缘

设计文档用一个 ASCII 架构图定义了命令系统的核心哲学:渠道从不解析或执法命令,它们只负责解包传输。所有解析、权限策略、执行与结果塑形只定义一次:

Slack slash POST Telegram DM WebUI composer /ironclaw status … /status … /status … │ │ │ [slack adapter] [telegram adapter] │ dispatcher unwrap → envelope only │ text "/status …" (text unchanged) │ └───────────┬───────────┘ │ ▼ ▼ generic ingress sink (extension_host) POST /threads/{id}/commands → shared slash parser (host_api) → same shared parser │ │ ▼ ▼ ┌────────── shared command center (ironclaw_assistant) ──────────┐ │ registry: names + metadata + audience (commands.rs) │ │ typed parse: ProductCommand::from_payload │ │ policy: direct-conv + declared set + required_audience × │ │ actor role (channel door: admission service + role port; │ │ webui door: same audience table, authenticated caller) │ │ execute: ProductSurface::invoke → per-command handlers │ │ result: CommandResultView (title/fields/lines) │ └──────────────────────────────────────────────────────────────┘ │ │ ▼ ▼ observer renders + delivers bot msg ephemeral system-notice (per-channel display prefix on help) (generic renderer)

两道门、零漂移:两扇入口(渠道准入门与 WebUI 门)查询的是同一个注册表、同一张 audience 表、同一组操作——策略只定义一次,从两个入口共用。这是整个设计最关键的架构约束,也是后续三个 PR 的公共地基。

PR-1 — 角色门控的命令准入

PR-1 是列车的第一节,负责把"谁可以执行什么命令"变成强制的、有源码落点的安全边界。它由四个部分组成。

注册表:audience 双表(commands.rs)

  • 新增CommandAudience { User, Admin }枚举(commands.rs);
  • ProductCommandDescriptor增加audience: CommandAudience字段——这是列示audience。model、status为User;所有LifecycleCommandKind描述符为Admin。它驱动帮助文本与(PR-2 中)面板清单。仓库现状中描述符还同时携带title/description/usage元数据(commands.rs),这正是 PR-2 设计要补上的部分,在落地实现中已与audience并存;
  • required_audience(&ProductCommand) -> CommandAudience——这是执行audience,按动作感知:commands.rs 中Model{Status|Use|Default}→ User,Model{Set|SetProvider}→ Admin,Status/New/Stop→ User,Lifecycle{..}→ Admin,Unknown→ User(Unknown永不执行——准入会在 audience 步骤前拒绝未声明 token,因此不能藏到 admin 门后)。它与解析规格同居一个文件,保证两张表由单一文件持有;
  • 别名机制整体删除(决策 8):progress别名、aliases描述符字段、名称匹配中的每个别名分支(command_spec_for_name、validate_declared_product_command、ProductCommand::descriptor)都被移除,连同别名不启用契约 pins。当前源码中的command_spec_for_name(commands.rs)只做精确名称匹配,印证了这一点。

角色解析端口(Role resolution port)

ironclaw_assistant中新增 trait,与ProductCommandAdmissionService并排:从准入上下文的installation_id+external_actor_ref解析绑定用户的AdminUserRole(reborn_services/admin_users.rs:Owner | Admin | Member,is_admin())。渠道宿主组装(crates/ironclaw_extension_host/src/channel_host.rs)提供实现:渠道身份绑定 → 绑定用户 id → admin-users 角色查询;组合层负责装配。

AdminUserRole的定义与is_admin()语义位于 admin_users.rs:Owner与Admin通过管理员授权边界,Member不通过;账户状态另有AdminUserStatus { Active, Suspended }。

失败即关闭(fail-closed)语义有三条:

  • 正向解析出非管理员 →永久AccessDenied;
  • 解析器报错→ 可重试的失败通知(绝不把管理员静默当成员、也绝不把成员静默当管理员);
  • 未配对/未知 actor 根本到不了准入(上游的配对拦截器先拒绝)。

准入服务(command_admission.rs)

DirectConversationCommandAdmission的执行顺序(源码admit方法,command_admission.rs):

  1. 直接会话检查:route_kind_for_trigger(context.trigger) != Direct→ 以PolicyDenied拒绝("commands are limited to direct conversations");
  2. 声明集合检查:requested_command不在allowed_commands(构造时经validate_declared_product_command校验、BTreeSet存储)→ 以InvalidRequest拒绝,附内部帮助文本(declared_command_help_text)——注释明确说明这是内部 reason,observer 永不回显;
  3. audience 检查(仅当required_audience为 Admin):self.roles.actor_role(context)解析角色,非is_admin()→ 以ProductRejectionKind::AccessDenied永久拒绝("admin-audience command from a non-admin actor")。

新拒绝通知使用独立的文案族("this command needs an admin account"),与直接会话通知分离。敏感命令永远不会到达其处理器。帮助文本是角色安全的:observer 的静态帮助只包含用户受众的已声明命令(对每个角色一致),准入拒绝只携带内部原因,observer 从不回显。管理员拒绝复用线缆稳定的ProductRejectionKind::AccessDenied键。

清单与测试

第一方清单crates/ironclaw_first_party_extensions/assets/slack/manifest.toml与.../telegram/manifest.toml声明commands = ["model", "status"](按决策 7,与门控同批落地)。仓库现状中,Slack 清单 manifest.toml 的声明已演进为commands = ["model", "status", "new", "stop", "interrupt"]——生命周期命令仍然未声明,管理员继续从 WebUI 管理扩展。

PR-1 的测试矩阵覆盖四层:

  • 契约层:注册表 audience 表 pinned(列示 + 执行,与描述符 1:1);
  • 工作流调用者准入矩阵:member/model读允许;member/model set以 admin 通知拒绝;admin/model set允许;解析器报错 → 可重试失败;直连限制保留;
  • observer/run-delivery 契约:静态命令帮助排除 admin-audience 命令(对每个 actor 统一,不按角色——见决策 4);AccessDenied拒绝投递固定文案而不泄漏内部原因;
  • channel-host e2e:member/model set→ 拒绝通知投递且零命令面调用记录;admin 路径恰好执行一次product.model.commandinvoke(作为绑定用户,两者都穿过一个记录型ProductSurfacedouble;两种情况下都零轮次提交)。

PR-2 — WebUI 命令面板(#6678 的 rebase)

PR-2 把 WebUI composer 变成与 Slack 同级的命令入口,同时修复了 PR-1 终审发现的一个角色解析器不对称问题。

Rebase 姿态

main 优先:注册表留在ironclaw_assistant::commands(丢弃 PR 中迁往ironclaw_host_api::product_commands的移动——ironclaw_extension_host已为校验依赖ironclaw_assistant);DirectConversationCommandAdmission保留(丢弃PairedDmCommandAdmission);已落地切片(分类、manifest opt-in、observer 范围化)脱落。存活切片:描述符元数据(title/description/usage加入 main 的描述符结构,与 PR-1 的audience并列——仓库现状 commands.rs 已确认此形态)、WebUI 后端、前端面板。

隐式所有者规则扩展到两道门(PR-1 审计修复)

PR-1 终审发现渠道角色解析器(ChannelActorRoleResolver::actor_role,crates/ironclaw_extension_host/src/channel_command_roles.rs)缺少环境 bearer 操作者旁路:没有 admin 目录记录的操作者会被永久拒绝渠道管理命令,而 WebUI 门(RebornServices::authorize_admin,及新的caller_is_command_admin)已把caller.operator_config当作隐式 admin。PR-2 关闭该缺口:当解析出的绑定用户等于解析器的operator_user_id、且 admin 目录完全没有记录(Ok(None))时,解析器也返回Ok(Some(AdminUserRole::Owner))。只要存在持久化目录记录——包括Suspended——就仍以记录为准;新分支只在"无记录"时触发。

两道门仍有一个不对称点:WebUI 的caller.operator_config旁路在目录查询之前短路,且完全没有"记录管治"行为,因此 Suspended 操作者记录会被渠道解析器拒绝、却仍能从 WebUI 门进入。该不对称被跟踪而非修复,记录于 issue #6877。

后端(reborn_services/product_commands.rsfacade + webui_v2 路由)

  • GET /api/webchat/v2/commands—— 带元数据的清单,按已认证调用者的AdminUserRole过滤(直接查询,无渠道端口),对照列示 audience。Member 得到:model+status;Admin 得到:+ 生命周期族。环境 bearer 操作者调用者(caller.operator_config)在这里同样是隐式 admin,无需目录记录。仓库中的路由落点见 handlers.rs 与描述符投影 descriptors.rs;
  • POST /api/webchat/v2/threads/{thread_id}/commands—— 共享解析器 → 与渠道准入完全相同的required_audience策略函数(表面不可漂移)→ 相同的类型化操作。/status保留线程所有权探测,但外来线程与从未创建的线程都解析为同一个常量空闲CommandResultView——永不 404。(设计评审裁定这种不可区分的空闲响应与原本计划的外来线程 404 等价甚至更优:404-vs-200 的分裂会让调用者逐次猜测其他用户的线程 id。)Member 的/model set得到同样的永久AccessDenied形态;处理器永不被触达。生命周期命令在此路由上仅列示——execute将每个ProductCommand::Lifecycle以InvalidRequest拒绝(与/status、/model帮助路径使用的角色过滤帮助文本同源),即使是对已通过 audience 门的 admin 调用者也是如此;管理员从 WebUI 的 Extensions 页管理扩展,而不是 composer。

前端(crates/ironclaw_webui/frontend/src/pages/chat/)

全程服务端清单驱动(无硬编码名称):保留 PR 的chat-commands.ts匹配器/菜单/渲染器与useChatCommands,因决策 8 简化(无别名匹配)。Composer 菜单升级到 Slack 质量:输入框上方锚定弹出层;行渲染/name— title — description,匹配前缀高亮;选中行显示 usage 提示;↑/↓ + Enter/Tab 补全 + Esc 关闭;支持 hover/click;随输入实时重新过滤。结果以通用 system-notice 气泡渲染,临时性(决策 6)。未知/text按普通消息提交,与渠道一致。

rebase 的alpine-fight切片之上还落了两处修复:(1)EmptyState(落地视图的 composer,在任何线程存在之前挂载)没有把commandsprop 转发给嵌套的ChatInput,导致全新线程的第一个 composer 打不开面板——chat.tsx现在把commands={activeThreadId ? chatCommands : []}同时传给EmptyState与ChatInput,EmptyState转发它,用专门的EmptyStateprop 转发测试 pinned;(2)chat.commandFailedlocale 键(en中为"Couldn't run that command.")跨全部 11 个 locale 文件加入,供useChat.ts的runCommand客户端执行失败路径使用,但评审抓到的缺陷一度让它死接线:catch 块调用的是通用failureMessageForRequestError辅助函数而不是这个键(且测试 mock 了该辅助函数,断链保持绿灯)。修复方式是让 catch 直接调用t("chat.commandFailed")并给测试解除 mock、绑定真实翻译器,使该键真正可达。

PR-2 测试面:WebUI 调用者分层(member vs admin 清单过滤,含操作者隐式 admin 用例);/status在自有线程返回渲染视图、外来线程与从未创建的线程不可区分(都落到常量空闲视图,永不 404);member/model set得到AccessDenied;admin 的生命周期命令执行尝试仍得到InvalidRequest(对 admin 也保持仅列示);前端 vitest 覆盖键盘导航与元数据渲染、落地 composer 转发修复、locale 键一致性;描述符→DTO 投影契约 pinned。

PR-3 — 原生 Slack 斜杠命令

PR-3 把 Slack 从"前导空格变通方案"升级为原生/ironclaw分发器,且不改动任何 manifest schema 或宿主。

传输层

复用唯一的签名[channel.ingress]events路由——Slack 允许每个斜杠命令指向任意 Request URL,且 HMAC 配方对原始 body 签名、与内容类型无关;验证先于内容类型分支发生,因此表单 body 上的伪造签名与伪造 JSON body 在同一入口层被拒绝。无需 manifest schema 或宿主改动。crates/ironclaw_slack_extension/src/payload.rs新增normalize_slack_inbound兄弟入口(仓库落点在 payload.rs):按(宿主转发的)Content-Type 头分支——application/x-www-form-urlencoded→ 新的斜杠命令表单解析器;其他一切(含缺失头)→ 原样委托给现有normalize_slack_event,两个入口共享恰好一份 JSON 解析实现。表单分支内部,一个极简的全Optionssl_check探测先于完整斜杠命令表单解析:Slack 的ssl_check端点验证 POST 只携带ssl_check+token,从不携带真实调用所必需的channel_id/user_id/command/trigger_id,所以探测必须先跑,否则握手必然失败于必填字段校验(源码顺序见 payload.rs)。

归一化(分发器映射)

唯一注册命令是/ironclaw,其text才是真正的命令。适配器把表单 payload 映射为与事件相同的归一化入站消息:

  • command="/ironclaw"、text="status …"→ 归一化文本"/status …"(对修剪后的 text 前置/;防御性剥离用户可能输入的引导/,因此/ironclaw /status也可用);
  • 裸/ironclaw或/ironclaw help→ 归一化文本"/help"—— 不是注册命令,所以确定性地走现有未知命令拒绝路径,投递角色过滤的 "Available commands" 帮助(若将来真加入help命令,此映射会优雅升级为执行它);
  • 指向同一 Request URL 的其他已注册命令(应用配置错误——第二个斜杠命令对准同一签名端点)按"{command} {text}"原样透传而非映射——适配器不猜测意图,由通用分类/准入层以未声明命令拒绝并附角色过滤帮助(payload.rs 的slash_command_dispatch_text精确实现这三条分支);
  • actor 取user_id,会话取channel_id;事件 id 为slack-{installation}-slash-{trigger_id}(与 event_callback id 空间分命名空间;每次调用唯一——Slack 不像 Events API 那样重投斜杠命令,payload.rs);
  • Trigger 是推导的,从不硬编码:仅当斜杠表单指示真实 DM(channel_name == "directmessage"或D前缀的channel_id——适配器既有is_dm_channel语义)时才是DirectChat,否则为BotCommand(映射到 Shared 路由,由直接会话准入拒绝)。硬编码DirectChat会静默击穿非 DM 拒绝边界和 connect-nudge 门——它们都依赖同一 trigger 分类。

下游——分类、配对、PR-1 准入、分发、observer bot-DM 投递——与空格前缀路径完全一致。入口 200 在持久化准入之后确认(命令执行本身在入口请求内同步完成,只有回复投递是异步的),通常远在 Slack ≤3s 规则之内;路由 20s 截止上限是既有退化后端暴露,在 PR 中值一行说明,不构成新风险。可见结果就是 bot 的 DM 消息。

帮助渲染:按渠道的调用前缀

中性帮助渲染/model,但在 Slack 里裸敲/model会失败(被客户端拦截)。ChannelPresentation(channel.rs)增加可选command_prefix: Option<String>字段,在 manifest 的[channel.presentation]节声明(与supports_markdown/max_message_chars并列);Slack 清单设置command_prefix = "/ironclaw "(仓库落点 manifest.toml),于是帮助与拒绝通知在那里渲染为/ironclaw model。其他渠道留None,保持裸/name渲染。ChannelDescriptor::validate拒绝空值、不以/开头、含控制字符或超过 32 字节的声明前缀(ChannelDescriptorError::InvalidCommandPrefix,channel.rs)。空格形式的/model路径作为未文档化回退继续工作。帮助文本渲染的 prefix 支持在 commands.rs 的declared_command_help_text_with_prefix中实现——prefix 按声明原样渲染,"/ironclaw "加model得/ironclaw model。

行为边界

  • bot DM 之外调用斜杠:走同一管线;直接会话准入拒绝,observer 的命令反馈路径把拒绝通知直接投到调用渠道(envelope.external_conversation_ref())——独立于任何共享会话绑定或slack_allowed_channels允许名单解析,因此即使渠道从未在那里配置也能送达。只有 Slack 自身拒绝发帖(bot 不是该特定渠道成员)时用户才什么也看不到——接受的 MVP 限制,PR 中注明;response_url投递可消除该依赖,是未来修复方向;
  • 未配对用户:走既有 connect-nudge 路径;
  • 原生注册但 manifest 未声明的命令:以角色过滤帮助拒绝。声明是唯一事实源;Slack 注册只是呈现层。

注册(文档而非代码)

docs/internal/reborn/setup-slack-for-reborn-binary.md与docs/channels/slack.mdx增加一条 app-manifest 注册项:注册/ironclaw(描述 + 用法提示status | model set <model> | help——Slack 在自动补全中渲染这些)指向 events URL,并说明理由:命名空间是 workspace 全局的、内置/status无法覆盖、应用命名分发器是生态惯例。Admin/生命周期命令不注册、不提用法提示(决策 4)。Slack 清单的声明集合保持["model", "status"]——声明管的是底层命令,不是分发器拼写。Telegram 不变。

PR-3 测试

  • 适配器一致性:分发器映射(/ironclaw status …→"/status …"、引导斜杠剥离、裸/help→"/help"、字段、trigger、事件 id);ssl_check短路;畸形表单拒绝;JSON 事件不受影响(测试落点 payload_normalized.rs);
  • channel-host e2e:签名斜杠形 body 对配对 DM 跑通/ironclaw status端到端 → 渲染的 status 结果投递、零轮次;裸/ironclaw→ 帮助通知以/ironclaw显示前缀渲染;非 DM 斜杠 → 直连拒绝;签名失败仍在入口拒绝(pin 扩展到表单 body)。

跨切面错误处理

  • 角色解析器失败 → 可重试、消毒后的通知;member 拒绝 → 永久的AccessDenied+ admin 账户文案;任何通知都不含后端字符串、路径或 provider 细节(沿用既有ProductSurfaceError分类法);
  • 所有新拒绝文案都流经既有 observer 通知路径;WebUI 返回同样的消毒ProductSurfaceErrorKind族。

范围外与标记的后续项

设计文档明确列出的后续工作,对理解边界很重要:

  • WebUI Inference 页角色缺口:llm-config 路由(LlmConfigService)似乎也没有角色门——同样的租户级漏洞经浏览器 Settings 可达。属兄弟修复,待产品决策,不在本列车;
  • Sergey 决策的应急方案:若产品决策是remove(而非 gate),audience 词汇表使增量很小——删除生命周期描述符/解析臂(注册表校验随即对任何声明它们的 manifest 失败关闭),保留/model set的 audience 机制。PR-2/PR-3 什么都不用改;
  • Telegram 原生命令:setMyCommands可以编程注册命令菜单——如需则是 PR-3 的廉价兄弟;
  • Slack 直接/model注册:无内置冲突;若日后想要更短拼写,纯粹是分发器旁的增量;
  • response_url投递:用于 DM 外斜杠拒绝;
  • WebUI 时间线中的持久命令结果(决策 6 的 revisit);
  • 已交付后续:/new、/stop、/interrupt现已搭载同一注册表 + audience 模型;连续渠道通过非破坏性轮换外部绑定来重置,WebUI/new则开启全新任务(仓库现状 commands.rs 已确认这三个命令的 User 级描述符与解析器);
  • 未来用户命令(/compact、Telegram/start深链)搭载同一注册表 + audience 模型。

源码地图:快速定位每一处落点

设计元素源码落点
命令注册表、audience 双表、描述符元数据commands.rs
准入服务(直连 + 声明集 + audience)command_admission.rs
Admin 角色模型与is_admin()admin_users.rs
渠道角色解析器(含隐式 owner 旁路)channel_command_roles.rs
ChannelPresentation.command_prefix与校验channel.rs
Slack 斜杠表单归一化、分发器映射、ssl_checkpayload.rs
Slack 清单(commands 声明 +/ironclaw前缀)manifest.toml
WebUI 命令路由与描述符投影handlers.rs、descriptors.rs
WebUI 前端命令菜单/匹配器chat-commands.test.ts、chat.tsx
命令面契约测试product_command_surface_contract.rs、webui_v2_handlers_contract.rs、e2e_tests.rs

结语:一节列车,三道门,一个中心

Product Command Train 的核心贡献不是"加了三个功能",而是把命令系统收敛为**一个中心(registry + audience 双表 + 共享解析器 + 统一操作面)、两道门(渠道准入门与 WebUI 门)、薄边缘(渠道只解包传输)**的架构。角色门控把此前潜伏的租户级控制漏洞变成源码级强制的安全边界;WebUI 面板让浏览器获得与 Slack 同级、且全程服务端清单驱动的命令体验;原生/ironclaw分发器在不改管线词汇的前提下解决了 Slack 客户端拦截问题。对后续命令(/new、/stop、/compact、Telegram 深链)而言,它们都只是往同一注册表和 audience 模型里再添一行的增量——这正是这份设计最持久的价值。

  • 人工智能
  • AI 应用
  • 交互助手
  • AI Agent

【免费下载链接】ironclaw

IronClaw is an Agent OS focused on privacy, security and extensibility

项目地址:https://gitcode.com/gh_mirrors/iro/ironclaw
点击查看免费下载

相关推荐

上一篇:bookdown多语言支持:国际化技术文档的编写技巧
下一篇:Apache SkyWalking 10.0.1 版本解析:SBOM 引入、JDBC 驱动组件库扩展与关键缺陷修复

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询