Token导航 LogoToken导航

Agent Skill · 研究检索

kit-sdk(KIT SDK 搜索)

kit-sdk 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

kit-sdk 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证信息还不明确,第三方扫描有提醒项,按安装量在研究检索类的 73,675 个 Skill 里排第 65,351。

总安装 282周安装 12GitHub Stars 45下载 99核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:kit-sdk(KIT SDK 搜索)
来源仓库:https://github.com/mark3labs/kit
仓库路径:skills/kit-sdk
安装命令:
npx skills add https://github.com/mark3labs/kit --skill kit-sdk
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/mark3labs/kit --skill kit-sdk

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

用于工具调用生命周期管理与事件流追踪,支持多种宿主环境。适合监控令牌使用、步骤执行与工具输出状态。通过 npx skills add 从 GitHub 安装,兼容 Codex、Claude、Cursor、Gemini CLI。

安装命令:npx skills add https://github.com/mark3labs/kit --skill kit-sdk。部分事件可能涉及敏感信息,需确保运行环境隔离与安全。

来源仓库内路径:skills/kit-sdk

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/mark3labs/kit --skill kit-sdk;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

kit-sdk 怎么安装?

在终端执行 npx skills add https://github.com/mark3labs/kit --skill kit-sdk。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

kit-sdk 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

kit-sdk 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

kit-sdk 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

kit-sdk 用的人多吗?

公开数据是累计安装 282 次,近一周安装 12 次,下载 99 次,GitHub 45 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

kit-sdk 安全吗?

第三方扫描有提醒项,说明存在需要人工确认的行为。安装前请打开源码看清它读了什么、联网到哪里。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
kit-sdk

KIT SDK 搜索 · 本页

28245接触敏感数据未明确有提醒

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

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

go get github.com/mark3labs/kit

Import path (alias recommended):

import kit "github.com/mark3labs/kit/pkg/kit"

Quick Start

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():

defer func() { _ = host.Close() }()

Options Reference

All fields are optional. Zero values use CLI defaults.

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

    // Generation parameters — override env/config/per-model defaults.
    // Leaving a field at its zero/nil value lets the precedence chain
    // resolve a value (KIT_* env → .kit.yml → modelSettings/customModels →
    // 8192 floor for MaxTokens, provider defaults for samplers).
    MaxTokens:        16384,             // 0 = auto-resolve; non-zero suppresses right-sizing
    ThinkingLevel:    "medium",          // "off", "none", "minimal", "low", "medium", "high" ("" = default)
    Temperature:      ptrFloat32(0.2),   // pointer so explicit 0.0 != unset
    TopP:             nil,                // nil = leave provider/per-model default
    TopK:             nil,                // nil = leave provider/per-model default
    FrequencyPenalty: nil,
    PresencePenalty:  nil,

    // Provider configuration — override env/config without viper.Set workarounds.
    ProviderAPIKey: "sk-...",                    // "" = use config / provider env var
    ProviderURL:    "https://proxy.internal/v1", // "" = provider default endpoint
    TLSSkipVerify:  false,                       // true only; can't force-disable via Options

    // 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
    SessionManager: myCustomSession,  // custom SessionManager implementation (advanced)

    // Tools
    Tools:            []kit.Tool{kit.NewBashTool()}, // REPLACES entire default tool set
    ExtraTools:       []kit.Tool{myTool},            // ADDS alongside core/MCP/extension tools
    DisableCoreTools: true,                        // Use no core tools (0 tools, for chat-only)

    // Configuration
    SkipConfig:   true,                        // Skip .kit.yml files (viper defaults + env vars still apply)

    // Skills
    Skills:    []string{"/path/to/skill.md"}, // explicit skill files (empty = auto-discover)
    SkillsDir: "/path/to/skills",             // override project-local skills dir
    NoSkills:  true,                          // disable skill loading entirely

    // Feature toggles
    NoExtensions:   true,                     // disable Yaegi extension loading entirely
    NoContextFiles: true,                     // disable automatic AGENTS.md loading

    // Compaction
    AutoCompact:       true,                        // auto-compact near context limit
    CompactionOptions: &kit.CompactionOptions{...}, // nil = defaults

    // MCP OAuth — both fields are opt-in. If MCPAuthHandler is nil,
    // remote MCP servers that require OAuth will fail to connect with
    // an authorization-required error instead of silently opening a
    // browser. CLI consumers use NewCLIMCPAuthHandler; other embedders
    // implement MCPAuthHandler or configure DefaultMCPAuthHandler.
    MCPAuthHandler: mcpAuthHandler,             // nil = OAuth disabled
    MCPTokenStoreFactory: func(serverURL string) (kit.MCPTokenStore, error) {
        return myCustomStore(serverURL), nil  // custom OAuth token storage
    },

    // In-Process MCP Servers
    InProcessMCPServers: map[string]*kit.MCPServer{
        "docs": mcpSrv,  // *server.MCPServer from mcp-go — no subprocess needed
    },
})

