Extend: Plugins, Config, Tools
Plugins extend fledge with community-built commands. They’re external executables distributed as GitHub repos, following the git-style subcommand pattern. fledge-<name> becomes fledge <name>.
Installing
All plugin commands live under fledge plugins.
# From GitHub
fledge plugins install someone/fledge-deploy
# Pin to a specific version (tag, branch, or commit)
fledge plugins install someone/fledge-deploy@v1.2.0
# Full URL works too
fledge plugins install https://github.com/someone/fledge-deploy.git
# Full URL with version pin
fledge plugins install https://github.com/someone/fledge-deploy.git@v1.2.0
# Reinstall (or upgrade a pinned plugin)
fledge plugins install someone/fledge-deploy@v2.0.0 --force
What happens when you install:
- Repo gets cloned to the platform plugin directory (e.g.
~/Library/Application Support/fledge/plugins/<name>/on macOS,~/.config/fledge/plugins/<name>/on Linux) - If
@refwas specified, that tag/branch/commit is checked out - fledge reads
plugin.toml - Build hook runs (or auto-detects Rust/Swift/Go/Node)
- Command binaries get symlinked to the
plugins/bin/directory - Plugin is registered in
plugins.toml(withpinned_refif pinned)
Using Plugins
# Via fledge
fledge plugins run deploy --target production
# Or directly if the binary is on PATH
fledge deploy --target production
Managing
fledge plugins list # what's installed
fledge plugins search deploy # find plugins on GitHub
fledge plugins update # update all unpinned plugins
fledge plugins update fledge-deploy # update a specific plugin
fledge plugins remove fledge-deploy
fledge plugins list --json # for scripting
Version Pinning
Use @ref to pin a plugin to a specific version:
fledge plugins install someone/fledge-deploy@v1.2.0
Pinned plugins behave differently on update:
- Unpinned plugins get
git pulland rebuild automatically - Pinned plugins check for newer tags and suggest an upgrade command, but don’t change automatically
To upgrade a pinned plugin:
fledge plugins install someone/fledge-deploy@v2.0.0 --force
Discovery
Plugins use the fledge-plugin topic on GitHub. To make yours findable:
- Add
fledge-pluginas a topic on your repo - Include a
plugin.tomlmanifest
fledge plugins search # browse all plugins
fledge plugins search deploy # search by keyword
WASM Plugins
WASM plugins run in a sandboxed Wasmtime runtime with no host access by default. They’re ideal for pure-computation tasks (linting, formatting, analysis) where you want strong isolation.
Creating
fledge plugins create fledge-my-tool --wasm
cd fledge-my-tool
This scaffolds a Rust project targeting wasm32-wasip1 with plugin.toml, Cargo.toml, and src/main.rs.
Building
cargo build --target wasm32-wasip1 --release
The build hook in plugin.toml runs this automatically during install.
Capabilities
WASM plugins support two additional capability fields beyond exec/store/metadata:
| Field | Values | Default | Description |
|---|---|---|---|
filesystem | "none", "project", "plugin" | "none" | "project" mounts project root read-only at /project. "plugin" adds read-write plugin dir at /plugin. |
network | true/false | false | Inherits host network stack when true |
[plugin]
name = "fledge-analyze"
version = "0.1.0"
protocol = "fledge-v1"
runtime = "wasm"
[[commands]]
name = "analyze"
binary = "target/wasm32-wasip1/release/fledge-analyze.wasm"
[hooks]
build = "cargo build --target wasm32-wasip1 --release"
[capabilities]
filesystem = "project"
network = false
Limitations
- Interactive UI (prompt/confirm/select) is not supported. Use non-interactive output
- Compute is bounded (fuel limit + 60s wall-clock timeout)
- Memory is limited to 256 MB
When to use WASM vs native
| Use WASM when… | Use native when… |
|---|---|
| Pure computation over project files | Need to shell out to external tools |
| Untrusted/community plugins | Need unrestricted filesystem access |
| Cross-platform single binary | Need pipes, redirects, or shell features |
Building a Plugin
1. Create the repo
The fastest way to start a plugin:
fledge plugins create fledge-deploy
cd fledge-deploy
For a WASM plugin, add --wasm:
fledge plugins create fledge-deploy --wasm
cd fledge-deploy
This scaffolds plugin.toml, a starter executable in bin/ (or src/main.rs for WASM), a README, and a .gitignore. Or create one manually:
mkdir fledge-deploy && cd fledge-deploy
2. Write plugin.toml
[plugin]
name = "fledge-deploy"
version = "0.1.0"
description = "Deploy to cloud providers"
author = "Your Name"
[capabilities]
exec = true
store = true
[[commands]]
name = "deploy"
description = "Deploy the project"
binary = "fledge-deploy"
[[commands]]
name = "rollback"
description = "Rollback to previous deployment"
binary = "fledge-rollback"
[hooks]
build = "cargo build --release"
post_install = "echo 'fledge-deploy installed'"
post_work_start = "scripts/setup-env.sh"
3. Add the executables
Each [[commands]] entry points to an executable in the repo. Can be compiled binaries, shell scripts, whatever:
#!/usr/bin/env bash
# fledge-deploy
echo "Deploying $(basename $(pwd))..."
Make them executable:
chmod +x fledge-deploy fledge-rollback
4. Validate
Check your plugin before publishing:
fledge plugins validate
This checks: plugin.toml is valid, name/version are set, binaries exist (or a build hook will create them), and commands are well-formed. Use --strict to fail on warnings, --json for machine-readable output.
5. Publish
Publish to GitHub (validates automatically before pushing):
fledge plugins publish
Or push manually and add the fledge-plugin topic. Users install with:
fledge plugins install yourname/fledge-deploy
plugin.toml Reference
[plugin]
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Plugin name |
version | string | Yes | Semver |
description | string | No | Short description (warned about if missing on validate) |
author | string | No | Who made it |
protocol | string | No | Set to "fledge-v1" to opt into the structured plugin protocol. Without it, the plugin runs with inherited stdio. |
runtime | string | No | Set to "wasm" for sandboxed WASM plugins. Omit or set to "native" for standard executable plugins. |
[[commands]]
Each entry registers a subcommand.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Command name (fledge plugins run <name>) |
description | string | No | What it does |
binary | string | Yes | Path to executable (relative to plugin root) |
[capabilities]
Capabilities declare what protocol features the plugin uses. All default to false. Plugins must opt in.
| Field | Type | Default | Description |
|---|---|---|---|
exec | bool | false | Execute shell commands on the host |
store | bool | false | Persist key-value data between runs |
metadata | bool | false | Read project metadata (language, name, git info) |
filesystem | string | "none" | WASM only. "project" for read-only project access, "plugin" for read-write plugin dir |
network | bool | false | WASM only. Inherit host network stack |
[capabilities]
exec = true
store = true
metadata = false
During installation, fledge displays the requested capabilities and the user must approve them. Granted capabilities are recorded in plugins.toml and enforced at runtime:
- Blocked exec → returns exit code 126
- Blocked store → silently dropped
- Blocked metadata → returns empty object
Plugins without a [capabilities] section work fine but cannot use exec, store, or metadata protocol features.
[hooks]
Hooks fire in response to fledge lifecycle events. All fields are optional, plugins only participate in events they declare.
| Field | Type | Description |
|---|---|---|
build | string | Runs after clone, before binary check |
post_install | string | Runs after fledge plugins install |
post_remove | string | Runs before fledge plugins remove deletes files |
pre_init | string | Runs before fledge templates init starts |
post_work_start | string | Runs after fledge work start creates a branch |
pre_push | string | Runs before fledge work push pushes to origin |
Values can be a path to a script (relative to plugin root) or an inline shell command.
Using Plugins in Lanes
Plugin commands can be called from lane steps as inline commands:
[lanes.deploy]
description = "Test, build, and deploy"
steps = [
"test",
{ run = "cargo build --release" },
{ run = "fledge deploy --target production" },
]
You can also run plugin commands in parallel with other tasks:
[lanes.ci]
steps = [
{ parallel = ["lint", "test"] },
"build",
{ parallel = [{ run = "fledge deploy --target staging" }, { run = "fledge notify --channel ci" }] },
]
See Run: Tasks and Lanes for full step type documentation.
Plugin Protocol (fledge-v1)
Plugins that opt into the protocol (protocol = "fledge-v1" in [plugin]) communicate with fledge via newline-delimited JSON over stdin/stdout. When a plugin starts, fledge sends an init message with project context and granted capabilities, then the plugin sends outbound messages and fledge replies to anything that includes an id.
Message types at a glance
Outbound (plugin → fledge):
| Type | Reply | Requires |
|---|---|---|
prompt | response with string | none |
confirm | response with boolean | none |
select | response with selected string | none |
multi_select | response with array of strings | none |
exec | response with {code, stdout, stderr} | exec |
store | (fire-and-forget) | store |
load | response with string or null | store |
metadata | response with object of requested keys | metadata |
progress | (fire-and-forget) | none |
log | (fire-and-forget; level: debug/info/warn/error) | none |
output | (fire-and-forget; printed verbatim to stdout) | none |
Reply messages always have shape {"type": "response", "id": "<echoed>", "value": <type-specific>}. There is no exec_result / store_ack / load_result envelope. Every reply uses the generic response type.
See the plugin protocol spec for full schemas, lifecycle, security model, and worked examples.
Authentication
Plugin install, update, and search operations use your GitHub token when available. This enables installing plugins from private repositories. See Configuration: GitHub for the full token resolution order and required scopes.
The easiest setup is gh auth login. Fledge uses it automatically as a fallback. The token is injected via git’s http.extraheader mechanism and is never embedded in remote URLs or persisted to disk.
Security Model
Warning (native plugins): Native plugins run as unsandboxed processes with your full user permissions. A plugin can read any file you can read, write to any directory you can write to, and make network requests, regardless of its declared capabilities. Capabilities gate the fledge-v1 protocol (exec/store/metadata RPC messages), not the process itself. Review plugin source before installing, especially from unknown authors.
WASM plugins run in a sandboxed Wasmtime runtime with no host access by default. Filesystem and network access are opt-in, scoped, and prompted at install time. See WASM Plugins above.
Fledge has several safeguards:
- Install confirmation: before cloning, fledge warns that plugins can execute arbitrary code and asks for confirmation. Pass
--forceto skip (CI/scripts). - Plugin name validation: repo names are checked for path traversal (
..,/,\, leading.) - Command name validation: command names that become symlinks (
fledge-<name>) are validated to reject/,\,.prefix,-prefix, and null bytes - Binary path traversal: plugin binaries cannot reference paths outside the plugin directory (both sides are canonicalized to defeat symlink bypass)
- Hook execution: hooks run as direct processes, not via a shell. This prevents shell injection but means pipes, redirects, and shell expansions won’t work in hook commands. Use a wrapper script if you need shell features.
CI / Non-Interactive Usage
| Flag | Where | What it does |
|---|---|---|
--force | fledge plugins install | Skips the install confirmation prompt |
--yes | fledge templates init | Skips the post-create hook confirmation prompt |
Without these flags, interactive prompts will cause CI pipelines to hang.
File Locations
Plugin storage uses the platform config directory:
| Platform | Base path |
|---|---|
| macOS | ~/Library/Application Support/fledge/ |
| Linux | ~/.config/fledge/ |
| Windows | %APPDATA%\fledge\ |
Under that base:
| Path | What’s there |
|---|---|
plugins/ | Installed plugin directories |
plugins/bin/ | Symlinked binaries |
plugins.toml | Plugin registry |