agentsclimarketplace

Finfocus plugin

Skill rshade/finfocus/.claude/skills/finfocus-plugin/finfocus-plugin

Guide for building FinFocus cost plugins using the pluginsdk and gRPC protocol. Use when creating a new plugin, implementing CostSourceService methods, setting up plugin scaffolding, debugging plugin communication, understanding the plugin lifecycle, or working with the recorder reference plugin. Triggers on: "create a plugin", "implement GetProjectedCost", "plugin gRPC", "pluginsdk", "plugin development", "recorder plugin", or any task involving finfocus plugin architecture.From its SKILL.md

Install
npx -y skills add rshade/finfocus --skill finfocus-plugin

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
  • runs commandsInstructs the agent to run 7 commands, including `make build-recorder` and 6 more.

SKILL.md

4.4 KB, 930 tokens by cl100k_base, as published. Nobody here has run it

FinFocus Plugin Development

Plugin Architecture

Plugins communicate with finfocus-core via gRPC using protocol buffers from finfocus-spec. Each plugin is a standalone binary that implements the CostSourceService.

Core CLI -> gRPC -> Plugin Binary
                    (CostSourceService)

Two launcher types:

  • ProcessLauncher (TCP) - Plugin listens on a port
  • StdioLauncher (stdin/stdout) - Plugin communicates over stdio

Quick Start: New Plugin

  1. Create Go module with finfocus-spec dependency
  2. Embed pluginsdk.BasePlugin for common functionality
  3. Implement required gRPC methods
  4. Build binary and install to ~/.finfocus/plugins/<name>/<version>/
import (
    "github.com/rshade/finfocus-spec/sdk/go/pluginsdk"
    pbc "github.com/rshade/finfocus-spec/sdk/go/proto/finfocus/v1"
)

type MyPlugin struct {
    *pluginsdk.BasePlugin
    logger zerolog.Logger
    mu     sync.Mutex
}

func (p *MyPlugin) Name() string { return "my-plugin" }

Required Methods

Every plugin must implement these CostSourceService methods:

MethodPurpose
GetProjectedCostEstimate future costs from resource descriptors
GetActualCostReturn historical costs for a time range
GetRecommendationsReturn cost optimization recommendations
GetPluginInfoReturn plugin metadata (name, version, providers)
ShutdownClean up resources on termination

Request Validation

Use pluginsdk validation helpers before processing:

func (p *MyPlugin) GetProjectedCost(ctx context.Context, req *pbc.GetProjectedCostRequest) (*pbc.GetProjectedCostResponse, error) {
    p.mu.Lock()
    defer p.mu.Unlock()

    if err := pluginsdk.ValidateProjectedCostRequest(req); err != nil {
        return nil, status.Errorf(codes.InvalidArgument, "validation: %v", err)
    }
    // Process request...
}

Plugin Installation

Plugins install to ~/.finfocus/plugins/<name>/<version>/:

# Build and install
make build-recorder
make install-recorder  # -> ~/.finfocus/plugins/recorder/0.1.0/

# Verify
./bin/finfocus plugin list
./bin/finfocus plugin validate

Environment Variables

Plugins receive these from core via pluginsdk constants:

ConstantEnv VarPurpose
pluginsdk.EnvPortFINFOCUS_PLUGIN_PORTgRPC port
pluginsdk.EnvLogLevelFINFOCUS_LOG_LEVELLog verbosity
pluginsdk.EnvLogFormatFINFOCUS_LOG_FORMATjson or text
pluginsdk.EnvLogFileFINFOCUS_LOG_FILELog file path
pluginsdk.EnvTraceIDFINFOCUS_TRACE_IDDistributed trace ID

Trace ID Propagation

// Server-side: extract trace ID from incoming gRPC metadata
server := grpc.NewServer(
    grpc.UnaryInterceptor(pluginsdk.TracingUnaryServerInterceptor()),
)

// In handlers: get trace ID from context
traceID := pluginsdk.TraceIDFromContext(ctx)

Reference Implementation

The recorder plugin at plugins/recorder/ demonstrates all patterns. See references/recorder-reference.md for the complete implementation walkthrough.

Plugin Communication Details

See references/pluginsdk-api.md for the full pluginsdk API, proto message types, and gRPC patterns.

Testing Plugins

go test ./plugins/recorder/...                       # Unit tests
go test ./test/integration/recorder_test.go          # Integration
go test -bench=BenchmarkRecorder ./plugins/recorder/... # Perf (<10ms)

Common Pitfalls

  • Always use sync.Mutex for thread safety in gRPC handlers
  • Return status.Errorf(codes.InvalidArgument, ...) for validation errors
  • Call cmd.Wait() after Kill() to prevent zombie processes
  • 10-second timeout with 100ms retry delays for plugin startup
  • Platform-specific binary detection (Unix permissions vs Windows .exe)

What ships with it: 2 files

7.6 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.