// Tiny helper to take the address of a literal for pointer fields.
func ptrFloat32(v float32) *float32 { return &v }

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.

In-process MCP servers bypass subprocess spawning entirely. Pass *server.MCPServer instances from mcp-go via InProcessMCPServers or call AddInProcessMCPServer() at runtime.

Generation & provider Options (cheat sheet)

FieldTypeEmpty/nil meansNotes
MaxTokensintAuto-resolve (env → config → per-model → 8192 floor)Non-zero suppresses rightSizeMaxTokens
ThinkingLevelstringAuto-resolve (→ "off")Valid: "off", "none", "minimal", "low", "medium", "high"
Temperature*float32Leave provider/per-model defaultPointer so explicit 0.0 ≠ unset
TopP*float32Leave provider/per-model default
TopK*int32Leave provider/per-model default
FrequencyPenalty*float32Leave provider/per-model defaultOpenAI-family
PresencePenalty*float32Leave provider/per-model defaultOpenAI-family
ProviderAPIKeystringUse config / provider env varOverrides pre-existing viper state
ProviderURLstringUse provider default endpointSame base URL flag as --provider-url
TLSSkipVerifybool—Only effective when true; cannot force-disable via Options

These fields eliminate the old viper.Set("max-tokens", 16384) dance many downstream embedders used to do before calling kit.New(). Everything is now discoverable via godoc on kit.Options.


Prompt Methods

Simple prompt — string in, string out

response, err := host.Prompt(ctx, "Explain this code")

Full result with usage stats

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.LLMUsage)
//                        LLMUsage{InputTokens, OutputTokens, TotalTokens,
//                                 ReasoningTokens, CacheCreationTokens, CacheReadTokens}
// result.FinalUsage   — tokens from last API call only (*kit.LLMUsage)
//                        For context window fill, sum: InputTokens + CacheReadTokens +
//                        CacheCreationTokens + OutputTokens (with prompt caching,
//                        InputTokens alone understates the context)
// result.Messages     — full updated conversation ([]kit.LLMMessage)
//                        LLMMessage{Role kit.LLMMessageRole, Content string}

Multimodal with file attachments

files := []kit.LLMFilePart{{
    Filename:  "screenshot.png",
    MediaType: "image/png",
    Data:      imageBytes,
}}
result, err := host.PromptResultWithFiles(ctx, "What's in this image?", files)

Per-call system message injection

response, err := host.PromptWithOptions(ctx, "Review this PR", kit.PromptOptions{
    SystemMessage: "Focus on security vulnerabilities only.",
})

System-level steering (no visible user message)

response, err := host.Steer(ctx, "Switch to a more formal tone")

Continue without new input

response, err := host.FollowUp(ctx, "") // empty = "Continue."

Multiple user messages in one turn

result, err := host.PromptResultWithMessages(ctx, []string{
    "Here is the code:",
    "@file.go", // content from earlier
    "Please review it.",
})

Event System

Events are read-only observations of the agent lifecycle. Register before calling Prompt.

Typed convenience subscribers

// 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.OnToolCallStart(func(e kit.ToolCallStartEvent) {
    // Fires when the LLM begins generating tool call arguments.
    // e.ToolCallID, e.ToolName, e.ToolKind
    // Use this to show a "running" indicator immediately — before the
    // full argument JSON finishes streaming (eliminates "dead air").
})

host.OnToolCallDelta(func(e kit.ToolCallDeltaEvent) {
    // Fires for each streamed fragment of tool call arguments.
    // e.ToolCallID, e.Delta (JSON fragment)
    // Useful for live-previewing artifact content or progress indicators.
})

host.OnToolCallEnd(func(e kit.ToolCallEndEvent) {
    // Fires when tool argument streaming is complete, before execution.
    // e.ToolCallID
    // Transition UI from "generating args" to "executing".
})

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.OnMessageUpdate(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
})

