donmai is in 0.x preview. APIs may change between minor releases. See the changelog.

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/core

ToolPlugin 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 plugin

Tool 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 operations
  • af_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.