plugin

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2026 License: MIT Imports: 4 Imported by: 0

README

prod-plugin-sdk

The Go SDK for building prod provider plugins — add a new deploy target (a cloud, an internal PaaS) without forking prod.

A plugin is the cloud-service half of a managed-container deploy: prod keeps the LLM, the analyzer, and the docker build+push; your plugin creates/polls/rolls-back the service. Your plugin never sees the user's source — only an image reference.

Use it

package main

import "github.com/pushtoprodai/prod-plugin-sdk" // package "plugin"

type myProvider struct{}

// ... implement the six plugin.Provider methods ...

func main() { plugin.Serve(myProvider{}) }

Build a binary named prod-provider-<name>, then prod plugin install ./prod-provider-<name>. The fastest start is prod plugin new <name>, which scaffolds a working module against this SDK.

This module is intentionally lean — it depends only on hashicorp/go-plugin, so building a plugin doesn't pull in prod's full dependency tree.

See the provider-plugin docs.

MIT licensed.

Documentation

Overview

Package plugin is the public contract for prod provider plugins — the SDK a third party implements to add a deploy target ("prod-provider-acme") without forking prod. A plugin is the cloud-service half of a managed-container deploy: prod (the host) keeps the LLM, the analyzer, and the docker build+push (to the registry the plugin names), and calls the plugin only to create/poll/roll-back the service. THE PLUGIN NEVER SEES THE USER'S SOURCE — it receives an image reference.

This package imports nothing from prod's internal packages so it can be imported by external plugin modules. Implement Provider, then call Serve(provider) in main().

Index

Constants

View Source
const ProtocolVersion = 1

ProtocolVersion is the plugin contract version. The host and plugin must agree on it (via the go-plugin handshake); bump it on any breaking change to Provider or the request/response types so old plugins are rejected with a clear message.

NOT bumped for the shape fields (Meta.Shapes, DeployRequest.Shape, DeployResult.Shape): they are additive named-string gob fields, so the wire form is compatible in both skew directions (an old plugin omits Shapes ⇒ the host reads nil ⇒ {web}; a new plugin's Shapes is an unknown field an old host's gob decoder ignores). A bump would strand every already-installed plugin at launch, so it's reserved for a genuinely breaking change.

Variables

View Source
var Handshake = goplugin.HandshakeConfig{
	ProtocolVersion:  ProtocolVersion,
	MagicCookieKey:   "PROD_PLUGIN",
	MagicCookieValue: "prod-provider",
}

Handshake is the go-plugin handshake config. Host and plugin must agree on the magic cookie and protocol version, or the launch is rejected with a clear message.

Functions

func HostPlugins

func HostPlugins() goplugin.PluginSet

HostPlugins is the go-plugin PluginSet the host uses to dispense a Provider client (the Impl is nil host-side).

func Serve

func Serve(impl Provider)

Serve runs a provider plugin, blocking until the host disconnects. A plugin's main() implements Provider and calls plugin.Serve(myProvider).

Types

type AuthReply

type AuthReply struct {
	Status AuthStatus
	Err    string
}

type AuthStatus

type AuthStatus struct {
	OK     bool
	Detail string // how it's configured, or why it isn't usable
}

AuthStatus is the result of a credential check.

type DeployInfo

type DeployInfo struct {
	ID     string
	Status string
}

DeployInfo describes a prior deployment (a rollback target).

type DeployReply

type DeployReply struct {
	Result DeployResult
	Err    string
}

type DeployRequest

type DeployRequest struct {
	ImageRef  string            // the pushed image, e.g. "registry.acme.app/team/my-app:1720000000"
	Name      string            // service name (sanitized)
	Port      int               // the container port the app listens on
	PlainEnv  map[string]string // non-sensitive env vars
	SecretEnv map[string]string // sensitive env vars (store as the cloud's secrets, not plain)
	// Shape is the deploy shape the host resolved for this project (from the user's intent
	// + analyzer). It tells the plugin AT DEPLOY TIME whether a URL is wanted: for a
	// non-HTTP shape (worker/cron) the plugin may skip allocating a public URL and return
	// DeployResult{URL:""}. Empty ⇒ ShapeWeb (a URL is expected). A plugin that only
	// serves web can ignore this field.
	Shape DeployShape
}

DeployRequest is what the host hands the plugin to create the service. It is the ONLY app data the plugin receives — an image reference plus this app's config.

type DeployResult

type DeployResult struct {
	ID   string // cloud resource id
	Name string
	URL  string // the public https URL (empty for a URL-less worker/cron shape)
	// Shape lets the plugin echo the shape it ACTUALLY deployed, overriding the host's
	// requested DeployRequest.Shape when the plugin is authoritative (e.g. a sandbox
	// runtime that runs an analyzer-classified "web" project as a URL-less worker). Empty
	// ⇒ the host keeps its requested shape. When it resolves to a non-HTTP shape the host
	// records a URL-less success and skips the liveness probe.
	Shape DeployShape
}

DeployResult is the created service.

type DeployShape added in v0.2.0

type DeployShape string

