Skip to main content
Plugins are packages of reusable agent capabilities. They let you bundle tools, lifecycle hooks, commands, and configuration into a single module that can be shared across projects or published for others to use.

Benefits of Plugins

Extension Glossary

What is a Plugin?

A plugin is an AgentPlugin — an object that implements the SDK’s extension interface. It can register tools, hook into agent lifecycle events, and provide configuration defaults.
Hooks are defined inside the hooks object, not directly on the extension. The available lifecycle hooks are beforeRun, afterRun, beforeModel, afterModel, beforeTool, afterTool, and onEvent.

Next Steps

Register with ClineCore:

File-Based Plugins

ClineCore supports plugin module paths via pluginPaths in session config:
Plugin files export an AgentPlugin.

How Plugins Run

By default each plugin runs in its own worker thread, one per session, inside the host’s runtime. Module-level state is never shared between sessions, no separate node or bun process is started (plugins work in the compiled CLI, the hub, and the desktop app without a runtime on PATH), and a plugin can use the host runtime’s globals, such as Bun under the Bun-built hub. A worker contains its plugin’s failures:
  • A plugin stuck in a loop is stopped at its timeout; the next call starts a fresh worker.
  • An uncaught error, an unhandled rejection, or process.exit() ends only that plugin’s worker. The plugin is marked failed and turned off, like any other fatal plugin error, and the hub and other plugins keep running.
  • Plugin console.log and stdout output are discarded, so they cannot corrupt --json output or a JSON-RPC stream. Use ctx.logger.
Values passed to and returned from a plugin cross a thread boundary, so they must be plain data; functions are dropped. process.cwd() reports the session’s directory, but relative file paths resolve against the host’s, so use ctx.cwd. Workers share the host’s memory limit, environment snapshot, and native addons: this is crash isolation, not a security boundary. Plugin code never runs on the host’s main thread. One other mode is available as an opt-in through CLINE_PLUGIN_MODE (or mode on resolveAndLoadAgentPlugins):
  • sandbox: the previous per-session subprocess sandbox. A compiled Cline CLI uses its embedded Bun runtime; other hosts need node or bun on PATH when the host isn’t node or bun itself, and this mode does not apply the per-session plugin policy or report plugin status.
Both modes need Core’s complete plugin runtime. An SDK host that bundles @cline/core should ship dist/plugin-runtime beside its bundle, or point CLINE_PLUGIN_RUNTIME_DIR at that directory. It includes the bootstrap and SDK package exports used by plugins. Compiled CLI binaries read this artifact directly from their embedded read-only filesystem, without installing SDK packages into each plugin directory. Hosts without a bootstrap fail closed with PluginBootstrapMissingError; plugin code never falls back to the host’s main thread. Plugins are bound to a session when it starts. Adding, editing, or reloading a plugin affects only sessions started afterwards; running sessions keep the plugins and code they started with. Every new session imports the plugin fresh, so any change is picked up; cline hub plugins --reload <plugin> re-checks it and clears a failed status.

Choosing Plugins per Session

Pass a plugins policy when you start a session. It’s shaped like toolPolicies: "*" sets the default, and named entries override it for one plugin. Plugins are enabled unless a policy turns them off.
A session only gets tools, hooks, rules, and providers from plugins it enabled. Plugin tools still go through toolPolicies. The policy applies in worker mode; the opt-in sandbox mode loads every discovered plugin.

Setup and Call Context

setup(api, ctx) receives the session’s context: When a session ends, the host runs your onDispose callbacks. Plugins share the host process, so stop everything you start for a session there: timers, child processes, sockets, listeners on shared emitters.
Plugin tools also receive cwd and emitEvent in their call context (execute(input, context)). globalThis.__clinePluginHost.emitEvent still works for plugins written for the sandbox; it routes to the session whose hook or tool is running.

Plugin Status and Errors

The host wraps every plugin call and records what goes wrong, so a broken plugin never just loses its tools silently. Five failures in a row turn a degraded plugin failed. An import failure, or five failed calls in a row, turns the plugin off for every session using it until it is reloaded or its source changes. A successful reload does not interrupt running sessions: they keep the copy they started with, and new sessions get the new code. A reload whose import fails turns the plugin off for running sessions too, and they are told why. In the hub, a stray exception or unhandled rejection whose stack points into a plugin marks that plugin failed instead of stopping the hub. Each plugin has a status of loading, ready, degraded, failed, or disabled. Its last error records the phase (discover, import, setup, hook:<name>, tool:<name>, command:<name>, or uncaught), the message, the stack, the plugin path, and a timestamp. The status also counts errors and timeouts. To read status:
  • StartSessionResult.pluginIssues lists the plugins the session asked for but doesn’t have.
  • Plugins that fail later in the session (setup() and hooks run on the first turn) are reported to that session as a status notice event, with the issue in metadata.pluginIssue.
  • Hub clients can send plugins.status (or plugins.list) for every plugin’s status, last error, and the sessions using it. plugins.reload with { plugin: "<name or path>" } re-imports one plugin without restarting the hub. The hub broadcasts a plugin.status_changed event when a status changes.

Installing Plugins via CLI

Plugins can also be installed from file URLs, npm, git, or local paths using cline plugin install. See Plugins for install commands, the manifest format, and directory layout.

Hooks

Plugin hooks are functions in the plugin’s hooks object. Each one receives a context with the current runtime snapshot (agent id, conversation id, iteration, messages, usage), and some can return a result that changes what happens next. To block dangerous tool calls, return { skip: true, reason } from beforeTool, or require approval with { policy: { autoApprove: false } }.

When a hook fails

Each plugin hook call has a 3-second timeout. If a hook throws, rejects, or times out, the session’s hookErrorMode decides what happens: A hook that keeps failing marks its plugin degraded, then failed after five failures in a row. See Plugin Status and Errors.

Build a Plugin

For a step-by-step plugin tutorial, see Writing Plugins.

SDK Examples

The SDK repository includes ready-to-run plugin examples under examples/plugins/, including tool registration, lifecycle metrics, notifications, custom compaction, policy guards, web search, background jobs, TypeScript LSP tools, and multi-agent teams. See Plugin Examples for the full list and usage commands.