host.OnStepStart(func(e kit.StepStartEvent) {
    // e.StepNumber — which LLM call step (1-based)
})

host.OnStepFinish(func(e kit.StepFinishEvent) {
    // e.StepNumber, e.HasToolCalls, e.FinishReason, e.Usage (LLMUsage)
})

host.OnWarnings(func(e kit.WarningsEvent) {
    for _, w := range e.Warnings {
        log.Printf("warning: %s", w)
    }
})

host.OnError(func(e kit.ErrorEvent) {
    log.Printf("agent error: %v", e.Error)
})

host.OnRetry(func(e kit.RetryEvent) {
    log.Printf("retrying (attempt %d): %v", e.Attempt, e.Error)
})

host.OnTextStart(func(e kit.TextStartEvent) {
    // e.ID — content block ID
})

host.OnTextEnd(func(e kit.TextEndEvent) {
    // e.ID — content block ID
})

host.OnReasoningStart(func(e kit.ReasoningStartEvent) {
    // e.ID — reasoning block ID
})

host.OnSource(func(e kit.SourceEvent) {
    // e.SourceType, e.ID, e.URL, e.Title
})

host.OnStreamFinish(func(e kit.StreamFinishEvent) {
    // e.Usage (LLMUsage), e.FinishReason
})

// Additional typed subscribers for previously generic-only events:
host.OnMessageStart(func(e kit.MessageStartEvent) {})
host.OnMessageEnd(func(e kit.MessageEndEvent) { /* e.Content */ })
host.OnReasoningDelta(func(e kit.ReasoningDeltaEvent) { /* e.Delta */ })
host.OnReasoningComplete(func(e kit.ReasoningCompleteEvent) {})
host.OnToolExecutionStart(func(e kit.ToolExecutionStartEvent) { /* e.ToolCallID, e.ToolName, e.ToolKind, e.ToolArgs */ })
host.OnToolExecutionEnd(func(e kit.ToolExecutionEndEvent) { /* e.ToolCallID, e.ToolName, e.ToolKind */ })
host.OnToolCallContent(func(e kit.ToolCallContentEvent) { /* e.Content */ })
host.OnStepUsage(func(e kit.StepUsageEvent) { /* e.InputTokens, e.OutputTokens, e.CacheReadTokens, e.CacheWriteTokens */ })
host.OnCompaction(func(e kit.CompactionEvent) { /* e.Summary, e.OriginalTokens, e.CompactedTokens, ... */ })
host.OnSteerConsumed(func(e kit.SteerConsumedEvent) { /* e.Count */ })
Rename note: OnStreaming has been renamed to OnMessageUpdate. The old OnStreaming name is kept as a deprecated alias for one release cycle.

Generic subscriber (receives all events)

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 TypeStructKey Fields
turn_startTurnStartEventPrompt
turn_endTurnEndEventResponse, Error, StopReason
message_startMessageStartEvent*(none)*
message_updateMessageUpdateEventChunk
message_endMessageEndEventContent
tool_call_startToolCallStartEventToolCallID, ToolName, ToolKind
tool_call_deltaToolCallDeltaEventToolCallID, Delta
tool_call_endToolCallEndEventToolCallID
tool_callToolCallEventToolCallID, ToolName, ToolKind, ToolArgs, ParsedArgs
tool_execution_startToolExecutionStartEventToolCallID, ToolName, ToolKind, ToolArgs
tool_execution_endToolExecutionEndEventToolCallID, ToolName, ToolKind
tool_resultToolResultEventToolCallID, ToolName, ToolKind, ToolArgs, ParsedArgs, Result, IsError, Metadata
tool_call_contentToolCallContentEventContent
tool_outputToolOutputEventToolCallID, ToolName, Chunk, IsStderr
responseResponseEventContent
compactionCompactionEventSummary, OriginalTokens, CompactedTokens, MessagesRemoved, ReadFiles, ModifiedFiles
reasoning_deltaReasoningDeltaEventDelta
step_usageStepUsageEventInputTokens, OutputTokens, CacheReadTokens, CacheWriteTokens
steer_consumedSteerConsumedEventCount
step_startStepStartEventStepNumber
step_finishStepFinishEventStepNumber, HasToolCalls, FinishReason, Usage
text_startTextStartEventID
text_endTextEndEventID
reasoning_startReasoningStartEventID
warningsWarningsEventWarnings
sourceSourceEventSourceType, ID, URL, Title
stream_finishStreamFinishEventUsage, FinishReason
errorErrorEventError
retryRetryEventAttempt, Error
password_promptPasswordPromptEventPrompt, ResponseCh

