PromptKit SDK
Pack-first Go SDK that reduces boilerplate by ~80%
What is the PromptKit SDK?
Section titled “What is the PromptKit SDK?”The SDK uses a pack-first architecture that dramatically simplifies LLM application development:
- 5 lines to hello world - Open a pack, send a message, done
- Pack-first design - Load prompts tested with Arena, compiled with PackC
- Built-in tools - Register handlers with
OnTool, auto JSON serialization - Skills - Native AgentSkills.io support with progressive disclosure
- Workflows - Event-driven state machines with orchestration modes
- A2A - Multi-agent communication with agent-as-service pattern
- Streaming support - Channel-based streaming with
Stream() - Human-in-the-Loop - Approval workflows for sensitive operations
- Type-safe variables -
SetVar/GetVarwith concurrent access - Observability - EventBus integration for monitoring
Quick Start
Section titled “Quick Start”package main
import ( "context" "fmt" "log"
"github.com/AltairaLabs/PromptKit/sdk")
func main() { // Open a conversation from a pack file conv, err := sdk.Open("./hello.pack.json", "chat") if err != nil { log.Fatal(err) } defer conv.Close()
// Send a message and get a response resp, _ := conv.Send(context.Background(), "Hello!") fmt.Println(resp.Text())}That’s it. Five lines of functional code.
Core API
Section titled “Core API”Opening Conversations
Section titled “Opening Conversations”// Open from a pack file with a specific promptconv, err := sdk.Open("./myapp.pack.json", "assistant")
// Open with optionsconv, err := sdk.Open("./myapp.pack.json", "assistant", sdk.WithModel("gpt-4o"),)Sending Messages
Section titled “Sending Messages”// Simple sendresp, err := conv.Send(ctx, "What's the weather?")fmt.Println(resp.Text())
// Multi-turn conversations (context is maintained)resp1, _ := conv.Send(ctx, "My name is Alice")resp2, _ := conv.Send(ctx, "What's my name?") // "Alice"Template Variables
Section titled “Template Variables”// Set variables for prompt templatesconv.SetVar("user_name", "Alice")conv.SetVar("context", "admin role context")
// Get variablesname, ok := conv.GetVar("user_name")
// Bulk operationsconv.SetVars(map[string]any{ "user_name": "Alice", "language": "en",})Tool Handling
Section titled “Tool Handling”Register handlers that the LLM can call:
conv.OnTool("get_weather", func(args map[string]any) (any, error) { city := args["city"].(string)
// Return any JSON-serializable value return map[string]any{ "city": city, "temperature": 22.5, "conditions": "Sunny", }, nil})
// The LLM can now call this toolresp, _ := conv.Send(ctx, "What's the weather in London?")HTTP Tools
Section titled “HTTP Tools”For external API calls:
import "github.com/AltairaLabs/PromptKit/sdk/tools"
conv.OnToolHTTP("stock_price", tools.NewHTTPToolConfig( "https://api.stocks.example.com/v1/price", tools.WithMethod("GET"), tools.WithHeader("Authorization", "Bearer "+apiKey),))Streaming
Section titled “Streaming”Real-time response streaming:
// Channel-based streamingfor chunk := range conv.Stream(ctx, "Tell me a story") { if chunk.Error != nil { log.Printf("Error: %v", chunk.Error) break } if chunk.Type == sdk.ChunkDone { break } fmt.Print(chunk.Text)}Human-in-the-Loop (HITL)
Section titled “Human-in-the-Loop (HITL)”Approval workflows for sensitive operations:
import "github.com/AltairaLabs/PromptKit/sdk/tools"
conv.OnToolAsync( "process_refund", // Check if approval is needed func(args map[string]any) tools.PendingResult { amount := args["amount"].(float64) if amount > 100 { return tools.PendingResult{ Reason: "high_value", Message: fmt.Sprintf("$%.2f refund requires approval", amount), } } return tools.PendingResult{} // Auto-approve }, // Execute after approval func(args map[string]any) (any, error) { return map[string]any{"status": "completed"}, nil },)
// Handle pending approvalsresp, _ := conv.Send(ctx, "Refund $150 for order #123")for _, pending := range resp.PendingTools() { fmt.Printf("Pending: %s - %s\n", pending.Name, pending.Message)
// Approve or reject result, _ := conv.ResolveTool(pending.ID) // Approve // result, _ := conv.RejectTool(pending.ID, "Not authorized") // Reject}Observability
Section titled “Observability”Monitor events with hooks:
import ( "github.com/AltairaLabs/PromptKit/sdk/hooks" "github.com/AltairaLabs/PromptKit/runtime/events")
// Subscribe to eventshooks.On(conv, events.EventProviderCallCompleted, func(e *events.Event) { fmt.Printf("Provider call completed: %s\n", e.Type)})
hooks.OnToolCall(conv, func(name string, args map[string]any) { fmt.Printf("Tool called: %s\n", name)})Error Handling
Section titled “Error Handling”resp, err := conv.Send(ctx, input)if err != nil { switch { case errors.Is(err, sdk.ErrPackNotFound): // Pack file doesn't exist case errors.Is(err, sdk.ErrPromptNotFound): // Prompt ID not in pack case errors.Is(err, sdk.ErrProviderNotDetected): // No provider API key found case errors.Is(err, sdk.ErrToolNotRegistered): // Tool handler missing default: log.Printf("Unexpected error: %v", err) }}Examples
Section titled “Examples”Working examples are available in the sdk/examples/ directory:
- hello - Basic conversation in 5 lines
- tools - Tool registration and execution
- streaming - Real-time response streaming
- hitl - Human-in-the-loop approval workflows
- workflow-external - External orchestration via HTTP
Getting Help
Section titled “Getting Help”- Questions: GitHub Discussions
- Issues: Report a Bug
- Examples: SDK Examples
Workflows
Section titled “Workflows”Build stateful, multi-step conversations with event-driven state machines:
// Open a workflow from a pack with a workflow sectionwf, err := sdk.OpenWorkflow("./support.pack.json")if err != nil { log.Fatal(err)}defer wf.Close()
// Send a message in the current stateresp, _ := wf.Send(ctx, "I need help with billing")fmt.Println(resp.Text())
// Trigger a state transitionnewState, _ := wf.Transition("Escalate")fmt.Printf("Now in state: %s\n", newState)
// Query workflow statefmt.Println(wf.CurrentState()) // "specialist"fmt.Println(wf.IsComplete()) // falsefmt.Println(wf.AvailableEvents()) // ["Resolve"]Orchestration Modes
Section titled “Orchestration Modes”States can declare an orchestration mode that controls who drives transitions:
mode := wf.OrchestrationMode() // "internal", "external", or "hybrid"- Internal — The agent drives transitions automatically
- External — External callers (HTTP endpoints, queues) drive transitions via
Transition() - Hybrid — Both the agent and external callers can trigger transitions
Resuming Workflows
Section titled “Resuming Workflows”Restore a previously saved workflow:
wf, err := sdk.ResumeWorkflow("workflow-id", "./support.pack.json")Context Carry-Forward
Section titled “Context Carry-Forward”When enabled, a summary of the previous state’s conversation is injected as context into the next state:
wf, err := sdk.OpenWorkflow("./support.pack.json", sdk.WithContextCarryForward(true),)A2A Server
Section titled “A2A Server”Expose your agent as an A2A-compliant service:
opener := sdk.A2AOpener("./assistant.pack.json", "chat")server := sdk.NewA2AServer(opener, sdk.WithA2ACard(&card), sdk.WithA2APort(9999),)server.ListenAndServe()- A2A Server Tutorial — step-by-step guide
- A2A Server Reference — complete API docs
Skills
Section titled “Skills”Load knowledge and instructions on demand using the AgentSkills.io standard:
// Skills auto-detected from pack's skills sectionconv, _ := sdk.Open("./support.pack.json", "assistant")
// Or configure programmaticallyconv, _ := sdk.Open("./base.pack.json", "assistant", sdk.WithSkillsDir("./skills"), sdk.WithMaxActiveSkillsOption(5),)Skills use progressive disclosure — only name + description (~50 tokens each) are loaded at startup. Full instructions load on demand when the model calls skill__activate. Skills can also extend the available tool set (capped by the pack’s declared tools).
Workflow states can scope which skills are available by pointing to a skills subdirectory:
workflow: states: billing: prompt_task: billing_agent skills: ./skills/billing # Only billing skills available- Skills Concept — how skills work, progressive disclosure, three-level tool scoping
Related Tools
Section titled “Related Tools”- Arena: Test prompts before using them
- PackC: Compile prompts into packs
- Runtime: Extend the SDK with custom providers
- Complete Workflow: See all tools together