mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-14 03:30:26 +00:00
Add kit-sdk skill for building Go applications with the Kit SDK
Comprehensive reference covering the full pkg/kit API surface: - Core lifecycle (New, Prompt, Close) - All 8 prompt method variants - Event system with 14 event types - Hook system with 6 interceptor types and priorities - Tool constructors, bundles, and runtime querying - Session management (5 modes, branching, discovery) - Model management and registry lookups - Context estimation and compaction - In-process subagents with event streaming - Authentication, skills, config resolution - 7 common patterns (scripting, daemon, streaming, etc.) - Re-exported types reference
This commit is contained in:
@@ -0,0 +1,772 @@
|
||||
---
|
||||
name: kit-sdk
|
||||
description: Guide for building Go applications with the Kit SDK. Use when the user asks to create a program, service, script, or application that uses Kit programmatically as a Go library — e.g. embedding LLM interactions, building agents, creating CLI tools powered by Kit, or integrating Kit into backend services. Do NOT use for Kit extensions (use kit-extensions skill instead).
|
||||
---
|
||||
|
||||
# Kit SDK Development Guide
|
||||
|
||||
The Kit SDK (`pkg/kit`) lets you embed Kit's full agent capabilities — LLM interactions, tool execution, session management, streaming, hooks — into any Go application. Unlike extensions (which are interpreted scripts running inside Kit's TUI), SDK programs are standalone compiled Go binaries.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
go get github.com/mark3labs/kit
|
||||
```
|
||||
|
||||
Import path (alias recommended):
|
||||
|
||||
```go
|
||||
import kit "github.com/mark3labs/kit/pkg/kit"
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
kit "github.com/mark3labs/kit/pkg/kit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
host, err := kit.New(ctx, nil) // nil = load ~/.kit.yml defaults
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer func() { _ = host.Close() }()
|
||||
|
||||
response, err := host.Prompt(ctx, "What is 2+2?")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(response)
|
||||
}
|
||||
```
|
||||
|
||||
## Core Lifecycle
|
||||
|
||||
1. **Create**: `kit.New(ctx, opts)` — loads config, initializes MCP servers, creates LLM provider, sets up agent
|
||||
2. **Interact**: `host.Prompt(ctx, msg)` — send messages, agent uses tools as needed
|
||||
3. **Close**: `host.Close()` — cleans up MCP connections, model resources, session file handle
|
||||
|
||||
Always defer `Close()`:
|
||||
|
||||
```go
|
||||
defer func() { _ = host.Close() }()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Options Reference
|
||||
|
||||
All fields are optional. Zero values use CLI defaults.
|
||||
|
||||
```go
|
||||
host, err := kit.New(ctx, &kit.Options{
|
||||
// Model
|
||||
Model: "anthropic/claude-sonnet-4-5-20250929", // "provider/model" format
|
||||
SystemPrompt: "You are a helpful assistant",
|
||||
ConfigFile: "/path/to/config.yml", // default: ~/.kit.yml
|
||||
|
||||
// Behavior
|
||||
MaxSteps: 10, // 0 = unlimited tool-calling steps
|
||||
Streaming: true, // stream LLM output (default from config)
|
||||
Quiet: true, // suppress debug output
|
||||
Debug: true, // enable debug logging
|
||||
|
||||
// Session
|
||||
SessionDir: "/path/to/project", // base dir for session discovery (default: cwd)
|
||||
SessionPath: "/path/to/session.jsonl", // open specific session file
|
||||
Continue: true, // resume most recent session for SessionDir
|
||||
NoSession: true, // ephemeral in-memory session, no disk persistence
|
||||
|
||||
// Tools
|
||||
Tools: []kit.Tool{kit.NewBashTool()}, // REPLACES entire default tool set
|
||||
ExtraTools: []kit.Tool{myTool}, // ADDS alongside core/MCP/extension tools
|
||||
|
||||
// Skills
|
||||
Skills: []string{"/path/to/skill.md"}, // explicit skill files (empty = auto-discover)
|
||||
SkillsDir: "/path/to/skills", // override project-local skills dir
|
||||
|
||||
// Compaction
|
||||
AutoCompact: true, // auto-compact near context limit
|
||||
CompactionOptions: &kit.CompactionOptions{...}, // nil = defaults
|
||||
})
|
||||
```
|
||||
|
||||
**Critical distinction**: `Tools` replaces ALL default tools (core + MCP + extension). `ExtraTools` adds tools alongside the defaults. Use `Tools` to restrict the agent's capabilities; use `ExtraTools` to extend them.
|
||||
|
||||
---
|
||||
|
||||
## Prompt Methods
|
||||
|
||||
### Simple prompt — string in, string out
|
||||
|
||||
```go
|
||||
response, err := host.Prompt(ctx, "Explain this code")
|
||||
```
|
||||
|
||||
### Full result with usage stats
|
||||
|
||||
```go
|
||||
result, err := host.PromptResult(ctx, "Analyze this file")
|
||||
// result.Response — assistant's text
|
||||
// result.StopReason — "stop", "length", "tool-calls", "error", etc.
|
||||
// result.SessionID — session UUID
|
||||
// result.TotalUsage — aggregate tokens across all steps (*kit.FantasyUsage)
|
||||
// result.FinalUsage — tokens from last API call only
|
||||
// result.Messages — full updated conversation ([]kit.FantasyMessage)
|
||||
```
|
||||
|
||||
### Multimodal with file attachments
|
||||
|
||||
```go
|
||||
import "charm.land/fantasy"
|
||||
|
||||
files := []fantasy.FilePart{{
|
||||
Name: "screenshot.png",
|
||||
MediaType: "image/png",
|
||||
Data: imageBytes,
|
||||
}}
|
||||
result, err := host.PromptResultWithFiles(ctx, "What's in this image?", files)
|
||||
```
|
||||
|
||||
### Per-call system message injection
|
||||
|
||||
```go
|
||||
response, err := host.PromptWithOptions(ctx, "Review this PR", kit.PromptOptions{
|
||||
SystemMessage: "Focus on security vulnerabilities only.",
|
||||
})
|
||||
```
|
||||
|
||||
### System-level steering (no visible user message)
|
||||
|
||||
```go
|
||||
response, err := host.Steer(ctx, "Switch to a more formal tone")
|
||||
```
|
||||
|
||||
### Continue without new input
|
||||
|
||||
```go
|
||||
response, err := host.FollowUp(ctx, "") // empty = "Continue."
|
||||
```
|
||||
|
||||
### Multiple user messages in one turn
|
||||
|
||||
```go
|
||||
result, err := host.PromptResultWithMessages(ctx, []string{
|
||||
"Here is the code:",
|
||||
"@file.go", // content from earlier
|
||||
"Please review it.",
|
||||
})
|
||||
```
|
||||
|
||||
### Legacy inline callbacks (deprecated — use event subscribers instead)
|
||||
|
||||
```go
|
||||
response, err := host.PromptWithCallbacks(ctx, "List files",
|
||||
func(name, args string) { fmt.Printf("Tool: %s\n", name) },
|
||||
func(name, args, result string, isError bool) { /* tool result */ },
|
||||
func(chunk string) { fmt.Print(chunk) }, // streaming
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Event System
|
||||
|
||||
Events are read-only observations of the agent lifecycle. Register before calling Prompt.
|
||||
|
||||
### Typed convenience subscribers
|
||||
|
||||
```go
|
||||
// Each returns an unsubscribe function.
|
||||
unsub := host.OnToolCall(func(e kit.ToolCallEvent) {
|
||||
// e.ToolCallID, e.ToolName, e.ToolKind, e.ToolArgs, e.ParsedArgs
|
||||
})
|
||||
defer unsub()
|
||||
|
||||
host.OnToolResult(func(e kit.ToolResultEvent) {
|
||||
// e.ToolCallID, e.ToolName, e.ToolKind, e.ToolArgs, e.ParsedArgs
|
||||
// e.Result, e.IsError, e.Metadata (*ToolResultMetadata)
|
||||
})
|
||||
|
||||
host.OnToolOutput(func(e kit.ToolOutputEvent) {
|
||||
// e.ToolCallID, e.ToolName, e.Chunk, e.IsStderr
|
||||
// Streaming bash output chunks
|
||||
})
|
||||
|
||||
host.OnStreaming(func(e kit.MessageUpdateEvent) {
|
||||
fmt.Print(e.Chunk) // real-time text streaming
|
||||
})
|
||||
|
||||
host.OnResponse(func(e kit.ResponseEvent) {
|
||||
// e.Content — final response text
|
||||
})
|
||||
|
||||
host.OnTurnStart(func(e kit.TurnStartEvent) {
|
||||
// e.Prompt
|
||||
})
|
||||
|
||||
host.OnTurnEnd(func(e kit.TurnEndEvent) {
|
||||
// e.Response, e.Error, e.StopReason
|
||||
})
|
||||
```
|
||||
|
||||
### Generic subscriber (receives all events)
|
||||
|
||||
```go
|
||||
unsub := host.Subscribe(func(e kit.Event) {
|
||||
switch ev := e.(type) {
|
||||
case kit.ToolCallEvent:
|
||||
// ...
|
||||
case kit.MessageUpdateEvent:
|
||||
// ...
|
||||
case kit.CompactionEvent:
|
||||
// ev.Summary, ev.OriginalTokens, ev.CompactedTokens
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### All event types
|
||||
|
||||
| Event Type | Struct | Key Fields |
|
||||
|------------|--------|------------|
|
||||
| `turn_start` | `TurnStartEvent` | `Prompt` |
|
||||
| `turn_end` | `TurnEndEvent` | `Response`, `Error`, `StopReason` |
|
||||
| `message_start` | `MessageStartEvent` | *(none)* |
|
||||
| `message_update` | `MessageUpdateEvent` | `Chunk` |
|
||||
| `message_end` | `MessageEndEvent` | `Content` |
|
||||
| `tool_call` | `ToolCallEvent` | `ToolCallID`, `ToolName`, `ToolKind`, `ToolArgs`, `ParsedArgs` |
|
||||
| `tool_execution_start` | `ToolExecutionStartEvent` | `ToolCallID`, `ToolName`, `ToolKind`, `ToolArgs` |
|
||||
| `tool_execution_end` | `ToolExecutionEndEvent` | `ToolCallID`, `ToolName`, `ToolKind` |
|
||||
| `tool_result` | `ToolResultEvent` | `ToolCallID`, `ToolName`, `ToolKind`, `ToolArgs`, `ParsedArgs`, `Result`, `IsError`, `Metadata` |
|
||||
| `tool_call_content` | `ToolCallContentEvent` | `Content` |
|
||||
| `tool_output` | `ToolOutputEvent` | `ToolCallID`, `ToolName`, `Chunk`, `IsStderr` |
|
||||
| `response` | `ResponseEvent` | `Content` |
|
||||
| `compaction` | `CompactionEvent` | `Summary`, `OriginalTokens`, `CompactedTokens`, `MessagesRemoved`, `ReadFiles`, `ModifiedFiles` |
|
||||
| `reasoning_delta` | `ReasoningDeltaEvent` | `Delta` |
|
||||
|
||||
### Tool kind constants
|
||||
|
||||
Tools are classified by kind for UI rendering:
|
||||
|
||||
- `ToolKindExecute` = `"execute"` — bash
|
||||
- `ToolKindEdit` = `"edit"` — edit, write
|
||||
- `ToolKindRead` = `"read"` — read, ls
|
||||
- `ToolKindSearch` = `"search"` — grep, find
|
||||
- `ToolKindSubagent` = `"agent"` — spawn_subagent
|
||||
|
||||
---
|
||||
|
||||
## Hook System (Interceptors)
|
||||
|
||||
Hooks can **modify or cancel** operations. Events are read-only; hooks are read-write.
|
||||
|
||||
### BeforeToolCall — block tool execution
|
||||
|
||||
```go
|
||||
unsub := host.OnBeforeToolCall(kit.HookPriorityNormal, func(h kit.BeforeToolCallHook) *kit.BeforeToolCallResult {
|
||||
// h.ToolCallID, h.ToolName, h.ToolArgs
|
||||
if h.ToolName == "bash" {
|
||||
return &kit.BeforeToolCallResult{Block: true, Reason: "bash disabled"}
|
||||
}
|
||||
return nil // allow
|
||||
})
|
||||
```
|
||||
|
||||
### AfterToolResult — modify tool output
|
||||
|
||||
```go
|
||||
host.OnAfterToolResult(kit.HookPriorityNormal, func(h kit.AfterToolResultHook) *kit.AfterToolResultResult {
|
||||
// h.ToolCallID, h.ToolName, h.ToolArgs, h.Result, h.IsError
|
||||
if h.ToolName == "read" {
|
||||
filtered := redactSecrets(h.Result)
|
||||
return &kit.AfterToolResultResult{Result: &filtered}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
```
|
||||
|
||||
### BeforeTurn — modify prompt, inject messages
|
||||
|
||||
```go
|
||||
host.OnBeforeTurn(kit.HookPriorityNormal, func(h kit.BeforeTurnHook) *kit.BeforeTurnResult {
|
||||
// h.Prompt
|
||||
newPrompt := h.Prompt + "\nAlways respond in JSON."
|
||||
return &kit.BeforeTurnResult{Prompt: &newPrompt}
|
||||
// Also available: SystemPrompt *string, InjectText *string
|
||||
})
|
||||
```
|
||||
|
||||
### AfterTurn — observation only
|
||||
|
||||
```go
|
||||
host.OnAfterTurn(kit.HookPriorityNormal, func(h kit.AfterTurnHook) {
|
||||
// h.Response, h.Error
|
||||
log.Printf("Turn completed: %d chars", len(h.Response))
|
||||
})
|
||||
```
|
||||
|
||||
### ContextPrepare — filter/inject context window
|
||||
|
||||
```go
|
||||
host.OnContextPrepare(kit.HookPriorityNormal, func(h kit.ContextPrepareHook) *kit.ContextPrepareResult {
|
||||
// h.Messages — []fantasy.Message (the full context being sent to the LLM)
|
||||
// Return nil to pass through, or replace entire context:
|
||||
return &kit.ContextPrepareResult{Messages: filteredMessages}
|
||||
})
|
||||
```
|
||||
|
||||
### BeforeCompact — cancel or customize compaction
|
||||
|
||||
```go
|
||||
host.OnBeforeCompact(kit.HookPriorityNormal, func(h kit.BeforeCompactHook) *kit.BeforeCompactResult {
|
||||
// h.EstimatedTokens, h.ContextLimit, h.UsagePercent, h.MessageCount, h.IsAutomatic
|
||||
if h.IsAutomatic && h.UsagePercent < 0.9 {
|
||||
return &kit.BeforeCompactResult{Cancel: true, Reason: "not yet"}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
```
|
||||
|
||||
### Hook priorities
|
||||
|
||||
```go
|
||||
kit.HookPriorityHigh = 0 // runs first
|
||||
kit.HookPriorityNormal = 50 // default
|
||||
kit.HookPriorityLow = 100 // runs last
|
||||
```
|
||||
|
||||
Lower values run first. Within the same priority, registration order applies. First non-nil result wins.
|
||||
|
||||
---
|
||||
|
||||
## Tools
|
||||
|
||||
### Built-in tool constructors
|
||||
|
||||
```go
|
||||
kit.NewReadTool(opts...) // file reading
|
||||
kit.NewWriteTool(opts...) // file writing
|
||||
kit.NewEditTool(opts...) // surgical text editing
|
||||
kit.NewBashTool(opts...) // bash command execution
|
||||
kit.NewGrepTool(opts...) // content search (uses ripgrep when available)
|
||||
kit.NewFindTool(opts...) // file search (uses fd when available)
|
||||
kit.NewLsTool(opts...) // directory listing
|
||||
```
|
||||
|
||||
### Tool bundles
|
||||
|
||||
```go
|
||||
kit.AllTools(opts...) // all 7 core tools
|
||||
kit.CodingTools(opts...) // bash, read, write, edit
|
||||
kit.ReadOnlyTools(opts...) // read, grep, find, ls
|
||||
kit.SubagentTools(opts...) // all except spawn_subagent (prevents recursion)
|
||||
```
|
||||
|
||||
### Tool options
|
||||
|
||||
```go
|
||||
kit.WithWorkDir("/path/to/dir") // override working directory for file-based tools
|
||||
```
|
||||
|
||||
### Using tools in Options
|
||||
|
||||
```go
|
||||
// Restricted: agent can ONLY run bash
|
||||
host, _ := kit.New(ctx, &kit.Options{
|
||||
Tools: []kit.Tool{kit.NewBashTool()},
|
||||
})
|
||||
|
||||
// Extended: all defaults PLUS a custom tool
|
||||
host, _ := kit.New(ctx, &kit.Options{
|
||||
ExtraTools: []kit.Tool{myCustomTool},
|
||||
})
|
||||
```
|
||||
|
||||
### Querying tools at runtime
|
||||
|
||||
```go
|
||||
names := host.GetToolNames() // []string of all tool names
|
||||
tools := host.GetTools() // []kit.Tool (full tool objects)
|
||||
mcpCount := host.GetMCPToolCount() // tools from MCP servers
|
||||
extCount := host.GetExtensionToolCount() // tools from extensions
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Session Management
|
||||
|
||||
Sessions automatically persist as JSONL tree files. No explicit save needed.
|
||||
|
||||
### Session modes (via Options)
|
||||
|
||||
| Mode | Options | Behavior |
|
||||
|------|---------|----------|
|
||||
| Default | `{}` | New session file for cwd |
|
||||
| Specific file | `{SessionPath: "path.jsonl"}` | Open existing session |
|
||||
| Continue | `{Continue: true}` | Resume most recent session for cwd |
|
||||
| Ephemeral | `{NoSession: true}` | In-memory only, no disk persistence |
|
||||
| Custom dir | `{SessionDir: "/path"}` | Base directory for session discovery |
|
||||
|
||||
### Instance methods
|
||||
|
||||
```go
|
||||
host.GetSessionPath() // file path of active session
|
||||
host.GetSessionID() // UUID of active session
|
||||
host.ClearSession() // reset to fresh branch (doesn't delete file)
|
||||
host.Branch("entry-id") // branch from a specific entry
|
||||
host.SetSessionName("my session") // set display name
|
||||
|
||||
// Get conversation messages
|
||||
msgs := host.GetSessionMessages() // []extensions.SessionMessage (flattened text)
|
||||
msgs := host.GetStructuredMessages() // []kit.StructuredMessage (typed content parts)
|
||||
```
|
||||
|
||||
### Package-level session operations (no Kit instance needed)
|
||||
|
||||
```go
|
||||
sessions, _ := kit.ListSessions("/path/to/project") // sessions for a directory
|
||||
sessions, _ := kit.ListAllSessions() // all sessions everywhere
|
||||
kit.DeleteSession("/path/to/session.jsonl")
|
||||
tm, _ := kit.OpenTreeSession("/path/to/session.jsonl") // open for direct access
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Model Management
|
||||
|
||||
### At creation time
|
||||
|
||||
```go
|
||||
host, _ := kit.New(ctx, &kit.Options{
|
||||
Model: "openai/gpt-4o",
|
||||
})
|
||||
```
|
||||
|
||||
### At runtime
|
||||
|
||||
```go
|
||||
err := host.SetModel(ctx, "anthropic/claude-sonnet-4-5-20250929")
|
||||
modelStr := host.GetModelString() // "provider/model"
|
||||
info := host.GetModelInfo() // *kit.ModelInfo (capabilities, limits, pricing) or nil
|
||||
isReasoning := host.IsReasoningModel()
|
||||
level := host.GetThinkingLevel()
|
||||
err = host.SetThinkingLevel(ctx, "medium") // recreates agent with new thinking budget
|
||||
```
|
||||
|
||||
### Model registry
|
||||
|
||||
```go
|
||||
models := host.GetAvailableModels() // []extensions.ModelInfoEntry
|
||||
providers := kit.GetSupportedProviders() // []string
|
||||
providers := kit.GetFantasyProviders() // providers usable with fantasy
|
||||
models, _ := kit.GetModelsForProvider("anthropic") // map[string]kit.ModelInfo
|
||||
info := kit.LookupModel("anthropic", "claude-sonnet-4-5-20250929") // *kit.ModelInfo
|
||||
info := kit.GetProviderInfo("openai") // *kit.ProviderInfo (env vars, API URL)
|
||||
err := kit.ValidateEnvironment("anthropic", "") // check API keys
|
||||
suggestions := kit.SuggestModels("anthropic", "claudee") // fuzzy match
|
||||
kit.RefreshModelRegistry() // reload model database
|
||||
```
|
||||
|
||||
### Model string format
|
||||
|
||||
Always `"provider/model"`: `"anthropic/claude-sonnet-4-5-20250929"`, `"openai/gpt-4o"`, `"ollama/qwen3:8b"`.
|
||||
|
||||
```go
|
||||
provider, modelID, err := kit.ParseModelString("anthropic/claude-sonnet-4-5-20250929")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Context & Compaction
|
||||
|
||||
```go
|
||||
tokens := host.EstimateContextTokens() // heuristic token count
|
||||
shouldCompact := host.ShouldCompact() // true if near context limit
|
||||
|
||||
stats := host.GetContextStats()
|
||||
// stats.EstimatedTokens — uses API-reported count when available (more accurate)
|
||||
// stats.ContextLimit — model's context window size
|
||||
// stats.UsagePercent — fraction used (0.0–1.0)
|
||||
// stats.MessageCount — number of messages
|
||||
|
||||
// Manual compaction
|
||||
result, err := host.Compact(ctx, nil, "") // nil opts = defaults, "" = default prompt
|
||||
// result.Summary, result.OriginalTokens, result.CompactedTokens, result.MessagesRemoved
|
||||
|
||||
// Auto-compaction via Options
|
||||
host, _ := kit.New(ctx, &kit.Options{
|
||||
AutoCompact: true,
|
||||
CompactionOptions: &kit.CompactionOptions{
|
||||
ReserveTokens: 16384,
|
||||
KeepRecentTokens: 4096,
|
||||
ContextWindow: 200000,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## In-Process Subagents
|
||||
|
||||
Spawn child Kit instances without subprocess overhead:
|
||||
|
||||
```go
|
||||
result, err := host.Subagent(ctx, kit.SubagentConfig{
|
||||
Prompt: "Analyze the test files and summarize coverage",
|
||||
Model: "anthropic/claude-haiku-3-5-20241022", // empty = parent's model
|
||||
SystemPrompt: "You are a test analysis expert.",
|
||||
Tools: nil, // nil = SubagentTools() (all except spawn_subagent)
|
||||
NoSession: true, // ephemeral
|
||||
Timeout: 2 * time.Minute, // 0 = 5 minute default
|
||||
OnEvent: func(e kit.Event) {
|
||||
// Real-time events from the child agent
|
||||
if chunk, ok := e.(kit.MessageUpdateEvent); ok {
|
||||
fmt.Print(chunk.Chunk)
|
||||
}
|
||||
},
|
||||
})
|
||||
// result.Response, result.Error, result.SessionID, result.StopReason
|
||||
// result.Usage (*kit.FantasyUsage), result.Elapsed (time.Duration)
|
||||
```
|
||||
|
||||
### Subscribing to subagent events from parent
|
||||
|
||||
```go
|
||||
host.OnToolCall(func(e kit.ToolCallEvent) {
|
||||
if e.ToolName == "spawn_subagent" {
|
||||
host.SubscribeSubagent(e.ToolCallID, func(child kit.Event) {
|
||||
// Real-time events scoped to this subagent
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
```go
|
||||
cm, _ := kit.NewCredentialManager()
|
||||
hasKey := kit.HasAnthropicCredentials()
|
||||
apiKey := kit.GetAnthropicAPIKey() // stored creds → ANTHROPIC_API_KEY env var
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Skills
|
||||
|
||||
```go
|
||||
// Load a single skill file
|
||||
skill, _ := kit.LoadSkill("/path/to/SKILL.md")
|
||||
// skill.Name, skill.Description, skill.Content, skill.Path
|
||||
|
||||
// Load from directory
|
||||
skills, _ := kit.LoadSkillsFromDir("/path/to/skills")
|
||||
|
||||
// Auto-discover (global + project-local)
|
||||
skills, _ := kit.LoadSkills("/path/to/project")
|
||||
|
||||
// Prompt building with skills
|
||||
pb := kit.NewPromptBuilder("You are an assistant")
|
||||
pb.WithSkills(skills)
|
||||
pb.WithSection("", "Extra context here")
|
||||
systemPrompt := pb.Build()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Re-exported Types
|
||||
|
||||
The SDK re-exports internal types so you don't need direct internal imports:
|
||||
|
||||
```go
|
||||
// Message types
|
||||
kit.Message, kit.MessageRole, kit.ContentPart
|
||||
kit.TextContent, kit.ReasoningContent, kit.ToolCall, kit.ToolResult, kit.Finish
|
||||
kit.RoleUser, kit.RoleAssistant, kit.RoleTool, kit.RoleSystem
|
||||
|
||||
// Session types
|
||||
kit.SessionInfo, kit.TreeManager, kit.SessionHeader, kit.MessageEntry
|
||||
|
||||
// Config types
|
||||
kit.Config, kit.MCPServerConfig
|
||||
|
||||
// Provider types
|
||||
kit.ProviderConfig, kit.ProviderResult, kit.ModelInfo, kit.ModelCost, kit.ModelLimit
|
||||
|
||||
// Fantasy types (from charm.land/fantasy)
|
||||
kit.FantasyMessage, kit.FantasyUsage, kit.FantasyResponse
|
||||
|
||||
// Compaction types
|
||||
kit.CompactionResult, kit.CompactionOptions
|
||||
|
||||
// Conversion helpers
|
||||
msgs := kit.ConvertToFantasyMessages(&msg) // SDK message → fantasy messages
|
||||
msg := kit.ConvertFromFantasyMessage(fMsg) // fantasy message → SDK message
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern: Scripting / CLI pipe
|
||||
|
||||
Minimal program for automation — stdout-only output:
|
||||
|
||||
```go
|
||||
host, _ := kit.New(ctx, &kit.Options{Quiet: true})
|
||||
defer func() { _ = host.Close() }()
|
||||
|
||||
response, _ := host.Prompt(ctx, os.Args[1])
|
||||
fmt.Println(response)
|
||||
```
|
||||
|
||||
### Pattern: Long-running autonomous agent
|
||||
|
||||
Daemon that performs repeated independent tasks:
|
||||
|
||||
```go
|
||||
host, _ := kit.New(ctx, &kit.Options{
|
||||
SystemPrompt: taskPrompt,
|
||||
Tools: []kit.Tool{kit.NewBashTool()},
|
||||
NoSession: true,
|
||||
Quiet: true,
|
||||
})
|
||||
defer func() { _ = host.Close() }()
|
||||
|
||||
ticker := time.NewTicker(30 * time.Minute)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
host.ClearSession() // fresh context each iteration
|
||||
host.Prompt(ctx, "Perform the monitoring task")
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern: Streaming output to terminal
|
||||
|
||||
```go
|
||||
host.OnStreaming(func(e kit.MessageUpdateEvent) {
|
||||
fmt.Print(e.Chunk)
|
||||
})
|
||||
response, _ := host.Prompt(ctx, "Write a poem")
|
||||
```
|
||||
|
||||
### Pattern: Multi-turn conversation with memory
|
||||
|
||||
```go
|
||||
host.Prompt(ctx, "My name is Alice")
|
||||
response, _ := host.Prompt(ctx, "What's my name?")
|
||||
// Session automatically maintains context across calls
|
||||
fmt.Printf("Session: %s\n", host.GetSessionPath())
|
||||
```
|
||||
|
||||
### Pattern: Tool execution monitoring
|
||||
|
||||
```go
|
||||
host.OnToolCall(func(e kit.ToolCallEvent) {
|
||||
fmt.Printf("[%s] %s(%s)\n", e.ToolKind, e.ToolName, e.ToolArgs)
|
||||
})
|
||||
host.OnToolResult(func(e kit.ToolResultEvent) {
|
||||
status := "✓"
|
||||
if e.IsError { status = "✗" }
|
||||
fmt.Printf("[%s] %s %s\n", e.ToolKind, status, e.ToolName)
|
||||
})
|
||||
```
|
||||
|
||||
### Pattern: Guard rails with hooks
|
||||
|
||||
```go
|
||||
// Block dangerous commands
|
||||
host.OnBeforeToolCall(kit.HookPriorityHigh, func(h kit.BeforeToolCallHook) *kit.BeforeToolCallResult {
|
||||
if h.ToolName == "bash" && strings.Contains(h.ToolArgs, "rm -rf") {
|
||||
return &kit.BeforeToolCallResult{Block: true, Reason: "dangerous command"}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Inject context before every turn
|
||||
host.OnBeforeTurn(kit.HookPriorityNormal, func(h kit.BeforeTurnHook) *kit.BeforeTurnResult {
|
||||
context := "Current user: admin\nEnvironment: production"
|
||||
return &kit.BeforeTurnResult{InjectText: &context}
|
||||
})
|
||||
```
|
||||
|
||||
### Pattern: Parallel subagents
|
||||
|
||||
```go
|
||||
var wg sync.WaitGroup
|
||||
results := make([]*kit.SubagentResult, 3)
|
||||
|
||||
tasks := []string{"Analyze auth module", "Analyze database layer", "Analyze API routes"}
|
||||
for i, task := range tasks {
|
||||
wg.Add(1)
|
||||
go func(idx int, t string) {
|
||||
defer wg.Done()
|
||||
results[idx], _ = host.Subagent(ctx, kit.SubagentConfig{
|
||||
Prompt: t,
|
||||
NoSession: true,
|
||||
Timeout: 3 * time.Minute,
|
||||
})
|
||||
}(i, task)
|
||||
}
|
||||
wg.Wait()
|
||||
```
|
||||
|
||||
### Pattern: Read-only analysis agent
|
||||
|
||||
```go
|
||||
host, _ := kit.New(ctx, &kit.Options{
|
||||
SystemPrompt: "You are a code reviewer. Only read and analyze, never modify files.",
|
||||
Tools: kit.ReadOnlyTools(),
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
The SDK loads config identically to the CLI:
|
||||
|
||||
1. Explicit `ConfigFile` in Options (highest priority)
|
||||
2. `.kit.yml` in current directory
|
||||
3. `~/.kit.yml` in home directory
|
||||
4. Environment variables with `KIT_` prefix (`KIT_MODEL`, etc.)
|
||||
5. Provider-specific env vars (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc.)
|
||||
|
||||
Config files support `${ENV_VAR}` expansion.
|
||||
|
||||
```go
|
||||
// Initialize config manually (usually not needed — kit.New handles this)
|
||||
kit.InitConfig("/path/to/config.yml", false)
|
||||
kit.LoadConfigWithEnvSubstitution("/path/to/config.yml")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Files for Reference
|
||||
|
||||
- [`pkg/kit/kit.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/kit.go) — Kit struct, New(), Prompt methods, Subagent, Close
|
||||
- [`pkg/kit/types.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/types.go) — Re-exported types from internal packages
|
||||
- [`pkg/kit/tools.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/tools.go) — Tool constructors and bundles
|
||||
- [`pkg/kit/events.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/events.go) — Event types, EventBus, typed subscribers
|
||||
- [`pkg/kit/hooks.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/hooks.go) — Hook system (BeforeToolCall, AfterToolResult, etc.)
|
||||
- [`pkg/kit/sessions.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/sessions.go) — Session management
|
||||
- [`pkg/kit/compaction.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/compaction.go) — Context compaction
|
||||
- [`pkg/kit/models.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/models.go) — Model registry lookups
|
||||
- [`pkg/kit/config.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/config.go) — Config initialization and defaults
|
||||
- [`pkg/kit/skills.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/skills.go) — Skills loading and prompt building
|
||||
- [`pkg/kit/auth.go`](https://github.com/mark3labs/kit/blob/main/pkg/kit/auth.go) — Credential management
|
||||
- [`examples/sdk/`](https://github.com/mark3labs/kit/tree/main/examples/sdk) — Working example programs
|
||||
Reference in New Issue
Block a user