Tool call streaming lifecycle: ToolCallStartEvent → ToolCallDeltaEvent (repeated) → ToolCallEndEvent → ToolCallEvent → ToolExecutionStartEvent → ToolOutputEvent (optional, repeated) → ToolExecutionEndEvent → ToolResultEvent

PasswordPromptEvent (for sudo password handling):

// PasswordPromptEvent fires when a sudo command needs a password.
// The TUI should display a password prompt and send the result back via ResponseCh.
type PasswordPromptEvent struct {
    // Prompt is the message to display to the user.
    Prompt string
    // ResponseCh receives the password from the TUI.
    // The TUI must send exactly one value: (password, false) for submit
    // or ("", true) for cancel.
    ResponseCh chan<- PasswordPromptResponse
}

// PasswordPromptResponse carries the password prompt result.
type PasswordPromptResponse struct {
    Password  string
    Cancelled bool
}

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" — subagent

Hook System (Interceptors)

Hooks can modify or cancel operations. Events are read-only; hooks are read-write.

BeforeToolCall — block tool execution

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

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

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

host.OnAfterTurn(kit.HookPriorityNormal, func(h kit.AfterTurnHook) {
    // h.Response, h.Error
    log.Printf("Turn completed: %d chars", len(h.Response))
})

PrepareStep — intercept/replace messages before each LLM call

host.OnPrepareStep(kit.HookPriorityNormal, func(h kit.PrepareStepHook) *kit.PrepareStepResult {
    // h.StepNumber  — which step in the current turn (1-based)
    // h.Messages    — []kit.LLMMessage being sent to the LLM
    // Return nil to pass through unchanged, or replace messages:
    modified := filterSensitiveMessages(h.Messages)
    return &kit.PrepareStepResult{Messages: modified}
})

PrepareStep fires before every LLM API call within a turn (including tool-call loop iterations). Unlike ContextPrepare (which operates on the full context window once per turn), PrepareStep runs per-step and sees the messages that include the latest tool results.

ContextPrepare — filter/inject context window

