SDK Reference
The pkg/skyplugin package provides helpers that eliminate boilerplate
when building Sky plugins.
Installation
Section titled “Installation”go get github.com/albertocavalcante/sky/pkg/skypluginQuick Start
Section titled “Quick Start”package main
import ( "context" "fmt"
"github.com/albertocavalcante/sky/pkg/skyplugin")
func main() { skyplugin.Serve(skyplugin.Plugin{ Metadata: skyplugin.Metadata{ APIVersion: 1, Name: "my-plugin", Version: "1.0.0", Summary: "Does something useful", }, Run: func(ctx context.Context, args []string) error { fmt.Println("Hello!") return nil }, })}Core Types
Section titled “Core Types”Plugin
Section titled “Plugin”type Plugin struct { Metadata Metadata Run func(ctx context.Context, args []string) error}The main plugin definition. Contains metadata and the run function.
Metadata
Section titled “Metadata”type Metadata struct { APIVersion int `json:"api_version"` Name string `json:"name"` Version string `json:"version,omitempty"` Summary string `json:"summary,omitempty"` Commands []CommandMetadata `json:"commands,omitempty"`}Plugin metadata returned in metadata mode.
CommandMetadata
Section titled “CommandMetadata”type CommandMetadata struct { Name string `json:"name"` Summary string `json:"summary,omitempty"`}Describes a command the plugin provides.
Entry Points
Section titled “Entry Points”func Serve(p Plugin)The main entry point for plugins. Handles:
- Checking
SKY_PLUGINenvironment variable - Handling metadata mode
- Setting up context with interrupt handling
- Calling the Run function
- Exiting with appropriate code
ServeFunc
Section titled “ServeFunc”func ServeFunc(m Metadata, run func(ctx context.Context, args []string) error)Convenience wrapper for simple plugins:
skyplugin.ServeFunc( skyplugin.Metadata{Name: "hello", Version: "1.0.0"}, func(ctx context.Context, args []string) error { fmt.Println("Hello!") return nil },)Environment Helpers
Section titled “Environment Helpers”IsPlugin
Section titled “IsPlugin”func IsPlugin() boolReturns true if SKY_PLUGIN=1.
IsMetadataMode
Section titled “IsMetadataMode”func IsMetadataMode() boolReturns true if SKY_PLUGIN_MODE=metadata.
PluginName
Section titled “PluginName”func PluginName() stringReturns the value of SKY_PLUGIN_NAME.
WorkspaceRoot
Section titled “WorkspaceRoot”func WorkspaceRoot() stringReturns SKY_WORKSPACE_ROOT, falling back to current directory.
root := skyplugin.WorkspaceRoot()configPath := filepath.Join(root, ".sky.yaml")ConfigDir
Section titled “ConfigDir”func ConfigDir() stringReturns SKY_CONFIG_DIR, falling back to platform default:
- Linux/macOS:
~/.config/sky - Windows:
%APPDATA%\sky
OutputFormat
Section titled “OutputFormat”func OutputFormat() stringReturns SKY_OUTPUT_FORMAT, defaulting to "text".
IsJSONOutput
Section titled “IsJSONOutput”func IsJSONOutput() boolReturns true if JSON output is requested.
if skyplugin.IsJSONOutput() { json.NewEncoder(os.Stdout).Encode(result)} else { fmt.Println(result.String())}NoColor
Section titled “NoColor”func NoColor() boolReturns true if color should be disabled. Respects both
SKY_NO_COLOR and the NO_COLOR standard.
Verbose
Section titled “Verbose”func Verbose() intReturns the verbosity level (0-3) from SKY_VERBOSE.
if skyplugin.Verbose() >= 2 { fmt.Fprintln(os.Stderr, "Debug: processing file...")}Output Helpers
Section titled “Output Helpers”Output
Section titled “Output”type Output struct { ... }
func DefaultOutput() *Outputfunc NewOutput(stdout, stderr io.Writer) *OutputOutput formatting helper.
WriteJSON
Section titled “WriteJSON”func (o *Output) WriteJSON(v any) errorWrites a value as indented JSON to stdout.
WriteResult
Section titled “WriteResult”func (o *Output) WriteResult(v any, textFn func() string) errorWrites output based on SKY_OUTPUT_FORMAT:
out := skyplugin.DefaultOutput()out.WriteResult(result, func() string { return fmt.Sprintf("Found %d items", result.Count)})Println / Printf
Section titled “Println / Printf”func (o *Output) Println(args ...any)func (o *Output) Printf(format string, args ...any)Write to stdout.
Error / Errorf
Section titled “Error / Errorf”func (o *Output) Error(args ...any)func (o *Output) Errorf(format string, args ...any)Write to stderr.
Verbose / Verbosef
Section titled “Verbose / Verbosef”func (o *Output) Verbose(level int, args ...any)func (o *Output) Verbosef(level int, format string, args ...any)Write only if verbosity is at least the given level:
out.Verbose(1, "Processing files...")out.Verbose(2, "Reading", path)out.Verbosef(3, "Debug: parsed %d lines\n", lineCount)Testing Package
Section titled “Testing Package”The pkg/skyplugin/testing package provides test utilities.
MockEnv
Section titled “MockEnv”func MockEnv(mode, name string) func()Sets up plugin environment variables. Returns cleanup function.
func TestMyPlugin(t *testing.T) { cleanup := testing.MockEnv("exec", "my-plugin") defer cleanup()
// Run plugin code...}MockEnvFull
Section titled “MockEnvFull”type EnvConfig struct { Mode string Name string WorkspaceRoot string ConfigDir string OutputFormat string NoColor bool Verbose int}
func MockEnvFull(cfg EnvConfig) func()Full environment configuration:
cleanup := testing.MockEnvFull(testing.EnvConfig{ Mode: "exec", Name: "my-plugin", WorkspaceRoot: "/test/workspace", OutputFormat: "json", Verbose: 2,})defer cleanup()CaptureOutput
Section titled “CaptureOutput”type CaptureResult struct { Stdout string Stderr string ExitCode int}
func CaptureOutput(fn func()) CaptureResultCaptures stdout, stderr, and exit code:
result := testing.CaptureOutput(func() { main() // Run your plugin})
if result.ExitCode != 0 { t.Errorf("expected exit 0, got %d", result.ExitCode)}
if !strings.Contains(result.Stdout, "expected") { t.Errorf("unexpected output: %s", result.Stdout)}ClearEnv
Section titled “ClearEnv”func ClearEnv() func()Removes all Sky environment variables:
cleanup := testing.ClearEnv()defer cleanup()
// Test behavior when not running as a pluginComplete Example
Section titled “Complete Example”package main
import ( "context" "flag" "fmt"
"github.com/albertocavalcante/sky/pkg/skyplugin")
func main() { skyplugin.Serve(skyplugin.Plugin{ Metadata: skyplugin.Metadata{ APIVersion: 1, Name: "greeter", Version: "1.0.0", Summary: "Greets users", Commands: []skyplugin.CommandMetadata{ {Name: "greeter", Summary: "Greet someone"}, }, }, Run: run, })}
func run(ctx context.Context, args []string) error { fs := flag.NewFlagSet("greeter", flag.ContinueOnError) name := fs.String("name", "World", "name to greet")
if err := fs.Parse(args); err != nil { return err }
out := skyplugin.DefaultOutput()
result := map[string]string{ "greeting": fmt.Sprintf("Hello, %s!", *name), "workspace": skyplugin.WorkspaceRoot(), }
return out.WriteResult(result, func() string { return result["greeting"] })}