Finfocus plugin
Skill rshade/finfocus/.claude/skills/finfocus-plugin/finfocus-plugin
FinOps CLI for Pulumi — projected costs, actual spend tracking, budget enforcement, and cost optimization for cloud infrastructure
npx -y skills add rshade/finfocus --skill finfocus-pluginAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 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.
What its author says it does
Copied from the file, not written here
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.
SKILL.md
4.4 KB, 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 portStdioLauncher(stdin/stdout) - Plugin communicates over stdio
Quick Start: New Plugin
- Create Go module with
finfocus-specdependency - Embed
pluginsdk.BasePluginfor common functionality - Implement required gRPC methods
- 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:
| Method | Purpose |
|---|---|
GetProjectedCost | Estimate future costs from resource descriptors |
GetActualCost | Return historical costs for a time range |
GetRecommendations | Return cost optimization recommendations |
GetPluginInfo | Return plugin metadata (name, version, providers) |
Shutdown | Clean 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:
| Constant | Env Var | Purpose |
|---|---|---|
pluginsdk.EnvPort | FINFOCUS_PLUGIN_PORT | gRPC port |
pluginsdk.EnvLogLevel | FINFOCUS_LOG_LEVEL | Log verbosity |
pluginsdk.EnvLogFormat | FINFOCUS_LOG_FORMAT | json or text |
pluginsdk.EnvLogFile | FINFOCUS_LOG_FILE | Log file path |
pluginsdk.EnvTraceID | FINFOCUS_TRACE_ID | Distributed 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.Mutexfor thread safety in gRPC handlers - Return
status.Errorf(codes.InvalidArgument, ...)for validation errors - Call
cmd.Wait()afterKill()to prevent zombie processes - 10-second timeout with 100ms retry delays for plugin startup
- Platform-specific binary detection (Unix permissions vs Windows .exe)