A donmai plugin is a TypeScript package that exports an object implementing the
ToolPlugin interface. The interface is defined in @donmai/core and also
re-exported by the individual plugin packages for structural compatibility.
Install the types package
npm install --save-dev @donmai/coreToolPlugin interface
import type { SdkMcpToolDefinition } from '@anthropic-ai/claude-agent-sdk'
export interface ToolPlugin {
/** Unique plugin name, used as the MCP server name (e.g. 'af-linear') */
name: string
/** Human-readable description */
description: string
/**
* Return the MCP tool definitions this plugin contributes.
* Called once per agent spawn.
*/
createTools(context: ToolPluginContext): SdkMcpToolDefinition<any>[]
}ToolPluginContext
createTools(context) receives a ToolPluginContext with:
export interface ToolPluginContext {
/** Environment variables available to the agent */
env: Record<string, string>
/** Working directory for the agent session */
cwd: string
/**
* Optional delegate for cross-session file reservation.
* Present when the daemon orchestrates parallel sessions.
*/
fileReservation?: {
reserveFiles(
sessionId: string,
filePaths: string[],
reason?: string,
): Promise<{
reserved: string[]
conflicts: Array<{
filePath: string
heldBy: { sessionId: string; reservedAt: number }
}>
}>
checkFileConflicts(
sessionId: string,
filePaths: string[],
): Promise<Array<{
filePath: string
heldBy: { sessionId: string; reservedAt: number }
}>>
releaseFiles(sessionId: string, filePaths: string[]): Promise<number>
releaseAllSessionFiles(sessionId: string): Promise<number>
}
}Minimal example
The example below creates a single tool named greet that returns a greeting:
// src/index.ts
import { z } from 'zod'
import { tool } from '@anthropic-ai/claude-agent-sdk'
import type { ToolPlugin, ToolPluginContext } from '@donmai/core'
const plugin: ToolPlugin = {
name: 'example-plugin',
description: 'Example plugin that greets users.',
createTools(context: ToolPluginContext) {
return [
tool(
'example_greet',
'Return a greeting for the given name.',
{ name: z.string().describe('Name to greet') },
async (args) => {
return {
content: [
{
type: 'text' as const,
text: `Hello, ${args.name}! (cwd: ${context.cwd})`,
},
],
}
},
),
]
},
}
export default pluginTool naming convention
Tool names use the <namespace>_<action> pattern with underscores. The
namespace typically matches the plugin's functional area:
af_linear_*— Linear issue tracker operationsaf_code_*— Code intelligence operations
Follow this pattern for custom plugins to keep the tool palette consistent.
Using environment variables
Credentials and settings available to the agent session are passed through
context.env. Do not read process.env directly inside createTools() —
in hosted mode the agent runs in an isolated environment where process.env
may not carry the values you expect.
createTools(context: ToolPluginContext) {
const apiKey = context.env['MY_SERVICE_API_KEY']
// use apiKey in tool implementations
}Publishing
Plugins intended for the broader donmai ecosystem should be published under
the @donmai/* npm scope. To request scope access, open an issue in the
donmai repository.
For private or internal plugins, any npm package name works — just ensure the package is importable from the environment where your orchestrator runs.