Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
bmux Plugin SDK
Everything you need to write a bmux plugin.
Quick Start
A bmux plugin is a Rust crate with three files: a manifest, a library, and a Cargo.toml.
1. plugin.toml
= "example.hello"
= "Hello Plugin"
= "0.1.0"
[[]]
= "hello"
= "Print a greeting"
= true
2. src/lib.rs
use *;
;
export_plugin!;
3. Cargo.toml
[]
= "my_plugin"
= "2024"
= "0.1.0"
[]
= ["cdylib", "rlib"]
[]
= { = "..." }
[]
= []
crate-type must include cdylib (for dynamic loading) and rlib (for static bundling into the host binary).
The RustPlugin Trait
Every plugin implements RustPlugin. All five methods have default implementations -- override only what your plugin needs:
| Method | Return type | When to override |
|---|---|---|
run_command |
Result<i32, PluginCommandError> |
Plugin provides CLI commands |
invoke_service |
ServiceResponse |
Plugin provides services to other plugins |
activate |
Result<i32, PluginCommandError> |
Plugin needs setup on activation |
deactivate |
Result<i32, PluginCommandError> |
Plugin needs cleanup on deactivation |
handle_event |
Result<i32, PluginCommandError> |
Plugin subscribes to system events |
The trait requires Default + Send + 'static. Use #[derive(Default)] on your struct.
Writing Command Plugins
Dispatching commands
Use route_command! to match on the command name and auto-generate the unknown-command fallback:
Each arm must evaluate to Result<i32, PluginCommandError>. Unrecognised commands automatically return Err(PluginCommandError::unknown_command(...)).
Error handling
PluginCommandError implements From for common error types, so the ? operator works naturally:
Supported conversions: String, &str, std::io::Error, serde_json::Error, toml::de::Error, Box<dyn Error>, Box<dyn Error + Send + Sync>.
For custom error codes, construct directly:
Err
Err
Exit codes
| Constant | Value | Meaning |
|---|---|---|
EXIT_OK |
0 | Success |
EXIT_ERROR |
1 | Generic failure |
EXIT_USAGE |
64 | Bad arguments or unknown command |
EXIT_UNAVAILABLE |
70 | Plugin unavailable |
Arguments
Commands receive arguments as ctx.arguments: Vec<String>. The host CLI layer handles parsing and validation based on the argument declarations in plugin.toml -- the plugin receives the parsed values as strings.
Writing Service Plugins
Service plugins handle inbound requests from other plugins or the host runtime.
Dispatching services
Use route_service! to match on (interface_id, operation) pairs. Each handler receives a typed request and returns a typed response:
The macro wraps each handler in handle_service(), which handles request deserialization, response serialization, and error conversion. Unrecognised operations return a standard "unsupported" error.
Request and response types must implement serde::Deserialize and serde::Serialize respectively.
Returning errors from service handlers
Service handler closures return Result<Resp, ServiceResponse>. Use map_err to convert domain errors:
"my-service/v1", "create" => ,
The handle_service function
If you need more control than route_service! provides, use handle_service directly:
handle_service
The Prelude
use bmux_plugin_sdk::prelude::* imports the ~16 items most plugins need:
- Trait:
RustPlugin - Context types:
NativeCommandContext,NativeLifecycleContext,NativeServiceContext - Error type:
PluginCommandError - Exit codes:
EXIT_OK,EXIT_ERROR,EXIT_USAGE,EXIT_UNAVAILABLE - Service types:
ServiceKind,ServiceResponse - Events:
PluginEvent - Helpers:
handle_service,decode_service_message,encode_service_message
Types not in the prelude (import individually when needed):
- Host service DTOs:
SessionSelector,StorageGetRequest,ContextCreateRequest, etc. - Manifest types:
PluginCommand,PluginService,PluginEventSubscription - Capability types:
HostScope,PluginFeature
When to Also Depend on bmux_plugin
The bmux_plugin crate provides two traits that live outside the SDK:
ServiceCaller-- the low-level trait for dispatching cross-plugin service callsHostRuntimeApi-- ergonomic methods likectx.session_list(),ctx.storage_get(...),ctx.context_create(...)
If your plugin calls host services (session management, storage, pane operations, etc.), add bmux_plugin as a dependency and import these traits:
use ;
Simple plugins that only handle commands or receive service calls do not need bmux_plugin.
Manifest Reference (plugin.toml)
Top-Level Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | Yes | -- | Unique plugin identifier (e.g. "bmux.clipboard") |
name |
string | Yes | -- | Human-readable display name |
version |
string | Yes | -- | Plugin version (semver) |
description |
string | No | -- | Optional description |
homepage |
string | No | -- | Optional URL |
runtime |
string | No | "native" |
Runtime type (only "native" supported) |
entry |
path | No | -- | Path to .dylib/.so (only for external plugins) |
entry_symbol |
string | No | "bmux_plugin_entry_v1" |
FFI entry symbol |
provider_priority |
integer | No | 0 |
Ordering when multiple plugins provide the same capability |
required_capabilities |
list | No | [] |
Host capabilities this plugin needs |
provided_capabilities |
list | No | [] |
Capabilities this plugin provides |
provided_features |
list | No | [] |
Feature flags this plugin provides |
Compatibility (optional)
[]
= "1.0" # default; omit entire section if 1.0 is fine
= "2.0" # optional upper bound
[]
= "1.0" # default; omit entire section if 1.0 is fine
Commands
[[]]
= "hello" # required -- dispatch name (matches ctx.command)
= "Print a greeting" # required -- short description for help text
= true # default: false -- set true to show as CLI subcommand
= ["greet"] # optional -- CLI subcommand path
= [["say", "hi"]] # optional -- alternative CLI paths
= "provider_exec" # default: "provider_exec"
= "Longer help" # optional
execution = "provider_exec" runs the command in the plugin provider process.
Use execution = "caller_process" for commands that need caller-local runtime
facilities, such as an attach client's prompt/modal host.
Command Arguments
[[]]
= "target" # required
= "string" # required: string | integer | boolean | path | choice
= true # default: false
= 0 # optional: positional index (omit for flags/options)
= "target" # optional: --target
= "t" # optional: -t
= true # default: false
= "TARGET" # optional: displayed in help
= ["a", "b"] # for kind = "choice"
Services
[[]]
= "bmux.clipboard.write" # required -- host capability scope
= "clipboard-write/v1" # required -- service interface identifier
= "command" # required -- "command" or "query"
Event Subscriptions
[[]]
= ["system", "window"]
= ["server_started", "window_created"]
Dependencies
[[]]
= "bmux.permissions"
= "=0.0.1-alpha.0"
= true # default: true
Keybindings
[]
= "plugin:bmux.windows:new-window"
= "plugin:bmux.windows:switch-window"
[]
= "copy_scrollback"
[]
# global keybindings (active outside runtime mode)