host.OnContextPrepare(kit.HookPriorityNormal, func(h kit.ContextPrepareHook) *kit.ContextPrepareResult {
    // h.Messages — []kit.LLMMessage (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

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

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

Creating custom tools

Use kit.NewTool to create custom tools. The JSON schema is auto-generated from the input struct — no external dependencies required:

type WeatherInput struct {
    City string `json:"city" description:"City name, e.g. 'San Francisco'"`
}

weatherTool := kit.NewTool("get_weather", "Get current weather for a city",
    func(ctx context.Context, input WeatherInput) (kit.ToolOutput, error) {
        // Your logic here (API calls, database lookups, etc.)
        return kit.TextResult("72°F, sunny in " + input.City), nil
    },
)

host, _ := kit.New(ctx, &kit.Options{
    ExtraTools: []kit.Tool{weatherTool},
})

Struct tags control the generated schema:

TagPurposeExample
json:"name"Parameter namejson:"city"
description:"..."Description shown to the LLMdescription:"City name"
enum:"a,b,c"Restrict valid valuesenum:"json,text,csv"
omitemptyMarks parameter as optionaljson:"limit,omitempty"

Return helpers:

FunctionDescription
kit.TextResult(content)Successful text result
kit.ErrorResult(content)Error result (LLM sees it as a tool error)
kit.ImageResult(content, data, mediaType)Image result with binary data (e.g. "image/png")
kit.MediaResult(content, data, mediaType)Non-image media result (e.g. "audio/mpeg")

ToolOutput fields (for advanced use):

kit.ToolOutput{
    Content:   "result text",     // text returned to the LLM
    IsError:   false,             // true = LLM sees this as an error
    Data:      pngBytes,          // optional binary data (images, audio)
    MediaType: "image/png",       // MIME type for binary Data
    Metadata:  map[string]any{},  // opaque metadata for hooks/UI (not sent to LLM)
}

Parallel tools — mark as safe for concurrent execution:

searchTool := kit.NewParallelTool("search", "Search the web",
    func(ctx context.Context, input SearchInput) (kit.ToolOutput, error) {
        return kit.TextResult("results..."), nil
    },
)

Tool call ID — available in context for logging/tracing:

tool := kit.NewTool("my_tool", "...",
    func(ctx context.Context, input MyInput) (kit.ToolOutput, error) {
        callID := kit.ToolCallIDFromContext(ctx) // correlation ID from the LLM
        log.Printf("[%s] my_tool called", callID)
        return kit.TextResult("ok"), nil
    },
)

Built-in tool constructors

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

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 subagent (prevents recursion)

Tool options

kit.WithWorkDir("/path/to/dir") // override working directory for file-based tools

Using tools in Options

// 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

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
ready := host.MCPToolsReady()      // true when async MCP tool loading is complete

Session Management

Sessions automatically persist as JSONL tree files. No explicit save needed.

Session modes (via Options)

ModeOptionsBehavior
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

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)

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

Custom Session Manager (Advanced)

You can provide a custom session manager to store conversation history in your own backend (database, cloud storage, etc.) instead of the default JSONL files.

// Implement the SessionManager interface
type MyDatabaseSessionManager struct {
    db *sql.DB
    // ... other fields
}

func (s *MyDatabaseSessionManager) AppendMessage(msg kit.LLMMessage) (string, error) {
    // Store message in your database
}

func (s *MyDatabaseSessionManager) GetMessages() []kit.LLMMessage {
    // Retrieve messages from your database
}

// ... implement all other SessionManager methods

// Use with Kit
host, _ := kit.New(ctx, &kit.Options{
    SessionManager: myCustomSession,  // Your custom implementation
    Model: "anthropic/claude-sonnet-latest",
})

SessionManager Interface:

type SessionManager interface {
    AppendMessage(msg kit.LLMMessage) (entryID string, err error)
    GetMessages() []kit.LLMMessage
    BuildContext() (messages []kit.LLMMessage, provider string, modelID string)
    Branch(entryID string) error
    GetCurrentBranch() []kit.BranchEntry
    GetChildren(parentID string) []string
    GetEntry(entryID string) *kit.BranchEntry
    GetSessionID() string
    GetSessionName() string
    SetSessionName(name string) error
    GetCreatedAt() time.Time
    IsPersisted() bool
    AppendCompaction(summary string, firstKeptEntryID string,
        tokensBefore, tokensAfter int, messagesRemoved int, readFiles, modifiedFiles []string) (string, error)
    GetLastCompaction() *kit.CompactionEntry
    AppendExtensionData(extType, data string) (string, error)
    GetExtensionData(extType string) []kit.ExtensionDataEntry
    AppendModelChange(provider, modelID string) (string, error)
    GetContextEntryIDs() []string
    Close() error
}

Use Cases:

  • PocketBase integration: Store sessions as PocketBase records
  • Cloud storage: Persist sessions to S3, GCS, or Azure Blob
  • Multi-user apps: Store sessions per user in a database
  • Custom retention: Implement your own session cleanup policies

Note: When using a custom SessionManager, the following Options are ignored:

  • SessionPath - your manager handles its own storage
  • Continue - your manager handles session selection
  • NoSession - use an in-memory implementation instead

Model Management

At creation time

host, _ := kit.New(ctx, &kit.Options{
    Model: "openai/gpt-4o",
})

At runtime

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

models := host.GetAvailableModels()      // []extensions.ModelInfoEntry
providers := kit.GetSupportedProviders() // []string
providers := kit.GetLLMProviders()       // providers with LLM support
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".

provider, modelID, err := kit.ParseModelString("anthropic/claude-sonnet-4-5-20250929")

Per-model system prompts

Models can have per-model system prompts configured via modelSettings or customModels in .kit.yml. When the user hasn't explicitly set a system prompt (via --system-prompt, config, or Options.SystemPrompt), the per-model prompt is used as the base and composed with AGENTS.md context and skills.

On SetModel(), if the new model has a per-model system prompt and no custom global prompt was set, the per-model prompt automatically replaces the previous one.

Per-model generation parameters

Models can define default generation parameters (temperature, top_p, top_k, frequency_penalty, presence_penalty) via modelSettings or customModels params in .kit.yml. These defaults apply when the user hasn't explicitly set the parameter. Explicit CLI flags or config values always take priority.


Dynamic MCP Server Management

Add, remove, and inspect MCP servers at runtime without restarting Kit:

// Add a new MCP server — tools become available immediately
n, err := host.AddMCPServer(ctx, "github", kit.MCPServerConfig{
    Command:     []string{"npx", "-y", "@modelcontextprotocol/server-github"},
    Environment: map[string]string{"GITHUB_TOKEN": os.Getenv("GITHUB_TOKEN")},
})
fmt.Printf("Loaded %d tools from github server\n", n)

// Remove an MCP server — its tools are no longer available
err = host.RemoveMCPServer("github")

// List all currently loaded MCP servers
servers := host.ListMCPServers()
for _, s := range servers {
    fmt.Printf("Server %s: %d tools\n", s.Name, s.ToolCount)
}

AddMCPServer is safe to call while the agent is idle. If a turn is in progress, new tools are visible starting from the next LLM step. Tool names are prefixed with the server name (e.g. "github__create_issue").

In-Process MCP Servers

Register mcp-go servers that run in the same process — no subprocess spawning, no network I/O:

import (
    "github.com/mark3labs/mcp-go/mcp"
    "github.com/mark3labs/mcp-go/server"
)

mcpSrv := server.NewMCPServer("my-tools", "1.0.0",
    server.WithToolCapabilities(true),
)
mcpSrv.AddTool(mcp.NewTool("search_docs",
    mcp.WithDescription("Search documentation"),
    mcp.WithString("query", mcp.Required()),
), searchHandler)

// At init time
host, _ := kit.New(ctx, &kit.Options{
    InProcessMCPServers: map[string]*kit.MCPServer{
        "docs": mcpSrv,
    },
})

// Or at runtime
n, err := host.AddInProcessMCPServer(ctx, "docs", mcpSrv)

Kit does not own the server lifecycle — the caller handles cleanup. Tools are prefixed as usual (e.g. "docs__search_docs").

MCP Prompts

Query and expand prompts defined by connected MCP servers:

// List all prompts from all connected MCP servers
prompts := host.ListMCPPrompts()
for _, p := range prompts {
    fmt.Printf("%s/%s: %s\n", p.ServerName, p.Name, p.Description)
    for _, arg := range p.Arguments {
        fmt.Printf("  arg: %s (required: %v)\n", arg.Name, arg.Required)
    }
}

// Expand a specific prompt with arguments
result, err := host.GetMCPPrompt(ctx, "myserver", "code-review", map[string]string{
    "language": "go",
    "style":    "thorough",
})
// result.Description — optional server description
// result.Messages — []MCPPromptMessage with Role, Content, and FileParts
for _, msg := range result.Messages {
    fmt.Printf("[%s] %s\n", msg.Role, msg.Content)
    // msg.FileParts contains binary attachments (images, embedded resources)
}

MCP Resources

Read and subscribe to resources exposed by MCP servers:

// List all resources from connected servers
resources := host.ListMCPResources()
for _, r := range resources {
    fmt.Printf("%s: %s (%s)\n", r.URI, r.Name, r.MIMEType)
}

// Read a specific resource
content, err := host.ReadMCPResource(ctx, "myserver", "file:///path/to/file")
if content.IsBlob {
    // Binary content in content.BlobData
} else {
    // Text content in content.Text
}

// Subscribe to resource change notifications
err = host.SubscribeMCPResource(ctx, "myserver", "file:///path/to/file")
// Unsubscribe later
err = host.UnsubscribeMCPResource(ctx, "myserver", "file:///path/to/file")

MCP OAuth Authorization

When a remote MCP server requires OAuth, Kit runs the full authorization flow (dynamic client registration → PKCE → user consent → token exchange → token persistence) but delegates the user-facing step — displaying the authorization URL and receiving the callback — to an MCPAuthHandler.

The SDK ships three building blocks:

Building blockWhen to use
No handler (Options.MCPAuthHandler = nil)Default. OAuth is disabled; 401s from remote MCP servers surface as errors. Correct for library, daemon, and web-app embedders that don't want side effects.
kit.NewCLIMCPAuthHandler()CLI/TUI apps. Opens the system browser, prints status to stderr (or via NotifyFunc), runs a localhost callback server. This is what the kit binary uses.
kit.NewDefaultMCPAuthHandler() + OnAuthURLCustom UX. Get the transport mechanics (port reservation + callback server) from the SDK; wire your own presentation in the OnAuthURL(serverName, authURL) closure.
Implement kit.MCPAuthHandler directlyFull control. No localhost binding — e.g. return the URL from an HTTP endpoint and have the consumer POST the callback URL back.

CLI-style embedder (browser + stderr):

authHandler, err := kit.NewCLIMCPAuthHandler()
if err != nil {
    log.Fatal(err)
}
defer authHandler.Close() // release the reserved port

host, _ := kit.New(ctx, &kit.Options{
    MCPAuthHandler: authHandler,
})

Custom UX embedder (TUI modal, QR code, web redirect, etc.):

authHandler, _ := kit.NewDefaultMCPAuthHandler()
authHandler.OnAuthURL = func(serverName, authURL string) {
    // Render the URL however you like — no browser or terminal assumptions.
    myUI.ShowAuthPrompt(serverName, authURL)
}
defer authHandler.Close()

host, _ := kit.New(ctx, &kit.Options{
    MCPAuthHandler: authHandler,
})

Important: DefaultMCPAuthHandler with no OnAuthURL set will silently drop the authorization URL and block until the 2-minute callback timeout fires. Always set OnAuthURL, or use a higher-level wrapper like CLIMCPAuthHandler.

MCP OAuth Token Storage

Once authorization succeeds, the resulting access/refresh tokens are persisted by an MCPTokenStore. By default tokens are written to $XDG_CONFIG_HOME/.kit/mcp_tokens.json (fallback ~/.config/.kit/mcp_tokens.json), keyed by server URL, with 0600 file permissions.

Provide a custom store for encrypted storage, database persistence, or in-memory-only flows:

host, _ := kit.New(ctx, &kit.Options{
    MCPTokenStoreFactory: func(serverURL string) (kit.MCPTokenStore, error) {
        return &MyDatabaseTokenStore{serverURL: serverURL}, nil
    },
})

The MCPTokenStore interface requires GetToken/SetToken/DeleteToken methods. Return kit.ErrMCPNoToken from GetToken when no token is stored.


Context & Compaction

tokens := host.EstimateContextTokens()  // heuristic token count
shouldCompact := host.ShouldCompact()    // true if near context limit
// ShouldCompact() uses API-reported token counts (including cache tokens)
// when available, falling back to text-based heuristic before the first turn.

stats := host.GetContextStats()
// stats.EstimatedTokens — uses API-reported count when available (more accurate;
//                          includes system prompts, tool definitions, cache tokens)
// 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:

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 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.LLMUsage), result.Elapsed (time.Duration)

