Skip to content

Plugins

Plugins are swappable, shape-conforming components. Built-in and user-provided plugins follow the exact same shapes — the plugin registry auto-discovers both on startup.

Plugin Shape

Every plugin has a top-level Plugin record:

gleam
pub type Plugin {
  Plugin(
    name: String,
    description: String,
    plugin_type: PluginType,
    supervised: Bool,
    start: fn() -> Result(Nil, String),
    stop: fn() -> Result(Nil, String),
    health: fn() -> Result(String, String),
  )
}

The plugin_type determines which sub-type shape the plugin must also implement.

Plugin Types

Tools

Things the agent can do. Each tool implements the Tool shape:

gleam
pub type Tool {
  Tool(
    name: String,
    description: String,
    parameters: JsonSchema,
    execute: fn(Map(String, JsonValue)) -> Result(String, String),
    parallel_safe: Bool,
  )
}

Built-in tools:

ToolModuleDescription
bashplugins/tools/bash/Shell command execution (sandboxed)
webplugins/tools/web/Web page fetching (SSRF-hardened)
browserplugins/tools/browser/Playwright browser automation (6 actions)
codeplugins/tools/code/Python/Node/Bash code executor
memoryplugins/tools/memory/Memory CRUD (SQLite-backed)
session_searchplugins/tools/session_search/Search past conversations
cronplugins/tools/cron/Cron job management
send_messageplugins/tools/gateways/telegram/Send Telegram messages

Gateways

Channels the agent communicates through. Each gateway implements the Gateway shape:

gleam
pub type Gateway {
  Gateway(
    name: String,
    gateway_type: GatewayType,
    start: fn() -> Result(Nil, String),
    stop: fn() -> Result(Nil, String),
    health: fn() -> Result(String, String),
  )
}

Built-in gateways:

  • Telegram — real Telegram bot using telega's OTP supervision tree with long-polling
  • TUI — terminal UI for the CLI REPL

Hooks

Lifecycle callbacks that fire at specific points in the conversation loop.

Built-in hooks:

  • Context Compressor — summarizes middle conversation messages when the context window fills up
  • Reflection — post-turn memory consolidation (nudge engine)
  • Tool Guardrails — circuit breaker for detecting and interrupting stuck tool loops

Memory Plugins

Persistence backends for agent memory.

Built-in memory plugins:

  • File Memory — file-based memory storage

Writing a Custom Plugin

Custom Tool

Create a module at ~/.agent/tools/my_tool.gleam:

gleam
import plugins/shapes

pub fn plugin() -> shapes.Plugin {
  shapes.Plugin(
    name: "my_tool",
    description: "Does something useful",
    plugin_type: shapes.ToolType(my_tool()),
    supervised: False,
    start: fn() { Ok(Nil) },
    stop: fn() { Ok(Nil) },
    health: fn() { Ok("ok") },
  )
}

fn my_tool() -> shapes.Tool {
  shapes.Tool(
    name: "my_tool",
    description: "Does something useful",
    parameters: shapes.empty_schema(),
    execute: fn(_params) { Ok("Hello from my_tool!") },
    parallel_safe: True,
  )
}

The plugin registry auto-discovers any .gleam file in ~/.agent/tools/ on startup. Your tool appears in the agent's tool list immediately.

Custom Hook

Same pattern — create a module in ~/.agent/hooks/ that implements the Hook shape. Hooks can be BeforeTool (fire before tool execution), AfterTool (after tool execution), or AfterTurn (after each conversation turn).

Custom Gateway

Gateways follow the same pattern in ~/.agent/gateways/. A gateway's job is to translate between the agent's internal message format and an external chat platform. See the built-in Telegram gateway as a reference.

Built with Gleam on the BEAM/Erlang VM.