Answer in brief
Walk from apply(ctx) through configuration, tool registration, result observation, and unload verification.
This exercise follows the official Cordis interfaces while using a small project-status Tool. Developer Preview commands may move, so compare with the current upstream tutorial before running.
1. Start with apply(ctx)
import type { Context } from '@deepseek-ai/cordis'
export const name = 'project-status'
export function apply(ctx: Context) {
console.log('project-status mounted')
}
The Plugin describes contributions; cordis.yml composes them. Rows may start concurrently, so service ordering belongs in inject, not YAML position.
2. Validate Configuration
import Schema from '@deepseek-ai/schemastery'
export interface Config { label: string; maxLength: number }
export const Config: Schema<Config> = Schema.object({
label: Schema.string().default('workspace'),
maxLength: Schema.number().default(200),
})
Values that deployments may change belong in Config. Invalid configuration should fail clearly during load.
3. Register the Tool
import { defineTool } from '@deepseek-ai/dsh-tools'
export const inject = ['tools']
export function apply(ctx: Context, config: Config) {
ctx.tools.register(defineTool({
name: 'project_status',
description: 'Return the configured tutorial workspace label.',
parameters: {},
output: {
schema: { type: 'string' },
render: (_args, value) => [{ type: 'text', text: value }],
},
async execute() {
return config.label.slice(0, config.maxLength)
},
}))
}
The registration disposer belongs to the Plugin lifecycle, so unload should remove the Tool.
4. Compose and Observe
- name: '@deepseek-ai/dsh-system-prompt'
- name: '@deepseek-ai/dsh-tools'
- name: './project-status.ts'
config:
label: 'tutorial-workspace'
maxLength: 80
Add a separate observer for tools/result and log only tool name, status, and a bounded summary. The producer and observer remain decoupled through registry and events.
Verify one mount, Tool discovery, valid output, load-time rejection of invalid config, no duplicate registration after HMR, removal on unload, and no credentials in logs.
Test first through the real execution pipeline without a model key; then mount the patch into Web UI and test model selection. This separates implementation failures from model routing behavior.
Return to the Tutorial Hub for architecture and security tracks.