diff --git a/.agents/skills/dsh-pre-push-checks/SKILL.md b/.agents/skills/dsh-pre-push-checks/SKILL.md
index 7c0d629fff..4ce005ee79 100644
--- a/.agents/skills/dsh-pre-push-checks/SKILL.md
+++ b/.agents/skills/dsh-pre-push-checks/SKILL.md
@@ -54,7 +54,7 @@ pnpm run test:snapshot
Run built-bin smoke tests after `pnpm run build` when app packages, app boot, package runtime imports, bin entries, loader behavior, or published artifact paths change.
```sh
-pnpm exec vitest run --config vitest.e2e.config.ts packages/ui/stdio-agent/tests/built-bin.e2e.ts packages/ui/acp-agent/tests/built-bin.e2e.ts
+pnpm exec vitest run --config vitest.e2e.config.ts packages/examples/stdio-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts
```
Run real e2e when behavior depends on a real model/API, tool-use loop, ACP integration, prompt injection, or end-to-end agent UX. If `.env` is available, use it; do not print secrets.
diff --git a/docs/architecture.md b/docs/architecture.md
index b17c3302d8..4049049e25 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -138,7 +138,7 @@ Some seams bend the template deliberately. LLM keeps interface and consumer voca
### Bundles And Apps
-`dsh-agent-core` is the default composition bundle: one plugin loading the shared spine ([README](../packages/core/agent-core/README.md)). App packages compose it with a front door and boot `bin`: `dsh-stdio-agent` for terminal REPL, and `dsh-acp-agent` for ACP over JSON-RPC stdio with no stdout logger ([ui/](../packages/ui/README.md)). `dsh-jsonrpc-agent` instead boots an external `cordis.yml`; the Python SDK injects the package default only when no explicit config channel is set and drives `dsh-jsonrpc` over line-delimited stdio JSON-RPC ([Python SDK](../python/README.md)). A deployment is a thin `cordis.yml` leaf: swappable backends, one app entry, and optional product tools ([examples/](../examples/AGENTS.md), [runnable wirings](cookbook/extension-cookbook.md#runnable-wirings), [graph atlas](graph-atlas.md)).
+`dsh-agent-spine-demo` is the default composition bundle: one plugin loading the shared spine ([README](../packages/examples/agent-spine-demo/README.md)). App packages compose it with a front door and boot `bin`: `dsh-stdio-demo` for terminal REPL, and `dsh-acp-demo` for ACP over JSON-RPC stdio with no stdout logger ([ui/](../packages/ui/README.md)). `dsh-jsonrpc-agent` instead boots an external `cordis.yml`; the Python SDK injects the package default only when no explicit config channel is set and drives `dsh-jsonrpc` over line-delimited stdio JSON-RPC ([Python SDK](../python/README.md)). A deployment is a thin `cordis.yml` leaf: swappable backends, one app entry, and optional product tools ([examples/](../examples/AGENTS.md), [runnable wirings](cookbook/extension-cookbook.md#runnable-wirings), [graph atlas](graph-atlas.md)).
### Where New Behavior Goes
diff --git a/docs/capability-seams.md b/docs/capability-seams.md
index fb4746dc68..af22ba4c15 100644
--- a/docs/capability-seams.md
+++ b/docs/capability-seams.md
@@ -40,13 +40,13 @@ flowchart LR
pkg_tool_todo["tool-todo"]
pkg_user_interaction["user-interaction"]
svc_userInteraction["ctx.userInteraction
Human question/answer seam"]
- pkg_stdio_agent["stdio-agent"]
+ pkg_stdio_demo["stdio-demo"]
pkg_skill["skill"]
svc_skills["ctx.skills
Skill provider registry"]
pkg_skill_local["skill-local"]
svc_agents["ctx.agents
Agent registry"]
svc_agentLoop["ctx.agentLoop
Concrete loop driver"]
- pkg_agent_core["agent-core"]
+ pkg_agent_spine_demo["agent-spine-demo"]
pkg_bash["bash"]
svc_bash["ctx.bash
Bash executor seam"]
pkg_bash_local["bash-local"]
@@ -113,7 +113,7 @@ flowchart LR
pkg_session_query --> svc_sessionQuery
pkg_skill --> svc_skills
pkg_skill_local --> svc_skills
- pkg_stdio_agent --> svc_userInteraction
+ pkg_stdio_demo --> svc_userInteraction
pkg_subagent --> svc_subagents
pkg_subagent_acp --> svc_subagents
pkg_subagent_fork --> svc_subagents
@@ -129,11 +129,11 @@ flowchart LR
pkg_web_search_perplexity --> svc_web
pkg_workflow --> svc_workflows
pkg_workflow_workerthread --> svc_workflows
- svc_agentLoop --> pkg_agent_core
+ svc_agentLoop --> pkg_agent_spine_demo
svc_agents --> pkg_acp
svc_agents --> pkg_agent_loop
svc_agents --> pkg_invariants
- svc_agents --> pkg_stdio_agent
+ svc_agents --> pkg_stdio_demo
svc_agents --> pkg_subagent_inprocess
svc_approval --> pkg_tool_bash
svc_approval --> pkg_tools
@@ -173,7 +173,7 @@ flowchart LR
svc_tools --> pkg_tool_todo
svc_tools --> pkg_tool_web
svc_userInteraction --> pkg_acp
- svc_userInteraction --> pkg_stdio_agent
+ svc_userInteraction --> pkg_stdio_demo
svc_userInteraction --> pkg_tool_ask_user
svc_web --> pkg_tool_web
svc_workflows --> pkg_tool_workflow
@@ -188,10 +188,10 @@ flowchart LR
| `ctx.sessionQuery` | `seam` | [`session-query`](../packages/session-query/session-query) | - | - | - | Resolves live and optional persisted logs into one logical corpus for exact reads. |
| `ctx.systemPrompt` | `core` | [`system-prompt`](../packages/core/system-prompt) | - | [`agent-loop`](../packages/core/agent-loop), [`tools`](../packages/core/tools), [`tool-fs`](../packages/fs/tool-fs), [`tool-web`](../packages/web/tool-web) | - | Collects prompt sections and model-facing tool schemas for each step. |
| `ctx.tools` | `core` | [`tools`](../packages/core/tools) | - | [`agent-loop`](../packages/core/agent-loop), [`tool-ask-user`](../packages/ui/tool-ask-user), [`tool-bash`](../packages/bash/tool-bash), [`tool-cordis`](../packages/cordis/tool-cordis), [`tool-fs`](../packages/fs/tool-fs), [`tool-skill`](../packages/skill/tool-skill), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-todo`](../packages/todo/tool-todo), [`tool-web`](../packages/web/tool-web), [`acp`](../packages/ui/acp) | - | Registers capabilities, owns Code Mode transport, and routes calls through pre-policy, monotonic guards, around dispatch, post-policy, and final-result observation. |
-| `ctx.userInteraction` | `seam` | [`user-interaction`](../packages/ui/user-interaction) | [`stdio-agent`](../packages/ui/stdio-agent), [`acp`](../packages/ui/acp) | [`tool-ask-user`](../packages/ui/tool-ask-user), [`stdio-agent`](../packages/ui/stdio-agent), [`acp`](../packages/ui/acp) | - | UI front doors provide the active human-answer provider; tool-ask-user pauses a tool call on the provider-neutral ask() promise. |
+| `ctx.userInteraction` | `seam` | [`user-interaction`](../packages/ui/user-interaction) | [`stdio-demo`](../packages/examples/stdio-demo), [`acp`](../packages/ui/acp) | [`tool-ask-user`](../packages/ui/tool-ask-user), [`stdio-demo`](../packages/examples/stdio-demo), [`acp`](../packages/ui/acp) | - | UI front doors provide the active human-answer provider; tool-ask-user pauses a tool call on the provider-neutral ask() promise. |
| `ctx.skills` | `seam` | [`skill`](../packages/skill/skill) | [`skill-local`](../packages/skill/skill-local) | [`tool-skill`](../packages/skill/tool-skill) | - | Merges provider skill catalogs; tool-skill renders the session-prefix catalog and loads complete skill bodies. |
-| `ctx.agents` | `core` | [`agent`](../packages/core/agent) | - | [`agent-loop`](../packages/core/agent-loop), [`acp`](../packages/ui/acp), [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`stdio-agent`](../packages/ui/stdio-agent), [`invariants`](../packages/support/invariants) | - | Owns live Agent handles and the create/resume factory seam. |
-| `ctx.agentLoop` | `bundle` | [`agent-loop`](../packages/core/agent-loop) | - | [`agent-core`](../packages/core/agent-core) | - | The one concrete loop plugin; extension packages depend on dsh-agent events and services, not on this package. |
+| `ctx.agents` | `core` | [`agent`](../packages/core/agent) | - | [`agent-loop`](../packages/core/agent-loop), [`acp`](../packages/ui/acp), [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`stdio-demo`](../packages/examples/stdio-demo), [`invariants`](../packages/support/invariants) | - | Owns live Agent handles and the create/resume factory seam. |
+| `ctx.agentLoop` | `bundle` | [`agent-loop`](../packages/core/agent-loop) | - | [`agent-spine-demo`](../packages/examples/agent-spine-demo) | - | The one concrete loop plugin; extension packages depend on dsh-agent events and services, not on this package. |
| `ctx.bash` | `seam` | [`bash`](../packages/bash/bash) | [`bash-local`](../packages/bash/bash-local), [`bash-sandbox`](../packages/bash/bash-sandbox) | [`tool-bash`](../packages/bash/tool-bash), [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | - | The model-facing bash tools and hook bridges consume this seam; sandboxed or remote executors replace bash-local without touching them. |
| `ctx.sandbox` | `seam` | [`sandbox`](../packages/sandbox/sandbox) | [`sandbox-local`](../packages/sandbox/sandbox-local) | [`bash-sandbox`](../packages/bash/bash-sandbox) | - | Consumers hand over the exact argv they are about to spawn; same-world backends wrap it under a per-call policy and report enforcement. |
| `ctx.approval` | `seam` | `approval` | [`acp`](../packages/ui/acp) | [`tools`](../packages/core/tools), [`tool-bash`](../packages/bash/tool-bash) | - | One-shot permission decisions dispatched over the `approval/request` waterfall; answerers are listeners (the ACP bridge for its own agents), absence fails closed to `unavailable`. |
diff --git a/docs/config-catalog.md b/docs/config-catalog.md
index 57e3576d05..af8ef0832c 100644
--- a/docs/config-catalog.md
+++ b/docs/config-catalog.md
@@ -27,7 +27,7 @@ Depends on: `Stream` (`@agentclientprotocol/sdk`)
Source: [`packages/ui/acp/src/index.ts:203`](../packages/ui/acp/src/index.ts)
-## `@deepseek-ai/dsh-acp-agent`
+## `@deepseek-ai/dsh-acp-demo`
```ts config-catalog
/**
@@ -37,7 +37,7 @@ Source: [`packages/ui/acp/src/index.ts:203`](../packages/ui/acp/src/index.ts)
* deployment persona (forwarded to the system-prompt plugin); `toolOrder` is
* the explicit model-facing tool order (forwarded to the system-prompt plugin);
* `tools` is the tool registry's config (its presentation `mode`, forwarded
- * through agent-core); `persistenceRoot` is the JSONL backend's directory.
+ * through agent-spine-demo); `persistenceRoot` is the JSONL backend's directory.
*/
export interface Config {
/** Model name for ACP-created agents (must have a registered adapter). */
@@ -46,20 +46,43 @@ export interface Config {
persona?: string
/** Explicit model-facing tool order (the system-prompt plugin's `toolOrder` config; see dsh-system-prompt). */
toolOrder?: string[]
- /** Tool-registry config — its presentation `mode` (forwarded through agent-core; see dsh-tools). */
+ /** Tool-registry config — its presentation `mode` (forwarded through agent-spine-demo; see dsh-tools). */
tools?: ToolsConfig
/** Directory the JSONL session backend writes under. Defaults to `./.sessions`. */
persistenceRoot?: string
- /** Skill registry, local-provider, and model-facing consumer config forwarded to agent-core. */
+ /** Skill registry, local-provider, and model-facing consumer config forwarded to agent-spine-demo. */
skills?: agentCore.SkillConfig
}
```
-Depends on: [`agentCore`](../packages/core/agent-core/src/index.ts) · [`ToolsConfig`](#deepseek-aidsh-tools)
+Depends on: [`agentCore`](../packages/examples/agent-spine-demo/src/index.ts) · [`ToolsConfig`](#deepseek-aidsh-tools)
-Source: [`packages/ui/acp-agent/src/index.ts:31`](../packages/ui/acp-agent/src/index.ts)
+Source: [`packages/examples/acp-demo/src/index.ts:31`](../packages/examples/acp-demo/src/index.ts)
-## `@deepseek-ai/dsh-agent-core`
+## `@deepseek-ai/dsh-agent-loop`
+
+Requires: `agents` · `sessions` · `llm` · `tools` · `systemPrompt`
+
+```ts config-catalog
+/** Plugin configuration for declarative startup agents. */
+export interface Config {
+ /** Agents created or resumed at plugin startup. */
+ agents: (AgentOptions & {
+ /** Registry identity for the live agent. */
+ id: AgentId
+ /** Optional workspace for a fresh session. */
+ cwd?: string
+ /** Persisted session to resume instead of creating a fresh session. */
+ resumeSessionId?: SessionId
+ })[]
+}
+```
+
+Depends on: [`AgentId`](../packages/core/agent/src/index.ts) · [`AgentOptions`](../packages/core/agent/src/index.ts) · [`SessionId`](../packages/core/session/src/index.ts)
+
+Source: [`packages/core/agent-loop/src/index.ts:322`](../packages/core/agent-loop/src/index.ts)
+
+## `@deepseek-ai/dsh-agent-spine-demo`
```ts config-catalog
/**
@@ -97,30 +120,7 @@ export interface SkillConfig {
Depends on: [`AgentLoopConfig`](#deepseek-aidsh-agent-loop) · [`SkillLocal`](../packages/skill/skill-local/src/index.ts) · [`SkillRegistryConfig`](#deepseek-aidsh-skill) · [`SystemPromptConfig`](#deepseek-aidsh-system-prompt) · [`ToolsConfig`](#deepseek-aidsh-tools) · [`toolSkill`](../packages/skill/tool-skill/src/index.ts)
-Source: [`packages/core/agent-core/src/index.ts:46`](../packages/core/agent-core/src/index.ts)
-
-## `@deepseek-ai/dsh-agent-loop`
-
-Requires: `agents` · `sessions` · `llm` · `tools` · `systemPrompt`
-
-```ts config-catalog
-/** Plugin configuration for declarative startup agents. */
-export interface Config {
- /** Agents created or resumed at plugin startup. */
- agents: (AgentOptions & {
- /** Registry identity for the live agent. */
- id: AgentId
- /** Optional workspace for a fresh session. */
- cwd?: string
- /** Persisted session to resume instead of creating a fresh session. */
- resumeSessionId?: SessionId
- })[]
-}
-```
-
-Depends on: [`AgentId`](../packages/core/agent/src/index.ts) · [`AgentOptions`](../packages/core/agent/src/index.ts) · [`SessionId`](../packages/core/session/src/index.ts)
-
-Source: [`packages/core/agent-loop/src/index.ts:322`](../packages/core/agent-loop/src/index.ts)
+Source: [`packages/examples/agent-spine-demo/src/index.ts:46`](../packages/examples/agent-spine-demo/src/index.ts)
## `@deepseek-ai/dsh-bash-local`
@@ -675,13 +675,13 @@ export interface Config {
Source: [`packages/ui/stdio/src/index.ts:30`](../packages/ui/stdio/src/index.ts)
-## `@deepseek-ai/dsh-stdio-agent`
+## `@deepseek-ai/dsh-stdio-demo`
```ts config-catalog
/**
* App config: the swappable per-demo values, each routed to where the app wires
* it. `model`/`resumeSessionId` configure the pre-created `main` agent (through
- * {@link @deepseek-ai/dsh-agent-core}'s forwarded `agents` list); `persona` is
+ * {@link @deepseek-ai/dsh-agent-spine-demo}'s forwarded `agents` list); `persona` is
* the deployment persona (forwarded to the system-prompt plugin); `toolOrder`
* is the explicit model-facing tool order (forwarded to the system-prompt plugin);
* fresh sessions use `process.cwd()` as their workspace cwd; resumed sessions
@@ -695,13 +695,13 @@ export interface Config {
persona?: string
/** Explicit model-facing tool order (the system-prompt plugin's `toolOrder` config; see dsh-system-prompt). */
toolOrder?: string[]
- /** Tool-registry config — its presentation `mode` (forwarded through agent-core; see dsh-tools). */
+ /** Tool-registry config — its presentation `mode` (forwarded through agent-spine-demo; see dsh-tools). */
tools?: ToolsConfig
/** Directory the JSONL session backend writes under. Defaults to `./.sessions`. */
persistenceRoot?: string
/** stdin-chat banner printed once on start. Defaults to `'ready.'`. */
welcome?: string
- /** Skill registry, local-provider, and model-facing consumer config forwarded to agent-core. */
+ /** Skill registry, local-provider, and model-facing consumer config forwarded to agent-spine-demo. */
skills?: agentCore.SkillConfig
/**
* If set, the `main` agent RESUMES this persisted session id instead of
@@ -712,9 +712,9 @@ export interface Config {
}
```
-Depends on: [`agentCore`](../packages/core/agent-core/src/index.ts) · [`ToolsConfig`](#deepseek-aidsh-tools)
+Depends on: [`agentCore`](../packages/examples/agent-spine-demo/src/index.ts) · [`ToolsConfig`](#deepseek-aidsh-tools)
-Source: [`packages/ui/stdio-agent/src/index.ts:36`](../packages/ui/stdio-agent/src/index.ts)
+Source: [`packages/examples/stdio-demo/src/index.ts:36`](../packages/examples/stdio-demo/src/index.ts)
## `@deepseek-ai/dsh-subagent-acp`
@@ -1242,7 +1242,7 @@ Imported as libraries by other packages; a `cordis.yml` cannot load them.
- `@deepseek-ai/dsh-app-boot` ([`packages/ui/app-boot/src/index.ts`](../packages/ui/app-boot/src/index.ts))
- `@deepseek-ai/dsh-brand` ([`packages/util/brand/src/index.ts`](../packages/util/brand/src/index.ts))
- `@deepseek-ai/dsh-hook-protocol` ([`packages/hooks/hook-protocol/src/index.ts`](../packages/hooks/hook-protocol/src/index.ts))
-- `@deepseek-ai/dsh-jsonrpc-agent` ([`packages/ui/jsonrpc-agent/src/index.ts`](../packages/ui/jsonrpc-agent/src/index.ts))
+- `@deepseek-ai/dsh-jsonrpc-demo` ([`packages/examples/jsonrpc-demo/src/index.ts`](../packages/examples/jsonrpc-demo/src/index.ts))
- `@deepseek-ai/dsh-loader-smoke` ([`packages/support/loader-smoke/src/index.ts`](../packages/support/loader-smoke/src/index.ts))
- `@deepseek-ai/dsh-scope` ([`packages/core/scope/src/index.ts`](../packages/core/scope/src/index.ts))
- `@deepseek-ai/dsh-subagent-inprocess` ([`packages/subagent/subagent-inprocess/src/index.ts`](../packages/subagent/subagent-inprocess/src/index.ts))
diff --git a/docs/cookbook/extension-cookbook.md b/docs/cookbook/extension-cookbook.md
index 40ee22b352..3474bc116b 100644
--- a/docs/cookbook/extension-cookbook.md
+++ b/docs/cookbook/extension-cookbook.md
@@ -87,7 +87,7 @@ export function apply(ctx: Context) {
## Runnable wirings
-Three complete examples load their plugin trees from `cordis.yml`: [`examples/echo-agent`](../../examples/echo-agent) (mock model + echo tool — the all-mock skeleton check, `pnpm run demo:echo`), [`examples/coding-agent`](../../examples/coding-agent) (DeepSeek V4 + the bash tool suite behind a terminal REPL UI, `pnpm run demo:repl`), and [`examples/acp-agent`](../../examples/acp-agent) (an agent exposed as an ACP server over JSON-RPC stdio — the client-driver shape, `pnpm run demo:acp`). Each leaf is just its swappable backends plus an app-package entry: the stdio demos load [`@deepseek-ai/dsh-stdio-agent`](../../packages/ui/stdio-agent), the ACP demo loads [`@deepseek-ai/dsh-acp-agent`](../../packages/ui/acp-agent), and both app packages share the spine via the [`@deepseek-ai/dsh-agent-core`](../../packages/core/agent-core) bundle.
+Three complete examples load their plugin trees from `cordis.yml`: [`examples/echo-agent`](../../examples/echo-agent) (mock model + echo tool — the all-mock skeleton check, `pnpm run demo:echo`), [`examples/coding-agent`](../../examples/coding-agent) (DeepSeek V4 + the bash tool suite behind a terminal REPL UI, `pnpm run demo:repl`), and [`examples/acp-agent`](../../examples/acp-agent) (an agent exposed as an ACP server over JSON-RPC stdio — the client-driver shape, `pnpm run demo:acp`). Each leaf is just its swappable backends plus an app-package entry: the stdio demos load [`@deepseek-ai/dsh-stdio-demo`](../../packages/examples/stdio-demo), the ACP demo loads [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo), and both app packages share the spine via the [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) bundle.
## The feature → mechanism map
diff --git a/docs/cookbook/extension-cookbook.zh.md b/docs/cookbook/extension-cookbook.zh.md
index 4e5bc68c97..1a605b20fe 100644
--- a/docs/cookbook/extension-cookbook.zh.md
+++ b/docs/cookbook/extension-cookbook.zh.md
@@ -87,7 +87,7 @@ export function apply(ctx: Context) {
## 可运行的组装示例
-三个完整示例从 `cordis.yml` 加载各自的插件树:[`examples/echo-agent`](../../examples/echo-agent)(mock 模型 + echo 工具——全 mock 骨架检查,`pnpm run demo:echo`)、[`examples/coding-agent`](../../examples/coding-agent)(DeepSeek V4 + bash 工具套件,配合终端 REPL UI,`pnpm run demo:repl`)、[`examples/acp-agent`](../../examples/acp-agent)(通过 JSON-RPC stdio 暴露为 ACP 服务器的 agent——客户端驱动形态,`pnpm run demo:acp`)。每个叶子只是其可替换后端加一个 app 包入口:stdio 演示加载 [`@deepseek-ai/dsh-stdio-agent`](../../packages/ui/stdio-agent),ACP 演示加载 [`@deepseek-ai/dsh-acp-agent`](../../packages/ui/acp-agent),两个 app 包通过 [`@deepseek-ai/dsh-agent-core`](../../packages/core/agent-core) bundle 共享主干。
+三个完整示例从 `cordis.yml` 加载各自的插件树:[`examples/echo-agent`](../../examples/echo-agent)(mock 模型 + echo 工具——全 mock 骨架检查,`pnpm run demo:echo`)、[`examples/coding-agent`](../../examples/coding-agent)(DeepSeek V4 + bash 工具套件,配合终端 REPL UI,`pnpm run demo:repl`)、[`examples/acp-agent`](../../examples/acp-agent)(通过 JSON-RPC stdio 暴露为 ACP 服务器的 agent——客户端驱动形态,`pnpm run demo:acp`)。每个叶子只是其可替换后端加一个 app 包入口:stdio 演示加载 [`@deepseek-ai/dsh-stdio-demo`](../../packages/examples/stdio-demo),ACP 演示加载 [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo),两个 app 包通过 [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) bundle 共享主干。
## 功能→机制映射
diff --git a/docs/core-data-structures/user-interaction.md b/docs/core-data-structures/user-interaction.md
index 6155fd9896..4edc415039 100644
--- a/docs/core-data-structures/user-interaction.md
+++ b/docs/core-data-structures/user-interaction.md
@@ -1,6 +1,6 @@
# User Interaction
-The user-interaction seam of [dsh-user-interaction](../../packages/ui/user-interaction). It is the provider-neutral vocabulary a tool or permission plugin uses when it needs the human to answer before the agent can continue. UI surfaces provide the active `UserInteractionProvider`: `dsh-stdio-agent` renders questions in readline, and `dsh-acp` maps them to ACP form elicitations.
+The user-interaction seam of [dsh-user-interaction](../../packages/ui/user-interaction). It is the provider-neutral vocabulary a tool or permission plugin uses when it needs the human to answer before the agent can continue. UI surfaces provide the active `UserInteractionProvider`: `dsh-stdio-demo` renders questions in readline, and `dsh-acp` maps them to ACP form elicitations.
Source: [`packages/ui/user-interaction/src/index.ts`](../../packages/ui/user-interaction/src/index.ts)
diff --git a/docs/i18n/style-samples.md b/docs/i18n/style-samples.md
index e97cc331a9..6d9e82d184 100644
--- a/docs/i18n/style-samples.md
+++ b/docs/i18n/style-samples.md
@@ -10,9 +10,9 @@
本文介绍 DeepSeek Harness 整体架构,它是 **DeepSeek Code** 的底层基座。微内核设计讨论中确立了核心设计准则:**一切皆插件**。内核刻意做得极精简,仅包含少量抽象服务,外加一个实体循环插件 `dsh-agent-loop`。所有产品功能均基于本文定义的扩展接口开发为独立插件,无需改动主循环逻辑。
-> Dependency rule: extension plugins depend on interfaces, never on `dsh-agent-loop` (the loop is swappable); the sanctioned exception is the composition bundle `dsh-agent-core`, whose job is assembling the concrete spine.
+> Dependency rule: extension plugins depend on interfaces, never on `dsh-agent-loop` (the loop is swappable); the sanctioned exception is the composition bundle `dsh-agent-spine-demo`, whose job is assembling the concrete spine.
-依赖约束规范:各类扩展插件仅依赖抽象接口,严禁直接依赖 `dsh-agent-loop`(该主循环支持替换实现);唯一允许的特例是组合包 `dsh-agent-core`,它的职责是组装整套实体主干。
+依赖约束规范:各类扩展插件仅依赖抽象接口,严禁直接依赖 `dsh-agent-loop`(该主循环支持替换实现);唯一允许的特例是组合包 `dsh-agent-spine-demo`,它的职责是组装整套实体主干。
> This document covers **behavior**; type shapes live in [core-data-structures/](../core-data-structures/core.md), the per-event/service reference in the [generated catalog](../cordis-catalog/events.md), per-package contracts in the package READMEs ([map](../../packages/README.md)).
diff --git a/docs/module-graph.md b/docs/module-graph.md
index 1b804e5214..5d5ef1addf 100644
--- a/docs/module-graph.md
+++ b/docs/module-graph.md
@@ -18,7 +18,6 @@ flowchart TD
end
subgraph group_core["packages/core"]
pkg_agent["agent"]
- pkg_agent_core["agent-core"]
pkg_agent_loop["agent-loop"]
pkg_scope["scope"]
pkg_session["session"]
@@ -94,13 +93,10 @@ flowchart TD
end
subgraph group_ui["packages/ui"]
pkg_acp["acp"]
- pkg_acp_agent["acp-agent"]
pkg_app_boot["app-boot"]
pkg_jsonrpc["jsonrpc"]
- pkg_jsonrpc_agent["jsonrpc-agent"]
pkg_permission["permission"]
pkg_stdio["stdio"]
- pkg_stdio_agent["stdio-agent"]
pkg_tool_ask_user["tool-ask-user"]
pkg_user_approval["user-approval"]
pkg_user_interaction["user-interaction"]
@@ -112,6 +108,12 @@ flowchart TD
subgraph group_context["packages/context"]
pkg_time_context["time-context"]
end
+ subgraph group_examples["packages/examples"]
+ pkg_acp_demo["acp-demo"]
+ pkg_agent_spine_demo["agent-spine-demo"]
+ pkg_jsonrpc_demo["jsonrpc-demo"]
+ pkg_stdio_demo["stdio-demo"]
+ end
subgraph group_guard["packages/guard"]
pkg_repeat_tool_guard["repeat-tool-guard"]
end
@@ -280,17 +282,6 @@ flowchart TD
pkg_tool_workflow --> pkg_system_prompt
pkg_tool_workflow --> pkg_tools
pkg_tool_workflow --> pkg_workflow
- pkg_agent_core --> pkg_agent
- pkg_agent_core --> pkg_agent_loop
- pkg_agent_core --> pkg_invariants
- pkg_agent_core --> pkg_llm
- pkg_agent_core --> pkg_session
- pkg_agent_core --> pkg_skill
- pkg_agent_core --> pkg_skill_local
- pkg_agent_core --> pkg_system_prompt
- pkg_agent_core --> pkg_tool_bash
- pkg_agent_core --> pkg_tool_skill
- pkg_agent_core --> pkg_tools
pkg_subagent_acp --> pkg_agent
pkg_subagent_acp --> pkg_llm
pkg_subagent_acp --> pkg_subagent
@@ -319,6 +310,17 @@ flowchart TD
pkg_jsonrpc --> pkg_llm_deepseek
pkg_jsonrpc --> pkg_session
pkg_jsonrpc --> pkg_subagent
+ pkg_agent_spine_demo --> pkg_agent
+ pkg_agent_spine_demo --> pkg_agent_loop
+ pkg_agent_spine_demo --> pkg_invariants
+ pkg_agent_spine_demo --> pkg_llm
+ pkg_agent_spine_demo --> pkg_session
+ pkg_agent_spine_demo --> pkg_skill
+ pkg_agent_spine_demo --> pkg_skill_local
+ pkg_agent_spine_demo --> pkg_system_prompt
+ pkg_agent_spine_demo --> pkg_tool_bash
+ pkg_agent_spine_demo --> pkg_tool_skill
+ pkg_agent_spine_demo --> pkg_tools
pkg_workflow_workerthread --> pkg_agent
pkg_workflow_workerthread --> pkg_brand
pkg_workflow_workerthread --> pkg_llm
@@ -332,22 +334,22 @@ flowchart TD
pkg_subagent_fork --> pkg_subagent_inprocess
pkg_subagent_spawn --> pkg_subagent
pkg_subagent_spawn --> pkg_subagent_inprocess
- pkg_acp_agent --> pkg_acp
- pkg_acp_agent --> pkg_agent_core
- pkg_acp_agent --> pkg_app_boot
- pkg_acp_agent --> pkg_session_persistence_jsonl
- pkg_acp_agent --> pkg_tools
- pkg_acp_agent --> pkg_user_interaction
- pkg_stdio_agent --> pkg_agent
- pkg_stdio_agent --> pkg_agent_core
- pkg_stdio_agent --> pkg_app_boot
- pkg_stdio_agent --> pkg_llm
- pkg_stdio_agent --> pkg_session
- pkg_stdio_agent --> pkg_session_persistence_jsonl
- pkg_stdio_agent --> pkg_stdio
- pkg_stdio_agent --> pkg_tool_ask_user
- pkg_stdio_agent --> pkg_tools
- pkg_stdio_agent --> pkg_user_interaction
+ pkg_acp_demo --> pkg_acp
+ pkg_acp_demo --> pkg_agent_spine_demo
+ pkg_acp_demo --> pkg_app_boot
+ pkg_acp_demo --> pkg_session_persistence_jsonl
+ pkg_acp_demo --> pkg_tools
+ pkg_acp_demo --> pkg_user_interaction
+ pkg_stdio_demo --> pkg_agent
+ pkg_stdio_demo --> pkg_agent_spine_demo
+ pkg_stdio_demo --> pkg_app_boot
+ pkg_stdio_demo --> pkg_llm
+ pkg_stdio_demo --> pkg_session
+ pkg_stdio_demo --> pkg_session_persistence_jsonl
+ pkg_stdio_demo --> pkg_stdio
+ pkg_stdio_demo --> pkg_tool_ask_user
+ pkg_stdio_demo --> pkg_tools
+ pkg_stdio_demo --> pkg_user_interaction
```
| Package | Group | Depends on |
@@ -360,8 +362,8 @@ flowchart TD
| [`acp-snapshot`](../packages/support/acp-snapshot) | `support` | — |
| [`loader-smoke`](../packages/support/loader-smoke) | `support` | — |
| [`app-boot`](../packages/ui/app-boot) | `ui` | — |
-| [`jsonrpc-agent`](../packages/ui/jsonrpc-agent) | `ui` | — |
| [`code-runtime`](../packages/code-runtime/code-runtime) | `code-runtime` | — |
+| [`jsonrpc-demo`](../packages/examples/jsonrpc-demo) | `examples` | — |
| [`llm`](../packages/llm/llm) | `llm` | [`brand`](../packages/util/brand) |
| [`code-runtime-worker`](../packages/code-runtime/code-runtime-worker) | `code-runtime` | [`code-runtime`](../packages/code-runtime/code-runtime) |
| [`llm-deepseek`](../packages/llm/llm-deepseek) | `llm` | [`llm`](../packages/llm/llm) |
@@ -414,15 +416,15 @@ flowchart TD
| [`repeat-tool-guard`](../packages/guard/repeat-tool-guard) | `guard` | [`agent`](../packages/core/agent), [`tools`](../packages/core/tools) |
| [`mcp-client`](../packages/mcp/mcp-client) | `mcp` | [`llm`](../packages/llm/llm), [`tools`](../packages/core/tools) |
| [`tool-workflow`](../packages/workflow/tool-workflow) | `workflow` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
-| [`agent-core`](../packages/core/agent-core) | `core` | [`agent`](../packages/core/agent), [`agent-loop`](../packages/core/agent-loop), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`skill`](../packages/skill/skill), [`skill-local`](../packages/skill/skill-local), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/bash/tool-bash), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) |
| [`subagent-acp`](../packages/subagent/subagent-acp) | `subagent` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`subagent-subprocess`](../packages/subagent/subagent-subprocess) |
| [`subagent-inprocess`](../packages/subagent/subagent-inprocess) | `subagent` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`tool-subagent`](../packages/subagent/tool-subagent) | `subagent` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`hooks-claude`](../packages/hooks/hooks-claude) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`subagent-mock`](../packages/support/subagent-mock) | `support` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent) |
| [`jsonrpc`](../packages/ui/jsonrpc) | `ui` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
+| [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-loop`](../packages/core/agent-loop), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`skill`](../packages/skill/skill), [`skill-local`](../packages/skill/skill-local), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/bash/tool-bash), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) |
| [`workflow-workerthread`](../packages/workflow/workflow-workerthread) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`subagent-fork`](../packages/subagent/subagent-fork) | `subagent` | [`agent`](../packages/core/agent), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-inprocess`](../packages/subagent/subagent-inprocess) |
| [`subagent-spawn`](../packages/subagent/subagent-spawn) | `subagent` | [`subagent`](../packages/subagent/subagent), [`subagent-inprocess`](../packages/subagent/subagent-inprocess) |
-| [`acp-agent`](../packages/ui/acp-agent) | `ui` | [`acp`](../packages/ui/acp), [`agent-core`](../packages/core/agent-core), [`app-boot`](../packages/ui/app-boot), [`session-persistence-jsonl`](../packages/session-persistence/session-persistence-jsonl), [`tools`](../packages/core/tools), [`user-interaction`](../packages/ui/user-interaction) |
-| [`stdio-agent`](../packages/ui/stdio-agent) | `ui` | [`agent`](../packages/core/agent), [`agent-core`](../packages/core/agent-core), [`app-boot`](../packages/ui/app-boot), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence-jsonl`](../packages/session-persistence/session-persistence-jsonl), [`stdio`](../packages/ui/stdio), [`tool-ask-user`](../packages/ui/tool-ask-user), [`tools`](../packages/core/tools), [`user-interaction`](../packages/ui/user-interaction) |
+| [`acp-demo`](../packages/examples/acp-demo) | `examples` | [`acp`](../packages/ui/acp), [`agent-spine-demo`](../packages/examples/agent-spine-demo), [`app-boot`](../packages/ui/app-boot), [`session-persistence-jsonl`](../packages/session-persistence/session-persistence-jsonl), [`tools`](../packages/core/tools), [`user-interaction`](../packages/ui/user-interaction) |
+| [`stdio-demo`](../packages/examples/stdio-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-spine-demo`](../packages/examples/agent-spine-demo), [`app-boot`](../packages/ui/app-boot), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence-jsonl`](../packages/session-persistence/session-persistence-jsonl), [`stdio`](../packages/ui/stdio), [`tool-ask-user`](../packages/ui/tool-ask-user), [`tools`](../packages/core/tools), [`user-interaction`](../packages/ui/user-interaction) |
diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md
index f3d4178e3b..0582515c62 100644
--- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md
+++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md
@@ -12,18 +12,18 @@ The leaf configs also owned a coupled front door. ACP requires stdout purity and
Each example is now **mostly an invocation of an app package**, splitting the wiring along the existing [interface / implementation / consumer seam](2026-06-13-capability-seams.md): the **app package owns the composition**, the leaf `cordis.yml` owns only the **swappable choices** (which LLM adapter, which bash executor, model, prompt, persistence root).
-- **`@deepseek-ai/dsh-agent-core`** ([packages/core/agent-core](../../../../packages/core/agent-core)) composes the providerless, executor-less, UI-less spine and forwards the loop's agent-list config. Its dependency on the concrete loop is intentional because this package composes the spine rather than extending it; swapping the loop means supplying another bundle.
-- **`@deepseek-ai/dsh-stdio-agent`** ([packages/ui/stdio-agent](../../../../packages/ui/stdio-agent)) and **`@deepseek-ai/dsh-acp-agent`** ([packages/ui/acp-agent](../../../../packages/ui/acp-agent)) bake in their front doors. Stdio includes `ui-stdio`, a console logger, and `main`; ACP includes the bridge and JSONL persistence but no stdout logger or pre-created agent. Leaves may add plugins, but the safe composition is now the default artifact.
-- **`start.ts` is gone.** Each app package exposes a `bin` (`dsh-stdio-agent` / `dsh-acp-agent`); the `demo:*` scripts invoke it (e.g. `dsh-stdio-agent ./cordis.yml`). The Loader-boot tail, `.env` loading, and fail-loud guards live in the shared [`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot) package (unit-tested under the per-file coverage gate — see [share the app bins' boot glue](../simplification/2026-07-04-share-app-bin-boot-glue.md)); each bin is a thin self-executing composition over those helpers plus its app-specific lifecycle (the ACP bin: snapshot-mode selection and stdin-dispose). The `bin.ts` files themselves stay coverage-excluded (self-executing CLI entries, like the old `start.ts`) and are driven by the keyless Loader-path tests.
+- **`@deepseek-ai/dsh-agent-spine-demo`** ([packages/examples/agent-spine-demo](../../../../packages/examples/agent-spine-demo)) composes the providerless, executor-less, UI-less spine and forwards the loop's agent-list config. Its dependency on the concrete loop is intentional because this package composes the spine rather than extending it; swapping the loop means supplying another bundle.
+- **`@deepseek-ai/dsh-stdio-demo`** ([packages/examples/stdio-demo](../../../../packages/examples/stdio-demo)) and **`@deepseek-ai/dsh-acp-demo`** ([packages/examples/acp-demo](../../../../packages/examples/acp-demo)) bake in their front doors. Stdio includes `ui-stdio`, a console logger, and `main`; ACP includes the bridge and JSONL persistence but no stdout logger or pre-created agent. Leaves may add plugins, but the safe composition is now the default artifact.
+- **`start.ts` is gone.** Each app package exposes a `bin` (`dsh-stdio-demo` / `dsh-acp-demo`); the `demo:*` scripts invoke it (e.g. `dsh-stdio-demo ./cordis.yml`). The Loader-boot tail, `.env` loading, and fail-loud guards live in the shared [`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot) package (unit-tested under the per-file coverage gate — see [share the app bins' boot glue](../simplification/2026-07-04-share-app-bin-boot-glue.md)); each bin is a thin self-executing composition over those helpers plus its app-specific lifecycle (the ACP bin: snapshot-mode selection and stdin-dispose). The `bin.ts` files themselves stay coverage-excluded (self-executing CLI entries, like the old `start.ts`) and are driven by the keyless Loader-path tests.
- **Each leaf `cordis.yml` collapses** to backends + config: the LLM adapter (`llm-deepseek` with apiKey/models, or `llm-replay`), the bash executor (`bash-local`), `hmr` for the stdio demos (see the amendment below), and one app entry carrying the app's config (model, system prompt, persistence root — surfaced as the app package's own `Config`, which routes each value to wherever the app wires it: stdio onto its pre-created agent, acp onto the bridge plugin).
-- **echo-agent folds onto `dsh-stdio-agent`**, swapping the LLM backend to the local `mock-llm` and adding the local `echo-tool` (plus `bash-local`, which the spine's `tool-bash` injects) at the leaf — the clean demonstration of "swap the backend, keep the app". `mock-llm.ts` / `echo-tool.ts` stay as example-local teaching plugins.
-- **`base.yml`, `base-core.yml`, and `acp-agent/acp-tail.yml` are retired** — the spine they shared now lives in `dsh-agent-core`.
+- **echo-agent folds onto `dsh-stdio-demo`**, swapping the LLM backend to the local `mock-llm` and adding the local `echo-tool` (plus `bash-local`, which the spine's `tool-bash` injects) at the leaf — the clean demonstration of "swap the backend, keep the app". `mock-llm.ts` / `echo-tool.ts` stay as example-local teaching plugins.
+- **`base.yml`, `base-core.yml`, and `acp-agent/acp-tail.yml` are retired** — the spine they shared now lives in `dsh-agent-spine-demo`.
`bash-local` and the LLM adapter stay **leaf choices**: the bundle ships `tool-bash` (the consumer schema), the leaf picks the executor implementation, so a sandboxed executor or replay adapter swaps in without touching the app.
### Amendment on implementation: `hmr` stays a leaf entry
-The proposal listed `hmr` among the stdio app's baked-in front-door cluster. Validating against the code, baking `hmr` into the `dsh-stdio-agent` package fights cordis in two ways, so it ships as a **leaf `cordis.yml` entry** instead:
+The proposal listed `hmr` among the stdio app's baked-in front-door cluster. Validating against the code, baking `hmr` into the `dsh-stdio-demo` package fights cordis in two ways, so it ships as a **leaf `cordis.yml` entry** instead:
1. `@cordisjs/plugin-hmr` is a Loader-only, subprocess-only dev plugin — its constructor throws without `node --expose-internals` + a live `loader` service, so it can only run in the real `demo:*`/bin subprocess, never in the in-process unit/coverage tier.
2. The in-process test tier (vitest) cannot even *import* the vendored `hmr` module (its class-decorator `@Inject` form fails under Vite's transform), so a package whose `apply` statically imported it could never satisfy the per-file 100% coverage gate on its headline function.
@@ -45,11 +45,11 @@ The old `base*.yml`/`acp-tail.yml` includes already deduped the *config*, but a
## Consequences
-- **The bare-plugin-tree pedagogy.** echo-agent's inlined `cordis.yml` showed every plugin at once; the spine now lives behind a bundle, so seeing the whole tree means opening `dsh-agent-core`. The app package's README carries that teaching weight.
+- **The bare-plugin-tree pedagogy.** echo-agent's inlined `cordis.yml` showed every plugin at once; the spine now lives behind a bundle, so seeing the whole tree means opening `dsh-agent-spine-demo`. The app package's README carries that teaching weight.
- **A layer of indirection.** "What does this demo load?" becomes a package read, not a single YAML scan.
## Related
-- Supersedes [Make the shared example base providerless](../../rejected/architecture/2026-06-20-providerless-example-base.md): renaming `base.yml` to the providerless core is moot once the spine moves into `dsh-agent-core` and the `base*.yml` files are deleted.
+- Supersedes [Make the shared example base providerless](../../rejected/architecture/2026-06-20-providerless-example-base.md): renaming `base.yml` to the providerless core is moot once the spine moves into `dsh-agent-spine-demo` and the `base*.yml` files are deleted.
- Builds on the [capability-seams](2026-06-13-capability-seams.md) interface/implementation/consumer split — backends and presentation stay leaf choices; the spine is the shared bundle.
- Complements [Reorganize packages into a modular hierarchy](2026-06-20-package-hierarchy.md): the new app/core packages slot into existing groups under that hierarchy (`core` for the reusable spine bundle, `ui` for the app-specific front doors).
diff --git a/docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md b/docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md
index 372058dc04..b177af24e9 100644
--- a/docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md
+++ b/docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md
@@ -23,12 +23,12 @@ The exe is packaged with the **`--sea` (enhanced SEA) mode** of [@yao-pkg/pkg](h
Terminology reminder: pkg's `/snapshot` VFS has nothing to do with this repo's testing-system "snapshot" (ACP replay goldens, `$DSH_SNAPSHOT`); this document says "VFS" for the former.
-### The serving surface is a plugin: the two packages ui/jsonrpc + ui/jsonrpc-agent
+### The serving surface is a plugin: the two packages ui/jsonrpc + examples/jsonrpc-demo
-The deterministic protocol implementation (`server.ts` / `transport.ts`) lands as two packages on the existing `ui/acp` + `ui/acp-agent` pattern — the serving surface is itself a plugin:
+The deterministic protocol implementation (`server.ts` / `transport.ts`) lands as two packages on the existing `ui/acp` + `examples/acp-demo` pattern — the serving surface is itself a plugin:
- [`packages/ui/jsonrpc`](../../../../packages/ui/jsonrpc/README.md) (`@deepseek-ai/dsh-jsonrpc`): the pure protocol plugin; on apply it mounts `HarnessSdkServer` plus a line-delimited JSON-RPC transport on the process stdio, with disposal through `ctx.effect()`. Whether to serve is decided by `cordis.yml`; a yml that does not mount it is a legitimate process that does not serve. Protocol-level exit belongs to the plugin (after answering the `shutdown` request it disposes its own fiber, then `exit(0)`; an HMR-style unload only stops the service without exiting the process).
-- [`packages/ui/jsonrpc-agent`](../../../../packages/ui/jsonrpc-agent/README.md) (`@deepseek-ai/dsh-jsonrpc-agent`): a thin app bin — `installFailLoud` + `loadEnv` + config discovery + `boot()` from [`dsh-app-boot`](../../../../packages/ui/app-boot/src/index.ts), done once boot completes; the server is brought up by the `dsh-jsonrpc` entry in the yml. Its only dependency is app-boot. Process-level exit belongs to the bin (stdin EOF/SIGTERM → dispose then 0, SIGINT → 130).
+- [`packages/examples/jsonrpc-demo`](../../../../packages/examples/jsonrpc-demo/README.md) (`@deepseek-ai/dsh-jsonrpc-demo`): a thin app bin — `installFailLoud` + `loadEnv` + config discovery + `boot()` from [`dsh-app-boot`](../../../../packages/ui/app-boot/src/index.ts), done once boot completes; the server is brought up by the `dsh-jsonrpc` entry in the yml. Its only dependency is app-boot. Process-level exit belongs to the bin (stdin EOF/SIGTERM → dispose then 0, SIGINT → 130).
Config discovery has two channels and fails loudly when both are missing: the `DSH_CORDIS_CONFIG` environment variable first (the SDK client convention), then an argv positional argument; no default path and no built-in fallback whatsoever — "the plugins actually booted are decided by an external cordis.yml" is a hard semantic.
@@ -40,13 +40,13 @@ The deploy root is [`python/sdk-runtime/package.json`](../../../../python/sdk-ru
### Build pipeline and artifacts
-[`scripts/build-exe-for-python-sdk.ts`](../../../../scripts/build-exe-for-python-sdk.ts): runtime closure verification → `pnpm run build` → (after clearing) `pnpm --filter dsh-jsonrpc-agent-pkg deploy --legacy --prod --config.node-linker=hoisted --config.auto-install-peers=false --config.link-workspace-packages=true` **directly into** `python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/` → inject the pkg configuration (`bin` points at `node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js` inside the closure, `assets` is a full glob — dynamic import is invisible to pkg's static analysis, so everything must be packed in explicitly) → one `pkg --sea` per target → the executables `dsh-jsonrpc-agent-pkg--` land in `dist-exe/` and are copied back into the runtime directory. CI treats them as intermediate test inputs and retains their platform wheels. All four deploy flags are grounded in measurement: `--legacy` is the mandatory path with inject-workspace-packages off; hoisted yields a zero-symlink file tree (most stable for the pkg VFS, physically guaranteeing a single cordis instance); disabling automatic peer installation keeps unpublished package names from triggering registry resolution; link-workspace-packages points the closure at workspace/vendor sources.
+[`scripts/build-exe-for-python-sdk.ts`](../../../../scripts/build-exe-for-python-sdk.ts): runtime closure verification → `pnpm run build` → (after clearing) `pnpm --filter dsh-jsonrpc-agent-pkg deploy --legacy --prod --config.node-linker=hoisted --config.auto-install-peers=false --config.link-workspace-packages=true` **directly into** `python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/` → inject the pkg configuration (`bin` points at `node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js` inside the closure, `assets` is a full glob — dynamic import is invisible to pkg's static analysis, so everything must be packed in explicitly) → one `pkg --sea` per target → the executables `dsh-jsonrpc-agent-pkg--` land in `dist-exe/` and are copied back into the runtime directory. CI treats them as intermediate test inputs and retains their platform wheels. All four deploy flags are grounded in measurement: `--legacy` is the mandatory path with inject-workspace-packages off; hoisted yields a zero-symlink file tree (most stable for the pkg VFS, physically guaranteeing a single cordis instance); disabling automatic peer installation keeps unpublished package names from triggering registry resolution; link-workspace-packages points the closure at workspace/vendor sources.
CI: [`.github/workflows/build-exe-for-python-sdk.yml`](../../../../.github/workflows/build-exe-for-python-sdk.yml), triggered explicitly only — `workflow_dispatch`, or the `build-exe` label on a pull request; native builds on the three platforms linux-x64 / linux-arm64 (`ubuntu-24.04-arm`) / macos-arm64, with `~/.pkg-cache` cached; macOS ad-hoc signing is handled by pkg. Each leg drives a mock SSE model through the SDK with the default config and a custom `cordis.yml`, drives the exe directly over NDJSON JSON-RPC, verifies the JSONL and final response, and installs release-shaped wheels into a clean venv without `runtime_bin`; Linux additionally inspects GLIBC requirements and runs in a manylinux 2.28 container. A full three-target run retains four artifacts, each containing one release file: the platform-independent SDK wheel and three native runtime wheels; a subset dispatch retains the SDK wheel and selected runtime wheels. Bare executables and source bundles remain intermediate test inputs. [`.gitlab-ci.yml`](../../../../.gitlab-ci.yml) accepts only `python-vX.Y.Z` tag pipelines whose version matches the root `package.json`, builds one SDK wheel and three native runtime wheels, then a single serialized job checks and publishes all four to the project PyPI registry. Windows is a non-goal.
### Python SDK distribution: two carriers, exe for production, node for development
-The Python SDK lives at [`python/`](../../../../python/README.md): `python/sdk` (the client) + `python/sdk-runtime` (the runtime carrier package). The runtime package's data directory holds three kinds of content: the checked-in default `runtime/cordis.yml`, the build-injected platform exe, and the build-injected `runtime/node/` closure tree. `resolve_bundled_launch_args()` automatic resolution **finds the exe only**; the node carrier is enabled only by an explicit `DSH_RUNTIME_MODE=node` (running `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js`, requiring a system node ≥22.19), positioned as the development-verification channel for members of this repo, and does not enter wheel distributions.
+The Python SDK lives at [`python/`](../../../../python/README.md): `python/sdk` (the client) + `python/sdk-runtime` (the runtime carrier package). The runtime package's data directory holds three kinds of content: the checked-in default `runtime/cordis.yml`, the build-injected platform exe, and the build-injected `runtime/node/` closure tree. `resolve_bundled_launch_args()` automatic resolution **finds the exe only**; the node carrier is enabled only by an explicit `DSH_RUNTIME_MODE=node` (running `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js`, requiring a system node ≥22.19), positioned as the development-verification channel for members of this repo, and does not enter wheel distributions.
[`scripts/build-python-release.py`](../../../../scripts/build-python-release.py) reads the authoritative stable `X.Y.Z` from the repository root `package.json` and stages both packages at that version, with the SDK depending exactly on `deepseek-harness-runtime-bin==X.Y.Z`. An optional `python-vX.Y.Z` release tag is a consistency assertion and is rejected when it differs from the repository version; the source `pyproject.toml` development sentinel never determines a release version. The SDK is a `py3-none-any` wheel; the wheel-only runtime package contains exactly one exe and uses one of `py3-none-manylinux_2_28_x86_64`, `py3-none-manylinux_2_28_aarch64`, or `py3-none-macosx_11_0_arm64`. Its Hatch hook rejects sdists, universal tags, mixed executable payloads, and unsupported platforms.
@@ -54,7 +54,7 @@ The exe's "must be explicitly configured" hard semantic is unchanged; the zero-c
### Naming lineage
-`@deepseek-ai/dsh-jsonrpc-agent` (the package) → `dsh-jsonrpc-agent` (the bin) → `dsh-jsonrpc-agent-pkg` (the closure manifest; no scope prefix, deliberately sidestepping the constraints' package-shape rules for `@deepseek-ai/dsh-*`) → `dsh-jsonrpc-agent-pkg--` (the exe artifacts). The wire `serverInfo.name` stays `deepseek-harness-sdk-runtime` (a protocol-stable value); the Python dist names are `deepseek-harness` / `deepseek-harness-runtime-bin`.
+`@deepseek-ai/dsh-jsonrpc-demo` (the package) → `dsh-jsonrpc-agent` (the bin) → `dsh-jsonrpc-agent-pkg` (the closure manifest; no scope prefix, deliberately sidestepping the constraints' package-shape rules for `@deepseek-ai/dsh-*`) → `dsh-jsonrpc-agent-pkg--` (the exe artifacts). The wire `serverInfo.name` stays `deepseek-harness-sdk-runtime` (a protocol-stable value); the Python dist names are `deepseek-harness` / `deepseek-harness-runtime-bin`.
## Disposition of worker-style plugins
diff --git a/docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md b/docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md
index cd12a65d18..0b964e8a74 100644
--- a/docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md
+++ b/docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md
@@ -23,12 +23,12 @@ exe 使用 [@yao-pkg/pkg](https://github.com/yao-pkg/pkg)(vercel/pkg 归档后
术语提醒:pkg 的 `/snapshot` VFS 与本仓库测试体系的“快照”(ACP 回放 golden、`$DSH_SNAPSHOT`)无关,本文用“VFS”指前者。
-### 对外服务接口也是插件:ui/jsonrpc + ui/jsonrpc-agent 两包
+### 对外服务接口也是插件:ui/jsonrpc + examples/jsonrpc-demo 两包
-确定性协议实现(`server.ts` / `transport.ts`)按 `ui/acp` + `ui/acp-agent` 的既有模式落为两包——对外服务接口本身也是插件:
+确定性协议实现(`server.ts` / `transport.ts`)按 `ui/acp` + `examples/acp-demo` 的既有模式落为两包——对外服务接口本身也是插件:
- [`packages/ui/jsonrpc`](../../../../packages/ui/jsonrpc/README.md)(`@deepseek-ai/dsh-jsonrpc`):纯协议插件;执行 `apply` 时,在进程 stdio 上挂载 `HarnessSdkServer` 与按行传输的 JSON-RPC 层,资源释放走 `ctx.effect()`。是否提供服务由 `cordis.yml` 决定;未挂载该插件的配置会启动一个不提供此服务的合法进程。协议级退出归插件所有(应答 `shutdown` 请求后 dispose 自身 fiber,再调用 `exit(0)`;HMR 式卸载只停止服务,不退出进程)。
-- [`packages/ui/jsonrpc-agent`](../../../../packages/ui/jsonrpc-agent/README.md)(`@deepseek-ai/dsh-jsonrpc-agent`):轻量应用入口——`installFailLoud` + `loadEnv` + 配置发现 + [`dsh-app-boot`](../../../../packages/ui/app-boot/src/index.ts) 的 `boot()`;`boot()` 完成后入口即完成,服务器由 `cordis.yml` 中的 `dsh-jsonrpc` 条目启动。它只依赖 `app-boot`。进程级退出归 `bin` 所有(stdin EOF/SIGTERM → dispose 后返回 0,SIGINT → 130)。
+- [`packages/examples/jsonrpc-demo`](../../../../packages/examples/jsonrpc-demo/README.md)(`@deepseek-ai/dsh-jsonrpc-demo`):轻量应用入口——`installFailLoud` + `loadEnv` + 配置发现 + [`dsh-app-boot`](../../../../packages/ui/app-boot/src/index.ts) 的 `boot()`;`boot()` 完成后入口即完成,服务器由 `cordis.yml` 中的 `dsh-jsonrpc` 条目启动。它只依赖 `app-boot`。进程级退出归 `bin` 所有(stdin EOF/SIGTERM → dispose 后返回 0,SIGINT → 130)。
配置发现有两个通道,均缺失时立即报错:优先使用 `DSH_CORDIS_CONFIG` 环境变量(SDK 客户端约定),其次使用 argv 位置参数;没有默认路径或内置回退——“实际启动的插件由外部 `cordis.yml` 决定”是硬语义。
@@ -40,13 +40,13 @@ exe 的 VFS 内是**构建产物形态的真实包树**(各包的 `lib/` + 真
### 构建管线与产物
-[`scripts/build-exe-for-python-sdk.ts`](../../../../scripts/build-exe-for-python-sdk.ts):运行时闭包校验 → `pnpm run build` →(清空后)`pnpm --filter dsh-jsonrpc-agent-pkg deploy --legacy --prod --config.node-linker=hoisted --config.auto-install-peers=false --config.link-workspace-packages=true` **直接写入** `python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/` → 注入 pkg 配置(`bin` 指向闭包内的 `node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js`;`assets` 使用全量 glob,因为动态 `import()` 对 pkg 静态分析不可见,必须显式打入全部内容)→ 每个构建目标调用一次 `pkg --sea` → 可执行文件 `dsh-jsonrpc-agent-pkg--` 写入 `dist-exe/`,并拷回运行时目录。CI 将这些文件作为测试中间输入,只保留对应平台的 wheel 包。四个部署标志都有实测依据:未启用 `inject-workspace-packages` 时必须使用 `--legacy`;`hoisted` 产出无符号链接的文件树(对 pkg VFS 最稳定,并从物理上保证只有一个 Cordis 实例);关闭对等依赖自动安装可避免未发布包名触发注册表解析;`link-workspace-packages` 让闭包指向工作区/vendor 源码。
+[`scripts/build-exe-for-python-sdk.ts`](../../../../scripts/build-exe-for-python-sdk.ts):运行时闭包校验 → `pnpm run build` →(清空后)`pnpm --filter dsh-jsonrpc-agent-pkg deploy --legacy --prod --config.node-linker=hoisted --config.auto-install-peers=false --config.link-workspace-packages=true` **直接写入** `python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/` → 注入 pkg 配置(`bin` 指向闭包内的 `node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js`;`assets` 使用全量 glob,因为动态 `import()` 对 pkg 静态分析不可见,必须显式打入全部内容)→ 每个构建目标调用一次 `pkg --sea` → 可执行文件 `dsh-jsonrpc-agent-pkg--` 写入 `dist-exe/`,并拷回运行时目录。CI 将这些文件作为测试中间输入,只保留对应平台的 wheel 包。四个部署标志都有实测依据:未启用 `inject-workspace-packages` 时必须使用 `--legacy`;`hoisted` 产出无符号链接的文件树(对 pkg VFS 最稳定,并从物理上保证只有一个 Cordis 实例);关闭对等依赖自动安装可避免未发布包名触发注册表解析;`link-workspace-packages` 让闭包指向工作区/vendor 源码。
CI 使用 [`.github/workflows/build-exe-for-python-sdk.yml`](../../../../.github/workflows/build-exe-for-python-sdk.yml),且只允许显式触发:手动派发 `workflow_dispatch`,或给 PR 添加 `build-exe` 标签。linux-x64、linux-arm64(`ubuntu-24.04-arm`)和 macos-arm64 三个平台分别进行原生构建,并缓存 `~/.pkg-cache`;macOS 的 ad-hoc 签名由 pkg 处理。每个平台都使用模拟 SSE 模型,分别通过默认配置和自定义 `cordis.yml` 驱动 SDK,再通过 NDJSON JSON-RPC 直接驱动 exe,校验 JSONL 与最终响应;最后把发布形态的 wheel 包安装到干净的 venv 中,并在不传 `runtime_bin` 的情况下运行。Linux 还会检查 GLIBC 依赖,并在 manylinux 2.28 容器中运行。完整构建三个目标时保留 4 个产物,每个产物只含一个发布文件:平台无关的 SDK wheel 包与 3 个原生运行时 wheel 包;手动选择部分目标时保留 SDK wheel 与所选运行时 wheel。裸 exe 与源码包只作为测试中间输入。[`.gitlab-ci.yml`](../../../../.gitlab-ci.yml) 只接受版本与根目录 `package.json` 匹配的 `python-vX.Y.Z` 标签流水线,构建一个 SDK wheel 包和 3 个原生运行时 wheel 包,再由单个串行任务校验并将这 4 个文件发布到项目的 PyPI 注册表。Windows 不在目标范围内。
### Python SDK 分发:双载体,exe 用于生产,`node` 用于开发
-Python SDK 位于 [`python/`](../../../../python/README.md):`python/sdk` 是客户端,`python/sdk-runtime` 是运行时载体包。运行时包的数据目录包含三类内容:检入的默认 `runtime/cordis.yml`、构建注入的平台 exe,以及构建注入的 `runtime/node/` 闭包树。`resolve_bundled_launch_args()` 的自动解析**只查找 exe**;`node` 载体仅在显式设置 `DSH_RUNTIME_MODE=node` 时启用(运行 `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js`,需要系统 Node ≥22.19),定位为本仓库成员的开发验证通道,不随 wheel 包分发。
+Python SDK 位于 [`python/`](../../../../python/README.md):`python/sdk` 是客户端,`python/sdk-runtime` 是运行时载体包。运行时包的数据目录包含三类内容:检入的默认 `runtime/cordis.yml`、构建注入的平台 exe,以及构建注入的 `runtime/node/` 闭包树。`resolve_bundled_launch_args()` 的自动解析**只查找 exe**;`node` 载体仅在显式设置 `DSH_RUNTIME_MODE=node` 时启用(运行 `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js`,需要系统 Node ≥22.19),定位为本仓库成员的开发验证通道,不随 wheel 包分发。
[`scripts/build-python-release.py`](../../../../scripts/build-python-release.py) 从仓库根目录的 `package.json` 读取权威的稳定版本 `X.Y.Z`,以该版本暂存两个包,并让 SDK 精确依赖 `deepseek-harness-runtime-bin==X.Y.Z`。可选的 `python-vX.Y.Z` 发布标签只是一项一致性断言,与仓库版本不同时会被拒绝;源码 `pyproject.toml` 中的开发占位版本从不决定发布版本。SDK 是 `py3-none-any` wheel 包;只提供 wheel 包的运行时包恰好包含一个 exe,标签为 `py3-none-manylinux_2_28_x86_64`、`py3-none-manylinux_2_28_aarch64` 或 `py3-none-macosx_11_0_arm64`。其 Hatch 钩子拒绝 sdist、通用标签、混合可执行载荷以及不支持的平台。
@@ -54,7 +54,7 @@ exe“必须显式配置”的硬语义不变;零配置体验由包装层恢
### 命名血统
-`@deepseek-ai/dsh-jsonrpc-agent`(包)→ `dsh-jsonrpc-agent`(`bin`)→ `dsh-jsonrpc-agent-pkg`(闭包清单;没有作用域前缀,刻意避开 `constraints` 对 `@deepseek-ai/dsh-*` 的包形状规则)→ `dsh-jsonrpc-agent-pkg--`(exe 产物)。协议字段 `serverInfo.name` 保持为 `deepseek-harness-sdk-runtime`(协议稳定值);Python 分发名为 `deepseek-harness` / `deepseek-harness-runtime-bin`。
+`@deepseek-ai/dsh-jsonrpc-demo`(包)→ `dsh-jsonrpc-agent`(`bin`)→ `dsh-jsonrpc-agent-pkg`(闭包清单;没有作用域前缀,刻意避开 `constraints` 对 `@deepseek-ai/dsh-*` 的包形状规则)→ `dsh-jsonrpc-agent-pkg--`(exe 产物)。协议字段 `serverInfo.name` 保持为 `deepseek-harness-sdk-runtime`(协议稳定值);Python 分发名为 `deepseek-harness` / `deepseek-harness-runtime-bin`。
## 工作线程插件
diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md
index 9320189de1..d7c6631b94 100644
--- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md
+++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md
@@ -20,7 +20,7 @@ Providers return `{ answers: [{ id, selected, custom? }] }`. `selected` is alway
## UI mappings
-`dsh-stdio-agent`'s in-package readline module renders each question, shows each option's `description` on the next line, supports comma/space-separated numeric choices for `multi_select`, accepts free-form custom answers, and rejects pending questions on abort, provider disposal, or stdin EOF. A batched request is asked in order and resolved as one answer object. The stdio provider serializes simultaneous requests with an internal queue so only one prompt owns stdin at a time.
+`dsh-stdio-demo`'s in-package readline module renders each question, shows each option's `description` on the next line, supports comma/space-separated numeric choices for `multi_select`, accepts free-form custom answers, and rejects pending questions on abort, provider disposal, or stdin EOF. A batched request is asked in order and resolved as one answer object. The stdio provider serializes simultaneous requests with an internal queue so only one prompt owns stdin at a time.
`dsh-acp` provides the same seam for ACP sessions. It routes an ask request from the calling `Agent` through the bridge's `agent→sessionId` reverse map and calls ACP `unstable_createElicitation` with a session-scoped form for each question. Single-select options become a `choice` string enum; `multi_select` options become a `choice` array enum; optionless questions use a required `custom` text field. If the client returns both `choice` and non-empty `custom`, the custom answer wins. ACP `decline`/`cancel`, a missing answer, a missing session, and a client without elicitation support all become structured `UserInteractionError`s.
@@ -46,4 +46,4 @@ The feature gives the model a powerful pause primitive, so prompt guidance matte
## Testing
-Unit coverage pins provider registration/disposal, duplicate-provider rejection, abort-before-provider, empty-question rejection, structured tool errors through `ctx.tools.execute()`, batched answers, multi-select answers, custom answers, and the model schema including the removal of `value`, `recommended`, `allow_custom`, and `desc`. `dsh-stdio-agent` tests cover option descriptions, queued requests, EOF/abort cleanup, optionless free-form input, invalid option reprompts, duplicate multi-select numbers, and batched question flows. ACP bridge tests drive a real in-memory ACP connection with the real `ask_user_question` tool and verify selected-option, custom-overrides-choice, multi-select, and optionless free-form elicitation paths continue the agent loop.
+Unit coverage pins provider registration/disposal, duplicate-provider rejection, abort-before-provider, empty-question rejection, structured tool errors through `ctx.tools.execute()`, batched answers, multi-select answers, custom answers, and the model schema including the removal of `value`, `recommended`, `allow_custom`, and `desc`. `dsh-stdio-demo` tests cover option descriptions, queued requests, EOF/abort cleanup, optionless free-form input, invalid option reprompts, duplicate multi-select numbers, and batched question flows. ACP bridge tests drive a real in-memory ACP connection with the real `ask_user_question` tool and verify selected-option, custom-overrides-choice, multi-select, and optionless free-form elicitation paths continue the agent loop.
diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.md b/docs/rfc/implemented/feature/2026-07-05-skill-system.md
index c29140a854..0b74aa00ae 100644
--- a/docs/rfc/implemented/feature/2026-07-05-skill-system.md
+++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.md
@@ -10,7 +10,7 @@ DeepSeek Harness uses the same primitive so project-specific review, plugin-auth
## Decision
-`@deepseek-ai/dsh-skill` is the pure provider registry (`ctx.skills`), `@deepseek-ai/dsh-skill-local` is the shipped local filesystem provider, and `@deepseek-ai/dsh-tool-skill` owns the session-prefix catalog and model-facing loader tool. `dsh-agent-core` loads the registry, local provider, and consumer by default so stdio and ACP apps get the same behavior while embedded or remote providers contribute skills without changing the registry or consumer. Its `skills` config forwards `registry`, `local`, and `tool` branches to those owners.
+`@deepseek-ai/dsh-skill` is the pure provider registry (`ctx.skills`), `@deepseek-ai/dsh-skill-local` is the shipped local filesystem provider, and `@deepseek-ai/dsh-tool-skill` owns the session-prefix catalog and model-facing loader tool. `dsh-agent-spine-demo` loads the registry, local provider, and consumer by default so stdio and ACP apps get the same behavior while embedded or remote providers contribute skills without changing the registry or consumer. Its `skills` config forwards `registry`, `local`, and `tool` branches to those owners.
Provider plugins register synchronously during `apply()`. Provider membership is direct effect-owned state: registration and disposal invalidate completed catalogs synchronously, and discovery reads the current provider map on demand rather than observing registry-change events. Provider catalogs return ranked candidates from awaited `list()` calls, where remote providers perform initialization, authentication, and discovery while honoring the lookup abort signal. The registry validates each candidate, resolves same-name skills first-wins by rank, provider registration order, and provider-local order, then sorts summaries by skill name for deterministic consumers. It caches only completed catalog snapshots and retries when a provider/runtime revision changes during discovery, so an unload cannot freeze a stale, unresolvable skill into a session prefix. Runtime `ctx.skills.register(...)` remains a convenience for embedded in-process skills and uses project-over-user priority; `runtime` is reserved as the registry-owned provider name.
diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.md b/docs/rfc/implemented/feature/2026-07-06-approval-seam.md
index 521ddd55e7..4ac066e393 100644
--- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.md
+++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.md
@@ -23,7 +23,7 @@ One `cordis.yml` entry mounts the seam. Not loading it is the fail-closed opt-ou
# policy: never # deployment default for sessions without an override; 'ask' when omitted
```
-The entry alone provides mechanism, not a channel: with no answerer composed, every ask resolves `unavailable` and the asking tool call denies — fail-closed needs no configuration. Composing the ACP app (`@deepseek-ai/dsh-acp-agent`, as in [the acp-agent example's default tree](../../../../examples/acp-agent/README.md)) completes the loop: its bridge registers an answerer that prompts the owning editor session via `session/request_permission`, so a hook's `ask` or an escalation request surfaces as a one-shot Allow/Reject prompt attached to the already-streamed tool call. `policy: never` is the unattended stance — every ask auto-rejects deterministically, stated in the system prompt, no human in the loop. `policy` is validated against the closed list at plugin load; anything else throws.
+The entry alone provides mechanism, not a channel: with no answerer composed, every ask resolves `unavailable` and the asking tool call denies — fail-closed needs no configuration. Composing the ACP app (`@deepseek-ai/dsh-acp-demo`, as in [the acp-agent example's default tree](../../../../examples/acp-agent/README.md)) completes the loop: its bridge registers an answerer that prompts the owning editor session via `session/request_permission`, so a hook's `ask` or an escalation request surfaces as a one-shot Allow/Reject prompt attached to the already-streamed tool call. `policy: never` is the unattended stance — every ask auto-rejects deterministically, stated in the system prompt, no human in the loop. `policy` is validated against the closed list at plugin load; anything else throws.
What a composed deployment observes: `allowed-once` lets exactly that call proceed; rejection, dismissal, and channel absence deny with three distinct reasons the model can tell apart; every ask lands a durable `approval/asked`/`approval/decided` pair on the asking agent's session log; nothing about a grant persists past the call that asked.
diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md
index e8ef337206..c56e1eb0ba 100644
--- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md
+++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md
@@ -21,7 +21,7 @@ The system-prompt assembly owns the canonical model-facing tool order, exactly w
Scope is deliberately narrow: this fixes the REGISTRATION-ORDER race, not plugin behavior. A `system-prompt/assemble` listener may still add, remove, or rearrange tools — same as it may edit sections after their sort — and owns the determinism of what it emits; the waterfall contract already demands deterministic listeners (the reconstructability invariant would catch a listener that diverges between build and replay).
-Config plumbing follows the `persona` precedent, and `toolOrder` sits beside it: the app configs (`dsh-stdio-agent`, `dsh-acp-agent`) accept the key and forward it through `dsh-agent-core` (whose schema is the intersection of the owners' schemas) to the `SystemPrompt` child. One schemastery footnote is load-bearing: a schemastery array defaults to `[]`, but an omitted `toolOrder` must stay ABSENT (= lexicographic) rather than become an explicitly-configured empty list (invalid — it lacks the rest entry), so every schema on the chain forces the default to `undefined`.
+Config plumbing follows the `persona` precedent, and `toolOrder` sits beside it: the app configs (`dsh-stdio-demo`, `dsh-acp-demo`) accept the key and forward it through `dsh-agent-spine-demo` (whose schema is the intersection of the owners' schemas) to the `SystemPrompt` child. One schemastery footnote is load-bearing: a schemastery array defaults to `[]`, but an omitted `toolOrder` must stay ABSENT (= lexicographic) rather than become an explicitly-configured empty list (invalid — it lacks the rest entry), so every schema on the chain forces the default to `undefined`.
## Alternatives considered
diff --git a/docs/rfc/implemented/feature/2026-07-14-time-context-plugin.md b/docs/rfc/implemented/feature/2026-07-14-time-context-plugin.md
index 13e0eff4b9..105bf53550 100644
--- a/docs/rfc/implemented/feature/2026-07-14-time-context-plugin.md
+++ b/docs/rfc/implemented/feature/2026-07-14-time-context-plugin.md
@@ -12,7 +12,7 @@ Prompt assembly can derive both facts per step from durable session timestamps,
## Decision
-`@deepseek-ai/dsh-time-context` is an opt-in function plugin at `packages/context/time-context/`. The `context/` product group holds bounded request-context enrichments that define neither a tool nor a service. `dsh-agent-core` and shipped examples do not load the package; deployments mount it explicitly when its token and disclosure costs are acceptable.
+`@deepseek-ai/dsh-time-context` is an opt-in function plugin at `packages/context/time-context/`. The `context/` product group holds bounded request-context enrichments that define neither a tool nor a service. `dsh-agent-spine-demo` and shipped examples do not load the package; deployments mount it explicitly when its token and disclosure costs are acceptable.
The plugin registers the global `context:time` system-prompt section at order 10, after the deployment persona and before tool guidance. For an active turn it emits an ISO-shaped timestamp with numeric UTC offset and IANA zone, plus a compact whole-second duration since the last model-visible message before the turn opened. Bare and idle assemblies receive an empty section.
@@ -45,7 +45,7 @@ Unit tests pin formatting, baselines, refresh policy, validation, per-agent stat
- **Refresh from a background timer** — rejected because a new value has no consumer outside request assembly. Timer-driven `agent.inject()` would create turns and wake idle sessions merely to report time passing.
- **Keep UTC as the omitted default** — rejected because an explicitly enabled clock should follow its deployment environment unless the operator chooses UTC. `timeZone: UTC` remains available when a deployment requires it.
- **Add a time-zone detection library** — rejected because Node's `Intl` runtime already exposes the process's IANA zone. Another dependency cannot infer a remote user's zone either.
-- **Mount the plugin in `dsh-agent-core`** — rejected because time zone, disclosure, token budget, and freshness are deployment policy. Opt-in keeps default context stable.
+- **Mount the plugin in `dsh-agent-spine-demo`** — rejected because time zone, disclosure, token budget, and freshness are deployment policy. Opt-in keeps default context stable.
- **Place the package in `core/`** — rejected because `core/` owns the product API spine, while this plugin is an optional leaf with no service key.
## Consequences
diff --git a/docs/rfc/implemented/feature/2026-07-14-time-context-plugin.zh.md b/docs/rfc/implemented/feature/2026-07-14-time-context-plugin.zh.md
index 5ee50a4d49..60e9004b14 100644
--- a/docs/rfc/implemented/feature/2026-07-14-time-context-plugin.zh.md
+++ b/docs/rfc/implemented/feature/2026-07-14-time-context-plugin.zh.md
@@ -12,7 +12,7 @@ Status: implemented
## 决策
-`@deepseek-ai/dsh-time-context` 是位于 `packages/context/time-context/`、需要显式启用的函数插件。`context/` 产品分组用于容纳既不定义工具、也不定义服务的有界请求上下文增强。`dsh-agent-core` 和仓库提供的示例都不会加载该 package;只有当 token 与信息披露成本可接受时,部署方才显式挂载它。
+`@deepseek-ai/dsh-time-context` 是位于 `packages/context/time-context/`、需要显式启用的函数插件。`context/` 产品分组用于容纳既不定义工具、也不定义服务的有界请求上下文增强。`dsh-agent-spine-demo` 和仓库提供的示例都不会加载该 package;只有当 token 与信息披露成本可接受时,部署方才显式挂载它。
该插件注册顺序值为 10 的全局系统提示词区段 `context:time`,位置在部署方角色设定之后、工具指导之前。对于活跃轮次,它会输出带数字 UTC 偏移和 IANA 时区、形似 ISO 的时间戳,以及从轮次开始前最后一条模型可见消息起算的紧凑整秒时长。未绑定 agent 或 agent 处于空闲状态时,该区段为空。
@@ -45,7 +45,7 @@ agent loop(智能体循环)会在发送前通过 `request/header` 和 `reque
- **通过后台计时器刷新**——不予采纳,因为请求组装之外没有消费新值的对象。由计时器驱动 `agent.inject()` 会创建轮次,并且只为报告时间流逝就唤醒空闲会话。
- **省略配置时仍默认使用 UTC**——不予采纳,因为显式启用的时钟应跟随部署环境,除非运维方选择 UTC。需要 UTC 的部署仍可配置 `timeZone: UTC`。
- **引入时区探测库**——不予采纳,因为 Node 的 `Intl` 运行时已经能够提供进程的 IANA 时区,而且额外依赖同样无法推断远程用户的时区。
-- **在 `dsh-agent-core` 中挂载插件**——不予采纳,因为时区、信息披露、token 预算和新鲜度都属于部署策略。选择加入能保持默认上下文稳定。
+- **在 `dsh-agent-spine-demo` 中挂载插件**——不予采纳,因为时区、信息披露、token 预算和新鲜度都属于部署策略。选择加入能保持默认上下文稳定。
- **将 package 放入 `core/`**——不予采纳,因为 `core/` 负责产品 API 主干,而该插件是没有服务键的可选叶节点。
## 后果
diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md
index 51328a5a1a..af08c96be3 100644
--- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md
+++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md
@@ -13,7 +13,7 @@ Set `engines.node` to `^22.19.0 || >=24.0.0` and test the keyless CI compatibili
Two Node features gate the source runtime:
- **`node:sqlite`** — `packages/session-persistence/session-persistence-sqlite` does a top-level `import { DatabaseSync } from 'node:sqlite'`. The module dropped its `--experimental-sqlite` flag requirement at **22.13** (LTS) and **23.4** (Current); before those, importing it throws at load.
-- **Native TypeScript type-stripping** — the `packages/ui/stdio-agent/tests/built-bin.e2e.ts` smoke boots the published `lib/bin.js` under plain `node` (no tsx) and loads the example's `.ts` plugins (`mock-llm.ts`, `echo-tool.ts`). Type-stripping is the default from **22.18** (LTS) and **23.6** (Current); before those it needs `--experimental-strip-types`.
+- **Native TypeScript type-stripping** — the `packages/examples/stdio-demo/tests/built-bin.e2e.ts` smoke boots the published `lib/bin.js` under plain `node` (no tsx) and loads the example's `.ts` plugins (`mock-llm.ts`, `echo-tool.ts`). Type-stripping is the default from **22.18** (LTS) and **23.6** (Current); before those it needs `--experimental-strip-types`.
Those source features clear on the 22.x line at **22.18**, but the installed Pi adapter dependency raises the advertised LTS floor. `@deepseek-ai/dsh-llm-pi-ai` depends on `@earendil-works/pi-ai@0.79.3`, whose package declares `engines.node >=22.19.0`, so the LTS floor is **22.19**. The 24.x branch remains `>=24.0.0`. The disjoint range excludes Node 23 entirely: Node 23.0–23.5 still has at least one flagged source feature, and the 23 line is non-LTS/EOL, so advertising `>=23.6` would add a dead release line and a CI leg no deployment should use.
diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md
index 634e8ac6ca..d3775754b9 100644
--- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md
+++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md
@@ -4,7 +4,7 @@ Status: implemented
## Problem
-The readline UI was a whole package (`@deepseek-ai/dsh-ui-stdio` under `packages/support/`) whose only runtime importer was the app package `@deepseek-ai/dsh-stdio-agent`. The examples reach the readline UI by loading the app, never by composing the helper themselves; every other repo reference was mechanical or descriptive surface that existed BECAUSE the package boundary existed — manifest and tsconfig entries, generated module-graph rows, dependency-graph and README rows, and doc comments naming the package. The ui group README recorded the support placement rationale ("exists chiefly for the examples and the coverage gate — `ui/` is reserved for surfaces shipped as product"), which left a standing tension: a shipped product app depending on a support package documented as NOT product surface.
+The readline UI was a whole package (`@deepseek-ai/dsh-ui-stdio` under `packages/support/`) whose only runtime importer was the app package `@deepseek-ai/dsh-stdio-demo`. The examples reach the readline UI by loading the app, never by composing the helper themselves; every other repo reference was mechanical or descriptive surface that existed BECAUSE the package boundary existed — manifest and tsconfig entries, generated module-graph rows, dependency-graph and README rows, and doc comments naming the package. The ui group README recorded the support placement rationale ("exists chiefly for the examples and the coverage gate — `ui/` is reserved for surfaces shipped as product"), which left a standing tension: a shipped product app depending on a support package documented as NOT product surface.
The boundary bought package metadata, workspace and tsconfig references, module-graph rows, README entries, and publint surface for a helper that is not independently swappable: the stdio app's front-door cluster always includes the readline UI, and nothing else can meaningfully consume it.
diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md
index 7253f8a1fe..191ddd833f 100644
--- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md
+++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md
@@ -6,7 +6,7 @@ Status: implemented
Two pieces of `dsh-acp` surface were unreachable from any shipped configuration:
-1. **`AcpConfig.agentName` / `agentVersion`** (`packages/ui/acp/src/index.ts`). The shipped app package hands the bridge only `{ model }` (`packages/ui/acp-agent/src/index.ts`), so no leaf `cordis.yml` — the only production config surface — could set the knobs at all; they were settable solely by direct-mounting the bridge, which only a unit test did. Every snapshot golden — the hook-matrix scenarios included — pins the schema defaults (`deepseek-harness-acp` / `0.0.1`). The pair also carried a live `TODO(double-default)`: the literals existed twice (schema `.default(...)` plus `??` fallbacks), with the TODO asking to pick one home.
+1. **`AcpConfig.agentName` / `agentVersion`** (`packages/ui/acp/src/index.ts`). The shipped app package hands the bridge only `{ model }` (`packages/examples/acp-demo/src/index.ts`), so no leaf `cordis.yml` — the only production config surface — could set the knobs at all; they were settable solely by direct-mounting the bridge, which only a unit test did. Every snapshot golden — the hook-matrix scenarios included — pins the schema defaults (`deepseek-harness-acp` / `0.0.1`). The pair also carried a live `TODO(double-default)`: the literals existed twice (schema `.default(...)` plus `??` fallbacks), with the TODO asking to pick one home.
2. **The `toolKindFor` name heuristic** (same file) special-cased `bash*`/`read*`/`write`/`edit*` tool names in the generic-fallback path. Since the [render-intent union](../architecture/2026-07-02-tool-render-intent-union.md), every first-party tool those arms matched ships its own `presentCall` carrying its kind, and the presenter-less production tools (`subagent`, `subagent_fork`) fell through to `other` anyway. The arms were production-reachable only when a tool declined to present its own call — a `presentCall` that THROWS (the containment fallback), or model arguments that fail the tool's schema so `defineTool`'s `presentCall` wrapper returns `undefined` (e.g. a `bash` call missing the required `description`) — and the bridge's own module doc states the design rule the heuristic violated: "the bridge never special-cases tool names".
## Decision
diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md
index b3b8831a32..1fb887db52 100644
--- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md
+++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md
@@ -22,7 +22,7 @@ The machinery lives in [`packages/support/acp-snapshot`](../../../../packages/su
- **Copy the modules into each example** — the fork this RFC exists to prevent: the record/guard logic is exactly the code that must stay byte-identical across suites, and examples are outside the coverage gate, so each copy is also unmeasured.
- **A shared module directory under `examples/`** — keeps the code outside the coverage gate and forces relative imports across example boundaries, against the package-name import convention; `examples/` leaves stay thin by design.
-- **A `/testing` subpath export of `dsh-acp-agent`** — couples test infrastructure into a product package's surface and dependency set; `packages/support/` exists precisely for real-but-lower-compatibility dev/test packages, with `dsh-llm-replay` as the precedent this package completes.
+- **A `/testing` subpath export of `dsh-acp-demo`** — couples test infrastructure into a product package's surface and dependency set; `packages/support/` exists precisely for real-but-lower-compatibility dev/test packages, with `dsh-llm-replay` as the precedent this package completes.
- **Export raw test-body functions instead of a suite factory** — each example would re-own the `describe`/`it` skeleton (~80 lines of registration boilerplate per suite) for no flexibility gain; the factory keeps consumers to a scenario table plus one call, and the exported pure helpers preserve unit-testability inside the factory design.
- **An injectable ACP `Client` factory instead of declarative `permissionAnswers`** — maximally flexible, but it leaks SDK client construction to every consumer and reopens per-example drift in exactly the layer being unified; a declarative queue keeps `input.json` the single scripting surface and stays golden-normalizable.
- **Generalize beyond ACP (a transport-agnostic snapshot harness)** — no second transport exists; the harness is ACP-shaped end to end (SDK client, JSON-RPC frames, `session/update` waiters), and a speculative abstraction would be a seam split ahead of any consumer.
diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md
index 9746d4ac07..0fd4ca27f7 100644
--- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md
+++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md
@@ -1,6 +1,6 @@
# RFC: Make the shared example base providerless
-Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-core` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename.
+Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-spine-demo` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename.
## Problem
diff --git a/examples/README.md b/examples/README.md
index 2cd4ea7a04..5db1e18372 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,12 +1,12 @@
# Examples
-Runnable demos (not workspaces) that showcase how the harness is wired. Each example is a **thin leaf**: a `cordis.yml` that picks the swappable backends (an LLM adapter, a bash executor), loads one app package, and may add optional product tools or demo-only mocks. The composition — the spine, the front-door cluster, and the boot glue — lives in the app packages ([`@deepseek-ai/dsh-stdio-agent`](../packages/ui/stdio-agent), [`@deepseek-ai/dsh-acp-agent`](../packages/ui/acp-agent)) and the [`@deepseek-ai/dsh-agent-core`](../packages/core/agent-core) bundle they share. There is no `start.ts`; the `demo:*` scripts invoke each app package's `bin`.
+Runnable demos (not workspaces) that showcase how the harness is wired. Each example is a **thin leaf**: a `cordis.yml` that picks the swappable backends (an LLM adapter, a bash executor), loads one app package, and may add optional product tools or demo-only mocks. The composition — the spine, the front-door cluster, and the boot glue — lives in the app packages ([`@deepseek-ai/dsh-stdio-demo`](../packages/examples/stdio-demo), [`@deepseek-ai/dsh-acp-demo`](../packages/examples/acp-demo)) and the [`@deepseek-ai/dsh-agent-spine-demo`](../packages/examples/agent-spine-demo) bundle they share. There is no `start.ts`; the `demo:*` scripts invoke each app package's `bin`.
## echo-agent
-A mock model + echo tool on the stdio chat app — the all-mock skeleton. The leaf swaps `dsh-stdio-agent`'s LLM backend to a local `mock-echo` adapter and adds a local `echo` tool. Demonstrates:
+A mock model + echo tool on the stdio chat app — the all-mock skeleton. The leaf swaps `dsh-stdio-demo`'s LLM backend to a local `mock-echo` adapter and adds a local `echo` tool. Demonstrates:
-- A thin leaf `cordis.yml` loading the `@deepseek-ai/dsh-stdio-agent` app
+- A thin leaf `cordis.yml` loading the `@deepseek-ai/dsh-stdio-demo` app
- Registering a mock `LlmAdapter` (streaming scripted responses)
- Registering a tool via `ctx.tools.register()`
- "Swap the backend, keep the app" — the only difference from `coding-agent` is the adapter
@@ -15,7 +15,7 @@ Run with: `pnpm run demo:echo`. When prompted, type "echo " to trigge
## coding-agent
-A REPL agent demo: DeepSeek V4 + the `read`/`write`/`edit` filesystem tools + the bash tool suite, `subagent` delegation, and the `todo_write` task tracker on the same `@deepseek-ai/dsh-stdio-agent` app. The UI is a terminal readline REPL.
+A REPL agent demo: DeepSeek V4 + the `read`/`write`/`edit` filesystem tools + the bash tool suite, `subagent` delegation, and the `todo_write` task tracker on the same `@deepseek-ai/dsh-stdio-demo` app. The UI is a terminal readline REPL.
Run with: `pnpm run demo:repl` (needs `DEEPSEEK_API_KEY` in the environment or a gitignored repo-root `.env`). See [coding-agent/README.md](coding-agent/README.md) for details.
@@ -29,7 +29,7 @@ Run with: `pnpm run demo:cordis` (needs `DEEPSEEK_API_KEY`). See [cordis-agent/R
## acp-agent
-An agent demo exposed as an **Agent Client Protocol (ACP)** server over JSON-RPC stdio, via the [`@deepseek-ai/dsh-acp-agent`](../packages/ui/acp-agent) app — drive it from Zed or any other ACP client. Also the home of the keyless snapshot tests.
+An agent demo exposed as an **Agent Client Protocol (ACP)** server over JSON-RPC stdio, via the [`@deepseek-ai/dsh-acp-demo`](../packages/examples/acp-demo) app — drive it from Zed or any other ACP client. Also the home of the keyless snapshot tests.
Run with: `pnpm run demo:acp` (needs `DEEPSEEK_API_KEY`); `pnpm run demo:code-mode acp` boots the same server in Code Mode via the `code-mode.cordis.yml` overlay. See [acp-agent/README.md](acp-agent/README.md) for the Zed setup and the snapshot-test design.
diff --git a/examples/acp-agent/README.md b/examples/acp-agent/README.md
index 7e796d4de7..35218f4753 100644
--- a/examples/acp-agent/README.md
+++ b/examples/acp-agent/README.md
@@ -11,7 +11,7 @@ The leaf config loads the ACP app, DeepSeek adapter, sandboxed bash, approval an
## stdout is the protocol
-This example loads **no stdout logger** — `stdout` carries the JSON-RPC frames, and any other write corrupts them. `@deepseek-ai/dsh-acp-agent` includes no logger entry, so this leaf has none to get wrong by default; do not add one (use a stderr exporter if you need logs).
+This example loads **no stdout logger** — `stdout` carries the JSON-RPC frames, and any other write corrupts them. `@deepseek-ai/dsh-acp-demo` includes no logger entry, so this leaf has none to get wrong by default; do not add one (use a stderr exporter if you need logs).
## Zed configuration
diff --git a/examples/acp-agent/advanced.cordis.snapshot.yml b/examples/acp-agent/advanced.cordis.snapshot.yml
index 5e14c40995..3c8a57f32a 100644
--- a/examples/acp-agent/advanced.cordis.snapshot.yml
+++ b/examples/acp-agent/advanced.cordis.snapshot.yml
@@ -8,7 +8,7 @@
name: '@deepseek-ai/dsh-llm-deepseek'
disabled: true
- id: acp-agent
- name: '@deepseek-ai/dsh-acp-agent'
+ name: '@deepseek-ai/dsh-acp-demo'
config:
model: deepseek-v4-flash
persistenceRoot: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
diff --git a/examples/acp-agent/advanced.cordis.yml b/examples/acp-agent/advanced.cordis.yml
index 39520be5a8..630a9c10f7 100644
--- a/examples/acp-agent/advanced.cordis.yml
+++ b/examples/acp-agent/advanced.cordis.yml
@@ -6,7 +6,7 @@
path: ./cordis.yml
patches:
- id: acp-agent
- name: '@deepseek-ai/dsh-acp-agent'
+ name: '@deepseek-ai/dsh-acp-demo'
config:
model: deepseek-v4-flash
persistenceRoot: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
diff --git a/examples/acp-agent/both-mode.cordis.snapshot.yml b/examples/acp-agent/both-mode.cordis.snapshot.yml
index 09dbe796fd..c82025252d 100644
--- a/examples/acp-agent/both-mode.cordis.snapshot.yml
+++ b/examples/acp-agent/both-mode.cordis.snapshot.yml
@@ -10,7 +10,7 @@
name: '@deepseek-ai/dsh-llm-deepseek'
disabled: true
- id: acp-agent
- name: '@deepseek-ai/dsh-acp-agent'
+ name: '@deepseek-ai/dsh-acp-demo'
config:
model: deepseek-v4-flash
persistenceRoot: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
diff --git a/examples/acp-agent/both-mode.cordis.yml b/examples/acp-agent/both-mode.cordis.yml
index d92a66c250..1624e43330 100644
--- a/examples/acp-agent/both-mode.cordis.yml
+++ b/examples/acp-agent/both-mode.cordis.yml
@@ -8,7 +8,7 @@
path: ./cordis.yml
patches:
- id: acp-agent
- name: '@deepseek-ai/dsh-acp-agent'
+ name: '@deepseek-ai/dsh-acp-demo'
config:
model: deepseek-v4-flash
persistenceRoot: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
diff --git a/examples/acp-agent/code-mode.cordis.snapshot.yml b/examples/acp-agent/code-mode.cordis.snapshot.yml
index 14c36e4399..ea3de598d8 100644
--- a/examples/acp-agent/code-mode.cordis.snapshot.yml
+++ b/examples/acp-agent/code-mode.cordis.snapshot.yml
@@ -10,7 +10,7 @@
name: '@deepseek-ai/dsh-llm-deepseek'
disabled: true
- id: acp-agent
- name: '@deepseek-ai/dsh-acp-agent'
+ name: '@deepseek-ai/dsh-acp-demo'
config:
model: deepseek-v4-flash
persistenceRoot: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
diff --git a/examples/acp-agent/code-mode.cordis.yml b/examples/acp-agent/code-mode.cordis.yml
index d7d60f5af9..0170e808ce 100644
--- a/examples/acp-agent/code-mode.cordis.yml
+++ b/examples/acp-agent/code-mode.cordis.yml
@@ -9,7 +9,7 @@
path: ./cordis.yml
patches:
- id: acp-agent
- name: '@deepseek-ai/dsh-acp-agent'
+ name: '@deepseek-ai/dsh-acp-demo'
config:
model: deepseek-v4-flash
persistenceRoot: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
diff --git a/examples/acp-agent/composition.md b/examples/acp-agent/composition.md
index b93b4cb1e2..194ff3dee0 100644
--- a/examples/acp-agent/composition.md
+++ b/examples/acp-agent/composition.md
@@ -18,9 +18,9 @@ flowchart LR
cfg --> plugin_acp_approval
plugin_acp_permission["permission
@deepseek-ai/dsh-permission"]
cfg --> plugin_acp_permission
- plugin_acp_acp_agent["acp-agent
@deepseek-ai/dsh-acp-agent"]
+ plugin_acp_acp_agent["acp-agent
@deepseek-ai/dsh-acp-demo"]
cfg --> plugin_acp_acp_agent
- plugin_acp_acp_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-core"]
+ plugin_acp_acp_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"]
plugin_acp_acp_agent --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"]
plugin_acp_acp_agent --> frontdoor_acp["@deepseek-ai/dsh-acp
JSON-RPC stdio bridge
sessions created by client"]
bundle_agent_core --> spine_llm["ctx.llm"]
@@ -58,7 +58,7 @@ flowchart LR
| `bash` | `@deepseek-ai/dsh-bash-sandbox` |
| `approval` | `@deepseek-ai/dsh-user-approval` |
| `permission` | `@deepseek-ai/dsh-permission` |
-| `acp-agent` | `@deepseek-ai/dsh-acp-agent` |
+| `acp-agent` | `@deepseek-ai/dsh-acp-demo` |
| `subagent` | `@deepseek-ai/dsh-subagent` |
| `subagent-spawn` | `@deepseek-ai/dsh-subagent-spawn` |
| `subagent-fork` | `@deepseek-ai/dsh-subagent-fork` |
diff --git a/examples/acp-agent/cordis.yml b/examples/acp-agent/cordis.yml
index 201feafe41..345fd49b45 100644
--- a/examples/acp-agent/cordis.yml
+++ b/examples/acp-agent/cordis.yml
@@ -37,7 +37,7 @@
# Persistence root: $DSH_SNAPSHOT_SESSIONS_ROOT when the snapshot harness sets it
# (so it can harvest / isolate the log), else ./.sessions for the demo.
- id: acp-agent
- name: '@deepseek-ai/dsh-acp-agent'
+ name: '@deepseek-ai/dsh-acp-demo'
config:
model: deepseek-v4-flash
persistenceRoot: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
diff --git a/examples/acp-agent/tests/acp.e2e.ts b/examples/acp-agent/tests/acp.e2e.ts
index e02f534fa6..23c6f58301 100644
--- a/examples/acp-agent/tests/acp.e2e.ts
+++ b/examples/acp-agent/tests/acp.e2e.ts
@@ -23,7 +23,7 @@ import {
*/
// The child runs from a temp cwd, so its bin and config path are absolute.
-const binScript = fileURLToPath(new URL('../../../packages/ui/acp-agent/src/bin.ts', import.meta.url))
+const binScript = fileURLToPath(new URL('../../../packages/examples/acp-demo/src/bin.ts', import.meta.url))
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
// Resolve tsx absolutely because the subprocess runs outside the repo.
const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
diff --git a/examples/acp-agent/tests/acp.snapshot.ts b/examples/acp-agent/tests/acp.snapshot.ts
index 0d29f7b5ce..3e605b3141 100644
--- a/examples/acp-agent/tests/acp.snapshot.ts
+++ b/examples/acp-agent/tests/acp.snapshot.ts
@@ -13,11 +13,11 @@ import { defineAcpSnapshotSuite, type Scenario, type SnapshotSuiteOptions } from
* docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md.
*/
-// The dsh-acp-agent bin (the demo:acp entry), this example's cordis.yml, and
+// The dsh-acp-demo bin (the demo:acp entry), this example's cordis.yml, and
// the repo-root tsconfig (four levels up from examples/acp-agent/tests) — all
// ABSOLUTE: the subprocess cwd is a temp dir outside the repo.
const AGENT = {
- binScript: fileURLToPath(new URL('../../../packages/ui/acp-agent/src/bin.ts', import.meta.url)),
+ binScript: fileURLToPath(new URL('../../../packages/examples/acp-demo/src/bin.ts', import.meta.url)),
configPath: fileURLToPath(new URL('../cordis.yml', import.meta.url)),
tsconfigPath: fileURLToPath(new URL('../../../tsconfig.json', import.meta.url)),
}
diff --git a/examples/acp-agent/tests/escalation.e2e.ts b/examples/acp-agent/tests/escalation.e2e.ts
index 1a690367aa..507e938950 100644
--- a/examples/acp-agent/tests/escalation.e2e.ts
+++ b/examples/acp-agent/tests/escalation.e2e.ts
@@ -26,7 +26,7 @@ import {
* or runner support self-skip; real denial markers remain on sandbox e2e tiers.
*/
-const binScript = fileURLToPath(new URL('../../../packages/ui/acp-agent/src/bin.ts', import.meta.url))
+const binScript = fileURLToPath(new URL('../../../packages/examples/acp-demo/src/bin.ts', import.meta.url))
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
// The subprocess runs from a temp cwd outside the repo; point tsx at the repo
diff --git a/examples/acp-agent/tests/hooks.e2e.ts b/examples/acp-agent/tests/hooks.e2e.ts
index dd7c6dca05..99cebb907e 100644
--- a/examples/acp-agent/tests/hooks.e2e.ts
+++ b/examples/acp-agent/tests/hooks.e2e.ts
@@ -23,7 +23,7 @@ import {
* The test owns and disposes the ACP subprocess.
*/
-const binScript = fileURLToPath(new URL('../../../packages/ui/acp-agent/src/bin.ts', import.meta.url))
+const binScript = fileURLToPath(new URL('../../../packages/examples/acp-demo/src/bin.ts', import.meta.url))
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
const repoTsconfig = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
diff --git a/examples/coding-agent/README.md b/examples/coding-agent/README.md
index 5d6713144c..380ab8134f 100644
--- a/examples/coding-agent/README.md
+++ b/examples/coding-agent/README.md
@@ -48,14 +48,14 @@ and watch the transcript: one `run_code` call, a program looping over tools, and
## What each leaf entry demonstrates
-This example is a thin leaf `cordis.yml`: it picks the swappable backends, loads one app package, and adds product tools that are intentionally outside the shared spine. The spine (sessions, system-prompt, tools, agents, invariants, `agent-loop`) and the front-door cluster (console logger, JSONL persistence, readline UI, the pre-created `main` agent) live inside the [`@deepseek-ai/dsh-stdio-agent`](../../packages/ui/stdio-agent) app and the [`@deepseek-ai/dsh-agent-core`](../../packages/core/agent-core) bundle it loads; the leaf wires the backends and model-facing optional tools:
+This example is a thin leaf `cordis.yml`: it picks the swappable backends, loads one app package, and adds product tools that are intentionally outside the shared spine. The spine (sessions, system-prompt, tools, agents, invariants, `agent-loop`) and the front-door cluster (console logger, JSONL persistence, readline UI, the pre-created `main` agent) live inside the [`@deepseek-ai/dsh-stdio-demo`](../../packages/examples/stdio-demo) app and the [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) bundle it loads; the leaf wires the backends and model-facing optional tools:
| Entry | Demonstrates |
|---|---|
| `hmr` (`@cordisjs/plugin-hmr`) | the dev/demo edit-reload loop — a **leaf** entry (not baked into the app) because it is Loader-only and needs `node --expose-internals`, which `demo:repl` passes |
| `llm-deepseek` | real `LlmAdapter` via config (`!!js process.env.…` secrets); swap one line to `@deepseek-ai/dsh-llm-pi-ai` for the library-backed twin |
| `bash` (`dsh-bash-local`) | the executor implementation — the swappable half of the bash seam. The model-facing `bash`/`bash_output`/`bash_kill` tool schemas (`tool-bash`) come from `agent-core`, so only the executor is a leaf choice |
-| `stdio-agent` (`@deepseek-ai/dsh-stdio-agent`) | the app bundle: the agent-core spine + console logger + JSONL persistence + readline UI + a pre-created `main` agent. Its config carries the model, system prompt, `persistenceRoot` (`./.sessions`), and `resumeSessionId` — so persistence and the agent are configured here, not wired as separate leaf plugins |
+| `stdio-agent` (`@deepseek-ai/dsh-stdio-demo`) | the app bundle: the agent-core spine + console logger + JSONL persistence + readline UI + a pre-created `main` agent. Its config carries the model, system prompt, `persistenceRoot` (`./.sessions`), and `resumeSessionId` — so persistence and the agent are configured here, not wired as separate leaf plugins |
| `subagent`, `subagent-spawn`, `subagent-fork` | the subagent provider registry plus the two in-process backends: a fresh child and a child seeded with the parent's completed-turn prefix |
| `tool-subagent`, `tool-subagent-fork` | two model-facing `dsh-tool-subagent` loads, each bound to a different provider and exposed under a distinct tool name (`subagent`, `subagent_fork`) |
| `tool-todo` | the model-facing `todo_write` tool; writes the whole task list to the session log and renders as a checklist in stdio |
diff --git a/examples/coding-agent/code-mode.cordis.yml b/examples/coding-agent/code-mode.cordis.yml
index 8b4d22b917..5d7198124c 100644
--- a/examples/coding-agent/code-mode.cordis.yml
+++ b/examples/coding-agent/code-mode.cordis.yml
@@ -9,7 +9,7 @@
path: ./cordis.yml
patches:
- id: stdio-agent
- name: '@deepseek-ai/dsh-stdio-agent'
+ name: '@deepseek-ai/dsh-stdio-demo'
config:
model: deepseek-v4-flash
resumeSessionId: !!js process.env.RESUME_SESSION_ID
diff --git a/examples/coding-agent/composition.md b/examples/coding-agent/composition.md
index be9a457124..90ff8222b9 100644
--- a/examples/coding-agent/composition.md
+++ b/examples/coding-agent/composition.md
@@ -14,9 +14,9 @@ flowchart LR
cfg --> plugin_coding_llm_deepseek
plugin_coding_bash["bash
@deepseek-ai/dsh-bash-local"]
cfg --> plugin_coding_bash
- plugin_coding_stdio_agent["stdio-agent
@deepseek-ai/dsh-stdio-agent"]
+ plugin_coding_stdio_agent["stdio-agent
@deepseek-ai/dsh-stdio-demo"]
cfg --> plugin_coding_stdio_agent
- plugin_coding_stdio_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-core"]
+ plugin_coding_stdio_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"]
plugin_coding_stdio_agent --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"]
plugin_coding_stdio_agent --> frontdoor_stdio["readline UI
console logger
pre-created main agent"]
bundle_agent_core --> spine_llm["ctx.llm"]
@@ -54,7 +54,7 @@ flowchart LR
| `hmr` | `@cordisjs/plugin-hmr` |
| `llm-deepseek` | `@deepseek-ai/dsh-llm-deepseek` |
| `bash` | `@deepseek-ai/dsh-bash-local` |
-| `stdio-agent` | `@deepseek-ai/dsh-stdio-agent` |
+| `stdio-agent` | `@deepseek-ai/dsh-stdio-demo` |
| `compact-basic` | `@deepseek-ai/dsh-compact-basic` |
| `subagent` | `@deepseek-ai/dsh-subagent` |
| `subagent-spawn` | `@deepseek-ai/dsh-subagent-spawn` |
diff --git a/examples/coding-agent/cordis.yml b/examples/coding-agent/cordis.yml
index 5581a910b1..600ffda160 100644
--- a/examples/coding-agent/cordis.yml
+++ b/examples/coding-agent/cordis.yml
@@ -1,4 +1,4 @@
-# REPL agent with swappable DeepSeek and local-bash backends. `dsh-stdio-agent`
+# REPL agent with swappable DeepSeek and local-bash backends. `dsh-stdio-demo`
# supplies the agent-core spine, logging, JSONL persistence, readline UI, and `main` agent.
# HMR remains a leaf because it requires Loader internals; `demo:repl` passes
# `--expose-internals`. The app bin loads the gitignored root `.env`; this file
@@ -29,7 +29,7 @@
# The app bundle pre-creates the REPL's `main` agent.
- id: stdio-agent
- name: '@deepseek-ai/dsh-stdio-agent'
+ name: '@deepseek-ai/dsh-stdio-demo'
config:
model: deepseek-v4-flash
# Set RESUME_SESSION_ID to continue a prior persisted session (the ids live
diff --git a/examples/coding-agent/tests/code-mode-keyless-smoke.e2e.ts b/examples/coding-agent/tests/code-mode-keyless-smoke.e2e.ts
index ac2cb9430b..dd4239a2c4 100644
--- a/examples/coding-agent/tests/code-mode-keyless-smoke.e2e.ts
+++ b/examples/coding-agent/tests/code-mode-keyless-smoke.e2e.ts
@@ -8,7 +8,7 @@ import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-l
* a prompt and assert the banner. No model or `run_code` turn runs.
*/
-const binScript = fileURLToPath(new URL('../../../packages/ui/stdio-agent/src/bin.ts', import.meta.url))
+const binScript = fileURLToPath(new URL('../../../packages/examples/stdio-demo/src/bin.ts', import.meta.url))
const configPath = fileURLToPath(new URL('../code-mode.cordis.yml', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
diff --git a/examples/coding-agent/tests/keyless-smoke.e2e.ts b/examples/coding-agent/tests/keyless-smoke.e2e.ts
index 6cfeca646e..831d0daf5c 100644
--- a/examples/coding-agent/tests/keyless-smoke.e2e.ts
+++ b/examples/coding-agent/tests/keyless-smoke.e2e.ts
@@ -9,7 +9,7 @@ import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-l
* immediate EOF guarantees there is no model call.
*/
-const binScript = fileURLToPath(new URL('../../../packages/ui/stdio-agent/src/bin.ts', import.meta.url))
+const binScript = fileURLToPath(new URL('../../../packages/examples/stdio-demo/src/bin.ts', import.meta.url))
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
diff --git a/examples/cordis-agent/composition.md b/examples/cordis-agent/composition.md
index 015bec724e..6a08c379fc 100644
--- a/examples/cordis-agent/composition.md
+++ b/examples/cordis-agent/composition.md
@@ -20,9 +20,9 @@ flowchart LR
cfg --> plugin_cordis_web
plugin_cordis_web_fetch_local["web-fetch-local
@deepseek-ai/dsh-web-fetch-local"]
cfg --> plugin_cordis_web_fetch_local
- plugin_cordis_stdio_agent["stdio-agent
@deepseek-ai/dsh-stdio-agent"]
+ plugin_cordis_stdio_agent["stdio-agent
@deepseek-ai/dsh-stdio-demo"]
cfg --> plugin_cordis_stdio_agent
- plugin_cordis_stdio_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-core"]
+ plugin_cordis_stdio_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"]
plugin_cordis_stdio_agent --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"]
plugin_cordis_stdio_agent --> frontdoor_stdio["readline UI
console logger
pre-created main agent"]
bundle_agent_core --> spine_llm["ctx.llm"]
@@ -41,7 +41,7 @@ flowchart LR
| `fs-local` | `@deepseek-ai/dsh-fs-local` |
| `web` | `@deepseek-ai/dsh-web` |
| `web-fetch-local` | `@deepseek-ai/dsh-web-fetch-local` |
-| `stdio-agent` | `@deepseek-ai/dsh-stdio-agent` |
+| `stdio-agent` | `@deepseek-ai/dsh-stdio-demo` |
| `tool-cordis` | `@deepseek-ai/dsh-tool-cordis` |
Source config: [`examples/cordis-agent/cordis.yml`](cordis.yml).
diff --git a/examples/cordis-agent/cordis.yml b/examples/cordis-agent/cordis.yml
index 2634233cec..8cd989e9e4 100644
--- a/examples/cordis-agent/cordis.yml
+++ b/examples/cordis-agent/cordis.yml
@@ -49,7 +49,7 @@
# The app bundle pre-creates the self-referential demo's `main` agent.
- id: stdio-agent
- name: '@deepseek-ai/dsh-stdio-agent'
+ name: '@deepseek-ai/dsh-stdio-demo'
config:
model: deepseek-v4-flash
resumeSessionId: !!js process.env.RESUME_SESSION_ID
diff --git a/examples/cordis-agent/tests/keyless-smoke.e2e.ts b/examples/cordis-agent/tests/keyless-smoke.e2e.ts
index c1f20f1987..24cf2138fb 100644
--- a/examples/cordis-agent/tests/keyless-smoke.e2e.ts
+++ b/examples/cordis-agent/tests/keyless-smoke.e2e.ts
@@ -8,7 +8,7 @@ import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-l
* prompt and assert the banner. The dummy key never reaches a model call.
*/
-const binScript = fileURLToPath(new URL('../../../packages/ui/stdio-agent/src/bin.ts', import.meta.url))
+const binScript = fileURLToPath(new URL('../../../packages/examples/stdio-demo/src/bin.ts', import.meta.url))
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
diff --git a/examples/echo-agent/README.md b/examples/echo-agent/README.md
index dad0ce348a..d6156130db 100644
--- a/examples/echo-agent/README.md
+++ b/examples/echo-agent/README.md
@@ -4,7 +4,7 @@ Runnable demo: stdin chat with a scripted mock model and an echo tool. The all-m
## What it shows
-This example is just a leaf `cordis.yml`: it loads the [`@deepseek-ai/dsh-stdio-agent`](../../packages/ui/stdio-agent) app (which bundles the whole [`@deepseek-ai/dsh-agent-core`](../../packages/core/agent-core) spine, the console logger, JSONL persistence, the readline UI, and a pre-created `main` agent), and swaps in two example-local backends plus `hmr`:
+This example is just a leaf `cordis.yml`: it loads the [`@deepseek-ai/dsh-stdio-demo`](../../packages/examples/stdio-demo) app (which bundles the whole [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) spine, the console logger, JSONL persistence, the readline UI, and a pre-created `main` agent), and swaps in two example-local backends plus `hmr`:
- `mock-llm.ts` — a mock `LlmAdapter` that streams scripted responses and calls the `echo` tool when the user types "echo ". Registered with `ctx.llm.registerAdapter(['mock-echo'], …)`.
- `echo-tool.ts` — a tool registered via `ctx.tools.register(defineTool(…))` with typed `execute` args; echoes text back uppercased.
@@ -17,16 +17,16 @@ Swapping `mock-llm` for the real `llm-deepseek` adapter is all that separates th
|---|---|---|
| `src/mock-llm.ts` | `LlmAdapter` registration | `ctx.llm.registerAdapter(['mock-echo'], …)`, streaming chunks with the proper `block-start`/`block-end` protocol |
| `src/echo-tool.ts` | Tool registration | `ctx.tools.register(defineTool(…))` with typed `execute` args, returning `ContentBlock[]` |
-| `cordis.yml` | Leaf wiring | the two backends + `hmr` + one `@deepseek-ai/dsh-stdio-agent` entry carrying the app config |
+| `cordis.yml` | Leaf wiring | the two backends + `hmr` + one `@deepseek-ai/dsh-stdio-demo` entry carrying the app config |
-The spine, UI, persistence, and boot glue all live in `@deepseek-ai/dsh-stdio-agent` and the bundle it loads — this folder holds only the demo-specific mocks and the leaf wiring.
+The spine, UI, persistence, and boot glue all live in `@deepseek-ai/dsh-stdio-demo` and the bundle it loads — this folder holds only the demo-specific mocks and the leaf wiring.
## Run
```sh
pnpm run demo:echo
# or:
-node --expose-internals --import tsx packages/ui/stdio-agent/src/bin.ts examples/echo-agent/cordis.yml
+node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/echo-agent/cordis.yml
```
Type a message and press Enter. "echo " triggers a tool call round-trip (the mock model requests the `echo` tool, which echoes the text uppercased, and the next model step acknowledges it).
diff --git a/examples/echo-agent/composition.md b/examples/echo-agent/composition.md
index 1491c56955..5160bd20b7 100644
--- a/examples/echo-agent/composition.md
+++ b/examples/echo-agent/composition.md
@@ -16,9 +16,9 @@ flowchart LR
cfg --> plugin_echo_echo_tool
plugin_echo_bash["bash
@deepseek-ai/dsh-bash-local"]
cfg --> plugin_echo_bash
- plugin_echo_stdio_agent["stdio-agent
@deepseek-ai/dsh-stdio-agent"]
+ plugin_echo_stdio_agent["stdio-agent
@deepseek-ai/dsh-stdio-demo"]
cfg --> plugin_echo_stdio_agent
- plugin_echo_stdio_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-core"]
+ plugin_echo_stdio_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"]
plugin_echo_stdio_agent --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"]
plugin_echo_stdio_agent --> frontdoor_stdio["readline UI
console logger
pre-created main agent"]
bundle_agent_core --> spine_llm["ctx.llm"]
@@ -33,7 +33,7 @@ flowchart LR
| `mock-llm` | `./src/mock-llm.ts` |
| `echo-tool` | `./src/echo-tool.ts` |
| `bash` | `@deepseek-ai/dsh-bash-local` |
-| `stdio-agent` | `@deepseek-ai/dsh-stdio-agent` |
+| `stdio-agent` | `@deepseek-ai/dsh-stdio-demo` |
Source config: [`examples/echo-agent/cordis.yml`](cordis.yml).
diff --git a/examples/echo-agent/cordis.yml b/examples/echo-agent/cordis.yml
index a476927a89..fbf998e770 100644
--- a/examples/echo-agent/cordis.yml
+++ b/examples/echo-agent/cordis.yml
@@ -3,7 +3,7 @@
# No API key: the `mock-echo` adapter never touches the network.
# Hot-module reload for the dev/demo loop (a leaf entry, not baked into
-# dsh-stdio-agent — it needs `node --expose-internals`, which `demo:echo` passes).
+# dsh-stdio-demo — it needs `node --expose-internals`, which `demo:echo` passes).
- id: hmr
name: '@cordisjs/plugin-hmr'
config:
@@ -24,7 +24,7 @@
# The app pre-creates `main` on the mock model and supplies logging, persistence, and readline UI.
- id: stdio-agent
- name: '@deepseek-ai/dsh-stdio-agent'
+ name: '@deepseek-ai/dsh-stdio-demo'
config:
model: mock-echo
persona: 'You are echo-agent, a demo agent.'
diff --git a/examples/echo-agent/tests/echo.e2e.ts b/examples/echo-agent/tests/echo.e2e.ts
index 1bd2733d94..db0d998336 100644
--- a/examples/echo-agent/tests/echo.e2e.ts
+++ b/examples/echo-agent/tests/echo.e2e.ts
@@ -8,7 +8,7 @@ import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-l
* and the complete behavior proof for the example.
*/
-const binScript = fileURLToPath(new URL('../../../packages/ui/stdio-agent/src/bin.ts', import.meta.url))
+const binScript = fileURLToPath(new URL('../../../packages/examples/stdio-demo/src/bin.ts', import.meta.url))
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
diff --git a/knip.json b/knip.json
index ad33bec613..71c9d1e01d 100644
--- a/knip.json
+++ b/knip.json
@@ -82,11 +82,11 @@
"entry": ["tests/**/*.spec.ts", "tests/**/*.e2e.ts"],
"project": ["src/**/*.ts", "tests/**/*.ts"]
},
- "packages/ui/acp-agent": {
+ "packages/examples/acp-demo": {
"entry": ["tests/**/*.spec.ts", "tests/**/*.e2e.ts"],
"project": ["src/**/*.ts", "tests/**/*.ts"]
},
- "packages/ui/stdio-agent": {
+ "packages/examples/stdio-demo": {
"entry": ["tests/**/*.spec.ts", "tests/**/*.e2e.ts"],
"project": ["src/**/*.ts", "tests/**/*.ts"]
},
@@ -94,7 +94,7 @@
"entry": ["tests/**/*.spec.ts"],
"project": ["src/**/*.ts", "tests/**/*.ts"]
},
- "packages/ui/jsonrpc-agent": {
+ "packages/examples/jsonrpc-demo": {
"project": ["src/**/*.ts"]
},
"packages/subagent/subagent-spawn": {
diff --git a/package.json b/package.json
index b436a161fe..081c2eb51e 100644
--- a/package.json
+++ b/package.json
@@ -71,11 +71,11 @@
"constraints": "tsx scripts/check-workspace-constraints.ts",
"doc-sync": "pnpm run doc-typecheck && pnpm run verify-cordis-catalog && pnpm run verify-cordis-api && pnpm run verify-export-jsdoc && pnpm run verify-tool-catalog && pnpm run verify-config-catalog && pnpm run verify-persistence-catalog && pnpm run verify-doc-graphs && pnpm run verify-scoped-events && pnpm run verify-md-wrap && pnpm run verify-md-links && pnpm run verify-doc-refs && pnpm run verify-package-paths && pnpm run verify-package-readme-model-experience && pnpm run verify-mermaid && pnpm run verify-rfc-classification && pnpm run verify-rfc-format && pnpm run verify-type-equiv && pnpm run verify-translation-pairing && pnpm run verify-doc-budgets && pnpm run verify-package-readme-limitations",
"hygiene": "pnpm run knip && pnpm run publint && pnpm run constraints && pnpm run verify-cordis-config && pnpm run verify-node-next-types && pnpm run verify-runtime-closure",
- "demo:echo": "node --expose-internals --import tsx packages/ui/stdio-agent/src/bin.ts examples/echo-agent/cordis.yml",
- "demo:repl": "node --expose-internals --import tsx packages/ui/stdio-agent/src/bin.ts examples/coding-agent/cordis.yml",
+ "demo:echo": "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/echo-agent/cordis.yml",
+ "demo:repl": "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/coding-agent/cordis.yml",
"demo:code-mode": "node scripts/demo-code-mode.mjs",
- "demo:cordis": "node --expose-internals --import tsx packages/ui/stdio-agent/src/bin.ts examples/cordis-agent/cordis.yml",
- "demo:acp": "node --import tsx packages/ui/acp-agent/src/bin.ts --config examples/acp-agent/cordis.yml",
+ "demo:cordis": "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/cordis-agent/cordis.yml",
+ "demo:acp": "node --import tsx packages/examples/acp-demo/src/bin.ts --config examples/acp-agent/cordis.yml",
"postinstall": "node scripts/install-lefthook.mjs"
},
"devDependencies": {
diff --git a/packages/context/README.md b/packages/context/README.md
index 49a297d11a..0045c6629c 100644
--- a/packages/context/README.md
+++ b/packages/context/README.md
@@ -1,6 +1,6 @@
# context/ — optional request context
-Opt-in plugins that add bounded model-visible request context without defining a tool or service. The default `dsh-agent-core` bundle excludes them.
+Opt-in plugins that add bounded model-visible request context without defining a tool or service. The default `dsh-agent-spine-demo` bundle excludes them.
| Package | Role | ctx key |
|---|---|---|
diff --git a/packages/context/time-context/README.md b/packages/context/time-context/README.md
index b50470aef7..84d487445b 100644
--- a/packages/context/time-context/README.md
+++ b/packages/context/time-context/README.md
@@ -1,6 +1,6 @@
# @deepseek-ai/dsh-time-context
-Opt-in dynamic system-prompt context with the current zoned time and elapsed time since the latest model-visible message before the turn. `dsh-agent-core` and shipped examples do not mount it. Decision record: [the time-context RFC](../../../docs/rfc/implemented/feature/2026-07-14-time-context-plugin.md).
+Opt-in dynamic system-prompt context with the current zoned time and elapsed time since the latest model-visible message before the turn. `dsh-agent-spine-demo` and shipped examples do not mount it. Decision record: [the time-context RFC](../../../docs/rfc/implemented/feature/2026-07-14-time-context-plugin.md).
## Config
diff --git a/packages/context/time-context/tests/fixtures/cordis.yml b/packages/context/time-context/tests/fixtures/cordis.yml
index e9558abec6..da18fc11df 100644
--- a/packages/context/time-context/tests/fixtures/cordis.yml
+++ b/packages/context/time-context/tests/fixtures/cordis.yml
@@ -9,7 +9,7 @@
name: '@deepseek-ai/dsh-time-context'
- id: stdio-agent
- name: '@deepseek-ai/dsh-stdio-agent'
+ name: '@deepseek-ai/dsh-stdio-demo'
config:
model: mock-echo
persona: 'Test the time-context plugin.'
diff --git a/packages/context/time-context/tests/time-context.e2e.ts b/packages/context/time-context/tests/time-context.e2e.ts
index daa6e9a9b8..f83b451ef7 100644
--- a/packages/context/time-context/tests/time-context.e2e.ts
+++ b/packages/context/time-context/tests/time-context.e2e.ts
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url'
import { afterEach, describe, expect, it } from 'vitest'
import { foldRequestHeader, type SessionEvent } from '@deepseek-ai/dsh-session'
-const binScript = fileURLToPath(new URL('../../../ui/stdio-agent/src/bin.ts', import.meta.url))
+const binScript = fileURLToPath(new URL('../../../examples/stdio-demo/src/bin.ts', import.meta.url))
const configPath = fileURLToPath(new URL('./fixtures/cordis.yml', import.meta.url))
const repoTsconfig = fileURLToPath(new URL('../../../../tsconfig.json', import.meta.url))
const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
diff --git a/packages/ui/acp-agent/README.md b/packages/examples/acp-demo/README.md
similarity index 79%
rename from packages/ui/acp-agent/README.md
rename to packages/examples/acp-demo/README.md
index 63c9d3df23..3bc9863ccf 100644
--- a/packages/ui/acp-agent/README.md
+++ b/packages/examples/acp-demo/README.md
@@ -1,8 +1,8 @@
-# @deepseek-ai/dsh-acp-agent
+# @deepseek-ai/dsh-acp-demo
-The **ACP server app**: a Cordis app plugin that composes the default agent spine ([`@deepseek-ai/dsh-agent-core`](../../core/agent-core/README.md)) with the front-door cluster an [Agent Client Protocol](../acp/README.md) server needs, and a `bin` that boots a leaf `cordis.yml` speaking ACP JSON-RPC on stdio.
+The **ACP server app**: a Cordis app plugin that composes the default agent spine ([`@deepseek-ai/dsh-agent-spine-demo`](../../examples/agent-spine-demo/README.md)) with the front-door cluster an [Agent Client Protocol](../acp/README.md) server needs, and a `bin` that boots a leaf `cordis.yml` speaking ACP JSON-RPC on stdio.
-It is the structured counterpart to [`@deepseek-ai/dsh-stdio-agent`](../stdio-agent/README.md): both consume the same spine, but this one bakes in the OPPOSITE front-door cluster.
+It is the structured counterpart to [`@deepseek-ai/dsh-stdio-demo`](../stdio-demo/README.md): both consume the same spine, but this one bakes in the OPPOSITE front-door cluster.
## What it bakes in — and what it deliberately omits
@@ -10,7 +10,7 @@ stdout is the ACP JSON-RPC channel, so the cluster is defined as much by what it
| Plugin | Why |
|---|---|
-| `@deepseek-ai/dsh-agent-core` | the spine, pre-creating **no** agents (ACP `session/new` creates them on demand) |
+| `@deepseek-ai/dsh-agent-spine-demo` | the spine, pre-creating **no** agents (ACP `session/new` creates them on demand) |
| `@deepseek-ai/dsh-user-interaction` | the human question/answer seam used by clients that can complete ACP elicitation requests |
| `@deepseek-ai/dsh-session-persistence-jsonl` | durable JSONL session log (the bridge advertises `loadSession`) |
| `@deepseek-ai/dsh-acp` | the bridge that owns stdout for JSON-RPC and provides ACP-backed user answers when a leaf explicitly exposes a user-question tool |
@@ -28,15 +28,15 @@ Because the package wires no logger entry, an ACP leaf has **nothing to get wron
| `model` | (required) | the per-session agent template the bridge creates agents from |
| `persona` | — | the deployment persona template (may reference `{{model}}`/`{{cwd}}`), routed to `dsh-system-prompt` |
| `toolOrder` | — | explicit model-facing tool order (a name list with one `''` rest entry; absent — lexicographic; an unregistered name fails each turn at prompt assembly), routed to `dsh-system-prompt` |
-| `tools` | `{ mode: 'native' }` | tool-registry presentation config (`native` / `code` / `both`), routed through `dsh-agent-core` |
-| `skills` | owner defaults | registry-cache, local-provider, and model-facing skill-tool config, routed through `dsh-agent-core` |
+| `tools` | `{ mode: 'native' }` | tool-registry presentation config (`native` / `code` / `both`), routed through `dsh-agent-spine-demo` |
+| `skills` | owner defaults | registry-cache, local-provider, and model-facing skill-tool config, routed through `dsh-agent-spine-demo` |
| `persistenceRoot` | `./.sessions` | the JSONL backend's root directory |
The leaf supplies the swappable backends: an LLM adapter (`llm-deepseek` for the real model, `llm-replay` for keyless snapshot replay) and a bash executor.
## The bin
-`dsh-acp-agent [--config path-to-cordis.yml]` (short form `-c`; default `./cordis.yml`):
+`dsh-acp-demo [--config path-to-cordis.yml]` (short form `-c`; default `./cordis.yml`):
- loads a gitignored `.env` from the cwd — **skipped** in snapshot REPLAY so a stray key can never trigger a live call;
- honors `DSH_SNAPSHOT=replay` by booting the sibling `cordis.snapshot.yml` (the keyless replay tree, `llm-replay` in place of `llm-deepseek`);
@@ -48,7 +48,7 @@ All diagnostics go to **stderr** — stdout is the protocol.
## Model Experience
-Indirectly, through `dsh-agent-core` and `dsh-acp`, which compose each ACP agent's prompt, tools, and message history; this app bundle adds no model-bound content itself.
+Indirectly, through `dsh-agent-spine-demo` and `dsh-acp`, which compose each ACP agent's prompt, tools, and message history; this app bundle adds no model-bound content itself.
## Known Limitations and Deferred Work
diff --git a/packages/ui/acp-agent/package.json b/packages/examples/acp-demo/package.json
similarity index 79%
rename from packages/ui/acp-agent/package.json
rename to packages/examples/acp-demo/package.json
index 0c1a45e713..3c4851c961 100644
--- a/packages/ui/acp-agent/package.json
+++ b/packages/examples/acp-demo/package.json
@@ -1,13 +1,13 @@
{
- "name": "@deepseek-ai/dsh-acp-agent",
- "description": "ACP server app: the agent-core spine + JSONL persistence + the ACP bridge (no stdout logger, no hmr, no pre-created agents), with a bin to boot a leaf cordis.yml over JSON-RPC stdio",
+ "name": "@deepseek-ai/dsh-acp-demo",
+ "description": "ACP server app: the agent-spine-demo bundle + JSONL persistence + the ACP bridge (no stdout logger, no hmr, no pre-created agents), with a bin to boot a leaf cordis.yml over JSON-RPC stdio",
"version": "0.0.1",
"private": true,
"type": "module",
"main": "lib/index.js",
"types": "lib/types/index.d.ts",
"bin": {
- "dsh-acp-agent": "lib/bin.js"
+ "dsh-acp-demo": "lib/bin.js"
},
"exports": {
".": {
@@ -34,7 +34,7 @@
"@cordisjs/plugin-loader": "^1.0.0-rc.5",
"@deepseek-ai/dsh-app-boot": "^0.0.1",
"@deepseek-ai/dsh-acp": "^0.0.1",
- "@deepseek-ai/dsh-agent-core": "^0.0.1",
+ "@deepseek-ai/dsh-agent-spine-demo": "^0.0.1",
"@deepseek-ai/dsh-session-persistence-jsonl": "^0.0.1",
"@deepseek-ai/dsh-tools": "^0.0.1",
"@deepseek-ai/dsh-user-interaction": "^0.0.1",
@@ -47,7 +47,7 @@
"@deepseek-ai/dsh-app-boot": "workspace:^",
"@deepseek-ai/dsh-acp": "workspace:^",
"@deepseek-ai/dsh-agent": "workspace:^",
- "@deepseek-ai/dsh-agent-core": "workspace:^",
+ "@deepseek-ai/dsh-agent-spine-demo": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-session-persistence-jsonl": "workspace:^",
diff --git a/packages/ui/acp-agent/src/bin.ts b/packages/examples/acp-demo/src/bin.ts
similarity index 89%
rename from packages/ui/acp-agent/src/bin.ts
rename to packages/examples/acp-demo/src/bin.ts
index 62e562ad58..60127760e4 100644
--- a/packages/ui/acp-agent/src/bin.ts
+++ b/packages/examples/acp-demo/src/bin.ts
@@ -1,19 +1,19 @@
#!/usr/bin/env node
/**
* Boot an ACP stdio server from `cordis.yml`; usage is
- * `dsh-acp-agent [--config path]`, defaulting to `./cordis.yml`. Shared env
+ * `dsh-acp-demo [--config path]`, defaulting to `./cordis.yml`. Shared env
* loading, Loader guards, snapshot config selection, and settled-tree boot live
* in dsh-app-boot. Replay skips `.env` and selects sibling
* `cordis.snapshot.yml` so a stray key cannot trigger a model call. EOF disposes
* and flushes snapshot runs; editors normally own process lifetime. Stdout is
* reserved for JSON-RPC, so diagnostics go only to stderr.
- * @module @deepseek-ai/dsh-acp-agent/bin
+ * @module @deepseek-ai/dsh-acp-demo/bin
*/
import { parseArgs } from 'node:util'
import { boot, installFailLoud, loadEnv, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
-const NAME = 'dsh-acp-agent'
+const NAME = 'dsh-acp-demo'
/* v8 ignore start -- thin self-executing composition over the unit-tested
dsh-app-boot helpers; exercised end-to-end by the snapshot suite and the
diff --git a/packages/ui/acp-agent/src/index.ts b/packages/examples/acp-demo/src/index.ts
similarity index 89%
rename from packages/ui/acp-agent/src/index.ts
rename to packages/examples/acp-demo/src/index.ts
index 8f76728d8f..0439363301 100644
--- a/packages/ui/acp-agent/src/index.ts
+++ b/packages/examples/acp-demo/src/index.ts
@@ -1,23 +1,23 @@
/**
- * The ACP server app: the default agent spine ({@link @deepseek-ai/dsh-agent-core}),
+ * The ACP server app: the default agent spine ({@link @deepseek-ai/dsh-agent-spine-demo}),
* JSONL session persistence, and the {@link @deepseek-ai/dsh-acp} bridge. It
* writes nothing to stdout.
* It pre-creates no agents and leaves adapters, executors, and optional tools to
* the leaf, which must likewise avoid stdout loggers. Named exports are
* required so Loader retains this plugin's `Config` schema (see
* docs/postmortem/0001).
- * @module @deepseek-ai/dsh-acp-agent
+ * @module @deepseek-ai/dsh-acp-demo
*/
import type { Context } from 'cordis'
import z from 'schemastery'
import * as acp from '@deepseek-ai/dsh-acp'
-import * as agentCore from '@deepseek-ai/dsh-agent-core'
+import * as agentCore from '@deepseek-ai/dsh-agent-spine-demo'
import ToolRegistry, { type Config as ToolsConfig } from '@deepseek-ai/dsh-tools'
import SessionPersistenceJsonl from '@deepseek-ai/dsh-session-persistence-jsonl'
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
-export const name = 'acp-agent'
+export const name = 'acp-demo'
/**
* App config: the swappable per-deployment values. `model` configures the
@@ -26,7 +26,7 @@ export const name = 'acp-agent'
* deployment persona (forwarded to the system-prompt plugin); `toolOrder` is
* the explicit model-facing tool order (forwarded to the system-prompt plugin);
* `tools` is the tool registry's config (its presentation `mode`, forwarded
- * through agent-core); `persistenceRoot` is the JSONL backend's directory.
+ * through agent-spine-demo); `persistenceRoot` is the JSONL backend's directory.
*/
export interface Config {
/** Model name for ACP-created agents (must have a registered adapter). */
@@ -35,11 +35,11 @@ export interface Config {
persona?: string
/** Explicit model-facing tool order (the system-prompt plugin's `toolOrder` config; see dsh-system-prompt). */
toolOrder?: string[]
- /** Tool-registry config — its presentation `mode` (forwarded through agent-core; see dsh-tools). */
+ /** Tool-registry config — its presentation `mode` (forwarded through agent-spine-demo; see dsh-tools). */
tools?: ToolsConfig
/** Directory the JSONL session backend writes under. Defaults to `./.sessions`. */
persistenceRoot?: string
- /** Skill registry, local-provider, and model-facing consumer config forwarded to agent-core. */
+ /** Skill registry, local-provider, and model-facing consumer config forwarded to agent-spine-demo. */
skills?: agentCore.SkillConfig
}
@@ -62,7 +62,7 @@ export const Config: z = z.object({
/* jscpd:ignore-end */
/**
- * Compose the spine with the ACP front door. The agent-core bundle pre-creates
+ * Compose the spine with the ACP front door. The agent-spine-demo bundle pre-creates
* NO agents (its `agents` list defaults to `[]`) and carries the deployment
* `persona`; the JSONL backend persists under `persistenceRoot`; the ACP
* bridge owns stdout for JSON-RPC and creates one agent per `session/new`
diff --git a/packages/ui/acp-agent/tests/acp-agent.spec.ts b/packages/examples/acp-demo/tests/acp-agent.spec.ts
similarity index 93%
rename from packages/ui/acp-agent/tests/acp-agent.spec.ts
rename to packages/examples/acp-demo/tests/acp-agent.spec.ts
index 52f62d8ac8..bb096776ff 100644
--- a/packages/ui/acp-agent/tests/acp-agent.spec.ts
+++ b/packages/examples/acp-demo/tests/acp-agent.spec.ts
@@ -10,7 +10,7 @@ import type { Message } from '@deepseek-ai/dsh-llm'
import * as acpAgent from '../src/index.ts'
/**
- * In-process unit coverage for the @deepseek-ai/dsh-acp-agent composition:
+ * In-process unit coverage for the @deepseek-ai/dsh-acp-demo composition:
* mounting it brings up the agent-core spine + JSONL persistence + the ACP
* bridge in one `ctx.plugin`. Unlike the stdio app, this one loads NO
* Loader-only plugin (no hmr), so it mounts in a plain Context.
@@ -29,7 +29,7 @@ async function mount(config: acpAgent.Config): Promise {
}
async function isolatedSkillsConfig(catalogDescriptionMaxLength?: number): Promise> {
- const home = await mkdtemp(join(tmpdir(), 'dsh-acp-agent-skills-'))
+ const home = await mkdtemp(join(tmpdir(), 'dsh-acp-demo-skills-'))
return {
local: { dshHome: join(home, '.dsh'), agentsHome: join(home, '.agents') },
...catalogDescriptionMaxLength !== undefined ? { tool: { catalogDescriptionMaxLength } } : {},
@@ -48,7 +48,7 @@ async function composePrefix(ctx: Context): Promise {
async function withIsolatedSkillHomes(run: () => Promise): Promise {
const oldDshHome = process.env.DSH_HOME
const oldAgentsHome = process.env.DSH_AGENTS_HOME
- const home = await mkdtemp(join(tmpdir(), 'dsh-acp-agent-default-skills-'))
+ const home = await mkdtemp(join(tmpdir(), 'dsh-acp-demo-default-skills-'))
process.env.DSH_HOME = join(home, '.dsh')
process.env.DSH_AGENTS_HOME = join(home, '.agents')
try {
@@ -67,9 +67,9 @@ async function withIsolatedSkillHomes(run: () => Promise): Promise {
}
}
-describe('dsh-acp-agent composition', () => {
+describe('dsh-acp-demo composition', () => {
it('brings up the spine + persistence + the ACP bridge', async () => {
- const ctx = await mount({ model: 'mock', persona: 'hi', persistenceRoot: '/tmp/dsh-acp-agent-test', skills: await isolatedSkillsConfig() })
+ const ctx = await mount({ model: 'mock', persona: 'hi', persistenceRoot: '/tmp/dsh-acp-demo-test', skills: await isolatedSkillsConfig() })
expect(ctx.get('agents')).toBeDefined()
expect(ctx.get('sessions')).toBeDefined()
expect(ctx.get('sessionPersistence')).toBeDefined()
@@ -121,7 +121,7 @@ describe('dsh-acp-agent composition', () => {
const ctx = await mount({
model: 'mock',
toolOrder: ['zulu', TOOL_ORDER_REST],
- persistenceRoot: '/tmp/dsh-acp-agent-test-tool-order',
+ persistenceRoot: '/tmp/dsh-acp-demo-test-tool-order',
})
// The bundle's own bash tools pend on the absent `ctx.bash` executor in
// this providerless mount, so register two plain tools to order.
diff --git a/packages/ui/acp-agent/tests/built-bin.e2e.ts b/packages/examples/acp-demo/tests/built-bin.e2e.ts
similarity index 95%
rename from packages/ui/acp-agent/tests/built-bin.e2e.ts
rename to packages/examples/acp-demo/tests/built-bin.e2e.ts
index b31082fa23..7b5749fee5 100644
--- a/packages/ui/acp-agent/tests/built-bin.e2e.ts
+++ b/packages/examples/acp-demo/tests/built-bin.e2e.ts
@@ -25,14 +25,14 @@ import { afterEach, describe, expect, it } from 'vitest'
*/
const repoRoot = fileURLToPath(new URL('../../../../', import.meta.url))
-const acpBin = join(repoRoot, 'packages/ui/acp-agent/lib/bin.js')
+const acpBin = join(repoRoot, 'packages/examples/acp-demo/lib/bin.js')
const dshPackages = [
- 'core/agent-core', 'core/agent', 'core/session', 'core/system-prompt',
+ 'examples/agent-spine-demo', 'core/agent', 'core/session', 'core/system-prompt',
'core/tools', 'core/agent-loop', 'llm/llm', 'llm/llm-deepseek', 'bash/bash',
'bash/bash-local', 'bash/tool-bash', 'support/invariants', 'ui/app-boot',
'session-persistence/session-persistence',
- 'session-persistence/session-persistence-jsonl', 'ui/acp', 'ui/acp-agent',
+ 'session-persistence/session-persistence-jsonl', 'ui/acp', 'examples/acp-demo',
]
const vendorPackages = [
'cordis', 'loader', 'include', 'timer', 'hmr', 'logger-console',
@@ -82,7 +82,7 @@ async function makeConsumer(): Promise {
'- id: bash',
' name: \'@deepseek-ai/dsh-bash-local\'',
'- id: acp-agent',
- ' name: \'@deepseek-ai/dsh-acp-agent\'',
+ ' name: \'@deepseek-ai/dsh-acp-demo\'',
' config:',
' model: deepseek-v4-flash',
' persona: \'test agent\'',
@@ -100,7 +100,7 @@ afterEach(async () => {
consumer = undefined
})
-describe.skipIf(!existsSync(acpBin))('dsh-acp-agent BUILT bin (node lib/bin.js, no tsx)', () => {
+describe.skipIf(!existsSync(acpBin))('dsh-acp-demo BUILT bin (node lib/bin.js, no tsx)', () => {
it('boots the published bin and answers an initialize JSON-RPC frame on stdout', async () => {
consumer = await makeConsumer()
child = spawn(process.execPath, ['--expose-internals', acpBin, '--config', './cordis.yml'], {
diff --git a/packages/ui/acp-agent/tests/load-path.e2e.ts b/packages/examples/acp-demo/tests/load-path.e2e.ts
similarity index 96%
rename from packages/ui/acp-agent/tests/load-path.e2e.ts
rename to packages/examples/acp-demo/tests/load-path.e2e.ts
index 2fd6db54d4..f1edf7832a 100644
--- a/packages/ui/acp-agent/tests/load-path.e2e.ts
+++ b/packages/examples/acp-demo/tests/load-path.e2e.ts
@@ -26,7 +26,7 @@ import {
const binScript = fileURLToPath(new URL('../src/bin.ts', import.meta.url))
const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
-// Repo root is four levels up from packages/ui/acp-agent/tests.
+// Repo root is four levels up from packages/examples/acp-demo/tests.
const repoTsconfig = fileURLToPath(new URL('../../../../tsconfig.json', import.meta.url))
// A minimal leaf that loads this app + the two backends — the same shape as
@@ -40,7 +40,7 @@ const CORDIS_YML = `
- id: bash
name: '@deepseek-ai/dsh-bash-local'
- id: acp-agent
- name: '@deepseek-ai/dsh-acp-agent'
+ name: '@deepseek-ai/dsh-acp-demo'
config:
model: deepseek-v4-flash
persona: 'You are a test agent.'
@@ -105,7 +105,7 @@ async function boot(): Promise {
return { ...spawned, cwd }
}
-describe('dsh-acp-agent real-load-path smoke (bin + Loader, keyless)', () => {
+describe('dsh-acp-demo real-load-path smoke (bin + Loader, keyless)', () => {
it('boots via its bin and answers initialize → session/new → session/load', async () => {
const { client, cwd, stderr } = await boot()
// initialize: a broken export shape (collapsed bridge plugin, dropped inject)
diff --git a/packages/ui/acp-agent/tsconfig.json b/packages/examples/acp-demo/tsconfig.json
similarity index 74%
rename from packages/ui/acp-agent/tsconfig.json
rename to packages/examples/acp-demo/tsconfig.json
index 5eb1c62282..6805405026 100644
--- a/packages/ui/acp-agent/tsconfig.json
+++ b/packages/examples/acp-demo/tsconfig.json
@@ -18,22 +18,22 @@
"path": "../../../vendor/loader"
},
{
- "path": "../app-boot"
+ "path": "../../ui/app-boot"
},
{
- "path": "../acp"
+ "path": "../../ui/acp"
},
{
"path": "../../core/agent"
},
{
- "path": "../../core/agent-core"
+ "path": "../agent-spine-demo"
},
{
- "path": "../user-interaction"
+ "path": "../../ui/user-interaction"
},
{
- "path": "../tool-ask-user"
+ "path": "../../ui/tool-ask-user"
},
{
"path": "../../session-persistence/session-persistence-jsonl"
diff --git a/packages/ui/acp-agent/tsdown.config.ts b/packages/examples/acp-demo/tsdown.config.ts
similarity index 100%
rename from packages/ui/acp-agent/tsdown.config.ts
rename to packages/examples/acp-demo/tsdown.config.ts
diff --git a/packages/core/agent-core/README.md b/packages/examples/agent-spine-demo/README.md
similarity index 91%
rename from packages/core/agent-core/README.md
rename to packages/examples/agent-spine-demo/README.md
index fac4f4819a..a85f3e0889 100644
--- a/packages/core/agent-core/README.md
+++ b/packages/examples/agent-spine-demo/README.md
@@ -1,4 +1,4 @@
-# @deepseek-ai/dsh-agent-core
+# @deepseek-ai/dsh-agent-spine-demo
The **default executor-less, UI-less agent spine** as ONE Cordis bundle plugin. It loads the fixed set of services every harness agent needs, including the local skill provider, and forwards the loop's `agents` list as its own config — so an app package composes a working agent by adding only a front door and the swappable backends.
@@ -31,14 +31,14 @@ The spine is everything COMMON to every front door. The swappable and front-door
- **the LLM adapter** — the bundle ships the abstract `llm` service; the leaf registers a concrete adapter on `ctx.llm` (`llm-deepseek`, `llm-pi-ai`, `llm-replay`).
- **the bash executor** — the bundle ships `tool-bash` (the consumer schema); the leaf provides `ctx.bash` (`bash-local` or a sandboxed impl).
- **non-local skill providers** — the bundle ships the skill registry, the local filesystem provider, and the `skill` tool; deployments can add other providers such as embedded or remote catalogs as siblings.
-- **presentation + per-app infra** — the stdio UI / ACP bridge, a console logger, `hmr`. These form the coupled "front-door cluster" that the app packages ([`dsh-stdio-agent`](../../ui/stdio-agent/README.md), [`dsh-acp-agent`](../../ui/acp-agent/README.md)) bake in. `timer` is in the spine (common to both, stdout-silent); a console logger is NOT (it writes to stdout, which the ACP bridge reserves for JSON-RPC).
+- **presentation + per-app infra** — the stdio UI / ACP bridge, a console logger, `hmr`. These form the coupled "front-door cluster" that the app packages ([`dsh-stdio-demo`](../../examples/stdio-demo/README.md), [`dsh-acp-demo`](../../examples/acp-demo/README.md)) bake in. `timer` is in the spine (common to both, stdout-silent); a console logger is NOT (it writes to stdout, which the ACP bridge reserves for JSON-RPC).
This is the [interface/implementation/consumer seam](../../../docs/rfc/implemented/architecture/2026-06-13-capability-seams.md) raised to the composition level: the bundle owns the shared spine, the leaf owns the backends, the app package owns the front door.
## Config
```ts
-import type { Config } from '@deepseek-ai/dsh-agent-core'
+import type { Config } from '@deepseek-ai/dsh-agent-spine-demo'
// { agents?, persona?, toolOrder?, tools?, skills? } — the schema intersects the owner schemas,
// so validation and defaulting can never drift from the owners.
```
diff --git a/packages/core/agent-core/package.json b/packages/examples/agent-spine-demo/package.json
similarity index 97%
rename from packages/core/agent-core/package.json
rename to packages/examples/agent-spine-demo/package.json
index 2c2b25e772..049530872a 100644
--- a/packages/core/agent-core/package.json
+++ b/packages/examples/agent-spine-demo/package.json
@@ -1,5 +1,5 @@
{
- "name": "@deepseek-ai/dsh-agent-core",
+ "name": "@deepseek-ai/dsh-agent-spine-demo",
"description": "The default executor-less/UI-less agent spine as one Cordis bundle plugin (timer + llm + sessions + system-prompt + tools + skills + agents + invariants + tool-bash + tool-skill + agent-loop)",
"version": "0.0.1",
"private": true,
diff --git a/packages/core/agent-core/src/index.ts b/packages/examples/agent-spine-demo/src/index.ts
similarity index 98%
rename from packages/core/agent-core/src/index.ts
rename to packages/examples/agent-spine-demo/src/index.ts
index 14ffbd6133..d1aecaa4c0 100644
--- a/packages/core/agent-core/src/index.ts
+++ b/packages/examples/agent-spine-demo/src/index.ts
@@ -4,7 +4,7 @@
* deployments still choose the LLM adapter, bash executor, and presentation.
* The plugin intentionally exposes named exports only because Loader default
* unwrapping would discard its `Config` schema (see docs/postmortem/0001).
- * @module @deepseek-ai/dsh-agent-core
+ * @module @deepseek-ai/dsh-agent-spine-demo
*/
import type { Context } from 'cordis'
@@ -22,7 +22,7 @@ import * as toolBash from '@deepseek-ai/dsh-tool-bash'
import * as toolSkill from '@deepseek-ai/dsh-tool-skill'
import AgentLoop, { type Config as AgentLoopConfig } from '@deepseek-ai/dsh-agent-loop'
-export const name = 'agent-core'
+export const name = 'agent-spine-demo'
/** Skill bundle config forwarded to the registry, local provider, and model-facing consumer. */
export interface SkillConfig {
diff --git a/packages/core/agent-core/tests/agent-core.spec.ts b/packages/examples/agent-spine-demo/tests/agent-core.spec.ts
similarity index 94%
rename from packages/core/agent-core/tests/agent-core.spec.ts
rename to packages/examples/agent-spine-demo/tests/agent-core.spec.ts
index 0bf0660364..38f046c6c6 100644
--- a/packages/core/agent-core/tests/agent-core.spec.ts
+++ b/packages/examples/agent-spine-demo/tests/agent-core.spec.ts
@@ -19,7 +19,7 @@ async function composePrefix(ctx: Context, cwd: string): Promise {
}
/**
- * Unit coverage for the @deepseek-ai/dsh-agent-core bundle: mounting it brings
+ * Unit coverage for the @deepseek-ai/dsh-agent-spine-demo bundle: mounting it brings
* up the whole default spine in one `ctx.plugin`, and the forwarded
* `agents` config reaches the loop (default `[]`, or a pre-created agent).
*
@@ -31,8 +31,8 @@ async function composePrefix(ctx: Context, cwd: string): Promise {
async function mount(config?: agentCore.Config): Promise {
const oldDshHome = process.env.DSH_HOME
const oldAgentsHome = process.env.DSH_AGENTS_HOME
- process.env.DSH_HOME = await mkdtemp(join(tmpdir(), 'dsh-agent-core-home-'))
- process.env.DSH_AGENTS_HOME = await mkdtemp(join(tmpdir(), 'dsh-agent-core-agents-'))
+ process.env.DSH_HOME = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-home-'))
+ process.env.DSH_AGENTS_HOME = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-agents-'))
const ctx = new Context()
try {
await ctx.plugin(agentCore, config)
@@ -57,8 +57,8 @@ async function mount(config?: agentCore.Config): Promise {
async function withIsolatedSkillHomes(run: () => Promise): Promise {
const oldDshHome = process.env.DSH_HOME
const oldAgentsHome = process.env.DSH_AGENTS_HOME
- process.env.DSH_HOME = await mkdtemp(join(tmpdir(), 'dsh-agent-core-home-'))
- process.env.DSH_AGENTS_HOME = await mkdtemp(join(tmpdir(), 'dsh-agent-core-agents-'))
+ process.env.DSH_HOME = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-home-'))
+ process.env.DSH_AGENTS_HOME = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-agents-'))
try {
return await run()
} finally {
@@ -75,7 +75,7 @@ async function withIsolatedSkillHomes(run: () => Promise): Promise {
}
}
-describe('dsh-agent-core bundle', () => {
+describe('dsh-agent-spine-demo bundle', () => {
it('brings up the full default spine', async () => {
const ctx = await mount()
// One service from each layer of the spine proves the children loaded.
@@ -131,9 +131,9 @@ describe('dsh-agent-core bundle', () => {
})
it('forwards skill config to the registry, local provider, and model-facing consumer', async () => {
- const home = await mkdtemp(join(tmpdir(), 'dsh-agent-core-skill-home-'))
- const agentsHome = await mkdtemp(join(tmpdir(), 'dsh-agent-core-skill-agents-'))
- const custom = await mkdtemp(join(tmpdir(), 'dsh-agent-core-skill-custom-'))
+ const home = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-skill-home-'))
+ const agentsHome = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-skill-agents-'))
+ const custom = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-skill-custom-'))
await mkdir(custom, { recursive: true })
await writeFile(join(custom, 'custom-skill.md'), '---\nname: custom-skill\ndescription: Custom skill\n---\n\nCustom body.\n')
const ctx = await mount({
diff --git a/packages/core/agent-core/tests/gen-config-catalog.spec.ts b/packages/examples/agent-spine-demo/tests/gen-config-catalog.spec.ts
similarity index 100%
rename from packages/core/agent-core/tests/gen-config-catalog.spec.ts
rename to packages/examples/agent-spine-demo/tests/gen-config-catalog.spec.ts
diff --git a/packages/core/agent-core/tsconfig.json b/packages/examples/agent-spine-demo/tsconfig.json
similarity index 100%
rename from packages/core/agent-core/tsconfig.json
rename to packages/examples/agent-spine-demo/tsconfig.json
diff --git a/packages/ui/jsonrpc-agent/README.md b/packages/examples/jsonrpc-demo/README.md
similarity index 98%
rename from packages/ui/jsonrpc-agent/README.md
rename to packages/examples/jsonrpc-demo/README.md
index 4ced8d038a..ef717f1e16 100644
--- a/packages/ui/jsonrpc-agent/README.md
+++ b/packages/examples/jsonrpc-demo/README.md
@@ -1,4 +1,4 @@
-# @deepseek-ai/dsh-jsonrpc-agent
+# @deepseek-ai/dsh-jsonrpc-demo
Bin-only app that boots an external `cordis.yml`; its [`jsonrpc`](../jsonrpc/README.md) entry serves SDK clients over newline-delimited stdio. The config composes the spine, backends, and serving plugin. `lib/bin.js` is also the [single-executable runtime](../../../docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md) entry.
diff --git a/packages/ui/jsonrpc-agent/package.json b/packages/examples/jsonrpc-demo/package.json
similarity index 95%
rename from packages/ui/jsonrpc-agent/package.json
rename to packages/examples/jsonrpc-demo/package.json
index 1919a7336a..3b04fcc977 100644
--- a/packages/ui/jsonrpc-agent/package.json
+++ b/packages/examples/jsonrpc-demo/package.json
@@ -1,5 +1,5 @@
{
- "name": "@deepseek-ai/dsh-jsonrpc-agent",
+ "name": "@deepseek-ai/dsh-jsonrpc-demo",
"description": "Bin that boots an external Cordis config for the stdio JSON-RPC SDK runtime",
"version": "0.0.1",
"private": true,
diff --git a/packages/ui/jsonrpc-agent/src/bin.ts b/packages/examples/jsonrpc-demo/src/bin.ts
similarity index 97%
rename from packages/ui/jsonrpc-agent/src/bin.ts
rename to packages/examples/jsonrpc-demo/src/bin.ts
index 09af1028b9..ad17709efc 100644
--- a/packages/ui/jsonrpc-agent/src/bin.ts
+++ b/packages/examples/jsonrpc-demo/src/bin.ts
@@ -7,7 +7,7 @@
* stdin EOF and SIGTERM dispose the root context and exit 0; SIGINT exits 130.
* Protocol `shutdown` belongs to the server plugin. Stdout is reserved for frames.
*
- * @module @deepseek-ai/dsh-jsonrpc-agent/bin
+ * @module @deepseek-ai/dsh-jsonrpc-demo/bin
*/
import { existsSync } from 'node:fs'
diff --git a/packages/ui/jsonrpc-agent/src/index.ts b/packages/examples/jsonrpc-demo/src/index.ts
similarity index 85%
rename from packages/ui/jsonrpc-agent/src/index.ts
rename to packages/examples/jsonrpc-demo/src/index.ts
index 032644a7c9..d4a4017f62 100644
--- a/packages/ui/jsonrpc-agent/src/index.ts
+++ b/packages/examples/jsonrpc-demo/src/index.ts
@@ -3,7 +3,7 @@
* process exit. This module exports no composition plugin; the config chooses
* whether to load the {@link @deepseek-ai/dsh-jsonrpc} serving plugin.
*
- * @module @deepseek-ai/dsh-jsonrpc-agent
+ * @module @deepseek-ai/dsh-jsonrpc-demo
*/
export {}
diff --git a/packages/ui/jsonrpc-agent/tsconfig.json b/packages/examples/jsonrpc-demo/tsconfig.json
similarity index 89%
rename from packages/ui/jsonrpc-agent/tsconfig.json
rename to packages/examples/jsonrpc-demo/tsconfig.json
index e76defe8e2..83d6cf5aa2 100644
--- a/packages/ui/jsonrpc-agent/tsconfig.json
+++ b/packages/examples/jsonrpc-demo/tsconfig.json
@@ -15,7 +15,7 @@
"path": "../../../vendor/loader"
},
{
- "path": "../app-boot"
+ "path": "../../ui/app-boot"
}
]
}
diff --git a/packages/ui/jsonrpc-agent/tsdown.config.ts b/packages/examples/jsonrpc-demo/tsdown.config.ts
similarity index 100%
rename from packages/ui/jsonrpc-agent/tsdown.config.ts
rename to packages/examples/jsonrpc-demo/tsdown.config.ts
diff --git a/packages/ui/stdio-agent/README.md b/packages/examples/stdio-demo/README.md
similarity index 73%
rename from packages/ui/stdio-agent/README.md
rename to packages/examples/stdio-demo/README.md
index 45e09c8dd6..5087a2fca0 100644
--- a/packages/ui/stdio-agent/README.md
+++ b/packages/examples/stdio-demo/README.md
@@ -1,8 +1,8 @@
-# @deepseek-ai/dsh-stdio-agent
+# @deepseek-ai/dsh-stdio-demo
-The **terminal stdio chat app**: a Cordis app plugin that composes the default agent spine ([`@deepseek-ai/dsh-agent-core`](../../core/agent-core/README.md)) with the front-door cluster a terminal chat needs, and a `bin` that boots a leaf `cordis.yml`.
+The **terminal stdio chat app**: a Cordis app plugin that composes the default agent spine ([`@deepseek-ai/dsh-agent-spine-demo`](../../examples/agent-spine-demo/README.md)) with the front-door cluster a terminal chat needs, and a `bin` that boots a leaf `cordis.yml`.
-It is the readline counterpart to [`@deepseek-ai/dsh-acp-agent`](../acp-agent/README.md): both consume the same spine, but each bakes in the OPPOSITE front-door cluster.
+It is the readline counterpart to [`@deepseek-ai/dsh-acp-demo`](../acp-demo/README.md): both consume the same spine, but each bakes in the OPPOSITE front-door cluster.
## What it bakes in
@@ -11,7 +11,7 @@ A terminal chat always wants the same cluster, so the package owns it rather tha
| Plugin | Why it is here |
|---|---|
| `@cordisjs/plugin-logger-console` | the console logger — stdout is just the terminal here, so logging to it is correct (the ACP app must NOT have this) |
-| `@deepseek-ai/dsh-agent-core` | the spine, pre-creating a `main` agent from this app's `model` with `process.cwd()` as the fresh session cwd and carrying its `persona` |
+| `@deepseek-ai/dsh-agent-spine-demo` | the spine, pre-creating a `main` agent from this app's `model` with `process.cwd()` as the fresh session cwd and carrying its `persona` |
| `@deepseek-ai/dsh-session-persistence-jsonl` | durable JSONL session log under `persistenceRoot` |
| `@deepseek-ai/dsh-user-interaction` | the human question/answer seam used by confirmation tools |
| `@deepseek-ai/dsh-tool-ask-user` | the model-facing `ask_user_question` tool |
@@ -28,17 +28,17 @@ The leaf `cordis.yml` supplies only the **swappable backends** — an LLM adapte
| `model` | (required) | the pre-created `main` agent's model |
| `persona` | — | the deployment persona template (may reference `{{model}}`/`{{cwd}}`), routed to `dsh-system-prompt` |
| `toolOrder` | — | explicit model-facing tool order (a name list with one `''` rest entry; absent — lexicographic; an unregistered name fails each turn at prompt assembly), routed to `dsh-system-prompt` |
-| `tools` | `{ mode: 'native' }` | tool-registry presentation config (`native` / `code` / `both`), routed through `dsh-agent-core` |
-| `skills` | owner defaults | registry-cache, local-provider, and model-facing skill-tool config, routed through `dsh-agent-core` |
+| `tools` | `{ mode: 'native' }` | tool-registry presentation config (`native` / `code` / `both`), routed through `dsh-agent-spine-demo` |
+| `skills` | owner defaults | registry-cache, local-provider, and model-facing skill-tool config, routed through `dsh-agent-spine-demo` |
| `persistenceRoot` | `./.sessions` | the JSONL backend's root directory |
| `welcome` | `ready.` | the stdin-chat banner |
| `resumeSessionId` | — | resume a persisted session id instead of starting fresh (sourced from an env var in the leaf) |
-Fresh stdio sessions use the process launch directory as `session.header.cwd`, so project-scoped features such as skill discovery and default bash workdir follow the directory where `dsh-stdio-agent` was started. Resumed sessions keep the cwd stored in the persisted session header.
+Fresh stdio sessions use the process launch directory as `session.header.cwd`, so project-scoped features such as skill discovery and default bash workdir follow the directory where `dsh-stdio-demo` was started. Resumed sessions keep the cwd stored in the persisted session header.
## The bin
-`dsh-stdio-agent [path-to-cordis.yml]` (default `./cordis.yml`) loads a gitignored `.env` from the cwd (`DEEPSEEK_API_KEY` / `DEEPSEEK_BASE_URL`), then drives the cordis Loader against the config and awaits the whole plugin tree before returning. Run it under `node --expose-internals`, or install the Loader's optional `node-addon-require-builtin` fallback, so the Loader can resolve the config's bare plugin specifiers (`@deepseek-ai/dsh-*`, npm packages). The `demo:echo` / `demo:repl` scripts use `--expose-internals`.
+`dsh-stdio-demo [path-to-cordis.yml]` (default `./cordis.yml`) loads a gitignored `.env` from the cwd (`DEEPSEEK_API_KEY` / `DEEPSEEK_BASE_URL`), then drives the cordis Loader against the config and awaits the whole plugin tree before returning. Run it under `node --expose-internals`, or install the Loader's optional `node-addon-require-builtin` fallback, so the Loader can resolve the config's bare plugin specifiers (`@deepseek-ai/dsh-*`, npm packages). The `demo:echo` / `demo:repl` scripts use `--expose-internals`.
## Example leaf `cordis.yml`
@@ -58,7 +58,7 @@ Fresh stdio sessions use the process launch directory as `session.header.cwd`, s
config:
timeoutMs: 60000
- id: stdio-agent
- name: '@deepseek-ai/dsh-stdio-agent'
+ name: '@deepseek-ai/dsh-stdio-demo'
config:
model: deepseek-v4-flash
persona: 'You are a coding assistant powered by the {{model}} model.'
@@ -70,7 +70,7 @@ Swap `llm-deepseek` for a `mock-llm` leaf plugin and you have the echo demo —
### Composed terminal agent request
-**What the model sees**: Through `dsh-agent-core`, the `main` agent receives the harness identity, configured persona, skill catalog, and visible tools; this app also composes the generated [`ask_user_question` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-ask-user). Each readline submission becomes a user message.
+**What the model sees**: Through `dsh-agent-spine-demo`, the `main` agent receives the harness identity, configured persona, skill catalog, and visible tools; this app also composes the generated [`ask_user_question` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-ask-user). Each readline submission becomes a user message.
**Token effect**: Child prompt and schema costs repeat per request; user input and tool history grow until compaction. The welcome banner, logger output, and rendered transcript are terminal-only and add zero model tokens.
diff --git a/packages/ui/stdio-agent/package.json b/packages/examples/stdio-demo/package.json
similarity index 84%
rename from packages/ui/stdio-agent/package.json
rename to packages/examples/stdio-demo/package.json
index 5861ae2b12..3fe11f47a2 100644
--- a/packages/ui/stdio-agent/package.json
+++ b/packages/examples/stdio-demo/package.json
@@ -1,13 +1,13 @@
{
- "name": "@deepseek-ai/dsh-stdio-agent",
- "description": "Terminal stdio chat app: the agent-core spine + console logger + readline UI + a pre-created main agent, with a bin to boot a leaf cordis.yml",
+ "name": "@deepseek-ai/dsh-stdio-demo",
+ "description": "Terminal stdio chat app: the agent-spine-demo bundle + console logger + readline UI + a pre-created main agent, with a bin to boot a leaf cordis.yml",
"version": "0.0.1",
"private": true,
"type": "module",
"main": "lib/index.js",
"types": "lib/types/index.d.ts",
"bin": {
- "dsh-stdio-agent": "lib/bin.js"
+ "dsh-stdio-demo": "lib/bin.js"
},
"exports": {
".": {
@@ -36,7 +36,7 @@
"@cordisjs/plugin-logger-console": "^1.0.0",
"@deepseek-ai/dsh-agent": "^0.0.1",
"@deepseek-ai/dsh-llm": "^0.0.1",
- "@deepseek-ai/dsh-agent-core": "^0.0.1",
+ "@deepseek-ai/dsh-agent-spine-demo": "^0.0.1",
"@deepseek-ai/dsh-session": "^0.0.1",
"@deepseek-ai/dsh-session-persistence-jsonl": "^0.0.1",
"@deepseek-ai/dsh-stdio": "^0.0.1",
@@ -53,7 +53,7 @@
"@cordisjs/plugin-logger-console": "workspace:^",
"@deepseek-ai/dsh-agent": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
- "@deepseek-ai/dsh-agent-core": "workspace:^",
+ "@deepseek-ai/dsh-agent-spine-demo": "workspace:^",
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-session": "workspace:^",
"@deepseek-ai/dsh-session-persistence-jsonl": "workspace:^",
diff --git a/packages/ui/stdio-agent/src/bin.ts b/packages/examples/stdio-demo/src/bin.ts
similarity index 85%
rename from packages/ui/stdio-agent/src/bin.ts
rename to packages/examples/stdio-demo/src/bin.ts
index f3eaf5cf34..462e821e50 100644
--- a/packages/ui/stdio-agent/src/bin.ts
+++ b/packages/examples/stdio-demo/src/bin.ts
@@ -1,14 +1,14 @@
#!/usr/bin/env node
/**
- * Boot a stdio app from a leaf `cordis.yml`; usage is `dsh-stdio-agent [config]`, defaulting to the
+ * Boot a stdio app from a leaf `cordis.yml`; usage is `dsh-stdio-demo [config]`, defaulting to the
* cwd file. Shared `.env` loading, fail-loud Loader guards, and settled-tree boot live in
* dsh-app-boot. The echo and REPL demos invoke this bin with their own leaf configs.
- * @module @deepseek-ai/dsh-stdio-agent/bin
+ * @module @deepseek-ai/dsh-stdio-demo/bin
*/
import { boot, installFailLoud, loadEnv, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
-const NAME = 'dsh-stdio-agent'
+const NAME = 'dsh-stdio-demo'
/* v8 ignore start -- thin self-executing composition over the unit-tested
dsh-app-boot helpers; exercised end-to-end by the keyless Loader-path and
diff --git a/packages/ui/stdio-agent/src/index.ts b/packages/examples/stdio-demo/src/index.ts
similarity index 91%
rename from packages/ui/stdio-agent/src/index.ts
rename to packages/examples/stdio-demo/src/index.ts
index fb125cec56..89f4142af6 100644
--- a/packages/ui/stdio-agent/src/index.ts
+++ b/packages/examples/stdio-demo/src/index.ts
@@ -1,12 +1,12 @@
/**
- * The stdio chat app: the default agent spine ({@link @deepseek-ai/dsh-agent-core}) plus the
+ * The stdio chat app: the default agent spine ({@link @deepseek-ai/dsh-agent-spine-demo}) plus the
* coupled front-door cluster a terminal chat needs — a console logger, the independently
* packaged readline UI, JSONL session persistence, the user-interaction seam with its
* `ask_user_question` tool, and a pre-created `main` agent the UI drives.
* Swappable adapters, executors, optional tools, and HMR stay in the leaf. This
* Loader plugin intentionally exposes named exports only; a default export
* would hide its `Config` schema (see docs/postmortem/0001).
- * @module @deepseek-ai/dsh-stdio-agent
+ * @module @deepseek-ai/dsh-stdio-demo
*/
import type { Context } from 'cordis'
@@ -15,18 +15,18 @@ import z from 'schemastery'
import { AgentId } from '@deepseek-ai/dsh-agent'
import { SessionId } from '@deepseek-ai/dsh-session'
import ToolRegistry, { type Config as ToolsConfig } from '@deepseek-ai/dsh-tools'
-import * as agentCore from '@deepseek-ai/dsh-agent-core'
+import * as agentCore from '@deepseek-ai/dsh-agent-spine-demo'
import SessionPersistenceJsonl from '@deepseek-ai/dsh-session-persistence-jsonl'
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
import * as toolAskUser from '@deepseek-ai/dsh-tool-ask-user'
import * as uiStdio from '@deepseek-ai/dsh-stdio'
-export const name = 'stdio-agent'
+export const name = 'stdio-demo'
/**
* App config: the swappable per-demo values, each routed to where the app wires
* it. `model`/`resumeSessionId` configure the pre-created `main` agent (through
- * {@link @deepseek-ai/dsh-agent-core}'s forwarded `agents` list); `persona` is
+ * {@link @deepseek-ai/dsh-agent-spine-demo}'s forwarded `agents` list); `persona` is
* the deployment persona (forwarded to the system-prompt plugin); `toolOrder`
* is the explicit model-facing tool order (forwarded to the system-prompt plugin);
* fresh sessions use `process.cwd()` as their workspace cwd; resumed sessions
@@ -40,13 +40,13 @@ export interface Config {
persona?: string
/** Explicit model-facing tool order (the system-prompt plugin's `toolOrder` config; see dsh-system-prompt). */
toolOrder?: string[]
- /** Tool-registry config — its presentation `mode` (forwarded through agent-core; see dsh-tools). */
+ /** Tool-registry config — its presentation `mode` (forwarded through agent-spine-demo; see dsh-tools). */
tools?: ToolsConfig
/** Directory the JSONL session backend writes under. Defaults to `./.sessions`. */
persistenceRoot?: string
/** stdin-chat banner printed once on start. Defaults to `'ready.'`. */
welcome?: string
- /** Skill registry, local-provider, and model-facing consumer config forwarded to agent-core. */
+ /** Skill registry, local-provider, and model-facing consumer config forwarded to agent-spine-demo. */
skills?: agentCore.SkillConfig
/**
* If set, the `main` agent RESUMES this persisted session id instead of
@@ -74,7 +74,7 @@ export const Config: z = z.object({
/**
* Compose the spine with the stdio front door. The console logger comes first
- * (infra), then the agent-core bundle pre-creating the `main` agent from this
+ * (infra), then the agent-spine-demo bundle pre-creating the `main` agent from this
* app's `model`/`resumeSessionId` with the deployment `persona`, then the JSONL
* backend, then the readline UI bound to `main`. The `hmr` dev-reload plugin is
* a leaf concern (see the module doc), so it is not mounted here.
diff --git a/packages/ui/stdio-agent/tests/built-bin.e2e.ts b/packages/examples/stdio-demo/tests/built-bin.e2e.ts
similarity index 95%
rename from packages/ui/stdio-agent/tests/built-bin.e2e.ts
rename to packages/examples/stdio-demo/tests/built-bin.e2e.ts
index 0f791782e8..fdbeb2b8e4 100644
--- a/packages/ui/stdio-agent/tests/built-bin.e2e.ts
+++ b/packages/examples/stdio-demo/tests/built-bin.e2e.ts
@@ -14,16 +14,16 @@ import { afterEach, describe, expect, it } from 'vitest'
*/
const repoRoot = fileURLToPath(new URL('../../../../', import.meta.url))
-const stdioBin = join(repoRoot, 'packages/ui/stdio-agent/lib/bin.js')
+const stdioBin = join(repoRoot, 'packages/examples/stdio-demo/lib/bin.js')
// Symlink each required workspace package by package name so plain Node resolves its built `main`,
// matching an installed dependency rather than tsconfig paths.
const dshPackages = [
- 'core/agent-core', 'core/agent', 'core/session', 'core/system-prompt',
+ 'examples/agent-spine-demo', 'core/agent', 'core/session', 'core/system-prompt',
'core/tools', 'core/agent-loop', 'llm/llm', 'bash/bash', 'bash/bash-local',
'bash/tool-bash', 'support/invariants', 'ui/app-boot',
'session-persistence/session-persistence',
- 'session-persistence/session-persistence-jsonl', 'ui/stdio-agent',
+ 'session-persistence/session-persistence-jsonl', 'examples/stdio-demo',
'ui/stdio', 'ui/tool-ask-user', 'ui/user-interaction',
]
const vendorPackages = [
@@ -71,7 +71,7 @@ async function makeConsumer(welcome: string, disabledBrokenEntry = false): Promi
'- id: bash',
' name: \'@deepseek-ai/dsh-bash-local\'',
'- id: stdio-agent',
- ' name: \'@deepseek-ai/dsh-stdio-agent\'',
+ ' name: \'@deepseek-ai/dsh-stdio-demo\'',
' config:',
' model: mock-echo',
' persona: \'demo\'',
@@ -120,7 +120,7 @@ afterEach(async () => {
consumer = undefined
})
-describe.skipIf(!existsSync(stdioBin))('dsh-stdio-agent BUILT bin (node lib/bin.js, no tsx)', () => {
+describe.skipIf(!existsSync(stdioBin))('dsh-stdio-demo BUILT bin (node lib/bin.js, no tsx)', () => {
it('boots the published bin, prints its banner, and runs the echo tool round-trip', async () => {
consumer = await makeConsumer('BUILT-BIN-OK ready.')
const { stdout, code, stderr } = await runBuiltBin(consumer, './cordis.yml', 'echo hi')
diff --git a/packages/ui/stdio-agent/tests/stdio-agent.spec.ts b/packages/examples/stdio-demo/tests/stdio-agent.spec.ts
similarity index 94%
rename from packages/ui/stdio-agent/tests/stdio-agent.spec.ts
rename to packages/examples/stdio-demo/tests/stdio-agent.spec.ts
index 6bbba0e492..6c867ca393 100644
--- a/packages/ui/stdio-agent/tests/stdio-agent.spec.ts
+++ b/packages/examples/stdio-demo/tests/stdio-agent.spec.ts
@@ -25,7 +25,7 @@ async function mount(config: stdioAgent.Config): Promise {
}
async function isolatedSkillsConfig(catalogDescriptionMaxLength?: number): Promise> {
- const home = await mkdtemp(join(tmpdir(), 'dsh-stdio-agent-skills-'))
+ const home = await mkdtemp(join(tmpdir(), 'dsh-stdio-demo-skills-'))
return {
local: { dshHome: join(home, '.dsh'), agentsHome: join(home, '.agents') },
...catalogDescriptionMaxLength !== undefined ? { tool: { catalogDescriptionMaxLength } } : {},
@@ -44,7 +44,7 @@ async function composePrefix(ctx: Context): Promise {
async function withIsolatedSkillHomes(run: () => Promise): Promise {
const oldDshHome = process.env.DSH_HOME
const oldAgentsHome = process.env.DSH_AGENTS_HOME
- const home = await mkdtemp(join(tmpdir(), 'dsh-stdio-agent-default-skills-'))
+ const home = await mkdtemp(join(tmpdir(), 'dsh-stdio-demo-default-skills-'))
process.env.DSH_HOME = join(home, '.dsh')
process.env.DSH_AGENTS_HOME = join(home, '.agents')
try {
@@ -63,9 +63,9 @@ async function withIsolatedSkillHomes(run: () => Promise): Promise {
}
}
-describe('dsh-stdio-agent app', () => {
+describe('dsh-stdio-demo app', () => {
it('composes the spine + front-door cluster and pre-creates the main agent', async () => {
- const ctx = await mount({ model: 'mock', persona: 'hi', persistenceRoot: '/tmp/dsh-stdio-agent-spec', skills: await isolatedSkillsConfig() })
+ const ctx = await mount({ model: 'mock', persona: 'hi', persistenceRoot: '/tmp/dsh-stdio-demo-spec', skills: await isolatedSkillsConfig() })
// The spine services (brought up by the agent-core bundle) are all present.
expect(ctx.get('agents')).toBeDefined()
expect(ctx.get('agentLoop')).toBeDefined()
@@ -111,7 +111,7 @@ describe('dsh-stdio-agent app', () => {
const ctx = await mount({
model: 'mock',
persona: 'hi',
- persistenceRoot: '/tmp/dsh-stdio-agent-spec-resume',
+ persistenceRoot: '/tmp/dsh-stdio-demo-spec-resume',
resumeSessionId: 'no-such-session',
skills: await isolatedSkillsConfig(),
})
@@ -135,7 +135,7 @@ describe('dsh-stdio-agent app', () => {
const ctx = await mount({
model: 'mock',
toolOrder: ['zulu', TOOL_ORDER_REST],
- persistenceRoot: '/tmp/dsh-stdio-agent-spec-tool-order',
+ persistenceRoot: '/tmp/dsh-stdio-demo-spec-tool-order',
})
// The bundle's own bash tools pend on the absent `ctx.bash` executor in
// this providerless mount, so register two plain tools to order.
diff --git a/packages/ui/stdio-agent/tsconfig.json b/packages/examples/stdio-demo/tsconfig.json
similarity index 77%
rename from packages/ui/stdio-agent/tsconfig.json
rename to packages/examples/stdio-demo/tsconfig.json
index b0bfa760c3..bb360810a5 100644
--- a/packages/ui/stdio-agent/tsconfig.json
+++ b/packages/examples/stdio-demo/tsconfig.json
@@ -18,7 +18,7 @@
"path": "../../../vendor/loader"
},
{
- "path": "../app-boot"
+ "path": "../../ui/app-boot"
},
{
"path": "../../../vendor/logger-console"
@@ -30,16 +30,16 @@
"path": "../../core/session"
},
{
- "path": "../../core/agent-core"
+ "path": "../agent-spine-demo"
},
{
- "path": "../user-interaction"
+ "path": "../../ui/user-interaction"
},
{
- "path": "../stdio"
+ "path": "../../ui/stdio"
},
{
- "path": "../tool-ask-user"
+ "path": "../../ui/tool-ask-user"
},
{
"path": "../../session-persistence/session-persistence-jsonl"
diff --git a/packages/ui/stdio-agent/tsdown.config.ts b/packages/examples/stdio-demo/tsdown.config.ts
similarity index 100%
rename from packages/ui/stdio-agent/tsdown.config.ts
rename to packages/examples/stdio-demo/tsdown.config.ts
diff --git a/packages/subagent/subagent-acp/README.md b/packages/subagent/subagent-acp/README.md
index 8adf5df07b..69a5f14181 100644
--- a/packages/subagent/subagent-acp/README.md
+++ b/packages/subagent/subagent-acp/README.md
@@ -33,7 +33,7 @@ ACP advertises no start-time capabilities because this process cannot enforce th
config:
providerName: acp
command: node
- args: ['--import', 'tsx', './packages/ui/acp-agent/src/bin.ts', '--config', './examples/acp-agent/cordis.yml']
+ args: ['--import', 'tsx', './packages/examples/acp-demo/src/bin.ts', '--config', './examples/acp-agent/cordis.yml']
permission: reject
env:
DEEPSEEK_API_KEY: !!js process.env.DEEPSEEK_API_KEY
diff --git a/packages/subagent/subagent-acp/tests/subagent-acp.e2e.ts b/packages/subagent/subagent-acp/tests/subagent-acp.e2e.ts
index 73070ab585..0c20b27fa1 100644
--- a/packages/subagent/subagent-acp/tests/subagent-acp.e2e.ts
+++ b/packages/subagent/subagent-acp/tests/subagent-acp.e2e.ts
@@ -15,7 +15,7 @@ import * as acp from '../src/index.ts'
*/
// The real acp-agent example: its bin + cordis.yml (the live DeepSeek config).
-const binScript = fileURLToPath(new URL('../../../ui/acp-agent/src/bin.ts', import.meta.url))
+const binScript = fileURLToPath(new URL('../../../examples/acp-demo/src/bin.ts', import.meta.url))
const exampleConfig = fileURLToPath(new URL('../../../../examples/acp-agent/cordis.yml', import.meta.url))
const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
const repoTsconfig = fileURLToPath(new URL('../../../../tsconfig.json', import.meta.url))
diff --git a/packages/support/README.md b/packages/support/README.md
index e9c72a558d..d1bb1883ed 100644
--- a/packages/support/README.md
+++ b/packages/support/README.md
@@ -10,4 +10,4 @@ Packages that exist to serve development, testing, and the examples rather than
| `llm-replay/` | Record/replay adapter: short-circuits `llm/stream` from a recorded session JSONL (keyless snapshot tests) | (listens on `llm/stream`) |
| `subagent-mock/` | Scripted `SubagentProvider` for deterministic seam/tool tests | (registers on `ctx.subagents`) |
-`invariants` is development support but has no environment guard: it runs wherever registered, and the default `dsh-agent-core` bundle mounts it unconditionally. `llm-replay` backs the demos and the snapshot test tier under the per-file coverage gate. `acp-snapshot` carries the snapshot tier's harness/normalizer/suite machinery, while `loader-smoke` owns the parallel stdio/Loader process boundary used by keyless example e2e suites. `subagent-mock` exercises the real `ctx.subagents` load path without a model or child agent. A package graduates OUT of `support/` into a product group only when it gains documented product consumers.
+`invariants` is development support but has no environment guard: it runs wherever registered, and the default `dsh-agent-spine-demo` bundle mounts it unconditionally. `llm-replay` backs the demos and the snapshot test tier under the per-file coverage gate. `acp-snapshot` carries the snapshot tier's harness/normalizer/suite machinery, while `loader-smoke` owns the parallel stdio/Loader process boundary used by keyless example e2e suites. `subagent-mock` exercises the real `ctx.subagents` load path without a model or child agent. A package graduates OUT of `support/` into a product group only when it gains documented product consumers.
diff --git a/packages/support/acp-snapshot/README.md b/packages/support/acp-snapshot/README.md
index 644ec2853d..03254a17a0 100644
--- a/packages/support/acp-snapshot/README.md
+++ b/packages/support/acp-snapshot/README.md
@@ -21,7 +21,7 @@ const SCENARIOS: Scenario[] = [
defineAcpSnapshotSuite({
agent: { // absolute paths, resolved from the suite's own location
- binScript: fileURLToPath(new URL('../../../packages/ui/acp-agent/src/bin.ts', import.meta.url)),
+ binScript: fileURLToPath(new URL('../../../packages/examples/acp-demo/src/bin.ts', import.meta.url)),
configPath: fileURLToPath(new URL('../cordis.yml', import.meta.url)),
tsconfigPath: fileURLToPath(new URL('../../../tsconfig.json', import.meta.url)),
},
diff --git a/packages/support/acp-snapshot/src/harness.ts b/packages/support/acp-snapshot/src/harness.ts
index 7fd8cf25a8..3bae0ba279 100644
--- a/packages/support/acp-snapshot/src/harness.ts
+++ b/packages/support/acp-snapshot/src/harness.ts
@@ -37,7 +37,7 @@ const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
* them from its own `import.meta.url`.
*/
export interface AgentUnderTest {
- /** The agent bin entry (e.g. `packages/ui/acp-agent/src/bin.ts`), run unbuilt via tsx. */
+ /** The agent bin entry (e.g. `packages/examples/acp-demo/src/bin.ts`), run unbuilt via tsx. */
binScript: string
/**
* The example's live `cordis.yml`. Under `DSH_SNAPSHOT=replay` the bin swaps
diff --git a/packages/support/invariants/README.md b/packages/support/invariants/README.md
index 54fb26b333..db8cf9e231 100644
--- a/packages/support/invariants/README.md
+++ b/packages/support/invariants/README.md
@@ -2,7 +2,7 @@
Runtime event-contract assertions intended for development diagnostics. This pure-listener plugin checks relationships among session events, agent states, scoped dispatches, and model requests; it does not own or change product behavior.
-The plugin has no environment guard: it is active wherever it is registered. The default [`dsh-agent-core`](../../core/agent-core/README.md) bundle mounts it unconditionally; a custom composition can omit it when the runtime cost is undesirable. It doubles as executable documentation of the event taxonomy — the assertions *are* the contract.
+The plugin has no environment guard: it is active wherever it is registered. The default [`dsh-agent-spine-demo`](../../examples/agent-spine-demo/README.md) bundle mounts it unconditionally; a custom composition can omit it when the runtime cost is undesirable. It doubles as executable documentation of the event taxonomy — the assertions *are* the contract.
Session itself owns immutable log storage in every composition: it takes one lossless JSON snapshot of each accepted event, deep-freezes that record, and exposes the log through immutable array snapshots. The invariants plugin checks the cross-record and cross-seam rules that storage immutability cannot express.
diff --git a/packages/support/invariants/src/index.ts b/packages/support/invariants/src/index.ts
index 8da5429b06..d6e2b37946 100644
--- a/packages/support/invariants/src/index.ts
+++ b/packages/support/invariants/src/index.ts
@@ -2,7 +2,7 @@
* Runtime listeners that fail loudly when cross-event contracts are broken:
* turn and step nesting, scoped dispatch, status transitions, and request
* reconstruction. The plugin has no environment guard and is active wherever
- * mounted, including the default `dsh-agent-core` bundle; custom compositions
+ * mounted, including the default `dsh-agent-spine-demo` bundle; custom compositions
* may omit it. Sessions still own event snapshots and freezing.
* @module @deepseek-ai/dsh-invariants
*/
diff --git a/packages/todo/README.md b/packages/todo/README.md
index 3f427295c1..b6a9ce2fc5 100644
--- a/packages/todo/README.md
+++ b/packages/todo/README.md
@@ -6,4 +6,4 @@ The model-facing todo tool. A single **product** package — there is no interfa
|---|---|---|
| `tool-todo/` | Model-facing `todo_write` tool; writes the whole list to the session log (`todo/write`) | (registers on `ctx.tools`) |
-The list lives on the event-sourced session log (`SessionEventMap['todo/write']`, owned by [`dsh-session`](../core/session)); this package is the thin consumer that appends the snapshot. UIs render off `session/event`: the [stdio app's readline UI](../ui/stdio-agent) prints the list, the [ACP bridge](../ui/acp) maps it to a `plan` sessionUpdate.
+The list lives on the event-sourced session log (`SessionEventMap['todo/write']`, owned by [`dsh-session`](../core/session)); this package is the thin consumer that appends the snapshot. UIs render off `session/event`: the [stdio app's readline UI](../examples/stdio-demo) prints the list, the [ACP bridge](../ui/acp) maps it to a `plan` sessionUpdate.
diff --git a/packages/todo/tool-todo/README.md b/packages/todo/tool-todo/README.md
index 5736d23e85..0b07539f3d 100644
--- a/packages/todo/tool-todo/README.md
+++ b/packages/todo/tool-todo/README.md
@@ -18,7 +18,7 @@ Beyond the schema's type/required/enum checks, `execute` rejects an empty or dup
## Rendering
-The tool writes only the session event; it does not render. UIs subscribe to `session/event` and render the `todo/write` data themselves: the [stdio app's readline UI](../../ui/stdio-agent) prints a glyphed checklist, and the [ACP bridge](../../ui/acp) maps the list to a `plan` sessionUpdate (synthesizing the `priority` ACP requires).
+The tool writes only the session event; it does not render. UIs subscribe to `session/event` and render the `todo/write` data themselves: the [stdio app's readline UI](../../examples/stdio-demo) prints a glyphed checklist, and the [ACP bridge](../../ui/acp) maps the list to a `plan` sessionUpdate (synthesizing the `priority` ACP requires).
## Export shape
diff --git a/packages/ui/app-boot/README.md b/packages/ui/app-boot/README.md
index c3deaa4f48..a0af1c5a69 100644
--- a/packages/ui/app-boot/README.md
+++ b/packages/ui/app-boot/README.md
@@ -1,6 +1,6 @@
# `@deepseek-ai/dsh-app-boot`
-Shared boot glue for the app bins ([`dsh-stdio-agent`](../stdio-agent/README.md), [`dsh-acp-agent`](../acp-agent/README.md)): each bin is a thin self-executing composition over these helpers, parameterized by its diagnostic prefix, so the loader-failure lore lives once — under the per-file coverage gate — instead of drifting between two published artifacts.
+Shared boot glue for the app bins ([`dsh-stdio-demo`](../stdio-agent/README.md), [`dsh-acp-demo`](../acp-agent/README.md)): each bin is a thin self-executing composition over these helpers, parameterized by its diagnostic prefix, so the loader-failure lore lives once — under the per-file coverage gate — instead of drifting between two published artifacts.
| Export | Role |
|---|---|
diff --git a/packages/ui/app-boot/src/index.ts b/packages/ui/app-boot/src/index.ts
index 3521769816..91ab0d3a2f 100644
--- a/packages/ui/app-boot/src/index.ts
+++ b/packages/ui/app-boot/src/index.ts
@@ -1,5 +1,5 @@
/**
- * Shared boot glue for the app bins (`dsh-stdio-agent`, `dsh-acp-agent`): load the gitignored
+ * Shared boot glue for the app bins (`dsh-stdio-demo`, `dsh-acp-demo`): load the gitignored
* `.env`, install the fail-loud Loader guards, resolve the config path (snapshot-aware), and
* drive the cordis Loader against a leaf `cordis.yml` until the whole tree has settled.
* @module @deepseek-ai/dsh-app-boot
diff --git a/packages/ui/jsonrpc/package.json b/packages/ui/jsonrpc/package.json
index be98f173de..bb91ab4fc2 100644
--- a/packages/ui/jsonrpc/package.json
+++ b/packages/ui/jsonrpc/package.json
@@ -35,7 +35,7 @@
"devDependencies": {
"@cordisjs/plugin-loader": "workspace:^",
"@deepseek-ai/dsh-agent": "workspace:^",
- "@deepseek-ai/dsh-agent-core": "workspace:^",
+ "@deepseek-ai/dsh-agent-spine-demo": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
"@deepseek-ai/dsh-llm-deepseek": "workspace:^",
"@deepseek-ai/dsh-session": "workspace:^",
diff --git a/packages/ui/jsonrpc/tests/plugin-apply.spec.ts b/packages/ui/jsonrpc/tests/plugin-apply.spec.ts
index 9c96e815dc..3b4e585ff6 100644
--- a/packages/ui/jsonrpc/tests/plugin-apply.spec.ts
+++ b/packages/ui/jsonrpc/tests/plugin-apply.spec.ts
@@ -6,7 +6,7 @@ import { tmpdir } from 'node:os'
import { PassThrough, Writable } from 'node:stream'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { Context } from 'cordis'
-import * as agentCore from '@deepseek-ai/dsh-agent-core'
+import * as agentCore from '@deepseek-ai/dsh-agent-spine-demo'
import SessionPersistenceJsonl from '@deepseek-ai/dsh-session-persistence-jsonl'
import * as jsonrpc from '../src/index.ts'
diff --git a/packages/ui/jsonrpc/tests/server.spec.ts b/packages/ui/jsonrpc/tests/server.spec.ts
index 1cde550f2e..8c024c6e81 100644
--- a/packages/ui/jsonrpc/tests/server.spec.ts
+++ b/packages/ui/jsonrpc/tests/server.spec.ts
@@ -7,7 +7,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest'
import { Context } from 'cordis'
import { AgentId, type Agent, type AgentHandle } from '@deepseek-ai/dsh-agent'
import { SessionId } from '@deepseek-ai/dsh-session'
-import * as agentCore from '@deepseek-ai/dsh-agent-core'
+import * as agentCore from '@deepseek-ai/dsh-agent-spine-demo'
import SessionPersistenceJsonl from '@deepseek-ai/dsh-session-persistence-jsonl'
import * as LlmDeepSeek from '@deepseek-ai/dsh-llm-deepseek'
import SubagentService, { type SubagentRunEndInfo } from '@deepseek-ai/dsh-subagent'
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4e0a2af98a..857a8406ed 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -332,52 +332,6 @@ importers:
specifier: ^4.0.0-rc.7
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
- packages/core/agent-core:
- dependencies:
- schemastery:
- specifier: ^3.18.0
- version: 3.18.0
- devDependencies:
- '@cordisjs/plugin-timer':
- specifier: workspace:^
- version: link:../../../vendor/timer
- '@deepseek-ai/dsh-agent':
- specifier: workspace:^
- version: link:../agent
- '@deepseek-ai/dsh-agent-loop':
- specifier: workspace:^
- version: link:../agent-loop
- '@deepseek-ai/dsh-invariants':
- specifier: workspace:^
- version: link:../../support/invariants
- '@deepseek-ai/dsh-llm':
- specifier: workspace:^
- version: link:../../llm/llm
- '@deepseek-ai/dsh-session':
- specifier: workspace:^
- version: link:../session
- '@deepseek-ai/dsh-skill':
- specifier: workspace:^
- version: link:../../skill/skill
- '@deepseek-ai/dsh-skill-local':
- specifier: workspace:^
- version: link:../../skill/skill-local
- '@deepseek-ai/dsh-system-prompt':
- specifier: workspace:^
- version: link:../system-prompt
- '@deepseek-ai/dsh-tool-bash':
- specifier: workspace:^
- version: link:../../bash/tool-bash
- '@deepseek-ai/dsh-tool-skill':
- specifier: workspace:^
- version: link:../../skill/tool-skill
- '@deepseek-ai/dsh-tools':
- specifier: workspace:^
- version: link:../tools
- cordis:
- specifier: ^4.0.0-rc.7
- version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
-
packages/core/agent-loop:
dependencies:
schemastery:
@@ -483,6 +437,152 @@ importers:
specifier: ^4.0.0-rc.7
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
+ packages/examples/acp-demo:
+ devDependencies:
+ '@cordisjs/plugin-include':
+ specifier: workspace:^
+ version: link:../../../vendor/include
+ '@cordisjs/plugin-loader':
+ specifier: workspace:^
+ version: link:../../../vendor/loader
+ '@deepseek-ai/dsh-acp':
+ specifier: workspace:^
+ version: link:../../ui/acp
+ '@deepseek-ai/dsh-agent':
+ specifier: workspace:^
+ version: link:../../core/agent
+ '@deepseek-ai/dsh-agent-spine-demo':
+ specifier: workspace:^
+ version: link:../agent-spine-demo
+ '@deepseek-ai/dsh-app-boot':
+ specifier: workspace:^
+ version: link:../../ui/app-boot
+ '@deepseek-ai/dsh-session-persistence-jsonl':
+ specifier: workspace:^
+ version: link:../../session-persistence/session-persistence-jsonl
+ '@deepseek-ai/dsh-system-prompt':
+ specifier: workspace:^
+ version: link:../../core/system-prompt
+ '@deepseek-ai/dsh-tools':
+ specifier: workspace:^
+ version: link:../../core/tools
+ '@deepseek-ai/dsh-user-interaction':
+ specifier: workspace:^
+ version: link:../../ui/user-interaction
+ cordis:
+ specifier: ^4.0.0-rc.7
+ version: 4.0.0-rc.7(@cordisjs/plugin-include@vendor+include)(@cordisjs/plugin-loader@vendor+loader)
+ schemastery:
+ specifier: ^3.17.0
+ version: 3.18.0
+
+ packages/examples/agent-spine-demo:
+ dependencies:
+ schemastery:
+ specifier: ^3.18.0
+ version: 3.18.0
+ devDependencies:
+ '@cordisjs/plugin-timer':
+ specifier: workspace:^
+ version: link:../../../vendor/timer
+ '@deepseek-ai/dsh-agent':
+ specifier: workspace:^
+ version: link:../../core/agent
+ '@deepseek-ai/dsh-agent-loop':
+ specifier: workspace:^
+ version: link:../../core/agent-loop
+ '@deepseek-ai/dsh-invariants':
+ specifier: workspace:^
+ version: link:../../support/invariants
+ '@deepseek-ai/dsh-llm':
+ specifier: workspace:^
+ version: link:../../llm/llm
+ '@deepseek-ai/dsh-session':
+ specifier: workspace:^
+ version: link:../../core/session
+ '@deepseek-ai/dsh-skill':
+ specifier: workspace:^
+ version: link:../../skill/skill
+ '@deepseek-ai/dsh-skill-local':
+ specifier: workspace:^
+ version: link:../../skill/skill-local
+ '@deepseek-ai/dsh-system-prompt':
+ specifier: workspace:^
+ version: link:../../core/system-prompt
+ '@deepseek-ai/dsh-tool-bash':
+ specifier: workspace:^
+ version: link:../../bash/tool-bash
+ '@deepseek-ai/dsh-tool-skill':
+ specifier: workspace:^
+ version: link:../../skill/tool-skill
+ '@deepseek-ai/dsh-tools':
+ specifier: workspace:^
+ version: link:../../core/tools
+ cordis:
+ specifier: ^4.0.0-rc.7
+ version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
+
+ packages/examples/jsonrpc-demo:
+ dependencies:
+ '@deepseek-ai/dsh-app-boot':
+ specifier: workspace:^
+ version: link:../../ui/app-boot
+ devDependencies:
+ cordis:
+ specifier: ^4.0.0-rc.7
+ version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
+
+ packages/examples/stdio-demo:
+ devDependencies:
+ '@cordisjs/plugin-include':
+ specifier: workspace:^
+ version: link:../../../vendor/include
+ '@cordisjs/plugin-loader':
+ specifier: workspace:^
+ version: link:../../../vendor/loader
+ '@cordisjs/plugin-logger-console':
+ specifier: workspace:^
+ version: link:../../../vendor/logger-console
+ '@deepseek-ai/dsh-agent':
+ specifier: workspace:^
+ version: link:../../core/agent
+ '@deepseek-ai/dsh-agent-spine-demo':
+ specifier: workspace:^
+ version: link:../agent-spine-demo
+ '@deepseek-ai/dsh-app-boot':
+ specifier: workspace:^
+ version: link:../../ui/app-boot
+ '@deepseek-ai/dsh-llm':
+ specifier: workspace:^
+ version: link:../../llm/llm
+ '@deepseek-ai/dsh-session':
+ specifier: workspace:^
+ version: link:../../core/session
+ '@deepseek-ai/dsh-session-persistence-jsonl':
+ specifier: workspace:^
+ version: link:../../session-persistence/session-persistence-jsonl
+ '@deepseek-ai/dsh-stdio':
+ specifier: workspace:^
+ version: link:../../ui/stdio
+ '@deepseek-ai/dsh-system-prompt':
+ specifier: workspace:^
+ version: link:../../core/system-prompt
+ '@deepseek-ai/dsh-tool-ask-user':
+ specifier: workspace:^
+ version: link:../../ui/tool-ask-user
+ '@deepseek-ai/dsh-tools':
+ specifier: workspace:^
+ version: link:../../core/tools
+ '@deepseek-ai/dsh-user-interaction':
+ specifier: workspace:^
+ version: link:../../ui/user-interaction
+ cordis:
+ specifier: ^4.0.0-rc.7
+ version: 4.0.0-rc.7(@cordisjs/plugin-include@vendor+include)(@cordisjs/plugin-loader@vendor+loader)
+ schemastery:
+ specifier: ^3.17.0
+ version: 3.18.0
+
packages/fs/fs:
devDependencies:
'@deepseek-ai/dsh-brand':
@@ -1313,45 +1413,6 @@ importers:
specifier: ^4.0.0-rc.7
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
- packages/ui/acp-agent:
- devDependencies:
- '@cordisjs/plugin-include':
- specifier: workspace:^
- version: link:../../../vendor/include
- '@cordisjs/plugin-loader':
- specifier: workspace:^
- version: link:../../../vendor/loader
- '@deepseek-ai/dsh-acp':
- specifier: workspace:^
- version: link:../acp
- '@deepseek-ai/dsh-agent':
- specifier: workspace:^
- version: link:../../core/agent
- '@deepseek-ai/dsh-agent-core':
- specifier: workspace:^
- version: link:../../core/agent-core
- '@deepseek-ai/dsh-app-boot':
- specifier: workspace:^
- version: link:../app-boot
- '@deepseek-ai/dsh-session-persistence-jsonl':
- specifier: workspace:^
- version: link:../../session-persistence/session-persistence-jsonl
- '@deepseek-ai/dsh-system-prompt':
- specifier: workspace:^
- version: link:../../core/system-prompt
- '@deepseek-ai/dsh-tools':
- specifier: workspace:^
- version: link:../../core/tools
- '@deepseek-ai/dsh-user-interaction':
- specifier: workspace:^
- version: link:../user-interaction
- cordis:
- specifier: ^4.0.0-rc.7
- version: 4.0.0-rc.7(@cordisjs/plugin-include@vendor+include)(@cordisjs/plugin-loader@vendor+loader)
- schemastery:
- specifier: ^3.17.0
- version: 3.18.0
-
packages/ui/app-boot:
devDependencies:
'@cordisjs/plugin-include':
@@ -1376,9 +1437,9 @@ importers:
'@deepseek-ai/dsh-agent':
specifier: workspace:^
version: link:../../core/agent
- '@deepseek-ai/dsh-agent-core':
+ '@deepseek-ai/dsh-agent-spine-demo':
specifier: workspace:^
- version: link:../../core/agent-core
+ version: link:../../examples/agent-spine-demo
'@deepseek-ai/dsh-llm':
specifier: workspace:^
version: link:../../llm/llm
@@ -1398,16 +1459,6 @@ importers:
specifier: ^4.0.0-rc.7
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@vendor+loader)
- packages/ui/jsonrpc-agent:
- dependencies:
- '@deepseek-ai/dsh-app-boot':
- specifier: workspace:^
- version: link:../app-boot
- devDependencies:
- cordis:
- specifier: ^4.0.0-rc.7
- version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
-
packages/ui/permission:
dependencies:
schemastery:
@@ -1455,57 +1506,6 @@ importers:
specifier: ^4.0.0-rc.6
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@vendor+loader)
- packages/ui/stdio-agent:
- devDependencies:
- '@cordisjs/plugin-include':
- specifier: workspace:^
- version: link:../../../vendor/include
- '@cordisjs/plugin-loader':
- specifier: workspace:^
- version: link:../../../vendor/loader
- '@cordisjs/plugin-logger-console':
- specifier: workspace:^
- version: link:../../../vendor/logger-console
- '@deepseek-ai/dsh-agent':
- specifier: workspace:^
- version: link:../../core/agent
- '@deepseek-ai/dsh-agent-core':
- specifier: workspace:^
- version: link:../../core/agent-core
- '@deepseek-ai/dsh-app-boot':
- specifier: workspace:^
- version: link:../app-boot
- '@deepseek-ai/dsh-llm':
- specifier: workspace:^
- version: link:../../llm/llm
- '@deepseek-ai/dsh-session':
- specifier: workspace:^
- version: link:../../core/session
- '@deepseek-ai/dsh-session-persistence-jsonl':
- specifier: workspace:^
- version: link:../../session-persistence/session-persistence-jsonl
- '@deepseek-ai/dsh-stdio':
- specifier: workspace:^
- version: link:../stdio
- '@deepseek-ai/dsh-system-prompt':
- specifier: workspace:^
- version: link:../../core/system-prompt
- '@deepseek-ai/dsh-tool-ask-user':
- specifier: workspace:^
- version: link:../tool-ask-user
- '@deepseek-ai/dsh-tools':
- specifier: workspace:^
- version: link:../../core/tools
- '@deepseek-ai/dsh-user-interaction':
- specifier: workspace:^
- version: link:../user-interaction
- cordis:
- specifier: ^4.0.0-rc.7
- version: 4.0.0-rc.7(@cordisjs/plugin-include@vendor+include)(@cordisjs/plugin-loader@vendor+loader)
- schemastery:
- specifier: ^3.17.0
- version: 3.18.0
-
packages/ui/tool-ask-user:
devDependencies:
'@deepseek-ai/dsh-agent':
@@ -1799,12 +1799,12 @@ importers:
'@deepseek-ai/dsh-agent':
specifier: workspace:^
version: link:../../packages/core/agent
- '@deepseek-ai/dsh-agent-core':
- specifier: workspace:^
- version: link:../../packages/core/agent-core
'@deepseek-ai/dsh-agent-loop':
specifier: workspace:^
version: link:../../packages/core/agent-loop
+ '@deepseek-ai/dsh-agent-spine-demo':
+ specifier: workspace:^
+ version: link:../../packages/examples/agent-spine-demo
'@deepseek-ai/dsh-app-boot':
specifier: workspace:^
version: link:../../packages/ui/app-boot
@@ -1853,9 +1853,9 @@ importers:
'@deepseek-ai/dsh-jsonrpc':
specifier: workspace:^
version: link:../../packages/ui/jsonrpc
- '@deepseek-ai/dsh-jsonrpc-agent':
+ '@deepseek-ai/dsh-jsonrpc-demo':
specifier: workspace:^
- version: link:../../packages/ui/jsonrpc-agent
+ version: link:../../packages/examples/jsonrpc-demo
'@deepseek-ai/dsh-llm':
specifier: workspace:^
version: link:../../packages/llm/llm
diff --git a/python/README.md b/python/README.md
index a04a0f99c9..30bca971f1 100644
--- a/python/README.md
+++ b/python/README.md
@@ -45,8 +45,8 @@ with DeepSeekHarness() as harness:
Two flavors, both for repo members:
-- **Built node carrier** — set `DSH_RUNTIME_MODE=node` and the SDK runs `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js` on the system Node (>= 22.19). The tree is refreshed on every build-script run and is the same dependency closure the exe snapshots, so plugin semantics are identical. Never auto-selected, never distributed.
-- **Unbuilt source (tsx)** — point the client straight at the bin's TypeScript source for edit-run loops and debugging: `launch_args_override=("./node_modules/.bin/tsx", "packages/ui/jsonrpc-agent/src/bin.ts")` with `cwd` at the repo root, plus a config via `cordis=...` (or rely on the default-config injection). [sdk/tests/manual_sdk_agent_smoke.py](sdk/tests/manual_sdk_agent_smoke.py) is the worked example.
+- **Built node carrier** — set `DSH_RUNTIME_MODE=node` and the SDK runs `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js` on the system Node (>= 22.19). The tree is refreshed on every build-script run and is the same dependency closure the exe snapshots, so plugin semantics are identical. Never auto-selected, never distributed.
+- **Unbuilt source (tsx)** — point the client straight at the bin's TypeScript source for edit-run loops and debugging: `launch_args_override=("./node_modules/.bin/tsx", "packages/examples/jsonrpc-demo/src/bin.ts")` with `cwd` at the repo root, plus a config via `cordis=...` (or rely on the default-config injection). [sdk/tests/manual_sdk_agent_smoke.py](sdk/tests/manual_sdk_agent_smoke.py) is the worked example.
## Distributing the Python packages
diff --git a/python/README.zh.md b/python/README.zh.md
index 04e58c5a39..d2eea59d14 100644
--- a/python/README.zh.md
+++ b/python/README.zh.md
@@ -45,8 +45,8 @@ with DeepSeekHarness() as harness:
两种方式,均面向仓库成员:
-- **已构建的 `node` 载体**——设置 `DSH_RUNTIME_MODE=node`,SDK 会用系统 Node(>= 22.19)运行 `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js`。这棵树每次运行构建脚本都会刷新,与 exe 打入 pkg 虚拟文件系统(VFS)的是同一份依赖闭包,因此插件语义一致。它不会被自动选中,也不进入分发物。
-- **未构建的源码(tsx)**——把客户端直接指向 `bin` 的 TypeScript 源码,用于编辑、运行和调试:`launch_args_override=("./node_modules/.bin/tsx", "packages/ui/jsonrpc-agent/src/bin.ts")`,`cwd` 设为仓库根,再通过 `cordis=...` 传入配置(或使用默认配置注入)。[sdk/tests/manual_sdk_agent_smoke.py](sdk/tests/manual_sdk_agent_smoke.py) 是现成范例。
+- **已构建的 `node` 载体**——设置 `DSH_RUNTIME_MODE=node`,SDK 会用系统 Node(>= 22.19)运行 `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js`。这棵树每次运行构建脚本都会刷新,与 exe 打入 pkg 虚拟文件系统(VFS)的是同一份依赖闭包,因此插件语义一致。它不会被自动选中,也不进入分发物。
+- **未构建的源码(tsx)**——把客户端直接指向 `bin` 的 TypeScript 源码,用于编辑、运行和调试:`launch_args_override=("./node_modules/.bin/tsx", "packages/examples/jsonrpc-demo/src/bin.ts")`,`cwd` 设为仓库根,再通过 `cordis=...` 传入配置(或使用默认配置注入)。[sdk/tests/manual_sdk_agent_smoke.py](sdk/tests/manual_sdk_agent_smoke.py) 是现成范例。
## 分发 Python 包
diff --git a/python/sdk-runtime/README.md b/python/sdk-runtime/README.md
index a28ae59971..5525e8a7b8 100644
--- a/python/sdk-runtime/README.md
+++ b/python/sdk-runtime/README.md
@@ -9,7 +9,7 @@ Runtime carrier package for the Python SDK (dist `deepseek-harness-runtime-bin`,
Two carriers coexist under `src/deepseek_harness_runtime/runtime/`, both injected by the repo's `scripts/build-exe-for-python-sdk.ts` build and both gitignored:
- **exe (production)** — single-file executables `dsh-jsonrpc-agent-pkg--` (platform: `linux`/`macos`; arch: `x64`/`arm64`). No Node installation needed on the target machine. This is the only carrier that ships in wheel distributions; this package does not publish sdists.
-- **node (dev-only)** — the full deploy closure under `runtime/node/` (`package.json` + `node_modules/`), executed as `node runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js` on a system Node >= 22.19. It is the current checkout's source build, meant for repo-local development and verification only; it is never selected automatically and is excluded from distributions.
+- **node (dev-only)** — the full deploy closure under `runtime/node/` (`package.json` + `node_modules/`), executed as `node runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js` on a system Node >= 22.19. It is the current checkout's source build, meant for repo-local development and verification only; it is never selected automatically and is excluded from distributions.
Both carriers hold the same content, defined once: the [package.json](package.json) at this package's root is the deploy root of the single-exe pipeline — a pure dependency manifest (no code of its own) whose dependency closure IS both the plugin set compiled into the exe and the tree materialized into `runtime/node/`. Adding a plugin to the distribution means adding one dependency line there and rebuilding.
diff --git a/python/sdk-runtime/README.zh.md b/python/sdk-runtime/README.zh.md
index 10dbb6b14f..30723d6d78 100644
--- a/python/sdk-runtime/README.zh.md
+++ b/python/sdk-runtime/README.zh.md
@@ -9,7 +9,7 @@ Python SDK 的运行时载体包(分发名 `deepseek-harness-runtime-bin`,
两种载体并存于 `src/deepseek_harness_runtime/runtime/` 之下,均由仓库的 `scripts/build-exe-for-python-sdk.ts` 构建注入,且均被 git 忽略:
- **exe(生产)**——单文件可执行程序 `dsh-jsonrpc-agent-pkg--`(platform:`linux`/`macos`;arch:`x64`/`arm64`)。目标机器无需安装 Node。这是唯一随 wheel 包分发的载体;本包不发布 sdist。
-- **`node`(仅限开发)**——`runtime/node/` 下的完整部署闭包(`package.json` + `node_modules/`),在系统 Node >= 22.19 上以 `node runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js` 执行。它是当前检出的源码构建,仅用于仓库本地的开发与验证;不会被自动选中,也不进入分发物。
+- **`node`(仅限开发)**——`runtime/node/` 下的完整部署闭包(`package.json` + `node_modules/`),在系统 Node >= 22.19 上以 `node runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js` 执行。它是当前检出的源码构建,仅用于仓库本地的开发与验证;不会被自动选中,也不进入分发物。
两种载体承载相同的内容,且只定义一次:本包根目录的 [package.json](package.json) 是 single-exe 流水线的部署根目录——一份零代码的纯依赖 manifest,其依赖闭包既是编译进 exe 的插件集,也是物化到 `runtime/node/` 的文件树。往分发物里加插件,就是在那里加一行依赖再重新构建。
diff --git a/python/sdk-runtime/package.json b/python/sdk-runtime/package.json
index cff5eda404..491d975e04 100644
--- a/python/sdk-runtime/package.json
+++ b/python/sdk-runtime/package.json
@@ -10,7 +10,7 @@
"@cordisjs/plugin-timer": "workspace:^",
"@deepseek-ai/dsh-acp": "workspace:^",
"@deepseek-ai/dsh-agent": "workspace:^",
- "@deepseek-ai/dsh-agent-core": "workspace:^",
+ "@deepseek-ai/dsh-agent-spine-demo": "workspace:^",
"@deepseek-ai/dsh-agent-loop": "workspace:^",
"@deepseek-ai/dsh-app-boot": "workspace:^",
"@deepseek-ai/dsh-bash": "workspace:^",
@@ -28,7 +28,7 @@
"@deepseek-ai/dsh-hooks-codex": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-jsonrpc": "workspace:^",
- "@deepseek-ai/dsh-jsonrpc-agent": "workspace:^",
+ "@deepseek-ai/dsh-jsonrpc-demo": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
"@deepseek-ai/dsh-llm-deepseek": "workspace:^",
"@deepseek-ai/dsh-llm-pi-ai": "workspace:^",
diff --git a/python/sdk-runtime/src/deepseek_harness_runtime/__init__.py b/python/sdk-runtime/src/deepseek_harness_runtime/__init__.py
index 9076861e88..4a014d5a5b 100644
--- a/python/sdk-runtime/src/deepseek_harness_runtime/__init__.py
+++ b/python/sdk-runtime/src/deepseek_harness_runtime/__init__.py
@@ -8,7 +8,7 @@ Two runtime carriers coexist under ``runtime/``, both injected by the repo's
{x64, arm64}); the target machine needs no Node installation.
- **node (dev-only)**: the full deploy closure under ``runtime/node/``
(``package.json`` + ``node_modules/``), executed as ``node
- runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js`` on a
+ runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js`` on a
system Node >= 22.19. It is the current checkout's source build, never
selected automatically, and excluded from wheel/sdist distributions.
diff --git a/python/sdk-runtime/src/deepseek_harness_runtime/runtime/cordis.yml b/python/sdk-runtime/src/deepseek_harness_runtime/runtime/cordis.yml
index 61e19be267..a47dcc26a7 100644
--- a/python/sdk-runtime/src/deepseek_harness_runtime/runtime/cordis.yml
+++ b/python/sdk-runtime/src/deepseek_harness_runtime/runtime/cordis.yml
@@ -8,7 +8,7 @@
# Agent spine; the SDK server creates agents per sessionId.
- id: agent-core
- name: '@deepseek-ai/dsh-agent-core'
+ name: '@deepseek-ai/dsh-agent-spine-demo'
# Stock DeepSeek adapters. Loading requires an API key; initialize and shutdown
# may use a dummy key because they do not call the model.
diff --git a/python/sdk/tests/manual_sdk_agent_smoke.py b/python/sdk/tests/manual_sdk_agent_smoke.py
index 8173c40f7f..39a00856b7 100644
--- a/python/sdk/tests/manual_sdk_agent_smoke.py
+++ b/python/sdk/tests/manual_sdk_agent_smoke.py
@@ -44,7 +44,7 @@ class MockCompletionHandler(BaseHTTPRequestHandler):
def run_smoke(repo_root: Path, keep_sessions: bool) -> None:
session_root = Path(tempfile.mkdtemp(prefix="dsh-sdk-smoke-sessions-"))
- runtime_entry = repo_root / "packages/ui/jsonrpc-agent/src/bin.ts"
+ runtime_entry = repo_root / "packages/examples/jsonrpc-demo/src/bin.ts"
server = ThreadingHTTPServer(("127.0.0.1", 0), MockCompletionHandler)
thread = threading.Thread(target=server.serve_forever, name="mock-openai-compatible-server", daemon=True)
thread.start()
diff --git a/python/sdk/tests/test_bundled_runtime.py b/python/sdk/tests/test_bundled_runtime.py
index e480147dfe..0ee373102e 100644
--- a/python/sdk/tests/test_bundled_runtime.py
+++ b/python/sdk/tests/test_bundled_runtime.py
@@ -21,7 +21,7 @@ _CORDIS_YML = """\
- id: jsonrpc
name: '@deepseek-ai/dsh-jsonrpc'
- id: agent-core
- name: '@deepseek-ai/dsh-agent-core'
+ name: '@deepseek-ai/dsh-agent-spine-demo'
- id: sessions
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
diff --git a/python/sdk/tests/test_runtime_resolution.py b/python/sdk/tests/test_runtime_resolution.py
index d05c4fded7..4858686191 100644
--- a/python/sdk/tests/test_runtime_resolution.py
+++ b/python/sdk/tests/test_runtime_resolution.py
@@ -15,7 +15,7 @@ from deepseek_harness_runtime import (
def test_default_config_is_shipped_with_the_package() -> None:
path = bundled_default_config_path()
assert path == bundled_package_dir() / "runtime" / "cordis.yml"
- assert "@deepseek-ai/dsh-agent-core" in path.read_text()
+ assert "@deepseek-ai/dsh-agent-spine-demo" in path.read_text()
def test_unknown_explicit_mode_fails_loud() -> None:
diff --git a/scripts/build-exe-for-python-sdk.ts b/scripts/build-exe-for-python-sdk.ts
index 8501bde1fe..ebca6cebd7 100644
--- a/scripts/build-exe-for-python-sdk.ts
+++ b/scripts/build-exe-for-python-sdk.ts
@@ -17,7 +17,7 @@ const root = resolve(import.meta.dirname, '..')
/** The closure manifest whose dependencies define the executable. */
const DEPLOY_ROOT_PACKAGE = 'dsh-jsonrpc-agent-pkg'
/** The app entry inside the deployed closure. */
-const ENTRY_BIN = 'node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js'
+const ENTRY_BIN = 'node_modules/@deepseek-ai/dsh-jsonrpc-demo/lib/bin.js'
const OUTPUT_BASENAME = 'dsh-jsonrpc-agent-pkg'
/** Default Node major; SEA mode requires at least Node 22. */
const DEFAULT_NODE_RANGE = 'node24'
diff --git a/scripts/demo-code-mode.mjs b/scripts/demo-code-mode.mjs
index 76d5fe9215..edfc26b4d5 100644
--- a/scripts/demo-code-mode.mjs
+++ b/scripts/demo-code-mode.mjs
@@ -9,8 +9,8 @@ import { spawn } from 'node:child_process'
// the overlay config (the stdio bin keeps --expose-internals for the cordis
// Loader's HMR path).
const UIS = new Map([
- ['repl', ['--expose-internals', '--import', 'tsx', 'packages/ui/stdio-agent/src/bin.ts', 'examples/coding-agent/code-mode.cordis.yml']],
- ['acp', ['--import', 'tsx', 'packages/ui/acp-agent/src/bin.ts', '--config', 'examples/acp-agent/code-mode.cordis.yml']],
+ ['repl', ['--expose-internals', '--import', 'tsx', 'packages/examples/stdio-demo/src/bin.ts', 'examples/coding-agent/code-mode.cordis.yml']],
+ ['acp', ['--import', 'tsx', 'packages/examples/acp-demo/src/bin.ts', '--config', 'examples/acp-agent/code-mode.cordis.yml']],
])
const ui = process.argv[2] ?? 'repl'
diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts
index a6660f7cd3..0e1774c2e0 100644
--- a/scripts/gen-doc-graphs.ts
+++ b/scripts/gen-doc-graphs.ts
@@ -129,8 +129,8 @@ const SERVICE_ROLES: ServiceRole[] = [
pkg: 'user-interaction',
title: 'Human question/answer seam',
mode: 'seam',
- implementations: ['stdio-agent', 'acp'],
- consumers: ['tool-ask-user', 'stdio-agent', 'acp'],
+ implementations: ['stdio-demo', 'acp'],
+ consumers: ['tool-ask-user', 'stdio-demo', 'acp'],
note: 'UI front doors provide the active human-answer provider; tool-ask-user pauses a tool call on the provider-neutral ask() promise.',
},
{
@@ -147,7 +147,7 @@ const SERVICE_ROLES: ServiceRole[] = [
pkg: 'agent',
title: 'Agent registry',
mode: 'core',
- consumers: ['agent-loop', 'acp', 'subagent-inprocess', 'stdio-agent', 'invariants'],
+ consumers: ['agent-loop', 'acp', 'subagent-inprocess', 'stdio-demo', 'invariants'],
note: 'Owns live Agent handles and the create/resume factory seam.',
},
{
@@ -155,7 +155,7 @@ const SERVICE_ROLES: ServiceRole[] = [
pkg: 'agent-loop',
title: 'Concrete loop driver',
mode: 'bundle',
- consumers: ['agent-core'],
+ consumers: ['agent-spine-demo'],
note: 'The one concrete loop plugin; extension packages depend on dsh-agent events and services, not on this package.',
},
{
@@ -422,11 +422,11 @@ type AppExample = typeof APP_EXAMPLES[number]
function renderAppExpansion(lines: string[], appNode: string, pluginName: string): void {
const agentCore = nodeId('bundle', 'agent_core')
const jsonl = nodeId('bundle', 'jsonl')
- lines.push(` ${appNode} --> ${agentCore}["@deepseek-ai/dsh-agent-core"]`)
+ lines.push(` ${appNode} --> ${agentCore}["@deepseek-ai/dsh-agent-spine-demo"]`)
lines.push(` ${appNode} --> ${jsonl}["@deepseek-ai/dsh-session-persistence-jsonl"]`)
- if (pluginName === '@deepseek-ai/dsh-stdio-agent') {
+ if (pluginName === '@deepseek-ai/dsh-stdio-demo') {
lines.push(` ${appNode} --> ${nodeId('frontdoor', 'stdio')}["readline UI
console logger
pre-created main agent"]`)
- } else if (pluginName === '@deepseek-ai/dsh-acp-agent') {
+ } else if (pluginName === '@deepseek-ai/dsh-acp-demo') {
lines.push(` ${appNode} --> ${nodeId('frontdoor', 'acp')}["@deepseek-ai/dsh-acp
JSON-RPC stdio bridge
sessions created by client"]`)
}
lines.push(
@@ -452,7 +452,7 @@ function renderAppComposition(example: AppExample): string {
const pluginNode = nodeId(`plugin_${example.id}`, plugin.id)
lines.push(` ${pluginNode}["${escLabel(plugin.id)}
${escLabel(plugin.name)}"]`)
lines.push(` cfg --> ${pluginNode}`)
- if (plugin.name === '@deepseek-ai/dsh-stdio-agent' || plugin.name === '@deepseek-ai/dsh-acp-agent') {
+ if (plugin.name === '@deepseek-ai/dsh-stdio-demo' || plugin.name === '@deepseek-ai/dsh-acp-demo') {
renderAppExpansion(lines, pluginNode, plugin.name)
}
}
diff --git a/scripts/run-gates.ts b/scripts/run-gates.ts
index 7f23a666ae..4de4742c9d 100644
--- a/scripts/run-gates.ts
+++ b/scripts/run-gates.ts
@@ -335,8 +335,8 @@ function builtBinSmokeGate(): Gate {
'run',
'--config',
'vitest.e2e.config.ts',
- 'packages/ui/stdio-agent/tests/built-bin.e2e.ts',
- 'packages/ui/acp-agent/tests/built-bin.e2e.ts',
+ 'packages/examples/stdio-demo/tests/built-bin.e2e.ts',
+ 'packages/examples/acp-demo/tests/built-bin.e2e.ts',
// The worker-entry packages' built bundles: the only automated proof
// that lib/index.js resolves its sibling lib/worker.cjs under plain node
// (the e2e lane runs unbuilt, so these files self-skip there).
diff --git a/scripts/smoke-python-runtime.py b/scripts/smoke-python-runtime.py
index 2c61d07c19..be9d36a6cd 100644
--- a/scripts/smoke-python-runtime.py
+++ b/scripts/smoke-python-runtime.py
@@ -55,7 +55,7 @@ CUSTOM_CORDIS = """\
- id: jsonrpc
name: '@deepseek-ai/dsh-jsonrpc'
- id: agent-core
- name: '@deepseek-ai/dsh-agent-core'
+ name: '@deepseek-ai/dsh-agent-spine-demo'
config:
tools:
mode: both
diff --git a/scripts/verify-package-readme-model-experience.ts b/scripts/verify-package-readme-model-experience.ts
index 7e7c4ada82..8bd2d615ed 100644
--- a/scripts/verify-package-readme-model-experience.ts
+++ b/scripts/verify-package-readme-model-experience.ts
@@ -42,7 +42,7 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly> = {
'packages/bash/bash-local': { kind: 'indirect', reason: 'The executor backend delegates model rendering to dsh-tool-bash.' },
'packages/code-runtime/code-runtime': { kind: 'indirect', reason: 'The service interface delegates model rendering to Code Mode in dsh-tools.' },
'packages/code-runtime/code-runtime-worker': { kind: 'indirect', reason: 'The worker backend delegates model rendering to Code Mode in dsh-tools.' },
- 'packages/core/agent-core': { kind: 'indirect', reason: 'The bundle only mounts model-facing child plugins.' },
+ 'packages/examples/agent-spine-demo': { kind: 'indirect', reason: 'The bundle only mounts model-facing child plugins.' },
'packages/fs/fs': { kind: 'indirect', reason: 'The service interface delegates model rendering to dsh-tool-fs.' },
'packages/fs/fs-local': { kind: 'indirect', reason: 'The provider backend delegates model rendering to dsh-tool-fs.' },
'packages/hooks/hook-protocol': { kind: 'indirect', reason: 'Only the hook bridge plugins render decoded hook output to a model.' },
@@ -58,9 +58,9 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly> = {
'packages/support/loader-smoke': { kind: 'none', reason: 'The test harness observes child-process streams without changing live requests.' },
'packages/support/llm-replay': { kind: 'none', reason: 'The keyless adapter invokes no provider model.' },
'packages/support/subagent-mock': { kind: 'indirect', reason: 'Only dsh-tool-subagent renders its configured test outcome.' },
- 'packages/ui/acp-agent': { kind: 'indirect', reason: 'The app bundle delegates request composition to dsh-agent-core and dsh-acp.' },
+ 'packages/examples/acp-demo': { kind: 'indirect', reason: 'The app bundle delegates request composition to dsh-agent-spine-demo and dsh-acp.' },
'packages/ui/app-boot': { kind: 'indirect', reason: 'Only the loaded plugin tree contributes model context.' },
- 'packages/ui/jsonrpc-agent': { kind: 'indirect', reason: 'Only the externally configured plugin tree contributes model context.' },
+ 'packages/examples/jsonrpc-demo': { kind: 'indirect', reason: 'Only the externally configured plugin tree contributes model context.' },
'packages/ui/permission': { kind: 'indirect', reason: 'The service writes mechanism events rendered by dsh-user-approval and dsh-tool-bash.' },
'packages/ui/user-interaction': { kind: 'indirect', reason: 'Model-facing consumers render provider answers and seam errors.' },
'packages/util/timeout': { kind: 'indirect', reason: 'Only timeout consumers render timeout outcomes.' },
diff --git a/tsconfig.build.json b/tsconfig.build.json
index fc1e9f488e..05725fe0ae 100644
--- a/tsconfig.build.json
+++ b/tsconfig.build.json
@@ -31,7 +31,7 @@
{ "path": "./packages/skill/tool-skill" },
{ "path": "./packages/ui/tool-ask-user" },
{ "path": "./packages/core/agent-loop" },
- { "path": "./packages/core/agent-core" },
+ { "path": "./packages/examples/agent-spine-demo" },
{ "path": "./packages/bash/bash" },
{ "path": "./packages/code-runtime/code-runtime" },
{ "path": "./packages/code-runtime/code-runtime-worker" },
@@ -57,12 +57,12 @@
{ "path": "./packages/timeout/timeout-policy" },
{ "path": "./packages/support/invariants" },
{ "path": "./packages/ui/acp" },
- { "path": "./packages/ui/acp-agent" },
+ { "path": "./packages/examples/acp-demo" },
{ "path": "./packages/ui/app-boot" },
{ "path": "./packages/ui/jsonrpc" },
- { "path": "./packages/ui/jsonrpc-agent" },
+ { "path": "./packages/examples/jsonrpc-demo" },
{ "path": "./packages/ui/stdio" },
- { "path": "./packages/ui/stdio-agent" },
+ { "path": "./packages/examples/stdio-demo" },
{ "path": "./packages/support/llm-replay" },
{ "path": "./packages/support/acp-snapshot" },
{ "path": "./packages/support/loader-smoke" },
diff --git a/tsconfig.json b/tsconfig.json
index 02b01678ca..af6e900f0f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -42,7 +42,7 @@
{ "path": "./packages/skill/tool-skill" },
{ "path": "./packages/ui/tool-ask-user" },
{ "path": "./packages/core/agent-loop" },
- { "path": "./packages/core/agent-core" },
+ { "path": "./packages/examples/agent-spine-demo" },
{ "path": "./packages/bash/bash" },
{ "path": "./packages/code-runtime/code-runtime" },
{ "path": "./packages/code-runtime/code-runtime-worker" },
@@ -68,12 +68,12 @@
{ "path": "./packages/timeout/timeout-policy" },
{ "path": "./packages/support/invariants" },
{ "path": "./packages/ui/acp" },
- { "path": "./packages/ui/acp-agent" },
+ { "path": "./packages/examples/acp-demo" },
{ "path": "./packages/ui/app-boot" },
{ "path": "./packages/ui/jsonrpc" },
- { "path": "./packages/ui/jsonrpc-agent" },
+ { "path": "./packages/examples/jsonrpc-demo" },
{ "path": "./packages/ui/stdio" },
- { "path": "./packages/ui/stdio-agent" },
+ { "path": "./packages/examples/stdio-demo" },
{ "path": "./packages/support/llm-replay" },
{ "path": "./packages/support/acp-snapshot" },
{ "path": "./packages/support/loader-smoke" },