Ver código fonte

refactor: rename agent teams service key

imccyu 1 mês atrás
pai
commit
4dd1be1a1f

+ 2 - 2
.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-05-agent-teams.md
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-05-agent-teams.md
-2026-08-05-agent-teams.md: 7a08dec2fc841e30fd8564f533086559a786d180
-2026-08-05-agent-teams.zh.md: dcab1bbe764da1ce51dc4dad56a180f22b9fffa3
+2026-08-05-agent-teams.md: d37777a0cca467edcec5d38999aee53aaf14dc36
+2026-08-05-agent-teams.zh.md: 78bb212d687f89da0911983ea9d7fa5e5bbe95a7

+ 1 - 1
.agents/notes/implemented/feature/2026-08-05-agent-teams.md

@@ -16,7 +16,7 @@ The model-visible Team tools remain opt-in so the default tool catalog and simpl
 
 
 Every ordinary runtime root is the implicit Lead of a Team identified by that root's `SessionId`. The Team has no creation event: its Lead pseudo-row exists by identity, while durable state begins with the first member, message, or task event. A roster is flat and contains at most the configured number of immutable lowercase-kebab-case names. Each teammate is a continuable direct child with a reserved Session id; only the Lead creates or interrupts teammates. Ordinary provider-owned subagents outside the roster are not Team members, and an ordinary fork is a new root whose inherited Team records are excluded by their ancestor `TeamId`.
 Every ordinary runtime root is the implicit Lead of a Team identified by that root's `SessionId`. The Team has no creation event: its Lead pseudo-row exists by identity, while durable state begins with the first member, message, or task event. A roster is flat and contains at most the configured number of immutable lowercase-kebab-case names. Each teammate is a continuable direct child with a reserved Session id; only the Lead creates or interrupts teammates. Ordinary provider-owned subagents outside the roster are not Team members, and an ordinary fork is a new root whose inherited Team records are excluded by their ancestor `TeamId`.
 
 
-The implementation is split into `@deepseek-ai/dsh-experimental-agent-team`, which owns `ctx.teams` and durable semantics, and `@deepseek-ai/dsh-experimental-tool-agent-team`, which owns scoped schemas and model guidance. Every Team tool declares its complete result schema and renders that value as compact JSON, so the compiler checks each `execute` against what the model is promised and no result spends tokens on indentation. Deployments mount both plugins explicitly and may disable legacy continuable controls with the same model-visible names. The explicit delegation policy permits Team creation only when the user asks for Agent Teams or teammates. Both packages are private members of `packages/experimental/`; the [experimental package decision](../architecture/2026-08-18-experimental-agent-teams-packages.md) owns release exclusion, dependency isolation, and promotion.
+The implementation is split into `@deepseek-ai/dsh-experimental-agent-team`, which owns `ctx.agentTeams` and durable semantics, and `@deepseek-ai/dsh-experimental-tool-agent-team`, which owns scoped schemas and model guidance. Every Team tool declares its complete result schema and renders that value as compact JSON, so the compiler checks each `execute` against what the model is promised and no result spends tokens on indentation. Deployments mount both plugins explicitly and may disable legacy continuable controls with the same model-visible names. The explicit delegation policy permits Team creation only when the user asks for Agent Teams or teammates. Both packages are private members of `packages/experimental/`; the [experimental package decision](../architecture/2026-08-18-experimental-agent-teams-packages.md) owns release exclusion, dependency isolation, and promotion.
 
 
 The Lead must wait for required work before its final answer. Process teardown remains the final lifecycle owner and drains continuation Activations; a Team task owner is durable state and is not automatically released by idle, interruption, or process exit.
 The Lead must wait for required work before its final answer. Process teardown remains the final lifecycle owner and drains continuation Activations; a Team task owner is durable state and is not automatically released by idle, interruption, or process exit.
 
 

+ 1 - 1
.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md

@@ -16,7 +16,7 @@ subagent seam 已提供 fresh/fork provider、持久 child Session、FIFO foll
 
 
 每个普通运行时 Root 都是一个隐式 Team 的 Lead,Team id 等于该 Root 的 `SessionId`。Team 没有 creation event:Lead pseudo-row 由身份直接存在,持久状态从第一条 member、message 或 task event 开始。roster 是扁平结构,最多包含配置数量、不可变且采用小写 kebab-case 的名字。每个 teammate 都是使用预留 Session id 的 continuable 直接 child;只有 Lead 可以创建或 interrupt teammate。roster 外由 provider 管理的普通 subagent 不是 Team member;普通 fork 是新的 Root,继承的 Team 记录会因 ancestor `TeamId` 被排除。
 每个普通运行时 Root 都是一个隐式 Team 的 Lead,Team id 等于该 Root 的 `SessionId`。Team 没有 creation event:Lead pseudo-row 由身份直接存在,持久状态从第一条 member、message 或 task event 开始。roster 是扁平结构,最多包含配置数量、不可变且采用小写 kebab-case 的名字。每个 teammate 都是使用预留 Session id 的 continuable 直接 child;只有 Lead 可以创建或 interrupt teammate。roster 外由 provider 管理的普通 subagent 不是 Team member;普通 fork 是新的 Root,继承的 Team 记录会因 ancestor `TeamId` 被排除。
 
 
-实现拆分为 `@deepseek-ai/dsh-experimental-agent-team` 与 `@deepseek-ai/dsh-experimental-tool-agent-team`:前者负责 `ctx.teams` 和持久语义,后者负责 scoped schema 与模型指引。每个 Team 工具都声明完整的结果 schema,并把该值渲染为紧凑 JSON,因此编译器会检查每个 `execute` 是否符合对模型的承诺,也没有结果把 token 花在缩进上。部署显式挂载两个插件,并可禁用具有相同模型可见名称的旧 continuable control。显式 delegation 策略只允许在用户要求 Agent Teams 或 teammate 时创建 Team。 两个包都是 `packages/experimental/` 的私有成员;[实验性包决策](../architecture/2026-08-18-experimental-agent-teams-packages.md)负责发布排除、依赖隔离与 promotion。
+实现拆分为 `@deepseek-ai/dsh-experimental-agent-team` 与 `@deepseek-ai/dsh-experimental-tool-agent-team`:前者负责 `ctx.agentTeams` 和持久语义,后者负责 scoped schema 与模型指引。每个 Team 工具都声明完整的结果 schema,并把该值渲染为紧凑 JSON,因此编译器会检查每个 `execute` 是否符合对模型的承诺,也没有结果把 token 花在缩进上。部署显式挂载两个插件,并可禁用具有相同模型可见名称的旧 continuable control。显式 delegation 策略只允许在用户要求 Agent Teams 或 teammate 时创建 Team。 两个包都是 `packages/experimental/` 的私有成员;[实验性包决策](../architecture/2026-08-18-experimental-agent-teams-packages.md)负责发布排除、依赖隔离与 promotion。
 
 
 Lead 必须等待所需工作后才能给出最终答案。进程 teardown 仍是最终生命周期 owner,并会 drain continuation Activation;Team task owner 是持久状态,不会因 idle、interrupt 或进程退出自动释放。
 Lead 必须等待所需工作后才能给出最终答案。进程 teardown 仍是最终生命周期 owner,并会 drain continuation Activation;Team task owner 是持久状态,不会因 idle、interrupt 或进程退出自动释放。
 
 

+ 2 - 2
docs/architecture.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/architecture.md
 #   pnpm run verify-translation-pairing --write docs/architecture.md
-architecture.md: 2a51992a4f99d1827259c0a2ca2daa309f0ddd95
-architecture.zh.md: d1629a088ed8d2fe61a7e20ab2ab1fd3709abd50
+architecture.md: 3c5e2bd74c1b1519128dac6f5d8502ba8c70c0e2
+architecture.zh.md: 39decd41b677db7c8f160c9e9888ec4ea30401c2

+ 1 - 1
docs/architecture.md

@@ -101,7 +101,7 @@ A **seam** is a swappable capability with three roles: a **Service Definition**
 
 
 Seams are why one provider swap changes the whole product. Filesystem and subprocess providers share one execution world, so pointing them at a remote sandbox moves Bash, PTY, and LSP with them, with no provider forks. [Subagent providers](subsystems/subagent.md) vary just as widely behind one interface, from a fresh child agent to a delegated turn in another product.
 Seams are why one provider swap changes the whole product. Filesystem and subprocess providers share one execution world, so pointing them at a remote sandbox moves Bash, PTY, and LSP with them, with no provider forks. [Subagent providers](subsystems/subagent.md) vary just as widely behind one interface, from a fresh child agent to a delegated turn in another product.
 
 
-[Experimental Agent Teams](subsystems/team.md) is a private opt-in coordination seam on `ctx.teams`, with a durable roster, task board, and mailbox layered over continuable subagents.
+[Experimental Agent Teams](subsystems/team.md) is a private opt-in coordination seam on `ctx.agentTeams`, with a durable roster, task board, and mailbox layered over continuable subagents.
 
 
 ## Where new behavior goes
 ## Where new behavior goes
 
 

+ 1 - 1
docs/architecture.zh.md

@@ -105,7 +105,7 @@ turn/end
 
 
 seam 正是替换一个提供方就能改变整个产品的原因。文件系统与进程提供方共享同一个执行世界,因此把它们指向远程沙箱,也就把 Bash、PTY 和 LSP 一并搬了过去,无需提供方专用 fork。[subagent 提供方](subsystems/subagent.md)在同一个接口之后同样千差万别,从新建一个子 agent,到把一个轮次委派给另一个产品。
 seam 正是替换一个提供方就能改变整个产品的原因。文件系统与进程提供方共享同一个执行世界,因此把它们指向远程沙箱,也就把 Bash、PTY 和 LSP 一并搬了过去,无需提供方专用 fork。[subagent 提供方](subsystems/subagent.md)在同一个接口之后同样千差万别,从新建一个子 agent,到把一个轮次委派给另一个产品。
 
 
-[实验性 Agent Teams](subsystems/team.md) 是 `ctx.teams` 上的私有显式启用协作 seam,在可继续 subagent 之上提供持久 roster、任务板和 mailbox。
+[实验性 Agent Teams](subsystems/team.md) 是 `ctx.agentTeams` 上的私有显式启用协作 seam,在可继续 subagent 之上提供持久 roster、任务板和 mailbox。
 
 
 ## 新行为的归属位置
 ## 新行为的归属位置
 
 

+ 2 - 2
examples/headless-agent/team.cordis.snapshot.yml

@@ -28,9 +28,9 @@
           backgroundMode: one-shot
           backgroundMode: one-shot
           maxDepth: 1
           maxDepth: 1
       - insert:
       - insert:
-          - id: team
+          - id: agent-team
             name: '@deepseek-ai/dsh-experimental-agent-team'
             name: '@deepseek-ai/dsh-experimental-agent-team'
-          - id: tool-team
+          - id: tool-agent-team
             name: '@deepseek-ai/dsh-experimental-tool-agent-team'
             name: '@deepseek-ai/dsh-experimental-tool-agent-team'
           - id: team-fixture-llm
           - id: team-fixture-llm
             name: './tests/fixtures/team-llm.mjs'
             name: './tests/fixtures/team-llm.mjs'

+ 2 - 2
packages/experimental/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write packages/experimental/README.md
 #   pnpm run verify-translation-pairing --write packages/experimental/README.md
-README.md: 5773cccdf189324f0f29b5aa2840960fa956c60b
-README.zh.md: 12f7cbd5160507cf46d83c115591ed901ce82b7a
+README.md: 0e92ebd2bd959ac807830400dd57807b87b1cbe2
+README.zh.md: a1751c39f53bf8f6c0a9c623aba57355f35c2681

+ 1 - 1
packages/experimental/README.md

@@ -6,7 +6,7 @@ This group contains prototypes and internal-only Cordis plugins that use the rep
 
 
 | Package | Role | ctx key |
 | Package | Role | ctx key |
 |---|---|---|
 |---|---|---|
-| `agent-team/` | Implicit-root Agent Teams roster, durable peer mailbox, shared task DAG, and runtime coordination | `ctx.teams` |
+| `agent-team/` | Implicit-root Agent Teams roster, durable peer mailbox, shared task DAG, and runtime coordination | `ctx.agentTeams` |
 | `tool-agent-team/` | Scoped model-facing Agent Teams tools and collaboration guidance | — |
 | `tool-agent-team/` | Scoped model-facing Agent Teams tools and collaboration guidance | — |
 
 
 The [subtree rules](AGENTS.md) define dependency isolation, release exclusion, and promotion.
 The [subtree rules](AGENTS.md) define dependency isolation, release exclusion, and promotion.

+ 1 - 1
packages/experimental/README.zh.md

@@ -6,7 +6,7 @@
 
 
 | 包 | 职责 | ctx key |
 | 包 | 职责 | ctx key |
 |---|---|---|
 |---|---|---|
-| `agent-team/` | 隐式 root Agent Teams roster、持久 peer mailbox、共享任务 DAG 与运行时协调 | `ctx.teams` |
+| `agent-team/` | 隐式 root Agent Teams roster、持久 peer mailbox、共享任务 DAG 与运行时协调 | `ctx.agentTeams` |
 | `tool-agent-team/` | 按 Agent 作用域提供的 Agent Teams 模型工具与协作指引 | — |
 | `tool-agent-team/` | 按 Agent 作用域提供的 Agent Teams 模型工具与协作指引 | — |
 
 
 [子树规则](AGENTS.md)规定依赖隔离、发布排除与 promotion。
 [子树规则](AGENTS.md)规定依赖隔离、发布排除与 promotion。

+ 2 - 2
packages/experimental/agent-team/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write packages/experimental/agent-team/README.md
 #   pnpm run verify-translation-pairing --write packages/experimental/agent-team/README.md
