Skip to content

title: CloudSlash - Custom Plugins Reference description: A plugin is a compiled binary that implements one gRPC interface: 5 methods. The engine orchestrates; the plugin does the cloud work. Every plugin is a hashi...


Custom Plugins

A plugin is a compiled binary that implements one gRPC interface: 5 methods. The engine orchestrates; the plugin does the cloud work.

The Provider Contract

Every plugin is a hashicorp/go-plugin binary exposing the Provider gRPC service:

service Provider {
    rpc Handshake(HandshakeRequest)     returns (HandshakeResponse);
    rpc Scan(ScanRequest)               returns (stream ScanResponse);
    rpc ApplyQuarantine(QuarantineRequest) returns (QuarantineResponse);
    rpc CheckReversibility(ReversibilityRequest) returns (ReversibilityProof);
}

Plugins that support remediation also implement the Remediator extension:

service Remediator {
    rpc Remediate(RemediateRequest) returns (RemediateResponse);
}

The engine discovers plugin capabilities at startup via the gRPC handshake: a plugin that doesn't implement Remediate degrades gracefully to scan-only mode.

Scaffold

A Plugin in 30 Seconds

DEVI AI

Recommended

Open the Web Dashboard → DEVI chat panel and type:

"Create a plugin for Hetzner Cloud that scans servers, volumes, and floating IPs"

DEVI generates a complete, compilable main.go with the Provider contract pre-wired, saves it to ~/.cloudslash/plugins/src/cloudslash-plugin-hetzner/, and offers to build it.

Manual Scaffold

package main

import (
    "context"
    "fmt"
    "os"

    "github.com/hashicorp/go-plugin"
    pb "github.com/DrSkyle/cloudslash/v2/pkg/engine/plugin/proto"
    "github.com/DrSkyle/cloudslash/v2/pkg/engine/plugin/shared"
)

type HetznerProvider struct {
    pb.UnimplementedProviderServer
    pb.UnimplementedRemediatorServer
}

func (p *HetznerProvider) Handshake(_ context.Context, _ *pb.HandshakeRequest) (*pb.HandshakeResponse, error) {
    return &pb.HandshakeResponse{
        Compatible:    true,
        PluginVersion: "v0.1.0",
        Message:       "Hetzner Cloud Plugin Ready",
    }, nil
}

func (p *HetznerProvider) Scan(req *pb.ScanRequest, stream pb.Provider_ScanServer) error {
    // Use the Hetzner Cloud Go SDK to discover resources.
    // For each resource, stream a pb.Node with:
    //   - Crn: "crn:devi:hetzner:<datacenter>:<project>:<type>/<id>"
    //   - Properties: JSON-encoded resource attributes
    //   - Cost: monthly cost in USD
    return nil
}

func (p *HetznerProvider) Remediate(ctx context.Context, req *pb.RemediateRequest) (*pb.RemediateResponse, error) {
    // Dispatch by resource type from CRN.
    // Always create a snapshot before destructive operations.
    return &pb.RemediateResponse{
        Success: false,
        Error:   "not yet implemented",
    }, nil
}

func main() {
    if len(os.Args) > 1 && os.Args[1] == "version" {
        fmt.Println("cloudslash-plugin-hetzner v0.1.0")
        return
    }
    plugin.Serve(&plugin.ServeConfig{
        HandshakeConfig: shared.Handshake,
        Plugins: map[string]plugin.Plugin{
            "provider": &shared.ProviderPlugin{Impl: &HetznerProvider{}},
        },
        GRPCServer: plugin.DefaultGRPCServer,
    })
}

The CRN Format

Every resource must be assigned a CloudSlash Resource Name (CRN):

crn:devi:<provider>:<region>:<account>:<resource_type>:<resource_id>

Examples:

Resource CRN
AWS EC2 Instance crn:devi:aws:us-east-1:123456789:ec2:instance:i-0abc123
GCP Compute Instance crn:devi:gcp:us-central1-a:my-project:compute:instance:vm-001
Hetzner Server crn:devi:hetzner:fsn1:12345:server:67890
Carbon Footprint crn:devi:carbon:us-east-1:org:estimate:monthly-2026-05

Remediate

Implementing

The Remediate RPC is called by the engine after s.a.u approval. Your plugin receives:

type RemediateRequest struct {
    Crn        string            // The resource to act on
    Action     string            // "stop", "delete", "throttle", "pause", etc.
    Properties map[string]string // Additional context (region, credentials, etc.)
    DryRun     bool              // If true, validate but don't execute
}

Rules:

  1. Always snapshot before destructive operations. Return the snapshot ID in the response so s.a.u can rollback.
  2. Support dry_run. If req.DryRun is true, validate permissions and return success without executing.
  3. Return structured errors. Never panic: return RemediateResponse{Success: false, Error: "..."}.
type RemediateResponse struct {
    Success  bool
    Status   string            // "stopped", "deleted", "throttled", etc.
    Error    string            // Empty on success
    Snapshot map[string]string // Snapshot IDs for rollback
}

Compilation and Registration

# Build the plugin binary
cd ~/.cloudslash/plugins/src/cloudslash-plugin-hetzner/
go build -o ~/.cloudslash/plugins/cloudslash-plugin-hetzner .

# Hot-reload into the running daemon
kill -HUP $(pgrep cloudslash)

Or use the DEVI chat in the Web Dashboard:

"Build the hetzner plugin"

Non-Cloud Use Cases

The engine operates on a generic graph: nodes with properties and edges with relationships. Nothing in the protocol is cloud-specific. Community plugins can target:

Use Case Plugin Name What It Scans
Carbon Footprint cloudslash-plugin-carbon COâ‚‚ estimates per compute region
SaaS License Audit cloudslash-plugin-okta Unused Okta seats and SSO configs
Database Optimization cloudslash-plugin-postgres Bloated tables, unused indexes
Network Security cloudslash-plugin-nmap Open ports and attack surface
Cost Attribution cloudslash-plugin-finops Cross-cloud cost allocation tags

The engine applies the same policy mesh, saga orchestration, and CRDT state resolution regardless of what domain the nodes represent.