Install
$ agentstack add skill-rshade-finfocus-finfocus-plugin ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
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///
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///:
# 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](references/recorder-reference.md) for the complete implementation walkthrough.
Plugin Communication Details
See [references/pluginsdk-api.md](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)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: rshade
- Source: rshade/finfocus
- License: Apache-2.0
- Homepage: https://rshade.github.io/finfocus/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.