Subscribing to subagent events from parent

host.OnToolCall(func(e kit.ToolCallEvent) {
    if e.ToolName == "subagent" {
        host.SubscribeSubagent(e.ToolCallID, func(child kit.Event) {
            // Real-time events scoped to this subagent
        })
    }
})

Extension API

The Extensions() method returns an ExtensionAPI interface that groups all extension-related functionality. This is the primary way to interact with extension state from the SDK.

extAPI := host.Extensions()

// Check if extensions are loaded
if extAPI.HasExtensions() {
    // Context management
    extAPI.SetContext(extensions.Context{...})
    ctx := extAPI.GetContext()
    extAPI.UpdateContextModel("anthropic/claude-sonnet-4-5-20250929")

    // Widgets, headers, footers
    extAPI.SetWidget(extensions.WidgetConfig{...})
    extAPI.RemoveWidget("widget-id")
    extAPI.SetHeader(extensions.HeaderFooterConfig{...})
    extAPI.SetFooter(extensions.HeaderFooterConfig{...})

    // Status bar
    extAPI.SetStatus(extensions.StatusBarEntry{...})
    extAPI.RemoveStatus("key")

    // Options
    extAPI.SetOption("name", "value")
    val := extAPI.GetOption("name")

    // Tools
    tools := extAPI.GetToolInfos()
    extAPI.SetActiveTools([]string{"bash", "read"})

    // Events
    extAPI.EmitSessionStart()
    extAPI.EmitModelChange("new/model", "old/model", "extension")
    extAPI.EmitCustomEvent("my-event", "data")

    // Commands and lifecycle
    cmds := extAPI.Commands()
    err := extAPI.Reload()
}

