2026-06-21 12:03:44 +08:00
# The acp-agent plugin tree: the ACP server. Also the snapshot RECORD config
# (the dsh-acp-agent bin selects it for DSH_SNAPSHOT=record): a real llm-deepseek
2026-06-30 20:07:52 +08:00
# run whose persisted log the snapshot harness harvests. The swappable DeepSeek
2026-07-14 01:09:44 +08:00
# adapter, sandboxed bash executor, the ACP server app
# (@deepseek-ai/dsh-acp-agent), and the optional model-facing
# fs/subagent/todo tools loaded below.
2026-06-16 11:10:25 +08:00
#
2026-06-21 12:03:44 +08:00
# CRITICAL: this tree loads NO stdout logger and NO hmr — stdout is reserved for
# the ACP JSON-RPC protocol (see packages/ui/acp). That guarantee is now a
# property of @deepseek-ai/dsh-acp-agent (it contains no logger entry), not a
# leaf convention: there is no logger here to get wrong.
2026-06-16 11:10:25 +08:00
#
2026-06-21 12:03:44 +08:00
# Requires DEEPSEEK_API_KEY (and optionally DEEPSEEK_BASE_URL) — the
# dsh-acp-agent bin loads the gitignored repo-root .env first (on STDERR only).
2026-06-16 11:10:25 +08:00
2026-06-21 12:03:44 +08:00
# The DeepSeek adapter.
- id : llm-deepseek
name : '@deepseek-ai/dsh-llm-deepseek'
config :
apiKey : !!js process.env.DEEPSEEK_API_KEY
baseURL : !!js process.env.DEEPSEEK_BASE_URL
models :
- deepseek-v4-flash
- deepseek-v4-pro
2026-06-16 11:10:25 +08:00
2026-07-14 01:09:44 +08:00
# The default composition confines bash to the workspace and asks before a
# wider retry. Snapshot runs select danger-full-access so the established
# scenarios remain runner-independent; DSH_PERMISSION_MODE provides the same
# explicit deployment/test override outside the snapshot harness.
- id : sandbox
name : '@deepseek-ai/dsh-sandbox-local'
2026-06-21 12:03:44 +08:00
- id : bash
2026-07-14 01:09:44 +08:00
name : '@deepseek-ai/dsh-bash-sandbox'
2026-06-16 11:10:25 +08:00
config :
2026-06-21 12:03:44 +08:00
timeoutMs : 60000
2026-07-14 01:09:44 +08:00
mode : !!js "process.env.DSH_PERMISSION_MODE ?? (process.env.DSH_SNAPSHOT === undefined ? 'workspace-write' : 'danger-full-access')"
workspaceRoot : !!js process.cwd()
- id : approval
name : '@deepseek-ai/dsh-user-approval'
config :
policy : !!js "(process.env.DSH_PERMISSION_MODE ?? (process.env.DSH_SNAPSHOT === undefined ? 'workspace-write' : 'danger-full-access')) === 'danger-full-access' ? 'never' : 'ask'"
- id : permission
name : '@deepseek-ai/dsh-permission'
2026-06-16 11:10:25 +08:00
2026-06-21 12:03:44 +08:00
# The ACP server app: the agent-core spine + JSONL persistence + the ACP bridge.
# 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'
2026-06-16 11:10:25 +08:00
config :
2026-06-21 12:03:44 +08:00
model : deepseek-v4-flash
persistenceRoot : !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
2026-07-05 23:23:46 +08:00
# The persona: identity + behavior only, nothing about transports or
# tooling — tool guidance lives with each tool plugin (descriptions +
# prompt sections). {{model}} and {{cwd}} are prompt variables the agent
# loop resolves per session (every ACP session carries the client's cwd,
# so the persona can state the workspace).
persona : |
2026-07-14 01:09:44 +08:00
You are a coding assistant powered by the {{model}} model. Your working directory is {{cwd}}. Your bash tool runs under a file sandbox — a `[sandbox: file access denied …]` result is policy, not a command bug.
2026-06-21 12:03:44 +08:00
2026-07-11 22:33:33 +08:00
Verify your work by running the code or tests. Keep answers brief and factual.
2026-06-29 10:30:52 +08:00
2026-06-22 17:00:59 +08:00
# The subagent seam + both in-process backends + two model-facing tools, as leaf
# entries after the app (which provides ctx.agents/ctx.tools). spawn (a fresh
# child) and fork (a child seeded with the parent's completed-turn prefix) are
# both reachable by the model: dsh-tool-subagent is loaded once per backend with
# a distinct toolName (subagent → spawn, subagent_fork → fork), so a multi-child
# scenario can exercise both transports.
2026-06-22 08:39:36 +08:00
- id : subagent
name : '@deepseek-ai/dsh-subagent'
- id : subagent-spawn
name : '@deepseek-ai/dsh-subagent-spawn'
config :
providerName : spawn
- id : subagent-fork
name : '@deepseek-ai/dsh-subagent-fork'
config :
providerName : fork
- id : tool-subagent
name : '@deepseek-ai/dsh-tool-subagent'
config :
provider : spawn
2026-06-22 17:00:59 +08:00
toolName : subagent
- id : tool-subagent-fork
name : '@deepseek-ai/dsh-tool-subagent'
config :
provider : fork
toolName : subagent_fork
2026-06-29 10:30:52 +08:00
2026-07-05 13:29:35 +08:00
2026-07-09 18:50:29 +08:00
# Dynamic workflows: the worker-thread engine (ctx.workflows) over the spawn
# subagent backend above, plus the model-facing `workflow` tool. The model
# writes a JavaScript orchestration script (meta + body); the engine runs it
# in its own worker thread and fans agent() calls out as spawn children.
2026-07-09 19:06:55 +08:00
- id : workflow-workerthread
name : '@deepseek-ai/dsh-workflow-workerthread'
2026-07-05 13:29:35 +08:00
config :
provider : spawn
- id : tool-workflow
name : '@deepseek-ai/dsh-tool-workflow'
2026-06-29 10:30:52 +08:00
# The model-facing todo_write tool: whole-list task tracking written to the
# session log (todo/write), surfaced to the ACP client as a `plan` update.
- id : tool-todo
name : '@deepseek-ai/dsh-tool-todo'
2026-07-01 04:22:00 +08:00
2026-07-08 14:24:20 +08:00
# The repeat-tool-call guard: advisory reminders (injected context, never a
# block) when the model re-issues the same tool call with identical arguments;
# defaults [3, 5, 8]. Loaded here so the snapshot tier exercises the reminder
# transcript (the repeat-tool-guard scenario) — no other scenario repeats a
# call three times, so it is inert everywhere else.
- id : repeat-tool-guard
name : '@deepseek-ai/dsh-repeat-tool-guard'
2026-07-14 01:09:44 +08:00
# Filesystem tools do not ride the bash sandbox, so the confined default omits
# them. Snapshot tests and explicit danger-full-access launches keep the
# established filesystem scenarios by enabling the whole stack together.
2026-07-02 12:55:01 +08:00
- id : fs-local
name : '@deepseek-ai/dsh-fs-local'
2026-07-14 01:09:44 +08:00
disabled : !!js "(process.env.DSH_PERMISSION_MODE ?? (process.env.DSH_SNAPSHOT === undefined ? 'workspace-write' : 'danger-full-access')) !== 'danger-full-access'"
2026-07-02 12:55:01 +08:00
config :
cwd : !!js process.cwd()
- id : fs-policy
name : '@deepseek-ai/dsh-fs-policy'
2026-07-14 01:09:44 +08:00
disabled : !!js "(process.env.DSH_PERMISSION_MODE ?? (process.env.DSH_SNAPSHOT === undefined ? 'workspace-write' : 'danger-full-access')) !== 'danger-full-access'"
2026-07-02 12:55:01 +08:00
- id : tool-fs
name : '@deepseek-ai/dsh-tool-fs'
2026-07-14 01:09:44 +08:00
disabled : !!js "(process.env.DSH_PERMISSION_MODE ?? (process.env.DSH_SNAPSHOT === undefined ? 'workspace-write' : 'danger-full-access')) !== 'danger-full-access'"
2026-07-04 03:09:37 +08:00
2026-07-01 16:34:28 +08:00
# The Claude Code hook bridge. `configPath` is PROCESS-LEVEL: it is read ONCE at
# load and the relative `./hooks.json` resolves against the ACP server's launch
# cwd, NOT each `session/new.cwd`. So a single `hooks.json` next to where the
# server starts applies to every session; a project-local, per-session hooks.json
# is NOT discovered (per-session config resolution is a TODO — see the bridge
# README). With no file present the parse fails-soft and the bridge registers
# nothing (a silent no-op). Hooks THEMSELVES run in the session cwd (the bridge
# passes it as the workdir); only WHERE the config is read from is process-level.
# stdout is the ACP JSON-RPC channel — the bridge's warnings go through ctx.logger
# (no exporter here), never to stdout.
2026-07-01 04:22:00 +08:00
- id : hooks-claude
name : '@deepseek-ai/dsh-hooks-claude'
config :
configPath : ./hooks.json
2026-07-04 00:40:35 +08:00
# The Codex hook bridge, loaded alongside the Claude one. It reads its OWN config
# file (`./codex-hooks.json`, Codex's snake_case five-event dialect) — the two
# bridges cannot share one file, so each owns a distinct path. Same process-level
# read-once semantics and same fails-soft-when-absent contract: a launch cwd with
# no `codex-hooks.json` registers nothing (a silent no-op through ctx.logger, never
# stdout). The example ships both bridges so a scenario can exercise EITHER dialect
# end-to-end by seeding the matching file in its workspace/.
- id : hooks-codex
name : '@deepseek-ai/dsh-hooks-codex'
config :
configPath : ./codex-hooks.json