DeepSeek Harness Plugin Playbooks
August 17, 2026 ยท View on GitHub
Use this reference to move from a user request to a first working plugin slice.
Type Router
| User asks for | Start with | Main extension point | Template |
|---|---|---|---|
| A new model-callable action | Model-facing tool | ctx.tools.register() | templates.md#model-facing-tool |
| Permission, approval, timeout, retry, audit, result filtering | Hook/policy plugin | tools/pre-execute, ctx.tools.guard(), tools/execute, tools/post-execute, tools/result | templates.md#hook-policy-plugin |
| Extra request context | Context injector | agent/pre-step or agent.inject() plus durable user/message source | templates.md#context-injector |
| A new swappable capability | Capability seam | Service Definition + Provider + Consumer | templates.md#service-definition-and-provider |
| A new provider for an existing capability | Service Provider | Register behind the existing ctx.<service> API | templates.md#service-definition-and-provider |
| A new model backend | LLM adapter | ctx.llm adapter registration | live docs/cookbook/adding-an-llm-adapter.md |
| A UI/business chat node | UI plugin | session/event, ctx.agents, or conversation node registration | live docs/cookbook/adding-a-conversation-node.md |
| A profile/bundle install path | Bundle/profile wiring | Cordis config rows and package dsh metadata | live bundle packages |
Universal First Slice
- Read
docs/architecture.md,packages/AGENTS.md, and the relevant cookbook. - Locate the closest package by role with
rgorfind packages -path '*/package.json'. - Copy the local style, not the exact code.
- Implement only one current behavior and one current caller.
- Add a package README section for owned API/config/model experience.
- Add
src/invariant.ts. If there is no runtime relation, write the specific no-runtime-invariant reason and register ownership. - Add focused tests. For product-visible behavior, include a real Loader/app/process composition test.
- Add an Agent Note for non-trivial changes.
- Run focused tests and the smallest relevant gates.
Model-Facing Tool Playbook
- Read
docs/cookbook/adding-a-tool.md. - Inspect a nearby
packages/*/tool-*package. - Define the canonical JSON return value before writing prose.
- Implement
defineTool()with schema,execute,output.schema, andoutput.render. - Put handles, ids, paths, and structured fields in the canonical value. Do not require Code Mode or UI to parse rendered text.
- Add pure
presentCall,presentResult, andpresentationMetaonly when UI replay needs card data. - Route deployment policy through
tools/*listeners instead of embedding it in the tool. - Test argument validation, success value, error containment, cancellation, rendering, and disposal.
- Add snapshot coverage when model-visible output changes in the assembled app.
Hook Or Policy Playbook
- Choose the event by ownership:
tools/pre-execute: allow, deny, or ask before execution.ctx.tools.guard(): final monotonic denial.tools/execute: wrap dispatch lifetime for deadlines, retries, or metrics.tools/post-execute: transform/block result or attach model-facing context.tools/result: observe immutable final outcome.agent/pre-step,agent/request,agent/turn-stopping: request and turn policies.
- Call
next()for waterfall listeners unless intentionally short-circuiting. - Keep policy decisions enforceable at the operation that makes the decision.
- Test allow and deny paths through the real executor, not only direct helper calls.
Context Injector Playbook
- Decide whether context wakes the agent.
agent.inject()queues context for the next admitted request; it does not wake an idle agent. - If the model sees the context, make it durable as a
user/messagewith source{ kind: 'plugin', plugin: '<name>' }or a package-owned session event rendered into history. - Derive scheduling from durable events when resume or compaction matters.
- Add an invariant that validates source ownership, rendering, and event position.
- Test first step, later steps, rejection/failure containment, resume behavior when relevant, and duplicate suppression.
Capability Seam Playbook
- Identify all current consumers before designing the Service Definition.
- Keep provider-specific concepts out of the Service Definition unless all current consumers need them.
- Put defaults in an explicit
resolve(request): Specstep owned by the implementation, not hidden insiderun(). - Split packages only when roles evolve independently.
- Test the Service Definition contract, at least one provider, and at least one consumer path.
- Document provider limitations and model/token effects in the owning READMEs.
Fast Scaffold Use
Use scripts/create-function-plugin.sh only for simple function plugins such as hooks, context injectors, or local policy plugins. Do not use it for Service Definition packages, LLM adapters, client plugins, or generated API packages.
After scaffolding:
- Add the package to
tsconfig.host.jsonortsconfig.client.json. - Add peer/dev dependencies for every injected service.
- Replace placeholder README and invariant text.
- Add tests under package-level
tests/. - Run
pnpm run constraints && pnpm run typecheckbefore expanding behavior.
Verification Matrix
| Change | Minimum useful evidence |
|---|---|
| New package skeleton | pnpm run constraints, pnpm run typecheck |
| Tool behavior | focused package tests plus real composition test |
| Model-visible text or tool schema | snapshot through a runnable example |
| README/JSDoc/prose | pnpm run doc-sync and prose review |
| Registry contribution | disposal/HMR test |
| Provider behavior | provider contract tests; e2e only when real external behavior is required |
| Published package surface | pnpm run build && pnpm run hygiene when the emitted package surface changes |