Deploy: Adapter SDK
Overview
Section titled “Overview”The Adapter SDK (runtime/deploy/adaptersdk) provides Go functions for building deploy adapter plugins. It handles JSON-RPC communication so you only need to implement the Provider interface.
Installation
Section titled “Installation”go get github.com/AltairaLabs/PromptKit/runtime/deployImport the packages:
import ( "github.com/AltairaLabs/PromptKit/runtime/deploy" "github.com/AltairaLabs/PromptKit/runtime/deploy/adaptersdk")Quick Start
Section titled “Quick Start”A minimal adapter:
package main
import ( "context" "log"
"github.com/AltairaLabs/PromptKit/runtime/deploy" "github.com/AltairaLabs/PromptKit/runtime/deploy/adaptersdk")
type myProvider struct{}
func (p *myProvider) GetProviderInfo(ctx context.Context) (*deploy.ProviderInfo, error) { return &deploy.ProviderInfo{ Name: "myprovider", Version: "0.1.0", }, nil}
func (p *myProvider) ValidateConfig(ctx context.Context, req *deploy.ValidateRequest) (*deploy.ValidateResponse, error) { return &deploy.ValidateResponse{Valid: true}, nil}
func (p *myProvider) Plan(ctx context.Context, req *deploy.PlanRequest) (*deploy.PlanResponse, error) { return &deploy.PlanResponse{ Changes: []deploy.ResourceChange{ {Type: "runtime", Name: "main", Action: deploy.ActionCreate, Detail: "Create runtime"}, }, Summary: "1 resource to create", }, nil}
func (p *myProvider) Apply(ctx context.Context, req *deploy.PlanRequest, callback deploy.ApplyCallback) (string, error) { // Create resources... return `{"resource_id": "abc123"}`, nil}
func (p *myProvider) Destroy(ctx context.Context, req *deploy.DestroyRequest, callback deploy.DestroyCallback) error { // Delete resources... return nil}
func (p *myProvider) Status(ctx context.Context, req *deploy.StatusRequest) (*deploy.StatusResponse, error) { return &deploy.StatusResponse{ Status: "deployed", Resources: []deploy.ResourceStatus{ {Type: "runtime", Name: "main", Status: "healthy"}, }, }, nil}
func (p *myProvider) Import(ctx context.Context, req *deploy.ImportRequest) (*deploy.ImportResponse, error) { // Look up existing resource by req.Identifier... return &deploy.ImportResponse{ Resource: deploy.ResourceStatus{ Type: req.ResourceType, Name: req.ResourceName, Status: "healthy", }, State: `{"resource_id": "` + req.Identifier + `"}`, }, nil}
func main() { if err := adaptersdk.Serve(&myProvider{}); err != nil { log.Fatal(err) }}Build the binary with the correct name:
go build -o promptarena-deploy-myprovider .API Reference
Section titled “API Reference”func Serve(provider deploy.Provider) errorStarts a JSON-RPC server on stdin/stdout. This is the main entry point for adapter binaries. It reads JSON-RPC requests from stdin, dispatches them to the appropriate Provider method, and writes responses to stdout.
Serve blocks until stdin is closed (the CLI exits).
ServeIO
Section titled “ServeIO”func ServeIO(provider deploy.Provider, r io.Reader, w io.Writer) errorSame as Serve but with custom I/O streams. Useful for testing.
ParsePack
Section titled “ParsePack”func ParsePack(packJSON []byte) (*prompt.Pack, error)Deserializes the pack JSON from a PlanRequest.PackJSON field into a prompt.Pack struct. Use this to inspect pack contents during Plan or Apply:
func (p *myProvider) Plan(ctx context.Context, req *deploy.PlanRequest) (*deploy.PlanResponse, error) { pack, err := adaptersdk.ParsePack([]byte(req.PackJSON)) if err != nil { return nil, fmt.Errorf("invalid pack: %w", err) } // Use pack.Prompts, pack.Name, etc.}ProgressReporter
Section titled “ProgressReporter”type ProgressReporter struct { ... }
func NewProgressReporter(callback deploy.ApplyCallback) *ProgressReporterHelper for emitting structured events during Apply:
func (p *myProvider) Apply(ctx context.Context, req *deploy.PlanRequest, callback deploy.ApplyCallback) (string, error) { reporter := adaptersdk.NewProgressReporter(callback)
reporter.Progress("Creating runtime...", 25) // ... create runtime ...
reporter.Resource(&deploy.ResourceResult{ Type: "runtime", Name: "main", Action: deploy.ActionCreate, Status: "created", })
reporter.Progress("Creating endpoint...", 75) // ... create endpoint ...
reporter.Resource(&deploy.ResourceResult{ Type: "runtime", Name: "endpoint", Action: deploy.ActionCreate, Status: "created", })
return `{"runtime_id": "abc"}`, nil}Methods:
| Method | Description |
|---|---|
Progress(message string, pct float64) | Emit a progress message with percentage (0-100) |
Resource(result *deploy.ResourceResult) | Report a completed resource operation |
Error(err error) | Report a non-fatal error |
Progress messages with valid percentages (0-100) are formatted as "message (XX%)".
Planning Helpers
Section titled “Planning Helpers”The SDK provides helper functions for building resource plans from PlanRequest fields. You can use the high-level GenerateResourcePlan for a complete plan, or compose the lower-level functions for custom logic.
GenerateResourcePlan
Section titled “GenerateResourcePlan”func GenerateResourcePlan(packJSON, arenaConfigJSON, deployConfigJSON string) (*ResourcePlan, error)Builds a combined resource plan by orchestrating all lower-level helpers. Call this from your Plan() method to get a complete plan in one step:
func (p *myProvider) Plan(ctx context.Context, req *deploy.PlanRequest) (*deploy.PlanResponse, error) { plan, err := adaptersdk.GenerateResourcePlan(req.PackJSON, req.ArenaConfig, req.DeployConfig) if err != nil { return nil, err } return &deploy.PlanResponse{ Changes: plan.Changes, Summary: adaptersdk.SummarizeChanges(plan.Changes), }, nil}What it does internally:
- Parses the pack JSON (required — returns error if invalid)
- Generates agent resources for multi-agent packs (
agent_runtime,a2a_endpoint,gateway) - Extracts tool info and policies from the arena config
- Filters out blocklisted tools
- Parses tool targets from the deploy config
- Generates
tool_gatewayresources for tools with targets - Combines agent + tool changes into a single plan
Empty arena config or deploy config are handled gracefully (no tool resources).
ResourcePlan
Section titled “ResourcePlan”type ResourcePlan struct { Changes []deploy.ResourceChange // Combined agent + tool resource changes Tools []ToolInfo // Filtered tools (blocklisted tools removed) Targets ToolTargetMap // Tool target mappings from deploy config Policy *ToolPolicyInfo // Merged tool policies from scenarios}Returned by GenerateResourcePlan. The Tools, Targets, and Policy fields are exposed for adapter-specific logic beyond the standard plan.
SummarizeChanges
Section titled “SummarizeChanges”func SummarizeChanges(changes []deploy.ResourceChange) stringGenerates a human-readable summary of resource changes:
adaptersdk.SummarizeChanges(changes)// "3 to create, 1 to update, 1 to delete"// "5 to create, 2 unchanged"// "No changes"FilterBlocklistedTools
Section titled “FilterBlocklistedTools”func FilterBlocklistedTools(tools []ToolInfo, policy *ToolPolicyInfo) []ToolInfoRemoves tools whose names appear in the policy blocklist. Returns tools unchanged if policy is nil or the blocklist is empty. Called automatically by GenerateResourcePlan, but available for custom plan logic.
Lower-Level Functions
Section titled “Lower-Level Functions”These are used internally by GenerateResourcePlan and are available for adapters that need finer control.
Agent Helpers
Section titled “Agent Helpers”// Returns true if the pack has an agents section with members.func IsMultiAgent(pack *prompt.Pack) bool
// Returns agent metadata for all members, sorted by name.// Defaults: text/plain for missing input/output modes.func ExtractAgents(pack *prompt.Pack) []AgentInfo
// Creates resource changes for multi-agent deployment.// Per member: agent_runtime + a2a_endpoint. Entry agent also gets a gateway.// Returns nil for single-agent packs.func GenerateAgentResourcePlan(pack *prompt.Pack) []deploy.ResourceChange
// Generates A2A agent cards from the pack.func GenerateAgentCards(pack *prompt.Pack) map[string]*a2a.AgentCardTool Helpers
Section titled “Tool Helpers”// Extracts tool metadata from ArenaConfig JSON (inline specs + loaded tool files).// Returns sorted tools with deduplication (inline specs take precedence).func ExtractToolInfo(arenaConfigJSON string) ([]ToolInfo, error)
// Extracts and merges tool blocklists from all scenarios in the ArenaConfig.// Returns nil if no policies are found.func ExtractToolPolicies(arenaConfigJSON string) (*ToolPolicyInfo, error)
// Extracts the tool_targets map from deploy config JSON.// Each value is raw JSON for adapter-specific unmarshaling.func ParseDeployToolTargets(deployConfigJSON string) (ToolTargetMap, error)
// Creates tool_gateway resource changes for tools that have target mappings.func GenerateToolGatewayPlan(tools []ToolInfo, targets ToolTargetMap) []deploy.ResourceChangePlanning Types
Section titled “Planning Types”AgentInfo
Section titled “AgentInfo”type AgentInfo struct { Name string `json:"name"` Description string `json:"description"` IsEntry bool `json:"is_entry"` Tags []string `json:"tags,omitempty"` InputModes []string `json:"input_modes"` OutputModes []string `json:"output_modes"`}ToolInfo
Section titled “ToolInfo”type ToolInfo struct { Name string `json:"name"` Description string `json:"description"` Mode string `json:"mode"` // "mock", "live", "local", "mcp", "client" HasSchema bool `json:"has_schema"` InputSchema interface{} `json:"input_schema,omitempty"` HTTPURL string `json:"http_url,omitempty"` HTTPMethod string `json:"http_method,omitempty"`}ToolTargetMap
Section titled “ToolTargetMap”// Opaque map of tool name → adapter-specific target config as raw JSON.type ToolTargetMap map[string]json.RawMessageEach adapter defines its own target schema. For example, a deploy config might specify:
{ "tool_targets": { "get_weather": { "lambda_arn": "arn:aws:lambda:us-east-1:123:function:weather" } }}The adapter unmarshals each json.RawMessage into its own target type.
ToolPolicyInfo
Section titled “ToolPolicyInfo”type ToolPolicyInfo struct { Blocklist []string `json:"blocklist,omitempty"`}Provider Interface
Section titled “Provider Interface”type Provider interface { GetProviderInfo(ctx context.Context) (*ProviderInfo, error) ValidateConfig(ctx context.Context, req *ValidateRequest) (*ValidateResponse, error) Plan(ctx context.Context, req *PlanRequest) (*PlanResponse, error) Apply(ctx context.Context, req *PlanRequest, callback ApplyCallback) (adapterState string, err error) Destroy(ctx context.Context, req *DestroyRequest, callback DestroyCallback) error Status(ctx context.Context, req *StatusRequest) (*StatusResponse, error) Import(ctx context.Context, req *ImportRequest) (*ImportResponse, error)}ProviderInfo
Section titled “ProviderInfo”type ProviderInfo struct { Name string `json:"name"` Version string `json:"version"` Capabilities []string `json:"capabilities,omitempty"` ConfigSchema string `json:"config_schema,omitempty"`}ValidateRequest / ValidateResponse
Section titled “ValidateRequest / ValidateResponse”type ValidateRequest struct { Config string `json:"config"`}
type ValidateResponse struct { Valid bool `json:"valid"` Errors []string `json:"errors,omitempty"`}PlanRequest / PlanResponse
Section titled “PlanRequest / PlanResponse”type PlanRequest struct { PackJSON string `json:"pack_json"` DeployConfig string `json:"deploy_config"` ArenaConfig string `json:"arena_config,omitempty"` Environment string `json:"environment"` PriorState string `json:"prior_state,omitempty"`}
type PlanResponse struct { Changes []ResourceChange `json:"changes"` Summary string `json:"summary"`}ArenaConfig contains the JSON-serialized arena config with loaded resources (tools, scenarios). Planning helpers use this to extract tool info and policies.
ResourceChange
Section titled “ResourceChange”type ResourceChange struct { Type string `json:"type"` Name string `json:"name"` Action Action `json:"action"` Detail string `json:"detail,omitempty"`}Action Constants
Section titled “Action Constants”const ( ActionCreate Action = "CREATE" ActionUpdate Action = "UPDATE" ActionDelete Action = "DELETE" ActionNoChange Action = "NO_CHANGE" ActionDrift Action = "DRIFT")ApplyEvent / ApplyCallback
Section titled “ApplyEvent / ApplyCallback”type ApplyEvent struct { Type string `json:"type"` Message string `json:"message,omitempty"` Resource *ResourceResult `json:"resource,omitempty"`}
type ApplyCallback func(event *ApplyEvent) errorEvent types: "progress", "resource", "error", "complete".
ResourceResult
Section titled “ResourceResult”type ResourceResult struct { Type string `json:"type"` Name string `json:"name"` Action Action `json:"action"` Status string `json:"status"` Detail string `json:"detail,omitempty"`}Status values: "created", "updated", "deleted", "failed".
DestroyRequest / DestroyEvent / DestroyCallback
Section titled “DestroyRequest / DestroyEvent / DestroyCallback”type DestroyRequest struct { DeployConfig string `json:"deploy_config"` Environment string `json:"environment"` PriorState string `json:"prior_state"`}
type DestroyEvent struct { Type string `json:"type"` Message string `json:"message,omitempty"`}
type DestroyCallback func(event *DestroyEvent) errorStatusRequest / StatusResponse
Section titled “StatusRequest / StatusResponse”type StatusRequest struct { DeployConfig string `json:"deploy_config"` Environment string `json:"environment"` PriorState string `json:"prior_state"`}
type StatusResponse struct { Status string `json:"status"` Resources []ResourceStatus `json:"resources,omitempty"` State string `json:"state,omitempty"`}ResourceStatus
Section titled “ResourceStatus”type ResourceStatus struct { Type string `json:"type"` Name string `json:"name"` Status string `json:"status"` Detail string `json:"detail,omitempty"`}ImportRequest / ImportResponse
Section titled “ImportRequest / ImportResponse”type ImportRequest struct { ResourceType string `json:"resource_type"` ResourceName string `json:"resource_name"` Identifier string `json:"identifier"` DeployConfig string `json:"deploy_config"` Environment string `json:"environment,omitempty"` PriorState string `json:"prior_state,omitempty"`}
type ImportResponse struct { Resource ResourceStatus `json:"resource"` State string `json:"state"`}Building and Installing
Section titled “Building and Installing”Build your adapter binary:
go build -o promptarena-deploy-myprovider .Install locally for testing:
mkdir -p ~/.promptarena/adapterscp promptarena-deploy-myprovider ~/.promptarena/adapters/Test with the CLI:
promptarena deploy adapter listpromptarena deploy planSee Also
Section titled “See Also”- Protocol — JSON-RPC wire protocol details
- Adapter Architecture — Design concepts
- CLI Commands — CLI usage