All methods are no-ops when extensions are disabled (nil runner), so callers don't need nil checks.


Authentication

cm, _ := kit.NewCredentialManager()
hasKey := kit.HasAnthropicCredentials()
apiKey := kit.GetAnthropicAPIKey() // stored creds → ANTHROPIC_API_KEY env var

Skills

// 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:

// 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

// LLM types — clean aliases (no external library dependency in consumer code)
kit.LLMMessage      // {Role LLMMessageRole, Content string}
kit.LLMMessagePart  // interface for message content parts
kit.LLMMessageRole  // "user" | "assistant" | "system" | "tool"
kit.LLMUsage        // {InputTokens, OutputTokens, TotalTokens, ReasoningTokens,
                     //  CacheCreationTokens, CacheReadTokens}
kit.LLMResponse     // {Content, FinishReason, Usage}
kit.LLMFilePart     // {Filename, Data []byte, MediaType}
kit.LLMTextPart     // plain-text content part
kit.LLMReasoningPart // reasoning/chain-of-thought content part
kit.LLMToolCall     // {ID, Name, Input string} — execution-layer tool call (for Tool.Run)
kit.LLMToolResponse // {Type, Content, Data, MediaType, IsError, ...} — raw tool response
kit.LLMToolCallPart    // LLM-initiated tool invocation within a message
kit.LLMToolResultPart  // tool result within a message
kit.LLMToolResultOutputContent      // interface for tool result output
kit.LLMToolResultOutputContentText  // text tool result
kit.LLMToolResultOutputContentError // error tool result
kit.LLMToolResultOutputContentMedia // media tool result {Data, MediaType, Text}
kit.LLMToolResultContentType        // "text" | "error" | "media"
kit.LLMToolInfo          // {Name, Description, Parameters, Required, Parallel}
kit.LLMProviderOptions   // provider-specific option maps (keyed by provider name)
kit.LLMProviderMetadata  // provider-specific response metadata
kit.LLMPrompt            // []LLMMessage — ordered prompt sequence
kit.LLMFinishReason      // "stop" | "length" | "tool-calls" | ...