-README.md: 6cf468648b7e9df2d40d358250ef65e2f1b742fb
-README.zh.md: bd43619cb0465edcf591e49a0984d8cb6176cce6
+README.md: 96983d58d5670866d113d4d0d1af57fe500bc5fc
+README.zh.md: 940cf1c9573e12ee0b562070fa67a4c829eb2e6d

+ 2 - 2
packages/experimental/agent-team/README.md

@@ -2,12 +2,12 @@
 
 
 English | [中文](README.zh.md)
 English | [中文](README.zh.md)
 
 
-Implicit-root Agent Teams domain. `ctx.teams` owns a flat Lead/teammate roster, a durable peer mailbox, and a shared task DAG in the Lead Session log. The [Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.md) owns the coordination and isolation decisions; the [Team subsystem catalog](../../../docs/subsystems/team.md) records the literal durable shapes and service API.
+Implicit-root Agent Teams domain. `ctx.agentTeams` owns a flat Lead/teammate roster, a durable peer mailbox, and a shared task DAG in the Lead Session log. The [Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.md) owns the coordination and isolation decisions; the [Team subsystem catalog](../../../docs/subsystems/team.md) records the literal durable shapes and service API.
 
 
 ## Config
 ## Config
 
 
 ```yaml
 ```yaml
-- id: team
+- id: agent-team
   name: '@deepseek-ai/dsh-experimental-agent-team'
   name: '@deepseek-ai/dsh-experimental-agent-team'
   config:
   config:
     maxMembers: 8
     maxMembers: 8

+ 2 - 2
packages/experimental/agent-team/README.zh.md

@@ -2,12 +2,12 @@
 
 
 [English](README.md) | 中文
 [English](README.md) | 中文
 
 
-隐式 Root Agent Teams 领域。`ctx.teams` 在 Lead Session 日志中维护扁平的 Lead/teammate roster、持久 peer mailbox 与共享任务 DAG。[Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.md)负责协作和隔离决策;[Team 子系统目录](../../../docs/subsystems/team.md)记录持久数据的字面形态与服务 API。
+隐式 Root Agent Teams 领域。`ctx.agentTeams` 在 Lead Session 日志中维护扁平的 Lead/teammate roster、持久 peer mailbox 与共享任务 DAG。[Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.md)负责协作和隔离决策;[Team 子系统目录](../../../docs/subsystems/team.md)记录持久数据的字面形态与服务 API。
 
 
 ## 配置
 ## 配置
 
 
 ```yaml
 ```yaml
-- id: team
+- id: agent-team
   name: '@deepseek-ai/dsh-experimental-agent-team'
   name: '@deepseek-ai/dsh-experimental-agent-team'
   config:
   config:
     maxMembers: 8
     maxMembers: 8

+ 3 - 3
packages/experimental/agent-team/src/index.ts

@@ -34,7 +34,7 @@ export { foldTeam } from './fold.ts'
 
 
 declare module '@deepseek-ai/cordis' {
 declare module '@deepseek-ai/cordis' {
   interface Context {
   interface Context {
-    teams: TeamService
+    agentTeams: TeamService
   }
   }
 }
 }
 
 
@@ -75,7 +75,7 @@ export class TeamService extends Service {
   private readonly tasks: TeamTaskBoard
   private readonly tasks: TeamTaskBoard
 
 
   constructor(ctx: Context, config: Config = {}) {
   constructor(ctx: Context, config: Config = {}) {
-    super(ctx, 'teams')
+    super(ctx, 'agentTeams')
     this.config = {
     this.config = {
       maxMembers: positiveLimit('maxMembers', config.maxMembers ?? DEFAULT_MAX_MEMBERS),
       maxMembers: positiveLimit('maxMembers', config.maxMembers ?? DEFAULT_MAX_MEMBERS),
       maxTasks: positiveLimit('maxTasks', config.maxTasks ?? DEFAULT_MAX_TASKS),
       maxTasks: positiveLimit('maxTasks', config.maxTasks ?? DEFAULT_MAX_TASKS),
@@ -110,7 +110,7 @@ export class TeamService extends Service {
       const membership = this.roster.tryMembership(agent)
       const membership = this.roster.tryMembership(agent)
       if (membership !== undefined) this.activity.notify(membership.id)
       if (membership !== undefined) this.activity.notify(membership.id)
     })
     })
-    ctx.effect(() => () => this.disposeRuntime(), 'teams.runtimeLifecycle()')
+    ctx.effect(() => () => this.disposeRuntime(), 'agentTeams.runtimeLifecycle()')
     for (const agent of ctx.agents.list()) this.scheduleRecovery(agent)
     for (const agent of ctx.agents.list()) this.scheduleRecovery(agent)
   }
   }
 
 

+ 5 - 5
packages/experimental/agent-team/tests/persistence.spec.ts

@@ -206,7 +206,7 @@ for (const backend of backends) {
         expect(failedMember?.error).toContain('child Session recovery failed')
         expect(failedMember?.error).toContain('child Session recovery failed')
       }, { timeout: 5_000 })
       }, { timeout: 5_000 })
 
 
-      const receipt = await second.ctx.teams.sendMessage(activeHandle.agent, {
+      const receipt = await second.ctx.agentTeams.sendMessage(activeHandle.agent, {
         target: 'recoverable',
         target: 'recoverable',
         content: [{ type: 'text', text: 'resume after reconciliation' }],
         content: [{ type: 'text', text: 'resume after reconciliation' }],
         delivery: 'wakeup',
         delivery: 'wakeup',
@@ -274,7 +274,7 @@ for (const backend of backends) {
 
 
       const first = await stack(backend, storageRoot, [textResponse('initial teammate answer')])
       const first = await stack(backend, storageRoot, [textResponse('initial teammate answer')])
       const firstLead = first.ctx.agentLoop.create(rootId, { provider: 'mock', model: 'mock' })
       const firstLead = first.ctx.agentLoop.create(rootId, { provider: 'mock', model: 'mock' })
-      const started = await first.ctx.teams.spawnTeammate(firstLead, {
+      const started = await first.ctx.agentTeams.spawnTeammate(firstLead, {
         name: 'mail-worker',
         name: 'mail-worker',
         description: 'mail recovery worker',
         description: 'mail recovery worker',
         prompt: [{ type: 'text', text: 'finish before restart' }],
         prompt: [{ type: 'text', text: 'finish before restart' }],
@@ -283,7 +283,7 @@ for (const backend of backends) {
         signal: SIGNAL,
         signal: SIGNAL,
       })
       })
       await vi.waitFor(() => { expect(first.ctx.agents.get(started.member.id)).toBeUndefined() }, { timeout: 5_000 })
       await vi.waitFor(() => { expect(first.ctx.agents.get(started.member.id)).toBeUndefined() }, { timeout: 5_000 })
-      const quiet = await first.ctx.teams.sendMessage(firstLead, {
+      const quiet = await first.ctx.agentTeams.sendMessage(firstLead, {
         target: 'mail-worker',
         target: 'mail-worker',
         content: [{ type: 'text', text: 'durable quiet context' }],
         content: [{ type: 'text', text: 'durable quiet context' }],
         delivery: 'quiet',
         delivery: 'quiet',
@@ -304,7 +304,7 @@ for (const backend of backends) {
       })
       })
       expect(second.ctx.agents.get(started.member.id)).toBeUndefined()
       expect(second.ctx.agents.get(started.member.id)).toBeUndefined()
 
 
-      const waking = await second.ctx.teams.sendMessage(rootHandle.agent, {
+      const waking = await second.ctx.agentTeams.sendMessage(rootHandle.agent, {
         target: 'mail-worker',
         target: 'mail-worker',
         content: [{ type: 'text', text: 'resume after restart' }],
         content: [{ type: 'text', text: 'resume after restart' }],
         delivery: 'wakeup',
         delivery: 'wakeup',
@@ -335,7 +335,7 @@ for (const backend of backends) {
 
 
       const first = await stack(backend, storageRoot, [textResponse('initial teammate answer')])
       const first = await stack(backend, storageRoot, [textResponse('initial teammate answer')])
       const firstLead = first.ctx.agentLoop.create(rootId, { provider: 'mock', model: 'mock' })
       const firstLead = first.ctx.agentLoop.create(rootId, { provider: 'mock', model: 'mock' })
-      const started = await first.ctx.teams.spawnTeammate(firstLead, {
+      const started = await first.ctx.agentTeams.spawnTeammate(firstLead, {
         name: 'dedup-worker',
         name: 'dedup-worker',
         description: 'mail deduplication worker',
         description: 'mail deduplication worker',
         prompt: [{ type: 'text', text: 'finish before the crash window' }],
         prompt: [{ type: 'text', text: 'finish before the crash window' }],

+ 128 - 128
packages/experimental/agent-team/tests/team.spec.ts

@@ -85,7 +85,7 @@ interface TeamServiceInternals {
 
 
 /** White-box access follows the runtime owners so coverage does not widen the service API. */
 /** White-box access follows the runtime owners so coverage does not widen the service API. */
 function teamInternals(ctx: Context): TeamServiceInternals {
 function teamInternals(ctx: Context): TeamServiceInternals {
-  return ctx.teams as unknown as TeamServiceInternals
+  return ctx.agentTeams as unknown as TeamServiceInternals
 }
 }
 
 
 function spawn(
 function spawn(
@@ -95,7 +95,7 @@ function spawn(
   options: { context?: 'fresh' | 'fork'; provider?: string } = {},
   options: { context?: 'fresh' | 'fork'; provider?: string } = {},
 ) {
 ) {
   const context = options.context ?? 'fresh'
   const context = options.context ?? 'fresh'
-  return ctx.teams.spawnTeammate(lead, {
+  return ctx.agentTeams.spawnTeammate(lead, {
     name,
     name,
     description: `${name} responsibility`,
     description: `${name} responsibility`,
     prompt: content(`${name} initial`),
     prompt: content(`${name} initial`),
@@ -187,7 +187,7 @@ describe('Team identity and provisioning', () => {
 
 
     expect((await ctx.sessionPersistence.inspect(forked.member.id)).meta.seedLength).toBeGreaterThan(0)
     expect((await ctx.sessionPersistence.inspect(forked.member.id)).meta.seedLength).toBeGreaterThan(0)
     expect((await ctx.sessionPersistence.inspect(fresh.member.id)).meta.seedLength ?? 0).toBe(0)
     expect((await ctx.sessionPersistence.inspect(fresh.member.id)).meta.seedLength ?? 0).toBe(0)
-    expect(ctx.teams.listMembers(lead).map(row => [row.name, row.context, row.status])).toEqual([
+    expect(ctx.agentTeams.listMembers(lead).map(row => [row.name, row.context, row.status])).toEqual([
       ['lead', undefined, 'idle'],
       ['lead', undefined, 'idle'],
       ['fork-worker', 'fork', 'inactive'],
       ['fork-worker', 'fork', 'inactive'],
       ['fresh-worker', 'fresh', 'inactive'],
       ['fresh-worker', 'fresh', 'inactive'],
@@ -288,7 +288,7 @@ describe('Team identity and provisioning', () => {
     const { ctx, lead } = await setup([], { maxMembers: 1 })
     const { ctx, lead } = await setup([], { maxMembers: 1 })
     await expect(spawn(ctx, lead, 'failed-worker', { provider: 'missing' })).rejects.toThrow()
     await expect(spawn(ctx, lead, 'failed-worker', { provider: 'missing' })).rejects.toThrow()
 
 
-    expect(ctx.teams.listMembers(lead)[1]).toMatchObject({
+    expect(ctx.agentTeams.listMembers(lead)[1]).toMatchObject({
       name: 'failed-worker',
       name: 'failed-worker',
       status: 'failed',
       status: 'failed',
       provider: 'missing',
       provider: 'missing',
@@ -301,11 +301,11 @@ describe('Team identity and provisioning', () => {
     const first = await setup([])
     const first = await setup([])
     vi.spyOn(first.ctx.subagents, 'startContinuable').mockRejectedValueOnce('string provider failure')
     vi.spyOn(first.ctx.subagents, 'startContinuable').mockRejectedValueOnce('string provider failure')
     await expect(spawn(first.ctx, first.lead, 'string-failure')).rejects.toBe('string provider failure')
     await expect(spawn(first.ctx, first.lead, 'string-failure')).rejects.toBe('string provider failure')
-    expect(first.ctx.teams.listMembers(first.lead)[1]).toMatchObject({
+    expect(first.ctx.agentTeams.listMembers(first.lead)[1]).toMatchObject({
       status: 'failed',
       status: 'failed',
       diagnostics: ['string provider failure'],
       diagnostics: ['string provider failure'],
     })
     })
-    await expect(first.ctx.teams.sendMessage(first.lead, {
+    await expect(first.ctx.agentTeams.sendMessage(first.lead, {
       target: 'string-failure', content: content('cannot deliver'), delivery: 'quiet', signal: SIGNAL,
       target: 'string-failure', content: content('cannot deliver'), delivery: 'quiet', signal: SIGNAL,
     })).rejects.toMatchObject({ code: 'TEAM_MEMBER_NOT_FOUND' })
     })).rejects.toMatchObject({ code: 'TEAM_MEMBER_NOT_FOUND' })
 
 
@@ -389,16 +389,16 @@ describe('Team identity and provisioning', () => {
     const started = await spawn(ctx, lead, 'worker')
     const started = await spawn(ctx, lead, 'worker')
     const worker = await waitRunning(ctx, started.member.id)
     const worker = await waitRunning(ctx, started.member.id)
     await expect(spawn(ctx, worker, 'nested')).rejects.toMatchObject({ code: 'TEAM_LEAD_REQUIRED' })
     await expect(spawn(ctx, worker, 'nested')).rejects.toMatchObject({ code: 'TEAM_LEAD_REQUIRED' })
-    expect(() => ctx.teams.interrupt(worker, 'worker')).toThrow(expect.objectContaining({ code: 'TEAM_LEAD_REQUIRED' }))
-    expect(ctx.teams.interrupt(lead, 'worker')).toEqual({ previousStatus: 'running' })
+    expect(() => ctx.agentTeams.interrupt(worker, 'worker')).toThrow(expect.objectContaining({ code: 'TEAM_LEAD_REQUIRED' }))
+    expect(ctx.agentTeams.interrupt(lead, 'worker')).toEqual({ previousStatus: 'running' })
     await waitNoAgent(ctx, worker.id)
     await waitNoAgent(ctx, worker.id)
-    expect(ctx.teams.interrupt(lead, 'worker')).toEqual({ previousStatus: 'inactive' })
-    expect(() => ctx.teams.interrupt(lead, 'lead')).toThrow(expect.objectContaining({ code: 'TEAM_INVALID_TARGET' }))
+    expect(ctx.agentTeams.interrupt(lead, 'worker')).toEqual({ previousStatus: 'inactive' })
+    expect(() => ctx.agentTeams.interrupt(lead, 'lead')).toThrow(expect.objectContaining({ code: 'TEAM_INVALID_TARGET' }))
   })
   })
 
 
   it('validates teammate text fields and pre-provisioning cancellation', async () => {
   it('validates teammate text fields and pre-provisioning cancellation', async () => {
     const { ctx, lead } = await setup([])
     const { ctx, lead } = await setup([])
-    await expect(ctx.teams.spawnTeammate(lead, {
+    await expect(ctx.agentTeams.spawnTeammate(lead, {
       name: 'empty-description',
       name: 'empty-description',
       description: ' ',
       description: ' ',
       prompt: content('unused'),
       prompt: content('unused'),
@@ -406,7 +406,7 @@ describe('Team identity and provisioning', () => {
       provider: 'spawn',
       provider: 'spawn',
       signal: SIGNAL,
       signal: SIGNAL,
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
-    await expect(ctx.teams.spawnTeammate(lead, {
+    await expect(ctx.agentTeams.spawnTeammate(lead, {
       name: 'empty-provider',
       name: 'empty-provider',
       description: 'valid description',
       description: 'valid description',
       prompt: content('unused'),
       prompt: content('unused'),
@@ -416,7 +416,7 @@ describe('Team identity and provisioning', () => {
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
     const controller = new AbortController()
     const controller = new AbortController()
     controller.abort(new TeamError('cancelled before provisioning', 'TEST_CANCELLED'))
     controller.abort(new TeamError('cancelled before provisioning', 'TEST_CANCELLED'))
-    await expect(ctx.teams.spawnTeammate(lead, {
+    await expect(ctx.agentTeams.spawnTeammate(lead, {
       name: 'cancelled-worker',
       name: 'cancelled-worker',
       description: 'never provisioned',
       description: 'never provisioned',
       prompt: content('unused'),
       prompt: content('unused'),
@@ -429,7 +429,7 @@ describe('Team identity and provisioning', () => {
 
 
   it('treats an ordinary fork as a new Root Team and filters inherited Team state', async () => {
   it('treats an ordinary fork as a new Root Team and filters inherited Team state', async () => {
     const { ctx, lead } = await setup([])
     const { ctx, lead } = await setup([])
-    await ctx.teams.createTask(lead, { subject: 'parent task', description: 'belongs to parent' })
+    await ctx.agentTeams.createTask(lead, { subject: 'parent task', description: 'belongs to parent' })
     const handle = await ctx.agents.create({
     const handle = await ctx.agents.create({
       sessionId: SessionId('ordinary-fork'),
       sessionId: SessionId('ordinary-fork'),
       seed: lead.session.events,
       seed: lead.session.events,
@@ -437,7 +437,7 @@ describe('Team identity and provisioning', () => {
       agentOptions: { provider: 'mock', model: 'mock' },
       agentOptions: { provider: 'mock', model: 'mock' },
     })
     })
 
 
-    expect(ctx.teams.membership(handle.agent)).toMatchObject({
+    expect(ctx.agentTeams.membership(handle.agent)).toMatchObject({
       id: TeamId(handle.agent.id),
       id: TeamId(handle.agent.id),
       role: 'lead',
       role: 'lead',
       name: 'lead',
       name: 'lead',
@@ -455,20 +455,20 @@ describe('Team identity and provisioning', () => {
       signal: SIGNAL,
       signal: SIGNAL,
     })
     })
     const live = ctx.agents.get(started.childId)
     const live = ctx.agents.get(started.childId)
-    if (live !== undefined) expect(ctx.teams.tryMembership(live)).toBeUndefined()
+    if (live !== undefined) expect(ctx.agentTeams.tryMembership(live)).toBeUndefined()
     await waitNoAgent(ctx, started.childId)
     await waitNoAgent(ctx, started.childId)
-    expect(() => ctx.teams.membership(lead)).not.toThrow()
+    expect(() => ctx.agentTeams.membership(lead)).not.toThrow()
 
 
     const impostor = { ...lead } as Agent
     const impostor = { ...lead } as Agent
-    expect(ctx.teams.tryMembership(impostor)).toBeUndefined()
-    expect(() => ctx.teams.membership(impostor)).toThrow(expect.objectContaining({ code: 'TEAM_NOT_MEMBER' }))
+    expect(ctx.agentTeams.tryMembership(impostor)).toBeUndefined()
+    expect(() => ctx.agentTeams.membership(impostor)).toThrow(expect.objectContaining({ code: 'TEAM_NOT_MEMBER' }))
 
 
     const orphanRoot = await ctx.agents.create({
     const orphanRoot = await ctx.agents.create({
       sessionId: SessionId('orphan-ordinary-root'),
       sessionId: SessionId('orphan-ordinary-root'),
       meta: { parentSession: SessionId('absent-parent') },
       meta: { parentSession: SessionId('absent-parent') },
       agentOptions: { provider: 'mock', model: 'mock' },
       agentOptions: { provider: 'mock', model: 'mock' },
     })
     })
-    expect(ctx.teams.membership(orphanRoot.agent)).toMatchObject({ role: 'lead', name: 'lead' })
+    expect(ctx.agentTeams.membership(orphanRoot.agent)).toMatchObject({ role: 'lead', name: 'lead' })
     await orphanRoot.dispose()
     await orphanRoot.dispose()
   })
   })
 
 
@@ -490,7 +490,7 @@ describe('Team identity and provisioning', () => {
       resumeSessionId: started.childId,
       resumeSessionId: started.childId,
       agentOptions: { provider: 'mock', model: 'mock' },
       agentOptions: { provider: 'mock', model: 'mock' },
     })
     })
-    expect(first.ctx.teams.tryMembership(orphan.agent)).toBeUndefined()
+    expect(first.ctx.agentTeams.tryMembership(orphan.agent)).toBeUndefined()
     expect(teamInternals(first.ctx).roster.liveChildrenByRoot()).toEqual(new Map())
     expect(teamInternals(first.ctx).roster.liveChildrenByRoot()).toEqual(new Map())
     await orphan.dispose()
     await orphan.dispose()
 
 
@@ -503,7 +503,7 @@ describe('Team identity and provisioning', () => {
     const journal = teamInternals(second.ctx).journal
     const journal = teamInternals(second.ctx).journal
     const state = journal.state.bind(journal)
     const state = journal.state.bind(journal)
     journal.state = () => { throw new Error('malformed Team stream') }
     journal.state = () => { throw new Error('malformed Team stream') }
-    expect(second.ctx.teams.tryMembership(child.agent)).toBeUndefined()
+    expect(second.ctx.agentTeams.tryMembership(child.agent)).toBeUndefined()
     journal.state = state
     journal.state = state
     await child.dispose()
     await child.dispose()
   })
   })
@@ -528,7 +528,7 @@ describe('Team shared task DAG', () => {
     })
     })
     await ctx.sessions.flush(lead.session)
     await ctx.sessions.flush(lead.session)
 
 
-    await expect(ctx.teams.createTask(lead, {
+    await expect(ctx.agentTeams.createTask(lead, {
       subject: 'cannot allocate',
       subject: 'cannot allocate',
       description: 'no safe numeric task id remains',
       description: 'no safe numeric task id remains',
     })).rejects.toMatchObject({ code: 'TEAM_TASK_LIMIT' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_LIMIT' })
@@ -536,20 +536,20 @@ describe('Team shared task DAG', () => {
 
 
   it('bounds non-deleted tasks while retaining deleted task ids as tombstones', async () => {
   it('bounds non-deleted tasks while retaining deleted task ids as tombstones', async () => {
     const { ctx, lead } = await setup([], { maxTasks: 1 })
     const { ctx, lead } = await setup([], { maxTasks: 1 })
-    const first = await ctx.teams.createTask(lead, { subject: 'first', description: 'first task' })
-    await expect(ctx.teams.createTask(lead, { subject: 'overflow', description: 'overflow task' }))
+    const first = await ctx.agentTeams.createTask(lead, { subject: 'first', description: 'first task' })
+    await expect(ctx.agentTeams.createTask(lead, { subject: 'overflow', description: 'overflow task' }))
       .rejects.toMatchObject({ code: 'TEAM_TASK_LIMIT' })
       .rejects.toMatchObject({ code: 'TEAM_TASK_LIMIT' })
 
 
-    const deleted = await ctx.teams.updateTask(lead, {
+    const deleted = await ctx.agentTeams.updateTask(lead, {
       taskId: first.id,
       taskId: first.id,
       expectedRevision: first.revision,
       expectedRevision: first.revision,
       action: 'delete',
       action: 'delete',
     })
     })
-    const second = await ctx.teams.createTask(lead, { subject: 'second', description: 'second task' })
+    const second = await ctx.agentTeams.createTask(lead, { subject: 'second', description: 'second task' })
     expect(deleted.status).toBe('deleted')
     expect(deleted.status).toBe('deleted')
     expect(second.id).toBe(TeamTaskId('task-2'))
     expect(second.id).toBe(TeamTaskId('task-2'))
-    expect(ctx.teams.getTask(lead, first.id).status).toBe('deleted')
-    expect(ctx.teams.listTasks(lead).map(task => task.id)).toEqual([second.id])
+    expect(ctx.agentTeams.getTask(lead, first.id).status).toBe('deleted')
+    expect(ctx.agentTeams.listTasks(lead).map(task => task.id)).toEqual([second.id])
   })
   })
 
 
   it('enforces CAS, ownership, dependencies, transitions, and write-scope warnings', async () => {
   it('enforces CAS, ownership, dependencies, transitions, and write-scope warnings', async () => {
@@ -559,63 +559,63 @@ describe('Team shared task DAG', () => {
     const secondMember = await spawn(ctx, lead, 'beta')
     const secondMember = await spawn(ctx, lead, 'beta')
     const beta = await waitRunning(ctx, secondMember.member.id)
     const beta = await waitRunning(ctx, secondMember.member.id)
 
 
-    const first = await ctx.teams.createTask(alpha, {
+    const first = await ctx.agentTeams.createTask(alpha, {
       subject: 'first',
       subject: 'first',
       description: 'first task',
       description: 'first task',
       writeScopes: ['src', './src/', 'src'],
       writeScopes: ['src', './src/', 'src'],
     })
     })
-    const second = await ctx.teams.createTask(beta, {
+    const second = await ctx.agentTeams.createTask(beta, {
       subject: 'second',
       subject: 'second',
       description: 'second task',
       description: 'second task',
       blockedBy: [first.id],
       blockedBy: [first.id],
       writeScopes: ['src/feature'],
       writeScopes: ['src/feature'],
     })
     })
     expect(first.writeScopes).toEqual(['src'])
     expect(first.writeScopes).toEqual(['src'])
-    await expect(ctx.teams.updateTask(beta, {
+    await expect(ctx.agentTeams.updateTask(beta, {
       taskId: second.id,
       taskId: second.id,
       expectedRevision: second.revision,
       expectedRevision: second.revision,
       action: 'claim',
       action: 'claim',
     })).rejects.toMatchObject({ code: 'TEAM_TASK_BLOCKED' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_BLOCKED' })
 
 
-    const claimed = await ctx.teams.updateTask(alpha, {
+    const claimed = await ctx.agentTeams.updateTask(alpha, {
       taskId: first.id,
       taskId: first.id,
       expectedRevision: first.revision,
       expectedRevision: first.revision,
       action: 'claim',
       action: 'claim',
     })
     })
-    await expect(ctx.teams.updateTask(beta, {
+    await expect(ctx.agentTeams.updateTask(beta, {
       taskId: first.id,
       taskId: first.id,
       expectedRevision: claimed.revision,
       expectedRevision: claimed.revision,
       action: 'claim',
       action: 'claim',
     })).rejects.toMatchObject({ code: 'TEAM_TASK_ALREADY_CLAIMED' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_ALREADY_CLAIMED' })
-    expect(ctx.teams.getTask(beta, second.id)).toMatchObject({
+    expect(ctx.agentTeams.getTask(beta, second.id)).toMatchObject({
       ready: false,
       ready: false,
       writeScopeWarnings: [`write scopes overlap with ${first.id}`],
       writeScopeWarnings: [`write scopes overlap with ${first.id}`],
     })
     })
-    await expect(ctx.teams.updateTask(beta, {
+    await expect(ctx.agentTeams.updateTask(beta, {
       taskId: first.id,
       taskId: first.id,
       expectedRevision: claimed.revision,
       expectedRevision: claimed.revision,
       action: 'edit',
       action: 'edit',
       subject: 'stolen',
       subject: 'stolen',
     })).rejects.toMatchObject({ code: 'TEAM_TASK_UNAUTHORIZED' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_UNAUTHORIZED' })
-    await expect(ctx.teams.updateTask(alpha, {
+    await expect(ctx.agentTeams.updateTask(alpha, {
       taskId: first.id,
       taskId: first.id,
       expectedRevision: first.revision,
       expectedRevision: first.revision,
       action: 'complete',
       action: 'complete',
     })).rejects.toMatchObject({ code: 'TEAM_TASK_STALE_REVISION' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_STALE_REVISION' })
 
 
-    const completed = await ctx.teams.updateTask(alpha, {
+    const completed = await ctx.agentTeams.updateTask(alpha, {
       taskId: first.id,
       taskId: first.id,
       expectedRevision: claimed.revision,
       expectedRevision: claimed.revision,
       action: 'complete',
       action: 'complete',
     })
     })
     expect(completed.status).toBe('completed')
     expect(completed.status).toBe('completed')
-    expect(ctx.teams.getTask(beta, second.id).ready).toBe(true)
-    const secondClaim = await ctx.teams.updateTask(beta, {
+    expect(ctx.agentTeams.getTask(beta, second.id).ready).toBe(true)
+    const secondClaim = await ctx.agentTeams.updateTask(beta, {
       taskId: second.id,
       taskId: second.id,
       expectedRevision: second.revision,
       expectedRevision: second.revision,
       action: 'claim',
       action: 'claim',
     })
     })
-    const released = await ctx.teams.updateTask(beta, {
+    const released = await ctx.agentTeams.updateTask(beta, {
       taskId: second.id,
       taskId: second.id,
       expectedRevision: secondClaim.revision,
       expectedRevision: secondClaim.revision,
       action: 'release',
       action: 'release',
@@ -623,40 +623,40 @@ describe('Team shared task DAG', () => {
     expect(released).toMatchObject({ status: 'pending', ready: true })
     expect(released).toMatchObject({ status: 'pending', ready: true })
     expect('ownerId' in released).toBe(false)
     expect('ownerId' in released).toBe(false)
 
 
-    ctx.teams.interrupt(lead, 'alpha')
-    ctx.teams.interrupt(lead, 'beta')
+    ctx.agentTeams.interrupt(lead, 'alpha')
+    ctx.agentTeams.interrupt(lead, 'beta')
     await Promise.all([waitNoAgent(ctx, alpha.id), waitNoAgent(ctx, beta.id)])
     await Promise.all([waitNoAgent(ctx, alpha.id), waitNoAgent(ctx, beta.id)])
   })
   })
 
 
   it('rejects malformed scopes and every invalid dependency relation', async () => {
   it('rejects malformed scopes and every invalid dependency relation', async () => {
     const { ctx, lead } = await setup([])
     const { ctx, lead } = await setup([])
-    const first = await ctx.teams.createTask(lead, { subject: 'one', description: 'one' })
-    const second = await ctx.teams.createTask(lead, {
+    const first = await ctx.agentTeams.createTask(lead, { subject: 'one', description: 'one' })
+    const second = await ctx.agentTeams.createTask(lead, {
       subject: 'two', description: 'two', blockedBy: [first.id],
       subject: 'two', description: 'two', blockedBy: [first.id],
     })
     })
-    await expect(ctx.teams.createTask(lead, {
+    await expect(ctx.agentTeams.createTask(lead, {
       subject: 'bad', description: 'bad', blockedBy: [TeamTaskId('missing')],
       subject: 'bad', description: 'bad', blockedBy: [TeamTaskId('missing')],
     })).rejects.toMatchObject({ code: 'TEAM_TASK_NOT_FOUND' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_NOT_FOUND' })
-    await expect(ctx.teams.updateTask(lead, {
+    await expect(ctx.agentTeams.updateTask(lead, {
       taskId: first.id,
       taskId: first.id,
       expectedRevision: first.revision,
       expectedRevision: first.revision,
       action: 'set_dependencies',
       action: 'set_dependencies',
       blockedBy: [second.id],
       blockedBy: [second.id],
     })).rejects.toMatchObject({ code: 'TEAM_TASK_DEPENDENCY_CYCLE' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_DEPENDENCY_CYCLE' })
-    await expect(ctx.teams.updateTask(lead, {
+    await expect(ctx.agentTeams.updateTask(lead, {
       taskId: first.id,
       taskId: first.id,
       expectedRevision: first.revision,
       expectedRevision: first.revision,
       action: 'set_dependencies',
       action: 'set_dependencies',
       blockedBy: [first.id],
       blockedBy: [first.id],
     })).rejects.toMatchObject({ code: 'TEAM_TASK_DEPENDENCY_CYCLE' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_DEPENDENCY_CYCLE' })
-    await expect(ctx.teams.updateTask(lead, {
+    await expect(ctx.agentTeams.updateTask(lead, {
       taskId: first.id,
       taskId: first.id,
       expectedRevision: first.revision,
       expectedRevision: first.revision,
       action: 'set_dependencies',
       action: 'set_dependencies',
       blockedBy: [second.id, second.id],
       blockedBy: [second.id, second.id],
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
     for (const scope of ['', '.', '..', '/root', 'C:\\root', 'C:root', 'a//b', 'a/../b']) {
     for (const scope of ['', '.', '..', '/root', 'C:\\root', 'C:root', 'a//b', 'a/../b']) {
-      await expect(ctx.teams.createTask(lead, {
+      await expect(ctx.agentTeams.createTask(lead, {
         subject: 'scope', description: 'scope', writeScopes: [scope],
         subject: 'scope', description: 'scope', writeScopes: [scope],
       })).rejects.toMatchObject({ code: 'TEAM_INVALID_WRITE_SCOPE' })
       })).rejects.toMatchObject({ code: 'TEAM_INVALID_WRITE_SCOPE' })
     }
     }
@@ -664,36 +664,36 @@ describe('Team shared task DAG', () => {
 
 
   it('rejects incomplete mutations, invalid transitions, and deletion of a live blocker', async () => {
   it('rejects incomplete mutations, invalid transitions, and deletion of a live blocker', async () => {
     const { ctx, lead } = await setup([])
     const { ctx, lead } = await setup([])
-    await expect(ctx.teams.createTask(lead, { subject: ' ', description: 'invalid' }))
+    await expect(ctx.agentTeams.createTask(lead, { subject: ' ', description: 'invalid' }))
       .rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
       .rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
-    await expect(ctx.teams.createTask(lead, { subject: 'invalid', description: '' }))
+    await expect(ctx.agentTeams.createTask(lead, { subject: 'invalid', description: '' }))
       .rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
       .rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
-    await expect(ctx.teams.createTask(lead, { subject: 'x'.repeat(201), description: 'too long' }))
+    await expect(ctx.agentTeams.createTask(lead, { subject: 'x'.repeat(201), description: 'too long' }))
       .rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
       .rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
-    const blocker = await ctx.teams.createTask(lead, { subject: 'blocker', description: 'blocker' })
-    await ctx.teams.createTask(lead, {
+    const blocker = await ctx.agentTeams.createTask(lead, { subject: 'blocker', description: 'blocker' })
+    await ctx.agentTeams.createTask(lead, {
       subject: 'dependent', description: 'dependent', blockedBy: [blocker.id],
       subject: 'dependent', description: 'dependent', blockedBy: [blocker.id],
     })
     })
-    expect(() => ctx.teams.getTask(lead, TeamTaskId('missing')))
+    expect(() => ctx.agentTeams.getTask(lead, TeamTaskId('missing')))
       .toThrow(expect.objectContaining({ code: 'TEAM_TASK_NOT_FOUND' }))
       .toThrow(expect.objectContaining({ code: 'TEAM_TASK_NOT_FOUND' }))
     for (const action of ['release', 'complete', 'reopen'] as const) {
     for (const action of ['release', 'complete', 'reopen'] as const) {
-      await expect(ctx.teams.updateTask(lead, {
+      await expect(ctx.agentTeams.updateTask(lead, {
         taskId: blocker.id,
         taskId: blocker.id,
         expectedRevision: blocker.revision,
         expectedRevision: blocker.revision,
         action,
         action,
       })).rejects.toMatchObject({ code: 'TEAM_TASK_INVALID_TRANSITION' })
       })).rejects.toMatchObject({ code: 'TEAM_TASK_INVALID_TRANSITION' })
     }
     }
-    await expect(ctx.teams.updateTask(lead, {
+    await expect(ctx.agentTeams.updateTask(lead, {
       taskId: blocker.id,
       taskId: blocker.id,
       expectedRevision: blocker.revision,
       expectedRevision: blocker.revision,
       action: 'edit',
       action: 'edit',
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
-    await expect(ctx.teams.updateTask(lead, {
+    await expect(ctx.agentTeams.updateTask(lead, {
       taskId: blocker.id,
       taskId: blocker.id,
       expectedRevision: blocker.revision,
       expectedRevision: blocker.revision,
       action: 'set_dependencies',
       action: 'set_dependencies',
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
     })).rejects.toMatchObject({ code: 'TEAM_INVALID_ARGUMENT' })
-    await expect(ctx.teams.updateTask(lead, {
+    await expect(ctx.agentTeams.updateTask(lead, {
       taskId: blocker.id,
       taskId: blocker.id,
       expectedRevision: blocker.revision,
       expectedRevision: blocker.revision,
       action: 'delete',
       action: 'delete',
@@ -704,54 +704,54 @@ describe('Team shared task DAG', () => {
     const { ctx, lead } = await setup(['hang'])
     const { ctx, lead } = await setup(['hang'])
     const started = await spawn(ctx, lead, 'owner')
     const started = await spawn(ctx, lead, 'owner')
     const owner = await waitRunning(ctx, started.member.id)
     const owner = await waitRunning(ctx, started.member.id)
-    const task = await ctx.teams.createTask(owner, { subject: 'lifecycle', description: 'lifecycle' })
-    const assigned = await ctx.teams.updateTask(lead, {
+    const task = await ctx.agentTeams.createTask(owner, { subject: 'lifecycle', description: 'lifecycle' })
+    const assigned = await ctx.agentTeams.updateTask(lead, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: task.revision,
       expectedRevision: task.revision,
       action: 'reassign',
       action: 'reassign',
       owner: 'owner',
       owner: 'owner',
     })
     })
-    await expect(ctx.teams.updateTask(owner, {
+    await expect(ctx.agentTeams.updateTask(owner, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: assigned.revision,
       expectedRevision: assigned.revision,
       action: 'reassign',
       action: 'reassign',
       owner: 'lead',
       owner: 'lead',
     })).rejects.toMatchObject({ code: 'TEAM_LEAD_REQUIRED' })
     })).rejects.toMatchObject({ code: 'TEAM_LEAD_REQUIRED' })
-    const complete = await ctx.teams.updateTask(owner, {
+    const complete = await ctx.agentTeams.updateTask(owner, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: assigned.revision,
       expectedRevision: assigned.revision,
       action: 'complete',
       action: 'complete',
     })
     })
-    await expect(ctx.teams.updateTask(lead, {
+    await expect(ctx.agentTeams.updateTask(lead, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: complete.revision,
       expectedRevision: complete.revision,
       action: 'reassign',
       action: 'reassign',
       owner: 'lead',
       owner: 'lead',
     })).rejects.toMatchObject({ code: 'TEAM_TASK_INVALID_TRANSITION' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_INVALID_TRANSITION' })
-    const reopened = await ctx.teams.updateTask(owner, {
+    const reopened = await ctx.agentTeams.updateTask(owner, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: complete.revision,
       expectedRevision: complete.revision,
       action: 'reopen',
       action: 'reopen',
     })
     })
-    const claimed = await ctx.teams.updateTask(owner, {
+    const claimed = await ctx.agentTeams.updateTask(owner, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: reopened.revision,
       expectedRevision: reopened.revision,
       action: 'claim',
       action: 'claim',
     })
     })
-    const deleted = await ctx.teams.updateTask(owner, {
+    const deleted = await ctx.agentTeams.updateTask(owner, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: claimed.revision,
       expectedRevision: claimed.revision,
       action: 'delete',
       action: 'delete',
     })
     })
     expect(deleted.status).toBe('deleted')
     expect(deleted.status).toBe('deleted')
-    expect(ctx.teams.listTasks(lead)).toEqual([])
-    await expect(ctx.teams.updateTask(owner, {
+    expect(ctx.agentTeams.listTasks(lead)).toEqual([])
+    await expect(ctx.agentTeams.updateTask(owner, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: deleted.revision,
       expectedRevision: deleted.revision,
       action: 'edit',
       action: 'edit',
       subject: 'late',
       subject: 'late',
     })).rejects.toMatchObject({ code: 'TEAM_TASK_DELETED' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_DELETED' })
-    ctx.teams.interrupt(lead, 'owner')
+    ctx.agentTeams.interrupt(lead, 'owner')
     await waitNoAgent(ctx, owner.id)
     await waitNoAgent(ctx, owner.id)
   })
   })
 
 
@@ -759,40 +759,40 @@ describe('Team shared task DAG', () => {
     const { ctx, lead } = await setup(['hang'])
     const { ctx, lead } = await setup(['hang'])
     const started = await spawn(ctx, lead, 'editor')
     const started = await spawn(ctx, lead, 'editor')
     const editor = await waitRunning(ctx, started.member.id)
     const editor = await waitRunning(ctx, started.member.id)
-    const blocker = await ctx.teams.createTask(lead, { subject: 'blocker', description: 'blocker' })
-    const task = await ctx.teams.createTask(lead, {
+    const blocker = await ctx.agentTeams.createTask(lead, { subject: 'blocker', description: 'blocker' })
+    const task = await ctx.agentTeams.createTask(lead, {
       subject: 'draft',
       subject: 'draft',
       description: 'draft description',
       description: 'draft description',
       blockedBy: [blocker.id],
       blockedBy: [blocker.id],
     })
     })
-    await expect(ctx.teams.updateTask(lead, {
+    await expect(ctx.agentTeams.updateTask(lead, {
       taskId: TeamTaskId('missing-update'), expectedRevision: 1, action: 'delete',
       taskId: TeamTaskId('missing-update'), expectedRevision: 1, action: 'delete',
     })).rejects.toMatchObject({ code: 'TEAM_TASK_NOT_FOUND' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_NOT_FOUND' })
-    await expect(ctx.teams.updateTask(lead, {
+    await expect(ctx.agentTeams.updateTask(lead, {
       taskId: task.id, expectedRevision: task.revision, action: 'reassign', owner: 'editor',
       taskId: task.id, expectedRevision: task.revision, action: 'reassign', owner: 'editor',
     })).rejects.toMatchObject({ code: 'TEAM_TASK_BLOCKED' })
     })).rejects.toMatchObject({ code: 'TEAM_TASK_BLOCKED' })
 
 
-    const leadClaim = await ctx.teams.updateTask(lead, {
+    const leadClaim = await ctx.agentTeams.updateTask(lead, {
       taskId: blocker.id, expectedRevision: blocker.revision, action: 'claim',
       taskId: blocker.id, expectedRevision: blocker.revision, action: 'claim',
     })
     })
     expect(leadClaim.ownerName).toBe('lead')
     expect(leadClaim.ownerName).toBe('lead')
-    const completedBlocker = await ctx.teams.updateTask(lead, {
+    const completedBlocker = await ctx.agentTeams.updateTask(lead, {
       taskId: blocker.id, expectedRevision: leadClaim.revision, action: 'complete',
       taskId: blocker.id, expectedRevision: leadClaim.revision, action: 'complete',
     })
     })
     expect(completedBlocker.status).toBe('completed')
     expect(completedBlocker.status).toBe('completed')
-    const assigned = await ctx.teams.updateTask(lead, {
+    const assigned = await ctx.agentTeams.updateTask(lead, {
       taskId: task.id, expectedRevision: task.revision, action: 'reassign', owner: 'editor',
       taskId: task.id, expectedRevision: task.revision, action: 'reassign', owner: 'editor',
     })
     })
-    const subject = await ctx.teams.updateTask(editor, {
+    const subject = await ctx.agentTeams.updateTask(editor, {
       taskId: task.id, expectedRevision: assigned.revision, action: 'edit', subject: 'edited subject',
       taskId: task.id, expectedRevision: assigned.revision, action: 'edit', subject: 'edited subject',
     })
     })
-    const description = await ctx.teams.updateTask(editor, {
+    const description = await ctx.agentTeams.updateTask(editor, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: subject.revision,
       expectedRevision: subject.revision,
       action: 'edit',
       action: 'edit',
       description: 'edited description',
       description: 'edited description',
     })
     })
-    const scopes = await ctx.teams.updateTask(editor, {
+    const scopes = await ctx.agentTeams.updateTask(editor, {
       taskId: task.id,
       taskId: task.id,
       expectedRevision: description.revision,
       expectedRevision: description.revision,
       action: 'edit',
       action: 'edit',
@@ -803,34 +803,34 @@ describe('Team shared task DAG', () => {
       description: 'edited description',
       description: 'edited description',
       writeScopes: ['src/nested'],
       writeScopes: ['src/nested'],
     })
     })
-    const unassigned = await ctx.teams.updateTask(lead, {
+    const unassigned = await ctx.agentTeams.updateTask(lead, {
       taskId: task.id, expectedRevision: scopes.revision, action: 'reassign', owner: ' ',
       taskId: task.id, expectedRevision: scopes.revision, action: 'reassign', owner: ' ',
     })
     })
     expect(unassigned).toMatchObject({ status: 'pending' })
     expect(unassigned).toMatchObject({ status: 'pending' })
     expect('ownerId' in unassigned).toBe(false)
     expect('ownerId' in unassigned).toBe(false)
 
 
-    const broad = await ctx.teams.createTask(lead, {
+    const broad = await ctx.agentTeams.createTask(lead, {
       subject: 'broad scope', description: 'broad scope', writeScopes: ['src'],
       subject: 'broad scope', description: 'broad scope', writeScopes: ['src'],
     })
     })
-    const narrow = await ctx.teams.createTask(lead, {
+    const narrow = await ctx.agentTeams.createTask(lead, {
       subject: 'narrow scope', description: 'narrow scope', writeScopes: ['src/nested'],
       subject: 'narrow scope', description: 'narrow scope', writeScopes: ['src/nested'],
     })
     })
-    const disjoint = await ctx.teams.createTask(lead, {
+    const disjoint = await ctx.agentTeams.createTask(lead, {
       subject: 'disjoint scope', description: 'disjoint scope', writeScopes: ['docs'],
       subject: 'disjoint scope', description: 'disjoint scope', writeScopes: ['docs'],
     })
     })
-    await ctx.teams.updateTask(lead, {
+    await ctx.agentTeams.updateTask(lead, {
       taskId: broad.id, expectedRevision: broad.revision, action: 'claim',
       taskId: broad.id, expectedRevision: broad.revision, action: 'claim',
     })
     })
-    await ctx.teams.updateTask(lead, {
+    await ctx.agentTeams.updateTask(lead, {
       taskId: narrow.id, expectedRevision: narrow.revision, action: 'claim',
       taskId: narrow.id, expectedRevision: narrow.revision, action: 'claim',
     })
     })
-    await ctx.teams.updateTask(lead, {
+    await ctx.agentTeams.updateTask(lead, {
       taskId: disjoint.id, expectedRevision: disjoint.revision, action: 'claim',
       taskId: disjoint.id, expectedRevision: disjoint.revision, action: 'claim',
     })
     })
-    expect(ctx.teams.getTask(lead, broad.id).writeScopeWarnings)
+    expect(ctx.agentTeams.getTask(lead, broad.id).writeScopeWarnings)
       .toEqual([`write scopes overlap with ${narrow.id}`])
       .toEqual([`write scopes overlap with ${narrow.id}`])
 
 
-    ctx.teams.interrupt(lead, 'editor')
+    ctx.agentTeams.interrupt(lead, 'editor')
     await waitNoAgent(ctx, editor.id)
     await waitNoAgent(ctx, editor.id)
   })
   })
 })
 })
@@ -843,10 +843,10 @@ describe('Team mailbox and waiting', () => {
     lead.followup(createUserMessage({ content: content('keep the Lead busy'), source: { kind: 'user' } }))
     lead.followup(createUserMessage({ content: content('keep the Lead busy'), source: { kind: 'user' } }))
     await waitRunning(ctx, lead.id)
     await waitRunning(ctx, lead.id)
 
 
-    const first = await ctx.teams.sendMessage(reporter, {
+    const first = await ctx.agentTeams.sendMessage(reporter, {
       target: 'lead', content: content('first wakeup report'), delivery: 'wakeup', signal: SIGNAL,
       target: 'lead', content: content('first wakeup report'), delivery: 'wakeup', signal: SIGNAL,
     })
     })
-    const second = await ctx.teams.sendMessage(reporter, {
+    const second = await ctx.agentTeams.sendMessage(reporter, {
       target: 'lead', content: content('second wakeup report'), delivery: 'wakeup', signal: SIGNAL,
       target: 'lead', content: content('second wakeup report'), delivery: 'wakeup', signal: SIGNAL,
     })
     })
     expect([first.status, second.status]).toEqual(['accepted', 'accepted'])
     expect([first.status, second.status]).toEqual(['accepted', 'accepted'])
@@ -890,7 +890,7 @@ describe('Team mailbox and waiting', () => {
     const { ctx, lead } = await setup(['hang'])
     const { ctx, lead } = await setup(['hang'])
     const started = await spawn(ctx, lead, 'pending-target')
     const started = await spawn(ctx, lead, 'pending-target')
     const target = await waitRunning(ctx, started.member.id)
     const target = await waitRunning(ctx, started.member.id)
-    const immediate = await ctx.teams.sendMessage(lead, {
+    const immediate = await ctx.agentTeams.sendMessage(lead, {
       target: 'pending-target',
       target: 'pending-target',
       content: content('live quiet receipt'),
       content: content('live quiet receipt'),
       delivery: 'quiet',
       delivery: 'quiet',
@@ -969,7 +969,7 @@ describe('Team mailbox and waiting', () => {
     await expect(teamInternals(ctx).mailbox.tryDispatch(lead, disappearing, SIGNAL)).resolves.toBe(false)
     await expect(teamInternals(ctx).mailbox.tryDispatch(lead, disappearing, SIGNAL)).resolves.toBe(false)
     expect(durable(lead).pendingMessages.map(pending => pending.id)).toEqual([disappearing.id])
     expect(durable(lead).pendingMessages.map(pending => pending.id)).toEqual([disappearing.id])
 
 
-    ctx.teams.interrupt(lead, 'pending-target')
+    ctx.agentTeams.interrupt(lead, 'pending-target')
     target.cancel({ kind: 'parent' })
     target.cancel({ kind: 'parent' })
     await waitNoAgent(ctx, target.id)
     await waitNoAgent(ctx, target.id)
   })
   })
@@ -985,7 +985,7 @@ describe('Team mailbox and waiting', () => {
       return flush(session)
       return flush(session)
     })
     })
 
 
-    const first = await ctx.teams.sendMessage(lead, {
+    const first = await ctx.agentTeams.sendMessage(lead, {
       target: 'busy-target', content: content('first waking message'), delivery: 'wakeup', signal: SIGNAL,
       target: 'busy-target', content: content('first waking message'), delivery: 'wakeup', signal: SIGNAL,
     })
     })
 
 
@@ -996,7 +996,7 @@ describe('Team mailbox and waiting', () => {
       && message.source.messageId === first.messageId)).toBe(true)
       && message.source.messageId === first.messageId)).toBe(true)
 
 
     flushed.length = 0
     flushed.length = 0
-    const second = await ctx.teams.sendMessage(lead, {
+    const second = await ctx.agentTeams.sendMessage(lead, {
       target: 'busy-target', content: content('second waking message'), delivery: 'wakeup', signal: SIGNAL,
       target: 'busy-target', content: content('second waking message'), delivery: 'wakeup', signal: SIGNAL,
     })
     })
 
 
@@ -1007,7 +1007,7 @@ describe('Team mailbox and waiting', () => {
       && (message.source.messageId === first.messageId || message.source.messageId === second.messageId)))
       && (message.source.messageId === first.messageId || message.source.messageId === second.messageId)))
       .toHaveLength(2)
       .toHaveLength(2)
 
 
-    ctx.teams.interrupt(lead, 'busy-target')
+    ctx.agentTeams.interrupt(lead, 'busy-target')
     target.cancel({ kind: 'parent' })
     target.cancel({ kind: 'parent' })
     await waitNoAgent(ctx, target.id)
     await waitNoAgent(ctx, target.id)
   })
   })
@@ -1030,12 +1030,12 @@ describe('Team mailbox and waiting', () => {
       return createUserMessage({ content: blocks, source: { kind: 'user' } }).id
       return createUserMessage({ content: blocks, source: { kind: 'user' } }).id
     })
     })
 
 
-    const first = ctx.teams.sendMessage(lead, {
+    const first = ctx.agentTeams.sendMessage(lead, {
       target: 'ordered-target', content: content('first waking'), delivery: 'wakeup', signal: SIGNAL,
       target: 'ordered-target', content: content('first waking'), delivery: 'wakeup', signal: SIGNAL,
     })
     })
     await entered.promise
     await entered.promise
     let secondSettled = false
     let secondSettled = false
-    const second = ctx.teams.sendMessage(lead, {
+    const second = ctx.agentTeams.sendMessage(lead, {
       target: 'ordered-target', content: content('second waking'), delivery: 'wakeup', signal: SIGNAL,
       target: 'ordered-target', content: content('second waking'), delivery: 'wakeup', signal: SIGNAL,
     }).finally(() => { secondSettled = true })
     }).finally(() => { secondSettled = true })
     await new Promise<void>((resolve) => { setTimeout(resolve, 0) })
     await new Promise<void>((resolve) => { setTimeout(resolve, 0) })
@@ -1135,21 +1135,21 @@ describe('Team mailbox and waiting', () => {
     const inactiveStarted = await spawn(ctx, lead, 'inactive-target')
     const inactiveStarted = await spawn(ctx, lead, 'inactive-target')
     await waitNoAgent(ctx, inactiveStarted.member.id)
     await waitNoAgent(ctx, inactiveStarted.member.id)
     const inspect = vi.spyOn(ctx.sessionPersistence, 'inspect').mockRejectedValueOnce(new Error('inspect unavailable'))
     const inspect = vi.spyOn(ctx.sessionPersistence, 'inspect').mockRejectedValueOnce(new Error('inspect unavailable'))
-    const uncertain = await ctx.teams.sendMessage(lead, {
+    const uncertain = await ctx.agentTeams.sendMessage(lead, {
       target: 'inactive-target', content: content('inspection failure'), delivery: 'wakeup', signal: SIGNAL,
       target: 'inactive-target', content: content('inspection failure'), delivery: 'wakeup', signal: SIGNAL,
     })
     })
     expect(uncertain.status).toBe('queued')
     expect(uncertain.status).toBe('queued')
     inspect.mockRestore()
     inspect.mockRestore()
 
 
     vi.spyOn(ctx.subagents, 'followup').mockRejectedValueOnce(new Error('delivery unavailable'))
     vi.spyOn(ctx.subagents, 'followup').mockRejectedValueOnce(new Error('delivery unavailable'))
-    const failed = await ctx.teams.sendMessage(lead, {
+    const failed = await ctx.agentTeams.sendMessage(lead, {
       target: 'inactive-target', content: content('delivery failure'), delivery: 'wakeup', signal: SIGNAL,
       target: 'inactive-target', content: content('delivery failure'), delivery: 'wakeup', signal: SIGNAL,
     })
     })
     expect(failed.status).toBe('queued')
     expect(failed.status).toBe('queued')
     expect(warnings.some(warning => warning.includes('inspect unavailable'))).toBe(true)
     expect(warnings.some(warning => warning.includes('inspect unavailable'))).toBe(true)
     expect(warnings.some(warning => warning.includes('delivery unavailable'))).toBe(true)
     expect(warnings.some(warning => warning.includes('delivery unavailable'))).toBe(true)
 
 
-    ctx.teams.interrupt(lead, 'live-target')
+    ctx.agentTeams.interrupt(lead, 'live-target')
     await waitNoAgent(ctx, live.id)
     await waitNoAgent(ctx, live.id)
   })
   })
 
 
@@ -1160,12 +1160,12 @@ describe('Team mailbox and waiting', () => {
     const betaStarted = await spawn(ctx, lead, 'beta')
     const betaStarted = await spawn(ctx, lead, 'beta')
     await waitNoAgent(ctx, betaStarted.member.id)
     await waitNoAgent(ctx, betaStarted.member.id)
 
 
-    const quiet = await ctx.teams.sendMessage(alpha, {
+    const quiet = await ctx.agentTeams.sendMessage(alpha, {
       target: 'beta', content: content('quiet info'), delivery: 'quiet', signal: SIGNAL,
       target: 'beta', content: content('quiet info'), delivery: 'quiet', signal: SIGNAL,
     })
     })
     expect(quiet.status).toBe('queued')
     expect(quiet.status).toBe('queued')
     expect(ctx.agents.get(betaStarted.member.id)).toBeUndefined()
     expect(ctx.agents.get(betaStarted.member.id)).toBeUndefined()
-    const waking = await ctx.teams.sendMessage(alpha, {
+    const waking = await ctx.agentTeams.sendMessage(alpha, {
       target: 'beta', content: content('do another turn'), delivery: 'wakeup', signal: SIGNAL,
       target: 'beta', content: content('do another turn'), delivery: 'wakeup', signal: SIGNAL,
     })
     })
     expect(waking.status).toBe('accepted')
     expect(waking.status).toBe('accepted')
@@ -1193,7 +1193,7 @@ describe('Team mailbox and waiting', () => {
       [waking.messageId, 'alpha'],
       [waking.messageId, 'alpha'],
     ])
     ])
 
 
-    ctx.teams.interrupt(lead, 'alpha')
+    ctx.agentTeams.interrupt(lead, 'alpha')
     await waitNoAgent(ctx, alpha.id)
     await waitNoAgent(ctx, alpha.id)
   })
   })
 
 
@@ -1204,25 +1204,25 @@ describe('Team mailbox and waiting', () => {
     })
     })
     const target = await spawn(ctx, lead, 'target')
     const target = await spawn(ctx, lead, 'target')
     await waitNoAgent(ctx, target.member.id)
     await waitNoAgent(ctx, target.member.id)
-    await expect(ctx.teams.sendMessage(lead, {
+    await expect(ctx.agentTeams.sendMessage(lead, {
       target: 'target', content: content('x'.repeat(300)), delivery: 'quiet', signal: SIGNAL,
       target: 'target', content: content('x'.repeat(300)), delivery: 'quiet', signal: SIGNAL,
     })).rejects.toMatchObject({ code: 'TEAM_MESSAGE_TOO_LARGE' })
     })).rejects.toMatchObject({ code: 'TEAM_MESSAGE_TOO_LARGE' })
-    const queued = await ctx.teams.sendMessage(lead, {
+    const queued = await ctx.agentTeams.sendMessage(lead, {
       target: 'target', content: content('one'), delivery: 'quiet', signal: SIGNAL,
       target: 'target', content: content('one'), delivery: 'quiet', signal: SIGNAL,
     })
     })
     expect(queued.status).toBe('queued')
     expect(queued.status).toBe('queued')
-    await expect(ctx.teams.sendMessage(lead, {
+    await expect(ctx.agentTeams.sendMessage(lead, {
       target: 'target', content: content('two'), delivery: 'quiet', signal: SIGNAL,
       target: 'target', content: content('two'), delivery: 'quiet', signal: SIGNAL,
     })).rejects.toMatchObject({ code: 'TEAM_MAILBOX_FULL' })
     })).rejects.toMatchObject({ code: 'TEAM_MAILBOX_FULL' })
-    await expect(ctx.teams.sendMessage(lead, {
+    await expect(ctx.agentTeams.sendMessage(lead, {
       target: 'lead', content: content('self'), delivery: 'quiet', signal: SIGNAL,
       target: 'lead', content: content('self'), delivery: 'quiet', signal: SIGNAL,
     })).rejects.toMatchObject({ code: 'TEAM_SELF_MESSAGE' })
     })).rejects.toMatchObject({ code: 'TEAM_SELF_MESSAGE' })
-    await expect(ctx.teams.sendMessage(lead, {
+    await expect(ctx.agentTeams.sendMessage(lead, {
       target: 'missing', content: content('unknown target'), delivery: 'quiet', signal: SIGNAL,
       target: 'missing', content: content('unknown target'), delivery: 'quiet', signal: SIGNAL,
     })).rejects.toMatchObject({ code: 'TEAM_MEMBER_NOT_FOUND' })
     })).rejects.toMatchObject({ code: 'TEAM_MEMBER_NOT_FOUND' })
     const controller = new AbortController()
     const controller = new AbortController()
     controller.abort(new TeamError('cancelled before queue', 'TEST_CANCELLED'))
     controller.abort(new TeamError('cancelled before queue', 'TEST_CANCELLED'))
-    await expect(ctx.teams.sendMessage(lead, {
+    await expect(ctx.agentTeams.sendMessage(lead, {
       target: 'target', content: content('cancelled'), delivery: 'quiet', signal: controller.signal,
       target: 'target', content: content('cancelled'), delivery: 'quiet', signal: controller.signal,
     })).rejects.toMatchObject({ code: 'TEST_CANCELLED' })
     })).rejects.toMatchObject({ code: 'TEST_CANCELLED' })
   })
   })
@@ -1231,11 +1231,11 @@ describe('Team mailbox and waiting', () => {
     const { ctx, lead } = await setup(['hang', textResponse('after interrupt')])
     const { ctx, lead } = await setup(['hang', textResponse('after interrupt')])
     const started = await spawn(ctx, lead, 'worker')
     const started = await spawn(ctx, lead, 'worker')
     const worker = await waitRunning(ctx, started.member.id)
     const worker = await waitRunning(ctx, started.member.id)
-    const followup = await ctx.teams.sendMessage(lead, {
+    const followup = await ctx.agentTeams.sendMessage(lead, {
       target: 'worker', content: content('retained follow-up'), delivery: 'wakeup', signal: SIGNAL,
       target: 'worker', content: content('retained follow-up'), delivery: 'wakeup', signal: SIGNAL,
     })
     })
     expect(followup.status).toBe('accepted')
     expect(followup.status).toBe('accepted')
-    expect(ctx.teams.interrupt(lead, 'worker')).toEqual({ previousStatus: 'running' })
+    expect(ctx.agentTeams.interrupt(lead, 'worker')).toEqual({ previousStatus: 'running' })
     await vi.waitFor(() => { expect(worker.status).toBe('idle') })
     await vi.waitFor(() => { expect(worker.status).toBe('idle') })
     expect(worker.inbox.nextTurn.some(message => message.source.kind === 'team-message'
     expect(worker.inbox.nextTurn.some(message => message.source.kind === 'team-message'
       && message.source.messageId === followup.messageId)).toBe(true)
       && message.source.messageId === followup.messageId)).toBe(true)
@@ -1252,7 +1252,7 @@ describe('Team mailbox and waiting', () => {
     await ctx.plugin(AgentLoop, { agents: [] })
     await ctx.plugin(AgentLoop, { agents: [] })
     await ctx.plugin(SubagentService)
     await ctx.plugin(SubagentService)
     const fiber = await ctx.plugin(TeamService)
     const fiber = await ctx.plugin(TeamService)
-    const service = ctx.teams
+    const service = ctx.agentTeams
     const lead = ctx.agentLoop.create(SessionId('wait-lead'), {})
     const lead = ctx.agentLoop.create(SessionId('wait-lead'), {})
 
 
     await expect(service.waitForChange(lead, 9_999, SIGNAL))
     await expect(service.waitForChange(lead, 9_999, SIGNAL))
@@ -1314,25 +1314,25 @@ describe('Team mailbox and waiting', () => {
     const disposed = service.waitForChange(lead, 10_000, SIGNAL)
     const disposed = service.waitForChange(lead, 10_000, SIGNAL)
     await fiber.dispose()
     await fiber.dispose()
     await expect(disposed).resolves.toEqual({ timedOut: false })
     await expect(disposed).resolves.toEqual({ timedOut: false })
-    expect(ctx.get('teams')).toBeUndefined()
+    expect(ctx.get('agentTeams')).toBeUndefined()
   })
   })
 
 
   it('disposes live teammate Activations and their waits when the Team service unloads', async () => {
   it('disposes live teammate Activations and their waits when the Team service unloads', async () => {
     const { ctx, lead, teamFiber } = await setup(['hang'])
     const { ctx, lead, teamFiber } = await setup(['hang'])
     const started = await spawn(ctx, lead, 'dispose-worker')
     const started = await spawn(ctx, lead, 'dispose-worker')
     await waitRunning(ctx, started.member.id)
     await waitRunning(ctx, started.member.id)
-    const waiting = ctx.teams.waitForChange(lead, 10_000, SIGNAL)
+    const waiting = ctx.agentTeams.waitForChange(lead, 10_000, SIGNAL)
 
 
     await teamFiber.dispose()
     await teamFiber.dispose()
 
 
     await expect(waiting).resolves.toEqual({ timedOut: false })
     await expect(waiting).resolves.toEqual({ timedOut: false })
     expect(ctx.agents.get(started.member.id)).toBeUndefined()
     expect(ctx.agents.get(started.member.id)).toBeUndefined()
-    expect(ctx.get('teams')).toBeUndefined()
+    expect(ctx.get('agentTeams')).toBeUndefined()
   })
   })
 
 
   it('closes creation admission and drains an in-flight spawn before unload completes', async () => {
   it('closes creation admission and drains an in-flight spawn before unload completes', async () => {
     const { ctx, lead, teamFiber } = await setup(['hang'])
     const { ctx, lead, teamFiber } = await setup(['hang'])
-    const service = ctx.teams
+    const service = ctx.agentTeams
     const start = ctx.subagents.startContinuable.bind(ctx.subagents)
     const start = ctx.subagents.startContinuable.bind(ctx.subagents)
     const entered = Promise.withResolvers<undefined>()
     const entered = Promise.withResolvers<undefined>()
     const release = Promise.withResolvers<undefined>()
     const release = Promise.withResolvers<undefined>()
@@ -1363,7 +1363,7 @@ describe('Team mailbox and waiting', () => {
     await rejected
     await rejected
     await disposal
     await disposal
     if (childId !== undefined) expect(ctx.agents.get(childId)).toBeUndefined()
     if (childId !== undefined) expect(ctx.agents.get(childId)).toBeUndefined()
-    expect(ctx.get('teams')).toBeUndefined()
+    expect(ctx.get('agentTeams')).toBeUndefined()
   })
   })
 
 
   it('retains an in-flight creation cleanup failure during disposal', async () => {
   it('retains an in-flight creation cleanup failure during disposal', async () => {
@@ -1433,9 +1433,9 @@ describe('Team mailbox and waiting', () => {
       },
       },
     })
     })
     await ctx.sessions.flush(lead.session)
     await ctx.sessions.flush(lead.session)
-    expect(ctx.teams.listMembers(lead)[1]?.status).toBe('failed')
+    expect(ctx.agentTeams.listMembers(lead)[1]?.status).toBe('failed')
 
 
-    const internal = ctx.teams as unknown as { disposeRuntime(): Promise<void> }
+    const internal = ctx.agentTeams as unknown as { disposeRuntime(): Promise<void> }
     await internal.disposeRuntime()
     await internal.disposeRuntime()
     expect(ctx.agents.get(childId)).toBeUndefined()
     expect(ctx.agents.get(childId)).toBeUndefined()
   })
   })
@@ -1460,14 +1460,14 @@ describe('Team mailbox and waiting', () => {
       })
       })
     })
     })
 
 
-    const sending = ctx.teams.sendMessage(lead, {
+    const sending = ctx.agentTeams.sendMessage(lead, {
       target: 'mailbox-worker',
       target: 'mailbox-worker',
       content: content('resume during disposal'),
       content: content('resume during disposal'),
       delivery: 'wakeup',
       delivery: 'wakeup',
       signal: SIGNAL,
       signal: SIGNAL,
     })
     })
     await entered.promise
     await entered.promise
-    const internal = ctx.teams as unknown as { disposeRuntime(): Promise<void> }
+    const internal = ctx.agentTeams as unknown as { disposeRuntime(): Promise<void> }
     let disposed = false
     let disposed = false
     const disposal = internal.disposeRuntime().then(() => { disposed = true })
     const disposal = internal.disposeRuntime().then(() => { disposed = true })
     await aborted.promise
     await aborted.promise
@@ -1521,7 +1521,7 @@ describe('Team mailbox and waiting', () => {
       },
       },
     }), { surfaceOp: 'append' })
     }), { surfaceOp: 'append' })
 
 
-    const internal = ctx.teams as unknown as { disposeRuntime(): Promise<void> }
+    const internal = ctx.agentTeams as unknown as { disposeRuntime(): Promise<void> }
     let disposed = false
     let disposed = false
     const disposal = internal.disposeRuntime().then(() => { disposed = true })
     const disposal = internal.disposeRuntime().then(() => { disposed = true })
     await entered.promise
     await entered.promise
@@ -1549,7 +1549,7 @@ describe('Team mailbox and waiting', () => {
     ])
     ])
     expect(outcome).toBe('disposed')
     expect(outcome).toBe('disposed')
     expect(drain).toHaveBeenCalledWith(lead, [started.member.id])
     expect(drain).toHaveBeenCalledWith(lead, [started.member.id])
-    expect(ctx.get('teams')).toBeUndefined()
+    expect(ctx.get('agentTeams')).toBeUndefined()
   })
   })
 
 
   it('bounds disposal while an admitted creation ignores cancellation', async () => {
   it('bounds disposal while an admitted creation ignores cancellation', async () => {
@@ -1558,7 +1558,7 @@ describe('Team mailbox and waiting', () => {
     internal.roster.inFlightCreations.add(new Promise(() => {}))
     internal.roster.inFlightCreations.add(new Promise(() => {}))
 
 
     await expect(internal.disposeRuntime()).rejects.toBeInstanceOf(AggregateError)
     await expect(internal.disposeRuntime()).rejects.toBeInstanceOf(AggregateError)
-    await expect(ctx.teams.spawnTeammate(lead, {
+    await expect(ctx.agentTeams.spawnTeammate(lead, {
       name: 'after-timeout',
       name: 'after-timeout',
       description: 'admission remains closed',
       description: 'admission remains closed',
       prompt: content('must reject'),
       prompt: content('must reject'),
@@ -1566,7 +1566,7 @@ describe('Team mailbox and waiting', () => {
       provider: 'spawn',
       provider: 'spawn',
       signal: SIGNAL,
       signal: SIGNAL,
     })).rejects.toMatchObject({ code: 'TEAM_DISPOSED' })
     })).rejects.toMatchObject({ code: 'TEAM_DISPOSED' })
-    await expect(ctx.teams.sendMessage(lead, {
+    await expect(ctx.agentTeams.sendMessage(lead, {
       target: 'nobody', content: content('must reject'), delivery: 'quiet', signal: SIGNAL,
       target: 'nobody', content: content('must reject'), delivery: 'quiet', signal: SIGNAL,
     })).rejects.toMatchObject({ code: 'TEAM_DISPOSED' })
     })).rejects.toMatchObject({ code: 'TEAM_DISPOSED' })
     await expect(internal.mailbox.tryDispatch(lead, {
     await expect(internal.mailbox.tryDispatch(lead, {
@@ -1626,7 +1626,7 @@ describe('Team mailbox and waiting', () => {
     vi.spyOn(ctx.subagents, 'drainContinuableDescendants').mockRejectedValueOnce(new Error('drain failure'))
     vi.spyOn(ctx.subagents, 'drainContinuableDescendants').mockRejectedValueOnce(new Error('drain failure'))
 
 
     await teamFiber.dispose()
     await teamFiber.dispose()
-    expect(ctx.get('teams')).toBeUndefined()
+    expect(ctx.get('agentTeams')).toBeUndefined()
   })
   })
 
 
   it('reconciles mismatched persisted children and ignores a concurrently settled member', async () => {
   it('reconciles mismatched persisted children and ignores a concurrently settled member', async () => {

+ 2 - 2
packages/experimental/tool-agent-team/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write packages/experimental/tool-agent-team/README.md
 #   pnpm run verify-translation-pairing --write packages/experimental/tool-agent-team/README.md
-README.md: c195f7e7fb977e81a507b8c1c58b1cc3ffaab230
-README.zh.md: 83c10a2d07ec6e0665c89adc69a8b2ccecdfc49a
+README.md: a0ff967199e8a22b60483aa59442a1cbefb261a8
+README.zh.md: 3dc4d9ea1631cc23e171d0689271f60ff84f92c4

+ 3 - 3
packages/experimental/tool-agent-team/README.md

@@ -2,12 +2,12 @@
 
 
 English | [中文](README.zh.md)
 English | [中文](README.zh.md)
 
 
-Scoped model-facing adapter for [`ctx.teams`](../agent-team/README.md). It installs the Agent Teams policy and collaboration tools in each implicit Lead and durable teammate scope. Scoped Team definitions shadow same-named legacy global continuable-subagent controls, so a composition that mounts both must disable the legacy definitions.
+Scoped model-facing adapter for [`ctx.agentTeams`](../agent-team/README.md). It installs the Agent Teams policy and collaboration tools in each implicit Lead and durable teammate scope. Scoped Team definitions shadow same-named legacy global continuable-subagent controls, so a composition that mounts both must disable the legacy definitions.
 
 
 ## Config
 ## Config
 
 
 ```yaml
 ```yaml
-- id: tool-team
+- id: tool-agent-team
   name: '@deepseek-ai/dsh-experimental-tool-agent-team'
   name: '@deepseek-ai/dsh-experimental-tool-agent-team'
   config:
   config:
     freshProvider: spawn
     freshProvider: spawn
@@ -20,7 +20,7 @@ Scoped model-facing adapter for [`ctx.teams`](../agent-team/README.md). It insta
 
 
 The generated [tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-experimental-tool-agent-team) owns exact schemas. The adapter supplies teammate creation; quiet and waking peer delivery; roster listing, waiting, and Lead-only interruption; and task create/list/get/compare-and-set update operations.
 The generated [tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-experimental-tool-agent-team) owns exact schemas. The adapter supplies teammate creation; quiet and waking peer delivery; roster listing, waiting, and Lead-only interruption; and task create/list/get/compare-and-set update operations.
 
 
-Every tool requires the exact calling `Agent`. `spawn_teammate` and `interrupt_agent` enforce Lead authority inside `ctx.teams`, not only in their descriptions. All members can communicate with any peer and use the task board. Task mutations retain the domain's owner/Lead and revision checks.
+Every tool requires the exact calling `Agent`. `spawn_teammate` and `interrupt_agent` enforce Lead authority inside `ctx.agentTeams`, not only in their descriptions. All members can communicate with any peer and use the task board. Task mutations retain the domain's owner/Lead and revision checks.
 
 
 `send_message` succeeds once mail is durable and never wakes an inactive target. `followup_task` also makes the message the target's next turn and can cold-resume it. A `queued` result is accepted durable work and must not be retried. Task readiness does not start an owner. Before arming its 10,000-through-3,600,000-millisecond edge wait, `wait_agent` checks for another member that is running or provisioning; without one it returns `noProgress` immediately with instructions to re-list and use `followup_task`. Otherwise it waits for one post-call Team edge, defaulting to 30,000 milliseconds, and callers re-list after wakeup or timeout because earlier changes are not replayed.
 `send_message` succeeds once mail is durable and never wakes an inactive target. `followup_task` also makes the message the target's next turn and can cold-resume it. A `queued` result is accepted durable work and must not be retried. Task readiness does not start an owner. Before arming its 10,000-through-3,600,000-millisecond edge wait, `wait_agent` checks for another member that is running or provisioning; without one it returns `noProgress` immediately with instructions to re-list and use `followup_task`. Otherwise it waits for one post-call Team edge, defaulting to 30,000 milliseconds, and callers re-list after wakeup or timeout because earlier changes are not replayed.
 
 

+ 3 - 3
packages/experimental/tool-agent-team/README.zh.md

@@ -2,12 +2,12 @@
 
 
 [English](README.md) | 中文
 [English](README.md) | 中文
 
 
-[`ctx.teams`](../agent-team/README.md) 的 scoped 模型适配器。它会在每个隐式 Lead 与持久 teammate scope 中安装 Agent Teams 策略和协作工具。scoped Team 定义会覆盖同名的旧全局 continuable-subagent control,因此同时挂载两者的组合必须禁用旧定义。
+[`ctx.agentTeams`](../agent-team/README.md) 的 scoped 模型适配器。它会在每个隐式 Lead 与持久 teammate scope 中安装 Agent Teams 策略和协作工具。scoped Team 定义会覆盖同名的旧全局 continuable-subagent control,因此同时挂载两者的组合必须禁用旧定义。
 
 
 ## 配置
 ## 配置
 
 
 ```yaml
 ```yaml
-- id: tool-team
+- id: tool-agent-team
   name: '@deepseek-ai/dsh-experimental-tool-agent-team'
   name: '@deepseek-ai/dsh-experimental-tool-agent-team'
   config:
   config:
     freshProvider: spawn
     freshProvider: spawn
@@ -20,7 +20,7 @@
 
 
 生成的[工具目录](../../../docs/tool-catalog.md#deepseek-aidsh-experimental-tool-agent-team)负责精确 schema。该适配器提供 teammate 创建;quiet 与 waking peer 投递;roster 列表、等待和仅限 Lead 的 interrupt;以及任务 create/list/get/CAS update 操作。
 生成的[工具目录](../../../docs/tool-catalog.md#deepseek-aidsh-experimental-tool-agent-team)负责精确 schema。该适配器提供 teammate 创建;quiet 与 waking peer 投递;roster 列表、等待和仅限 Lead 的 interrupt;以及任务 create/list/get/CAS update 操作。
 
 
-每个工具都要求完全相同的调用 `Agent`。`spawn_teammate` 与 `interrupt_agent` 在 `ctx.teams` 内部强制执行 Lead 权限,而不只依赖描述。所有成员都可以与任意 peer 通讯并使用任务板。任务变更保留领域层的 Owner/Lead 与 revision 校验。
+每个工具都要求完全相同的调用 `Agent`。`spawn_teammate` 与 `interrupt_agent` 在 `ctx.agentTeams` 内部强制执行 Lead 权限,而不只依赖描述。所有成员都可以与任意 peer 通讯并使用任务板。任务变更保留领域层的 Owner/Lead 与 revision 校验。
 
 
 `send_message` 在 mail 持久化后即成功,并且绝不会唤醒 inactive target。`followup_task` 还会让该消息成为 target 的下一个 turn,并可冷恢复 target。`queued` 结果表示持久工作已经接受,不能重试。任务 ready 不会启动 owner。`wait_agent` 在注册 10,000 到 3,600,000 毫秒的边等待前,会检查是否有另一个 running 或 provisioning member;如果没有,它会立即返回 `noProgress`,提示重新 list 并使用 `followup_task`。否则它会等待调用后发生的一条 Team 边,默认 30,000 毫秒;由于不会回放更早的变化,调用方需要在唤醒或超时后重新 list。
 `send_message` 在 mail 持久化后即成功,并且绝不会唤醒 inactive target。`followup_task` 还会让该消息成为 target 的下一个 turn,并可冷恢复 target。`queued` 结果表示持久工作已经接受,不能重试。任务 ready 不会启动 owner。`wait_agent` 在注册 10,000 到 3,600,000 毫秒的边等待前,会检查是否有另一个 running 或 provisioning member;如果没有,它会立即返回 `noProgress`,提示重新 list 并使用 `followup_task`。否则它会等待调用后发生的一条 Team 边,默认 30,000 毫秒;由于不会回放更早的变化,调用方需要在唤醒或超时后重新 list。
 
 

+ 1 - 1
packages/experimental/tool-agent-team/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@deepseek-ai/dsh-experimental-tool-agent-team",
   "name": "@deepseek-ai/dsh-experimental-tool-agent-team",
-  "description": "Scoped model-facing Agent Teams tools over ctx.teams",
+  "description": "Scoped model-facing Agent Teams tools over ctx.agentTeams",
   "version": "0.1.0-rc.7",
   "version": "0.1.0-rc.7",
   "private": true,
   "private": true,
   "repository": {
   "repository": {

+ 15 - 15
packages/experimental/tool-agent-team/src/index.ts

@@ -9,9 +9,9 @@ import { defineTool } from '@deepseek-ai/dsh-tools'
 import type { InferValue, ValueSchemaSpec } from '@deepseek-ai/dsh-tools'
 import type { InferValue, ValueSchemaSpec } from '@deepseek-ai/dsh-tools'
 
 
 /** Cordis plugin name. */
 /** Cordis plugin name. */
-export const name = 'tool-team'
+export const name = 'tool-agent-team'
 /** Services required by the Team tool plugin. */
 /** Services required by the Team tool plugin. */
-export const inject = ['agents', 'teams', 'tools', 'systemPrompt']
+export const inject = ['agents', 'agentTeams', 'tools', 'systemPrompt']
 
 
 /** Tool routing configuration. */
 /** Tool routing configuration. */
 export interface Config {
 export interface Config {
@@ -165,7 +165,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
       name: 'team:policy',
       name: 'team:policy',
       order: 60,
       order: 60,
       text: () => {
       text: () => {
-        const membership = ctx.teams.membership(agent)
+        const membership = ctx.agentTeams.membership(agent)
         return `${POLICY}\n\nYour Team role is ${membership.role}; your Team name is ${membership.name}; Team id is ${membership.id}.`
         return `${POLICY}\n\nYour Team role is ${membership.role}; your Team name is ${membership.name}; Team id is ${membership.id}.`
       },
       },
     }))
     }))
@@ -187,7 +187,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
       async execute(args, exec) {
       async execute(args, exec) {
         const agent = callingAgent(exec.agent, 'spawn_teammate')
         const agent = callingAgent(exec.agent, 'spawn_teammate')
         const context = args.context ?? 'fresh'
         const context = args.context ?? 'fresh'
-        return await ctx.teams.spawnTeammate(agent, {
+        return await ctx.agentTeams.spawnTeammate(agent, {
           name: args.name,
           name: args.name,
           description: args.description,
           description: args.description,
           prompt: [{ type: 'text', text: args.prompt }],
           prompt: [{ type: 'text', text: args.prompt }],
@@ -210,7 +210,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
         },
         },
         output: jsonOutput(SEND_VALUE_SCHEMA),
         output: jsonOutput(SEND_VALUE_SCHEMA),
         execute(args, exec) {
         execute(args, exec) {
-          return ctx.teams.sendMessage(callingAgent(exec.agent, toolName), {
+          return ctx.agentTeams.sendMessage(callingAgent(exec.agent, toolName), {
             target: args.target,
             target: args.target,
             content: [{ type: 'text', text: args.message }],
             content: [{ type: 'text', text: args.message }],
             delivery,
             delivery,
@@ -228,7 +228,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
       parameters: {},
       parameters: {},
       output: jsonOutput(MEMBER_LIST_VALUE_SCHEMA),
       output: jsonOutput(MEMBER_LIST_VALUE_SCHEMA),
       async execute(_args, exec) {
       async execute(_args, exec) {
-        return Promise.resolve(ctx.teams.listMembers(callingAgent(exec.agent, 'list_agents')))
+        return Promise.resolve(ctx.agentTeams.listMembers(callingAgent(exec.agent, 'list_agents')))
       },
       },
     })))
     })))
 
 
@@ -248,11 +248,11 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
         // Preserve TeamService's authoritative timeout validation before the
         // Preserve TeamService's authoritative timeout validation before the
         // model-only no-progress shortcut.
         // model-only no-progress shortcut.
         if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 10_000 || timeoutMs > 3_600_000) {
         if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 10_000 || timeoutMs > 3_600_000) {
-          return await ctx.teams.waitForChange(caller, timeoutMs, exec.signal)
+          return await ctx.agentTeams.waitForChange(caller, timeoutMs, exec.signal)
         }
         }
         // The active-peer read and waiter registration must remain one synchronous
         // The active-peer read and waiter registration must remain one synchronous
         // span; awaiting between them can lose the only peer-status edge.
         // span; awaiting between them can lose the only peer-status edge.
-        const hasActivePeer = ctx.teams.listMembers(caller).some(member =>
+        const hasActivePeer = ctx.agentTeams.listMembers(caller).some(member =>
           member.id !== caller.id && ACTIVE_WAIT_STATUSES.has(member.status))
           member.id !== caller.id && ACTIVE_WAIT_STATUSES.has(member.status))
         if (!hasActivePeer) {
         if (!hasActivePeer) {
           return {
           return {
@@ -263,7 +263,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
             },
             },
           }
           }
         }
         }
-        return await ctx.teams.waitForChange(caller, timeoutMs, exec.signal)
+        return await ctx.agentTeams.waitForChange(caller, timeoutMs, exec.signal)
       },
       },
     })))
     })))
 
 
@@ -275,7 +275,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
       },
       },
       output: jsonOutput(INTERRUPT_VALUE_SCHEMA),
       output: jsonOutput(INTERRUPT_VALUE_SCHEMA),
       async execute(args, exec) {
       async execute(args, exec) {
-        return Promise.resolve(ctx.teams.interrupt(
+        return Promise.resolve(ctx.agentTeams.interrupt(
           callingAgent(exec.agent, 'interrupt_agent'),
           callingAgent(exec.agent, 'interrupt_agent'),
           args.target,
           args.target,
         ))
         ))
@@ -297,7 +297,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
       },
       },
       output: jsonOutput(TASK_VIEW_SCHEMA),
       output: jsonOutput(TASK_VIEW_SCHEMA),
       async execute(args, exec) {
       async execute(args, exec) {
-        return await ctx.teams.createTask(callingAgent(exec.agent, 'team_task_create'), {
+        return await ctx.agentTeams.createTask(callingAgent(exec.agent, 'team_task_create'), {
           subject: args.subject,
           subject: args.subject,
           description: args.description,
           description: args.description,
           ...args.blocked_by === undefined ? {} : { blockedBy: args.blocked_by.map(TeamTaskId) },
           ...args.blocked_by === undefined ? {} : { blockedBy: args.blocked_by.map(TeamTaskId) },
@@ -323,7 +323,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
       output: jsonOutput(TASK_LIST_VALUE_SCHEMA),
       output: jsonOutput(TASK_LIST_VALUE_SCHEMA),
       execute(args, exec) {
       execute(args, exec) {
         const status = args.status
         const status = args.status
-        const filtered = ctx.teams.listTasks(callingAgent(exec.agent, 'team_task_list')).filter(task =>
+        const filtered = ctx.agentTeams.listTasks(callingAgent(exec.agent, 'team_task_list')).filter(task =>
           (status === undefined || task.status === status)
           (status === undefined || task.status === status)
           && (args.owner === undefined || (args.owner === 'unowned' ? task.ownerName === undefined : task.ownerName === args.owner))
           && (args.owner === undefined || (args.owner === 'unowned' ? task.ownerName === undefined : task.ownerName === args.owner))
           && (args.ready === undefined || task.ready === args.ready))
           && (args.ready === undefined || task.ready === args.ready))
@@ -346,7 +346,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
       },
       },
       output: jsonOutput(TASK_VIEW_SCHEMA),
       output: jsonOutput(TASK_VIEW_SCHEMA),
       async execute(args, exec) {
       async execute(args, exec) {
-        return Promise.resolve(ctx.teams.getTask(
+        return Promise.resolve(ctx.agentTeams.getTask(
           callingAgent(exec.agent, 'team_task_get'),
           callingAgent(exec.agent, 'team_task_get'),
           TeamTaskId(args.task_id),
           TeamTaskId(args.task_id),
         ))
         ))
@@ -373,7 +373,7 @@ function install(agent: Agent, ctx: Context, config: Required<Config>): () => vo
       },
       },
       output: jsonOutput(TASK_VIEW_SCHEMA),
       output: jsonOutput(TASK_VIEW_SCHEMA),
       async execute(args, exec) {
       async execute(args, exec) {
-        return await ctx.teams.updateTask(callingAgent(exec.agent, 'team_task_update'), {
+        return await ctx.agentTeams.updateTask(callingAgent(exec.agent, 'team_task_update'), {
           taskId: TeamTaskId(args.task_id),
           taskId: TeamTaskId(args.task_id),
           expectedRevision: args.expected_revision,
           expectedRevision: args.expected_revision,
           action: args.action,
           action: args.action,
@@ -402,7 +402,7 @@ export function apply(ctx: Context, config: Config = {}): void {
   }
   }
   const installed = new Map<Agent, () => void>()
   const installed = new Map<Agent, () => void>()
   const maybeInstall = (agent: Agent): void => {
   const maybeInstall = (agent: Agent): void => {
-    if (installed.has(agent) || ctx.teams.tryMembership(agent) === undefined) return
+    if (installed.has(agent) || ctx.agentTeams.tryMembership(agent) === undefined) return
     installed.set(agent, install(agent, ctx, resolved))
     installed.set(agent, install(agent, ctx, resolved))
   }
   }
   for (const agent of ctx.agents.list()) maybeInstall(agent)
   for (const agent of ctx.agents.list()) maybeInstall(agent)

+ 4 - 4
packages/experimental/tool-agent-team/tests/tool-team.spec.ts

@@ -402,7 +402,7 @@ describe('dsh-tool-team', () => {
     const childId = spawnedChildId(spawned)
     const childId = spawnedChildId(spawned)
     await vi.waitFor(() => { expect(ctx.agents.get(childId)).toBeUndefined() }, { timeout: 5_000 })
     await vi.waitFor(() => { expect(ctx.agents.get(childId)).toBeUndefined() }, { timeout: 5_000 })
 
 
-    await ctx.teams.sendMessage(lead, {
+    await ctx.agentTeams.sendMessage(lead, {
       target: 'cold-worker',
       target: 'cold-worker',
       content: [{ type: 'text', text: 'resume with Team scope' }],
       content: [{ type: 'text', text: 'resume with Team scope' }],
       delivery: 'wakeup',
       delivery: 'wakeup',
@@ -422,8 +422,8 @@ describe('dsh-tool-team', () => {
     expect(result.isError).toBe(true)
     expect(result.isError).toBe(true)
     expect(text(result)).toContain('unknown tool "list_agents"')
     expect(text(result)).toContain('unknown tool "list_agents"')
     expect('default' in toolTeam).toBe(false)
     expect('default' in toolTeam).toBe(false)
-    expect(toolTeam.name).toBe('tool-team')
-    expect(toolTeam.inject).toEqual(['agents', 'teams', 'tools', 'systemPrompt'])
+    expect(toolTeam.name).toBe('tool-agent-team')
+    expect(toolTeam.inject).toEqual(['agents', 'agentTeams', 'tools', 'systemPrompt'])
   })
   })
 
 
   it('uses configured fresh and fork provider names', async () => {
   it('uses configured fresh and fork provider names', async () => {
@@ -437,6 +437,6 @@ describe('dsh-tool-team', () => {
     expect(result.isError).toBe(false)
     expect(result.isError).toBe(false)
     const childId = spawnedChildId(result)
     const childId = spawnedChildId(result)
     await vi.waitFor(() => { expect(ctx.agents.get(childId)).toBeUndefined() }, { timeout: 5_000 })
     await vi.waitFor(() => { expect(ctx.agents.get(childId)).toBeUndefined() }, { timeout: 5_000 })
-    expect(ctx.teams.listMembers(lead)[1]).toMatchObject({ provider: 'team-fresh' })
+    expect(ctx.agentTeams.listMembers(lead)[1]).toMatchObject({ provider: 'team-fresh' })
   })
   })
 })
 })

+ 1 - 1
scripts/gen-cordis-catalog.ts

@@ -98,7 +98,7 @@ export const SERVICE_PAGE: Record<string, string> = {
   systemPrompt: 'system-prompt.md',
   systemPrompt: 'system-prompt.md',
   jobs: 'jobs.md',
   jobs: 'jobs.md',
   sessionTelemetry: 'session-telemetry.md',
   sessionTelemetry: 'session-telemetry.md',
-  teams: 'team.md',
+  agentTeams: 'agent-team.md',
   tokenMeter: 'token-meter.md',
   tokenMeter: 'token-meter.md',
   toolResultPruner: 'compaction.md',
   toolResultPruner: 'compaction.md',
   tools: 'tools.md',
   tools: 'tools.md',

+ 4 - 4
scripts/gen-doc-graphs.ts

@@ -479,12 +479,12 @@ const SERVICE_ROLES: ServiceRole[] = [
     note: 'Providers implement transports; the service also owns optional Activation-based continuation orchestration, tool-subagent selects one-shot or continuable delegation, tool-subagent-control delivers follow-ups, and tool-ralph requires one fresh structured-output route.',
     note: 'Providers implement transports; the service also owns optional Activation-based continuation orchestration, tool-subagent selects one-shot or continuable delegation, tool-subagent-control delivers follow-ups, and tool-ralph requires one fresh structured-output route.',
   },
   },
   {
   {
-    key: 'teams',
-    pkg: 'team',
+    key: 'agentTeams',
+    pkg: 'agent-team',
     title: 'Agent Teams coordination domain',
     title: 'Agent Teams coordination domain',
     mode: 'core',
     mode: 'core',
-    consumers: ['tool-team'],
-    note: 'Owns the implicit-root roster, durable peer mailbox, shared task DAG, and continuable-child lifecycle; tool-team contributes the scoped model policy and controls.',
+    consumers: ['tool-agent-team'],
+    note: 'Owns the implicit-root roster, durable peer mailbox, shared task DAG, and continuable-child lifecycle; tool-agent-team contributes the scoped model policy and controls.',
   },
   },
   {
   {
     key: 'jobs',
     key: 'jobs',

+ 3 - 3
scripts/gen-tool-catalog.ts

@@ -527,7 +527,7 @@ const TOOL_PACKAGES: ToolPackage[] = [
     pkg: '@deepseek-ai/dsh-experimental-tool-agent-team',
     pkg: '@deepseek-ai/dsh-experimental-tool-agent-team',
     dir: 'tool-agent-team',
     dir: 'tool-agent-team',
     source: 'packages/experimental/tool-agent-team/src/index.ts',
     source: 'packages/experimental/tool-agent-team/src/index.ts',
-    requires: ['ctx.tools', 'ctx.systemPrompt', 'ctx.teams', 'an exact live Team member Agent'],
+    requires: ['ctx.tools', 'ctx.systemPrompt', 'ctx.agentTeams', 'an exact live Team member Agent'],
     writes: ['tool/call', 'team/member', 'team/message/queued', 'team/message/delivered', 'team/task', 'tool/result'],
     writes: ['tool/call', 'team/member', 'team/message/queued', 'team/message/delivered', 'team/task', 'tool/result'],
     async mount(ctx) {
     async mount(ctx) {
       await ctx.plugin(AgentRegistry)
       await ctx.plugin(AgentRegistry)
@@ -540,7 +540,7 @@ const TOOL_PACKAGES: ToolPackage[] = [
         role: 'lead' as const,
         role: 'lead' as const,
         name: 'lead',
         name: 'lead',
       }
       }
-      ctx.provide('teams', {
+      ctx.provide('agentTeams', {
         tryMembership: (candidate: Agent) => candidate === agent ? membership : undefined,
         tryMembership: (candidate: Agent) => candidate === agent ? membership : undefined,
         membership: () => membership,
         membership: () => membership,
       } as unknown as TeamService)
       } as unknown as TeamService)
@@ -553,7 +553,7 @@ const TOOL_PACKAGES: ToolPackage[] = [
         } as unknown as Agent
         } as unknown as Agent
         Object.assign(agent, { ctx: createScope(inner, agent).ctx })
         Object.assign(agent, { ctx: createScope(inner, agent).ctx })
         inner.agents.register(agent)
         inner.agents.register(agent)
-      }, { inject: ['tools', 'systemPrompt', 'agents', 'teams'] }))
+      }, { inject: ['tools', 'systemPrompt', 'agents', 'agentTeams'] }))
       await ctx.plugin(ToolTeam)
       await ctx.plugin(ToolTeam)
       catalogChildScopes.set(ctx, agent)
       catalogChildScopes.set(ctx, agent)
     },
     },