Documentation

Authoring Feathers

Build a toowl Feather plugin — manifest, HostApi, and hot-start lifecycle.

Feathers are toowl plugins — sidebar panels and palette actions that hot-start on demand so launch stays fast.

Plugin types

TypeCrate patternWhen to use
In-processtoowl-plugin-* linked into toowl-appFirst-party, low-latency (Claude, Nest, MCP Hub, Scout)
SubprocessJSON-RPC over stdioThird-party; capability-gated

Manifest (subprocess)

Third-party subprocess plugins live in ~/.config/toowl/plugins/<name>/plugin.toml:

id = "my-feather"
name = "My Feather"
version = "0.1.0"
program = "./my-feather-binary"
capabilities = ["pane_spawn"]

The id field is used for enable/disable in config before spawn — disabled plugins must not start a subprocess.

Plugin trait (in-process)

Implement toowl_plugin::Plugin:

  • init(&mut self, ctx: &InitCtx, host: &mut dyn HostApi) — keep minimal; defer FS watchers until PluginEvent::PerchOpened
  • build_sidebar(&mut self, ctx: &ViewCtx) -> Option<View> — Perch UI tree
  • on_event(&mut self, event: PluginEvent, host: &mut dyn HostApi) — clicks, palette, lifecycle

HostApi capabilities

  • spawn_pane — new tab/split with command
  • inject_pane / inject_input — paste into active PTY
  • open_url / http_get — browser and HTTP (requires network allowlist)
  • show_banner — pane-attached notifications
  • read_file / watch_path — filesystem access
  • state_get / state_set — plugin-scoped persistence

Hot-start contract

Plugins register at startup but must not spawn subprocesses, watch filesystems, or block the first frame until the user opens the Perch or invokes a palette action. Failures surface as inline View::Banner in the sidebar.

Testing locally

TOOWL_DEV_PLUGINS=dummy cargo run --release
TOOWL_DEV_PLUGINS=none cargo run --release   # bisect: no plugins
bash scripts/feather-new.sh my-feather python

Publish to the Aviary

See the Aviary and the wire protocol. Run bash scripts/feather-submit.sh <id> before opening a PR.