Plugins

Plugins are how OpenVesper interacts with the outside world. They wrap APIs, expose tools, and ship with TypeScript types. Every external capability โ€” querying a price, sending a Telegram message, reading a file โ€” lives in a plugin.

Anatomy of a plugin

Each plugin is a workspace package:

packages/plugins/weather/
โ”œโ”€โ”€ package.json           Name, version, dependencies
โ”œโ”€โ”€ tsconfig.json          TypeScript config
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ index.ts           Plugin definition
โ””โ”€โ”€ README.md              Usage and examples (optional)

Minimal plugin

Here's a complete plugin with a single tool, in about 25 lines:

// packages/plugins/weather/src/index.ts
import axios from "axios";
import { definePlugin, defineTool, inputSchema } from "@openvesper/plugin-sdk";

async function getWeather(location: string) {
  // Open-Meteo is free, no API key required
  const r = await axios.get("https://api.open-meteo.com/v1/forecast", {
    params: { latitude: 52.52, longitude: 13.41, current_weather: true },
  });
  return {
    success: true,
    data: { location, ...r.data.current_weather },
  };
}

export default definePlugin({
  name: "weather",
  version: "1.0.0",
  description: "Current weather and forecast for any location",
  tools: [
    defineTool({
      name: "get_weather",
      description: "Get current weather for a location",
      inputSchema: inputSchema({
        location: { type: "string", description: "City name" },
      }, ["location"]),
      handler: async (input) => getWeather(input.location as string),
      category: "lifestyle",
      permission: "external",  // calls an external API
    }),
  ],
});

Plugin SDK reference

definePlugin(spec)

Top-level plugin definition. Returns the plugin so it can be loaded.

definePlugin({
  name: string;          // Unique plugin name
  version: string;       // semver
  description: string;   // One-line summary
  tools: Tool[];         // Array of tools this plugin exposes
  agents?: Agent[];      // Optional: agents shipped with this plugin
})

defineTool(spec)

Define a single callable tool.

defineTool({
  name: string;             // Tool name, snake_case
  description: string;      // Shown to the LLM โ€” make it clear
  inputSchema: object;      // JSON Schema for input validation
  handler: async (input) => ToolResult;
  category: ToolCategory;   // "crypto" | "research" | "lifestyle" | ...
  permission?: Permission;  // "external" | "filesystem" | "shell" | undefined
})

inputSchema(props, required)

Helper to build a JSON Schema. Less verbose than writing JSON by hand.

inputSchema(
  {
    symbol: { type: "string", description: "Ticker, e.g. BTC" },
    interval: { type: "string", description: "5m, 15m, 1h, 4h, 1d" },
  },
  ["symbol"]  // required fields
)

ToolResult shape

Every tool returns the same shape so the runtime can handle it uniformly:

type ToolResult =
  | { success: true; data: unknown }
  | { success: false; error: string };

The 47 shipped plugins

Plugins are grouped into 12 categories. Click any category for the full list at /integrations.

CategoryPlugins
Crypto corecrypto, derivatives, defi, whale, onchain, security
Solanasolana, solana-dev, bagsfm, memescan, base-meme
Trading datastrategies, macro, airdrop, nft, tracking
Commstelegram, slack, discord, email
Productivitycalendar, notes, tracking, code
Researchresearch, news, twitter, youtube, books
Systemfilesystem, shell, code, browser, dns
Datadatabase, banking, ecommerce
Mediamusic, movies, voice, translate, imagegen
Smart homesmarthome, weather, maps
Misctracking, smarthome, sports, gaming

Tool permissions

The permission field signals what the tool needs at runtime. The agent runtime uses this for confirmation prompts in interactive sessions and for audit logs.

PermissionMeaning
externalCalls an external HTTP API (CoinGecko, GitHub, etc.)
filesystemReads or writes local files
shellExecutes shell commands
networkOpens arbitrary network connections
mutationPerforms side-effects (transfer, post, send)

Tools without a permission flag are assumed to be pure / read-only. Mutating tools (sending messages, transferring funds, modifying files) must declare one. See Sandboxing for details.

Writing your first plugin

1. Scaffold the directory

mkdir packages/plugins/myplugin
cd packages/plugins/myplugin

2. Create package.json

{
  "name": "@openvesper/plugin-myplugin",
  "version": "1.0.0",
  "type": "module",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "build": "tsc"
  },
  "dependencies": {
    "@openvesper/plugin-sdk": "workspace:*",
    "axios": "^1.7.7"
  }
}

3. Create tsconfig.json

{
  "extends": "../../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}

4. Write your plugin

See the minimal plugin example at the top of this page.

5. Install and build

# From repo root
pnpm install
pnpm --filter @openvesper/plugin-myplugin build

6. Register the plugin

Add the plugin to apps/cli/src/index.ts (or whichever app should expose it):

import myplugin from "@openvesper/plugin-myplugin";

// In the runtime setup:
runtime.use(myplugin);

Design principles

Read-only by default

Most OpenVesper plugins are read-only. They fetch data from public APIs and return it. Mutating operations (sending, transferring, posting) are clearly marked and require explicit permission flags.

No key management

Plugins read credentials from environment variables only. They never write keys to disk, never transmit them to OpenVesper servers (there are no OpenVesper servers), and never log them. See Security.

Errors over exceptions

Tool handlers return { success: false, error: "..." } instead of throwing. This makes the runtime simpler and forces explicit error messaging that's helpful to the LLM.

What's next?

  • Agents โ€” how agents reference plugins
  • Skills โ€” modular instructions agents pull in
  • All 47 plugins โ€” browse the catalogue