// Compaction types
kit.CompactionResult, kit.CompactionOptions

// MCP OAuth types
kit.MCPAuthHandler         // interface: RedirectURI() + HandleAuth(ctx, server, authURL) for OAuth UX
kit.DefaultMCPAuthHandler  // SDK-provided transport mechanics (port + callback server); set OnAuthURL hook
kit.CLIMCPAuthHandler      // CLI wrapper around DefaultMCPAuthHandler: opens browser, prints status
kit.NewDefaultMCPAuthHandler()         // random port, no UX side effects
kit.NewDefaultMCPAuthHandlerWithPort() // fixed port (useful when registering a stable redirect URI)
kit.NewCLIMCPAuthHandler()             // CLI handler: browser + stderr + localhost callback
kit.MCPTokenStore        // interface for custom OAuth token storage
kit.MCPToken             // OAuth token struct (access, refresh, expiry)
kit.MCPTokenStoreFactory // func(serverURL string) (MCPTokenStore, error)
kit.ErrMCPNoToken        // sentinel error for "no token stored"
kit.MCPServer            // *server.MCPServer for in-process MCP transport
kit.MCPServerStatus      // {Name string, ToolCount int}
kit.MCPPrompt            // {Name, Description, Arguments []MCPPromptArgument, ServerName}
kit.MCPPromptArgument    // {Name, Description string, Required bool}
kit.MCPPromptMessage     // {Role, Content string, FileParts []LLMFilePart}
kit.MCPPromptResult      // {Description string, Messages []MCPPromptMessage}
kit.MCPResource          // {URI, Name, Description, MIMEType, ServerName}
kit.MCPResourceContent   // {URI, MIMEType, Text string, BlobData []byte, IsBlob bool}

// Conversion helpers
msgs := kit.ConvertToLLMMessages(&msg)   // SDK Message  → []LLMMessage
msg  := kit.ConvertFromLLMMessage(lMsg)  // LLMMessage   → SDK Message

Common Patterns

Pattern: Scripting / CLI pipe

Minimal program for automation — stdout-only output:

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:

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

host.OnMessageUpdate(func(e kit.MessageUpdateEvent) {
    fmt.Print(e.Chunk)
})
response, _ := host.Prompt(ctx, "Write a poem")

Pattern: Multi-turn conversation with memory

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

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

// 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

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

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.

// 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

平台分布

Codex

35.7%
按下载量换算35

Claude

29.92%
按下载量换算30

Cursor

20.41%
按下载量换算20

Gemini CLI

8.38%
按下载量换算8

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills