Skip to content

Building Plugins

Building Plugins

Plugins extend RemoteClaw with new capabilities: channels, model providers, speech, image generation, web search, agent tools, or any combination.

You do not need to add your plugin to the RemoteClaw repository. Publish to ClawHub or npm and users install with remoteclaw plugins install <package-name>. RemoteClaw tries ClawHub first and falls back to npm automatically.

Prerequisites

  • Node >= 22 and a package manager (npm or pnpm)
  • Familiarity with TypeScript (ESM)
  • For in-repo plugins: repository cloned and pnpm install done

What kind of plugin?

Connect RemoteClaw to a messaging platform (Discord, IRC, etc.) Add a model provider (LLM, proxy, or custom endpoint) Register agent tools, event hooks, or services — continue below

Quick start: tool plugin

This walkthrough creates a minimal plugin that registers an agent tool. Channel and provider plugins have dedicated guides linked above.

```json package.json { "name": "@myorg/remoteclaw-my-plugin", "version": "1.0.0", "type": "module", "remoteclaw": { "extensions": ["./index.ts"] } } ```
```json remoteclaw.plugin.json
{
"id": "my-plugin",
"name": "My Plugin",
"description": "Adds a custom tool to RemoteClaw",
"configSchema": {
"type": "object",
"additionalProperties": false
}
}
```
</CodeGroup>
Every plugin needs a manifest, even with no config. See
[Manifest](/plugins/manifest) for the full schema.
index.ts
```typescript
import { definePluginEntry } from "remoteclaw/plugin-sdk/plugin-entry";
import { Type } from "@sinclair/typebox";
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
description: "Adds a custom tool to RemoteClaw",
register(api) {
api.registerTool({
name: "my_tool",
description: "Do a thing",
parameters: Type.Object({ input: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: `Got: ${params.input}` }] };
},
});
},
});
```
`definePluginEntry` is for non-channel plugins. For channels, use
`defineChannelPluginEntry` — see [Channel Plugins](/plugins/sdk-channel-plugins).
For full entry point options, see [Entry Points](/plugins/sdk-entrypoints).
**External plugins:** publish to [ClawHub](/tools/clawhub) or npm, then install:
```bash
remoteclaw plugins install @myorg/remoteclaw-my-plugin
```
RemoteClaw checks ClawHub first, then falls back to npm.
**In-repo plugins:** place under `extensions/` — automatically discovered.
```bash
pnpm test -- extensions/my-plugin/
```

Plugin capabilities

A single plugin can register any number of capabilities via the api object:

CapabilityRegistration methodDetailed guide
Text inference (LLM)api.registerProvider(...)Provider Plugins
Channel / messagingapi.registerChannel(...)Channel Plugins
Speech (TTS/STT)api.registerSpeechProvider(...)Provider Plugins
Media understandingapi.registerMediaUnderstandingProvider(...)Provider Plugins
Image generationapi.registerImageGenerationProvider(...)Provider Plugins
Web searchapi.registerWebSearchProvider(...)Provider Plugins
Agent toolsapi.registerTool(...)Below
Custom commandsapi.registerCommand(...)Entry Points
Event hooksapi.registerHook(...)Entry Points
HTTP routesapi.registerHttpRoute(...)Internals
CLI subcommandsapi.registerCli(...)Entry Points

For the full registration API, see SDK Overview.

Registering agent tools

Tools are typed functions the LLM can call. They can be required (always available) or optional (user opt-in):

register(api) {
// Required tool — always available
api.registerTool({
name: "my_tool",
description: "Do a thing",
parameters: Type.Object({ input: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: params.input }] };
},
});
// Optional tool — user must add to allowlist
api.registerTool(
{
name: "workflow_tool",
description: "Run a workflow",
parameters: Type.Object({ pipeline: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: params.pipeline }] };
},
},
{ optional: true },
);
}

Users enable optional tools in config:

{
tools: { allow: ["workflow_tool"] },
}
  • Tool names must not clash with core tools (conflicts are skipped)
  • Use optional: true for tools with side effects or extra binary requirements
  • Users can enable all tools from a plugin by adding the plugin id to tools.allow

Import conventions

Always import from focused remoteclaw/plugin-sdk/<subpath> paths:

import { definePluginEntry } from "remoteclaw/plugin-sdk/plugin-entry";
import { createPluginRuntimeStore } from "remoteclaw/plugin-sdk/runtime-store";
// Wrong: monolithic root (deprecated, will be removed)
import { ... } from "remoteclaw/plugin-sdk";

For the full subpath reference, see SDK Overview.

Within your plugin, use local barrel files (api.ts, runtime-api.ts) for internal imports — never import your own plugin through its SDK path.

Pre-submission checklist

package.json has correct remoteclaw metadata remoteclaw.plugin.json manifest is present and valid Entry point uses defineChannelPluginEntry or definePluginEntry All imports use focused plugin-sdk/<subpath> paths Internal imports use local modules, not SDK self-imports Tests pass (pnpm test -- extensions/my-plugin/) pnpm check passes (in-repo plugins)

Next steps

Build a messaging channel plugin Build a model provider plugin Import map and registration API reference TTS, search, subagent via api.runtime Test utilities and patterns Full manifest schema reference