Plugin overview
What are plugins?
Plugins extend Jackadi’s functionality by providing two main capabilities:
- Tasks: Executable functions that agents can run on demand.
- Specs: Automatic system information collectors that run continuously.
This overview covers the core concepts and structure. For detailed implementation guides, see Writing Tasks and Writing Spec Collectors.
Plugin architecture
A Jackadi plugin is a Go binary that uses the SDK to register functionality with agents. Each plugin can provide multiple tasks and spec collectors.
Plugins are running in their own processes and communicate with the agent using gRPC, thanks to hashicorp/go-plugin.
Task naming convention
Tasks follow the format plugin:task
:
cmd:run
- Therun
task from thecmd
plugin.health:ping
- Theping
task from thehealth
plugin.specs:get
- Theget
task from thespecs
plugin.
Basic plugin structure
Here’s a minimal plugin with both a task and spec collector:
package main
import (
"context"
"fmt"
"runtime"
"github.com/jackadi-io/jackadi/sdk"
)
// Task options structure
type GreetOptions struct {
Name string
Age int
}
// Required SetDefaults method
func (o *GreetOptions) SetDefaults() {
o.Name = "Guest"
o.Age = 30
}
// Task function
func GreetTask(ctx context.Context, options *GreetOptions, greeting string) (string, error) {
return fmt.Sprintf("%s, %s! You are %d years old.", greeting, options.Name, options.Age), nil
}
// Spec collector function
func SystemInfoCollector(ctx context.Context) (map[string]interface{}, error) {
return map[string]interface{}{
"os": runtime.GOOS,
"architecture": runtime.GOARCH,
"cpu_cores": runtime.NumCPU(),
}, nil
}
func main() {
// Create plugin plugin
plugin := sdk.New("my-plugin")
// Register task
plugin.MustRegisterTask("greet", GreetTask).
WithSummary("Greets a person").
WithLockMode(sdk.NoLock)
// Register spec collector
plugin.MustRegisterSpecCollector("system", SystemInfoCollector)
// Serve the plugin
sdk.MustServe(plugin)
}
Core concepts
Tasks
Tasks are functions that can be invoked on agents via CLI or API*. They support:
- Optional context parameter for cancellation.
- Optional options struct for configuration.
- Positional arguments.
- Return any serializable type plus error.
Spec collectors
Spec collectors automatically gather system information:
- Run periodically in the background.
- Return structured data for querying.
- Enable intelligent task targeting.
- Must follow signature:
func(context.Context) (ReturnType, error)
.
Lock modes
Tasks can specify default concurrency behavior:
sdk.NoLock
- Allow concurrent execution (default).sdk.WriteLock
- Single writer, multiple readers.sdk.ExclusiveLock
- Exclusive access, blocks all other tasks.
See Lock Modes for detailed information.
Building and deployment
Building
CGO_ENABLED=0 go build -o my-plugin main.go
Deploying
- Place binary in manager’s plugin directory
- Configure distribution in
plugins.yaml
:"*": # All agents - my-plugin "worker-*": # Pattern-matched agents - worker-plugin
- Sync to agents:
jack run agent1 plugins:sync
Using
# Execute task with options
jack run agent1 my-plugin:greet --name="World" "Hello"
# Query spec data
jack run agent1 specs:get my-plugin.system.os
Built-in plugin features
All plugin binaries can be run manually with flags. The plugin won’t start, but the flags can be used to retrieve details about the plugin, such as its version.
Version information
./my-plugin --version
# Output: Version, commit, build time, Go version
Task helper
./my-plugin --describe
# Output: List of tasks with summaries and options
Cross-plugin usage
Direct cross-calling is not possible. Instead, if you want to create a workflow with tasks from another plugin, just import it as a library.
import "github.com/jackardi-io/other-plugin/tasks"
func MyTask() (Result, error) {
// Reuse functionality from another plugin:
r, err := tasks.Func1()
r2, err2 := tasks.Func2()
// ...
}
Best practices
- Error Handling: Return meaningful error messages.
- Context Awareness: Honor context cancellation.
- Documentation: Provide clear summaries and descriptions.
- Naming: Use descriptive names.
- Lock Modes: Choose appropriate default lock modes.