Files
deepseek-harness/docs/cookbook/extension-cookbook.md
T
Tianyi Cui 39b3db4b9c docs: accuracy sweep, architecture restructure, two ADRs, review skill
- AGENTS.md Commands: fix typecheck/build descriptions; add lint, lint:fix,
  test:coverage, knip, publint, hygiene (were undocumented).
- Drop the bare `yarn demo` for explicit `demo:echo` + `demo:coding`; update
  README, examples READMEs (and document coding-agent in examples/README).
- New cookbook guide: adding-a-vendored-package.md (the missing "add" half of
  vendor/README's update-only procedure).
- architecture.md: add a table-of-contents and extract the Extension cookbook
  to docs/cookbook/extension-cookbook.md (link-preserving); drop the completed
  "restructure this document" TODO.
- ADR 0009 (capability seams) + 0010 (twin LLM adapters), and a "when to write
  an ADR" standard in adr/README.
- Add a committed dsh-code-review skill under .agents/skills, exposed to Claude
  Code via a tracked .claude/skills symlink (gitignore carve-out).
2026-06-13 22:05:34 +08:00

2.2 KiB

Cookbook: extension plugin shapes

The three plugin shapes you write against the harness extension surface, as illustrative snippets (elided imports and helper stubs — not copy-paste-complete). For the full step-by-step guides see adding a package, adding a tool, and adding an LLM adapter; for the seams these hook into see docs/architecture.md.

A tool plugin

A tool registers on ctx.tools. The annotated defineTool example (typed execute args, result shaping, the run_in_background pattern) lives in adding-a-tool.md — that guide is the source of truth for the tool shape. Raw JSON-Schema ToolDefinitions are also accepted by ctx.tools.register() directly (that is how MCP-sourced tools arrive); defineTool is the typed sugar for first-party tools.

A hook plugin (permission gate)

A hook wraps the tools/execute waterfall to veto or rewrite a call — the seam where sandbox, permission, and plan-mode plugins live.

export const name = 'permission-gate'

export function apply(ctx: Context) {
  ctx.on('tools/execute', async (exec, next) => {
    if (!(await isAllowed(exec))) {
      return {
        callId: exec.callId,
        content: [{ type: 'text', text: 'Denied by policy.' }],
        isError: true,
      }
    }
    return next()
  })
}

A UI plugin

A UI plugin consumes agent/stream-chunk and session events for rendering, and drives input back in via agent.send() / agent.steer().

export const name = 'my-ui'
export const inject = ['agents']

export function apply(ctx: Context) {
  ctx.on('agent/stream-chunk', (agent, turn, step, chunk) => {
    if (chunk.type === 'text-delta') render(chunk.text)
  })
  onUserInput(text => ctx.agents.get('main')?.send([{ type: 'text', text }]))
}

Runnable wirings

Two complete examples load their plugin trees from cordis.yml with HMR: examples/echo-agent (mock model + echo tool — the all-mock skeleton check, yarn demo:echo) and examples/coding-agent (DeepSeek V4 + the bash tool suite — the real thing, yarn demo:coding).