Squadron SDK
May 7, 2026 · View on GitHub
Go SDK for building Squadron plugins.
Plugins extend Squadron agents with custom tools — browser automation, database queries, API integrations, or anything else you can write in Go. Each plugin is a standalone binary that Squadron manages as a subprocess, communicating over gRPC.
Quick Start
1. Create a new Go module
mkdir plugin_example && cd plugin_example
go mod init github.com/yourname/plugin_example
go get github.com/mlund01/squadron-sdk
2. Implement the plugin
Create main.go:
package main
import (
"context"
"fmt"
squadron "github.com/mlund01/squadron-sdk"
)
type GreetInput struct {
Name string `json:"name" jsonschema:"required,description=The name to greet"`
}
func main() {
app := squadron.New()
var greeting string
app.Configure(func(settings map[string]string) error {
greeting = settings["greeting"]
if greeting == "" {
greeting = "Hello"
}
return nil
})
squadron.Tool(app, "greet", "Greet someone by name",
func(ctx context.Context, in GreetInput) (string, error) {
return fmt.Sprintf("%s, %s!", greeting, in.Name), nil
})
app.Serve()
}
The schema is reflected from GreetInput's struct tags via
github.com/invopop/jsonschema. Use
the standard jsonschema: tag keys (required, description=...,
enum=...,enum=..., minimum=N, maximum=N, default=..., pattern=...,
etc.). For descriptions that need commas, use the dedicated
jsonschema_description: tag instead.
Pass struct{} as the input type for tools that take no parameters.
3. Build and install locally
mkdir -p ~/.squadron/plugins/example/local
go build -o ~/.squadron/plugins/example/local/plugin .
Or use the Squadron CLI:
squadron plugin build example .
4. Use it in your config
plugin "example" {
version = "local"
settings = {
greeting = "Hey there"
}
}
agent "assistant" {
model = models.anthropic.claude_sonnet_4
tools = [plugins.example.greet]
}
5. Test it
# List available tools
squadron plugin tools example
# Call a tool directly
squadron plugin call example greet '{"name": "World"}'
# Use all tools from the plugin
# tools = [plugins.example.all]
API layers
There are two ways to write a plugin:
App + Tool[I, O] (recommended)
A typed, generics-driven API. The schema is derived from the input struct, the payload is unmarshaled and the result marshaled automatically:
app := squadron.New()
app.Configure(func(settings map[string]string) error { ... })
squadron.Tool(app, name, description, func(ctx, in InputType) (Output, error) { ... })
app.Serve()
Behind the scenes this builds a ToolProvider (see below) that ships full
JSON Schema bytes — enum, default, minimum/maximum, $defs, etc. all
flow through to the LLM verbatim.
ToolProvider (low-level)
The underlying contract, useful when tools are dynamic or the typed API doesn't fit:
type ToolProvider interface {
Configure(settings map[string]string) error
Call(ctx context.Context, toolName string, payload string) (string, error)
GetToolInfo(toolName string) (*ToolInfo, error)
ListTools() ([]*ToolInfo, error)
}
ToolInfo.RawSchema (a json.RawMessage) ships verbatim and overrides the
typed Schema if both are set — use it to hand-write rich JSON Schema.
The entry point is squadron.Serve(provider) (or app.Serve(), which is
the same thing).
Settings
Plugins receive settings from the HCL config via Configure():
plugin "example" {
version = "local"
settings = {
api_url = "https://api.example.com"
timeout = "30"
headless = "true"
}
}
All values are strings — parse them in Configure() as needed.
Local Development
During development, use version = "local" to point Squadron at your local build:
# Build to the local plugin path
mkdir -p ~/.squadron/plugins/myplugin/local
go build -o ~/.squadron/plugins/myplugin/local/plugin .
# Or use the CLI shorthand
squadron plugin build myplugin .
# Reference in config
# plugin "myplugin" { version = "local" }
The plugin binary must be named plugin (or plugin.exe on Windows) and placed at:
~/.squadron/plugins/<name>/<version>/plugin
Plugin processes are managed by Squadron — they start when first referenced and persist for the duration of the mission (so state like database connections or browser sessions is maintained across tasks).
Releasing
To distribute your plugin, set up GoReleaser with GitHub Actions. Squadron auto-downloads published plugins on first use.
.goreleaser.yml
version: 2
project_name: plugin_example
builds:
- id: plugin
binary: plugin
main: .
goos:
- darwin
- linux
- windows
goarch:
- amd64
- arm64
ldflags:
- -s -w
archives:
- format: tar.gz
format_overrides:
- goos: windows
format: zip
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"
checksum:
name_template: "checksums.txt"
algorithm: sha256
release:
github:
owner: yourname
name: plugin_example
.github/workflows/release.yml
name: Release
on:
push:
tags:
- "v*"
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: "1.23"
- uses: goreleaser/goreleaser-action@v6
with:
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Publish a release
git tag v0.0.1
git push origin v0.0.1
GoReleaser builds cross-platform binaries, generates checksums, and creates a GitHub release. Users reference your plugin by source and version:
plugin "example" {
source = "github.com/yourname/plugin_example"
version = "v0.0.1"
}
Squadron downloads the correct binary for the user's platform, verifies the checksum, and installs it automatically.
Existing Plugins
| Plugin | Description |
|---|---|
| plugin_playwright | Browser automation (navigate, click, screenshot, aria snapshots) |
| plugin_pinger | Minimal example plugin (ping/pong/echo) |
| plugin_databricks_sql | Databricks SQL queries and schema exploration |
License
MIT