$dshubuser@dshub:~/plugins$
  • 插件
  • 提交插件
  • 博客
Cordis:五个核心概念,读懂一棵插件树
2026/08/19

Cordis:五个核心概念,读懂一棵插件树

用 Plugin、Context、inject、Events 与 Effect 五个概念,建立 Cordis 运行时的最小心智模型。

短结论:Cordis 的运行时可以压缩成五个概念:插件贡献能力,Context 按名称连接能力,inject 等待依赖,事件传递协作,Effect 负责回卷副作用。

如果先把 API 名称放在一边,Cordis 其实只在回答一个问题:一项能力怎样进入运行中的应用,并在依赖变化或重新加载时安全地离开?

01 / 五个概念是一条运行链

Cordis five concepts connected as a runtime chain from plugin contribution to reversible effects

这五个概念不是五个孤立的功能,而是一条从声明到撤销的链:

概念它回答的问题可观察结果
Plugin这项能力贡献什么?一个函数、对象或 Service 类被挂载
Context插件从哪里找到能力?服务以稳定名称出现在 ctx 上
inject什么时候可以开始?依赖未满足时保持 PENDING
Events不认识消费者时如何协作?发送者按约定分发,监听者独立加入
Effect卸载时如何清理?disposer 撤销注册、监听器和外部资源

02 / Plugin 只描述自己的贡献

最小插件不负责启动整个应用,它只导出自己的贡献:

import type { Context } from '@deepseek-ai/cordis'

export const name = 'hello'

export function apply(ctx: Context) {
  console.log('hello from my first plugin')
}

Loader 负责找到模块并调用 apply(ctx)。因此插件文件可以专注于行为,组合文件可以专注于选择哪些行为进入这次运行。

Cordis 接受三种插件形态:函数、带 apply 方法的对象,以及公开服务时常用的 Service 子类。它们最终都成为一个受 Fiber 管理的插件实例。

03 / Context 是按名称连接的服务容器

Cordis Context resolving named services through a shared root and child scopes

服务提供方把能力注册到一个名称上,消费者使用 ctx.tools、ctx.llm 或 ctx.agents 这样的入口。消费者不需要导入某个提供方的具体类,因此组合层可以替换实现。

这里的 Context 不是一个鼓励随处写入的全局对象。Cordis 的 Context 是代理和作用域容器:普通属性读取经过服务解析,extend()、isolate() 可以创建不修改父级的子上下文。

04 / inject 把启动顺序改成依赖关系

export const inject = ['greeter']

export function apply(ctx: Context) {
  console.log(ctx.greeter.greet('world'))
}

声明 inject 后,插件只有在 greeter 服务存在时才会进入 apply。所以交换 cordis.yml 中两行的顺序不会改变结果;真正决定就绪时机的是服务依赖。

如果功能可以在缺少服务时继续工作,不要伪造硬依赖,而是在使用处通过 ctx.get('greeter') 探测可选服务。

05 / Events 让发送者不知道谁在听

事件适合“发生了一件事,但不需要知道所有消费者”的场景。事件名和 payload 通过 TypeScript 声明合并加入 Events,再选择 emit、parallel、serial、bail 或 waterfall 分发。

例如统计服务可以发出 stats/report,日志插件只监听这个事件;两者不需要互相导入。事件模式是公开约定的一部分,决定是否等待、是否收集返回值,以及监听器能否短路。

06 / Effect 让注册可逆

Cordis Fiber owning event listeners, service registrations, and timers through reversible effects

在 Cordis 中,注册不是散落在应用各处的永久修改。ctx.on()、服务注册、子插件挂载以及显式的 ctx.effect() 都把清理动作附着到当前 Fiber。

ctx.effect(() => {
  const timer = setInterval(() => console.log('tick'), 200)
  return () => clearInterval(timer)
})

插件卸载时,返回的 disposer 执行,定时器不再继续运行。HMR 的“旧代码离场、新代码进场”正是建立在这条可逆关系上。

07 / 没有特权内核

DeepSeek Harness capabilities arranged as replaceable Cordis plugins without a privileged kernel

这五个概念共同带来一个架构结果:模型适配器、工具注册表、会话、Agent 管理,甚至 agent loop 都可以是插件。添加行为的通常路径不是修改一个特权内核,而是定义服务、提供实现、注册消费者,或接入一个已有事件。

在 DeepSeek Harness 中,这意味着 profile 可以选择组合,Context 负责连接,Fiber 负责实例所有权,Effect 负责撤销。“一切皆插件”指的是替换点和资源所有权都可见,而不是目录里有很多文件。

下一步

  • 动手:第一个插件
  • 服务与上下文:共享能力
  • 生命周期与 effect:可逆的注册

实现依据:Cordis 入门、教程总览、Context、Events。

全部文章

作者

avatar for DSH Research
DSH Research

分类

  • Agent 基础设施
01 / 五个概念是一条运行链02 / Plugin 只描述自己的贡献03 / Context 是按名称连接的服务容器04 / inject 把启动顺序改成依赖关系05 / Events 让发送者不知道谁在听06 / Effect 让注册可逆07 / 没有特权内核下一步

更多文章

动手:从 hello.ts 写出你的第一个 Cordis 插件
Agent 基础设施

动手:从 hello.ts 写出你的第一个 Cordis 插件

用一个函数插件和一份 cordis.yml,跑通 Loader、Context 与 Fiber 的最短路径。

avatar for DSH Research
DSH Research
2026/08/20
生命周期与 effect:让 Cordis 注册可以回卷
Agent 基础设施

生命周期与 effect:让 Cordis 注册可以回卷

跟随 Fiber 从 PENDING 到 DISPOSED,理解 effect、disposer 与 HMR 如何共同管理插件副作用。

avatar for DSH Research
DSH Research
2026/08/24
事件:不知道谁在听,也能让插件协作
Agent 基础设施

事件:不知道谁在听,也能让插件协作

从类型化事件和五种分发模式出发,理解 Cordis 如何让服务广播事实、并发工作或交出决策。

avatar for DSH Research
DSH Research
2026/08/25

邮件列表

加入我们的社区

订阅邮件列表,及时获取最新消息和更新

[dshub] [zsh]$ dshub ls$ dshub submit$ dshub blog
-- NORMAL -- ✓ 2026 dshub