Plugin docs

Amber is built to be extended. Its own providers, core tools, status bar and registry console are all plugins, the same API described here. There is no privileged internal path.

Two tiers

Where a plugin runs is an isolation decision, not a size decision. Pick deliberately:

Core pluginExternal plugin
LanguageC++17, compiled inAny executable
IsolationSame process; a crash takes amber downSeparate process; a crash cannot
Can contributeTools, providers, prompt blocks, status segments, panels, wallets, allowances, event subscriptionsTools only
Distributionplugins/<id>/, compiled in~/.config/amber/plugins/<id>/
Cost per callnone (direct call)IPC round trip

Which tier?

flowchart TD
    start(["Which plugin tier?"]) --> isolation{"Needs arbitrary or<br/>other-language code,<br/>or crash containment?"}
    isolation -->|yes| external["External plugin<br/>separate process · JSON-RPC<br/>tools only"]
    isolation -->|no| contributes{"Contributes anything<br/>beyond a tool?"}
    contributes -->|yes| core["Core plugin<br/>C++17 · compiled in"]
    contributes -->|no| wire{"OpenAI-wire<br/>compatible endpoint?"}
    wire -->|yes| file["No code needed<br/>a provider file is enough"]
    wire -->|no| core
Where a plugin runs is an isolation decision, not a size decision.

Quickstart

A complete, compiled, tested template ships in the repository atplugins/_template/ (exercised bytests/example_plugin_test.cpp). The shape:

class HelloPlugin : public agent::IPlugin {
public:
    std::string id()      const override { return "hello"; }
    std::string version() const override { return "1.0.0"; }
    std::string name()    const override { return "Hello"; }

    bool initialize(const agent::PluginContext&) override { return true; }
    void shutdown() override {}

    std::vector<std::unique_ptr<agent::Capability>> capabilities() override;
};

Then declare what it contributes:

std::vector<std::unique_ptr<agent::Capability>> HelloPlugin::capabilities() {
    std::vector<std::unique_ptr<agent::Capability>> caps;
    caps.push_back(std::make_unique<agent::ToolCapability>(
        "greet", [](agent::PluginServices&) {
            std::vector<std::unique_ptr<agent::Tool>> tools;
            tools.push_back(std::make_unique<GreetTool>());
            return tools;   // empty list = declined, not an error
        }));
    return caps;
}
  1. Create plugins/<id>/ with your plugin class.
  2. Declare capabilities in capabilities().
  3. Register it in make_bundled_plugins() (lib/plugins_bundled.cpp) and add the object to Makefile.in.
  4. Write a hermetic test (see Testing).

You declare; the runtime installs. Every contribution goes through the ledger, which is what makes disable total. A plugin that registers outside this path cannot be disabled cleanly, that is the one rule the framework is built around.

Slash command quickstart

To expose logic through the slash engine, contribute aCommandCapability: declare the JSON mapping, expose the callback, and the host binds it. The bundled plugins/hello/ is this exact example, type /hello greet amber and it returnsHello, amber!

agent::CommandSpec spec;
spec.root = "hello";
spec.help = "Say hello";
spec.subtree = agent::json::parse(R"({"greet": {"help": "Greet someone"}})");
spec.handlers["greet"] = [](const std::string& arg) {
    return "Hello, " + (arg.empty() ? std::string("world") : arg) + "!";
};
caps.push_back(std::make_unique<agent::CommandCapability>(std::move(spec)));

The handler returns the text to display and the host prints it, so the plugin stays free of any UI dependency. SeeCapabilities → Command for the full contract.

In this reference

Availability

What ships today, at a glance. Thedeveloper guideis the canonical source; this table mirrors it.

CapabilityStatus
External tool plugin (JSON-RPC)✅ Available
Tool contribution (incl. core tools)✅ Available
Typed event subscription✅ Available
Prompt block contribution✅ Available
Provider contribution✅ Available
Status segment contribution✅ Available
Panel contribution✅ Available
Wallet / allowance readout✅ Available
Command contribution (slash namespace)✅ Available
Host services to the user (ask/choose/confirm)Not available
Per-plugin settings, log sinksNot available
PluginLoaded / PluginUnloaded eventsDeclared, never published

Source

Found a gap in the framework? That is abug report or feature request, and a good one.

amber 0.5.8Apache 2.0C++17
utf-8ncursesJacek Trefon www.trefon.com2026