- Identify the capabilities a task actually needs.
- Avoid collecting unnecessary tools.
- Create a reproducible profile.
Minimum capabilities
A code review may need search, read access and tests. A document summary does not need shell access. Every extra tool increases the error surface and audit burden.
- Model: provider, name and parameters.
- Tools: files, shell, web or APIs only when necessary.
- Policy: which actions need confirmation.
- Observability: logs and execution evidence.
How a Profile is composed
A profile contains a `package.json` with plugin dependencies and a `dsh.profile` manifest with the ordered bundle list. It also has a `cordis.patch.yml` with your configuration layer.
The CLI composes bundle patches first, then the profile patch, then `$DSH_HOME/cordis.patch.yml`, then overlays passed through `--patch`.
Conceptual order: 1. profile bundles 2. profile cordis.patch.yml 3. $DSH_HOME/cordis.patch.yml 4. --patch overlays # Inspect without booting dsh --profile web --dump-default-config dsh --profile web --dump-config
Your first minimal plugin
The official development guide starts with a TypeScript plugin exporting `name` and `apply(ctx)`. Cordis calls `apply` when loading it, and the context registers capabilities.
To test it in the Web UI from a repository checkout, create an absolute-path patch and run `pnpm dsh web --patch ./scratch-plugin/cordis.yml`.
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) {
console.log('[hello-plugin] plugin loaded!')
}Dependencies and cleanup
If a plugin consumes a service such as `tools`, declare `inject = ['tools']`; Cordis waits for the service before loading it.
Everything registered through `ctx` is cleaned up on unload. For external resources such as sockets or timers, use `ctx.effect()` and return a disposer.
export const name = 'my-tool-plugin'
export const inject = ['tools']
export function apply(ctx) {
ctx.tools.register(/* ... */)
ctx.effect(() => {
const timer = setInterval(() => {}, 5000)
return () => clearInterval(timer)
})
}Regression check
After adding a plugin, repeat a short task you already know. If it worsens the result, raises cost or introduces unrequested actions, revert to the previous profile.
Profile: read-only-review Tools: search, read Forbidden: write, network, destructive commands Output: findings with file and line evidence
Si has guardado la evidencia de esta lección, continúa con «Subagents, skills and orchestration». Si no, repite la comprobación antes de avanzar.