DeployShape is the kind of thing a provider deploys — it selects whether the host expects a URL and how it probes liveness. A web/mcp-server serves HTTP (URL required, probed); a worker/cron has no URL (the host records a URL-less success and skips the probe).

SOURCE OF TRUTH: these string values MUST stay byte-identical to prod-cli's internal/deployment/shape.go (ShapeWeb/ShapeMCPServer/ShapeWorker/ShapeCron). The SDK can't import that package (separate module + internal/), so the strings are mirrored here; prod-cli maps SDK↔core via deployment.ParseShape/String on the matching strings, and a prod-cli drift test fails CI if they ever diverge. As a named-string type it gob-encodes as its underlying string, so the RPC wire form is a plain string.

const (
	ShapeWeb       DeployShape = "web"        // serves HTTP; liveness is a URL probe
	ShapeMCPServer DeployShape = "mcp-server" // an MCP server; HTTP + a protocol handshake
	ShapeWorker    DeployShape = "worker"     // a continuous non-HTTP process; no URL
	ShapeCron      DeployShape = "cron"       // a scheduled/periodic job; no URL
)

type ErrReply

type ErrReply struct{ Err string }

type Meta

type Meta struct {
	Name             string   // display name, e.g. "Acme Cloud"
	Aliases          []string // lowercase natural-language matches, e.g. "acme", "acme-cloud"
	DomainSuffix     string   // default hostname suffix, e.g. ".acme.app" (framework host allow-lists)
	SupportsRollback bool
	// Shapes are the deploy shapes this provider can serve. Empty ⇒ {ShapeWeb} (a
	// URL-serving web service — the back-compatible default, so plugins predating this
	// field behave exactly as before). Declare ShapeWorker/ShapeMCPServer here to tell the
	// host you may deploy a URL-less agent/worker; the host then relaxes its URL
	// requirement for a non-HTTP shape instead of failing "returned no URL".
	Shapes []DeployShape
}

Meta describes a provider platform.

type MetaReply

type MetaReply struct {
	Meta Meta
	Err  string
}

type NoArgs

type NoArgs struct{}

type PrevArgs

type PrevArgs struct{ AppName string }

type PrevReply

type PrevReply struct {
	Info DeployInfo
	Err  string
}

type Provider

type Provider interface {
	// Metadata describes the platform: display name, natural-language aliases, the
	// hostname suffix for framework host allow-lists, and capabilities. Called first.
	Metadata(ctx context.Context) (Meta, error)

	// RegistryInfo returns where and how the host should push the built image. The
	// host runs the docker build+push with these credentials; the plugin then deploys
	// from the resulting image reference.
	RegistryInfo(ctx context.Context, project string) (RegistryInfo, error)

	// CheckAuth reports whether the user's credentials for this cloud are usable, so
	// prod can fail fast with a clear message before building.
	CheckAuth(ctx context.Context) (AuthStatus, error)

	// Deploy creates or updates the service from a pushed image and returns it once
	// serving. It owns all cloud-specific work: the service create/update, secrets,
	// public access, and readiness polling.
	Deploy(ctx context.Context, req DeployRequest) (DeployResult, error)

	// PreviousDeployment returns the deployment to roll back to (the one before the
	// current), or an empty ID if there's nothing to roll back to. Optional — a
	// provider without rollback returns an empty result and sets Meta.SupportsRollback
	// false.
	PreviousDeployment(ctx context.Context, appName string) (DeployInfo, error)

	// Rollback reverts the app to targetID (from PreviousDeployment). Optional.
	Rollback(ctx context.Context, appName, targetID string) error
}

Provider is the interface a prod provider plugin implements. Every method may be called in a fresh subprocess, so implementations must be self-contained (resolve their own cloud credentials from the user's ambient config, like the built-in adapters read ~/.aws).

func Dispense

func Dispense(conn goplugin.ClientProtocol) (Provider, error)

Dispense returns the Provider RPC client from a launched plugin connection.

type ProviderPlugin

type ProviderPlugin struct{ Impl Provider }

ProviderPlugin is the go-plugin net/rpc Plugin for a Provider. Impl is set on the plugin (server) side; the host side leaves it nil and gets a client.

func (*ProviderPlugin) Client

func (p *ProviderPlugin) Client(_ *goplugin.MuxBroker, c *rpc.Client) (interface{}, error)

func (*ProviderPlugin) Server

func (p *ProviderPlugin) Server(*goplugin.MuxBroker) (interface{}, error)

type RegistryArgs

type RegistryArgs struct{ Project string }

type RegistryInfo

type RegistryInfo struct {
	Host       string // registry host, e.g. "registry.acme.app"
	Repository string // namespaced repository for this app, e.g. "team/my-app"
	Username   string
	Token      string
}

RegistryInfo tells the host where to push the built image. The host tags and pushes as Host + "/" + Repository and authenticates with Username/Token.

type RegistryReply

type RegistryReply struct {
	Info RegistryInfo
	Err  string
}

type RollbackArgs

type RollbackArgs struct{ AppName, TargetID string }

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL