SDK Options

# SDK Options Pass an `Options` struct to `kit.New()` to configure the Kit instance. ::: tip For simple setups, `kit.NewAgent(ctx, ...Option)` provides functional-options helpers (`WithModel`, `WithStreaming`, `Ephemeral`, ...) over the same `Options` struct. See [Functional options](/sdk/overview#functional-options-newagent). ::: Each `kit.New` / `kit.NewAgent` call owns an isolated configuration store, so these options never leak between Kit instances in the same process. See [Per-instance config isolation](/sdk/overview#per-instance-config-isolation). ## Full options reference ```go host, err := kit.New(ctx, &kit.Options{ // Model Model: "ollama/llama3", SystemPrompt: "You are a helpful bot", ConfigFile: "/path/to/config.yml", // Behavior MaxSteps: 10, Streaming: ptrBool(true), // *bool: nil = unset (default true), &false = off Quiet: true, Debug: true, // Generation parameters (override env/config/per-model defaults) MaxTokens: 16384, // 0 = auto-resolve; non-zero suppresses right-sizing ThinkingLevel: "medium", // "off", "none", "minimal", "low", "medium", "high" Temperature: ptrFloat32(0.2), // pointer so explicit 0.0 != unset TopP: nil, // nil = provider/per-model default TopK: nil, FrequencyPenalty: nil, PresencePenalty: nil, // Provider configuration ProviderAPIKey: "sk-...", // "" = use config / provider env var ProviderURL: "https://proxy.internal/v1", // "" = provider default endpoint TLSSkipVerify: false, // only effective when true // Session SessionPath: "./session.jsonl", SessionDir: "/custom/sessions/", Continue: true, NoSession: true, // Tools Tools: []kit.Tool{...}, // Replace default tool set entirely ExtraTools: []kit.Tool{...}, // Add tools alongside defaults DisableCoreTools: true, // Use no core tools (0 tools, for chat-only) // Configuration SkipConfig: true, // Skip .kit.yml files (viper defaults + env vars still apply) // Compaction AutoCompact: true, // Skills Skills: []string{"/path/to/skill.md"}, SkillsDir: "/path/to/skills/", NoSkills: true, // Feature toggles NoExtensions: true, // disable Yaegi extension loading NoContextFiles: true, // disable automatic AGENTS.md loading // Session (advanced) SessionManager: myCustomSession, // custom SessionManager implementation // MCP OAuth — both opt-in. Leave MCPAuthHandler nil to disable // OAuth entirely (remote MCP 401s bubble up as errors). CLI apps // pass kit.NewCLIMCPAuthHandler(); custom UX embedders implement // MCPAuthHandler or configure DefaultMCPAuthHandler + OnAuthURL. MCPAuthHandler: authHandler, // nil = OAuth disabled MCPTokenStoreFactory: func(serverURL string) (kit.MCPTokenStore, error) { return myStore(serverURL), nil }, // In-Process MCP Servers InProcessMCPServers: map[string]*kit.MCPServer{ "docs": mcpSrv, // *server.MCPServer from mcp-go }, }) ``` ## Options fields ### Core | Field | Type | Default | Description | |-------|------|---------|-------------| | `Model` | `string` | config default | Model string (provider/model format) | | `SystemPrompt` | `string` | — | System prompt text or file path | | `ConfigFile` | `string` | `~/.kit.yml` | Path to config file | | `MaxSteps` | `int` | `0` | Max agent steps (0 = unlimited) | | `Streaming` | `*bool` | `nil` | Enable streaming output. `nil` leaves it to the precedence chain (env → config → default `true`); `&true`/`&false` forces it. Pointer so unset is distinct from explicit `false`. | | `Quiet` | `bool` | `false` | Suppress output | | `Debug` | `bool` | `false` | Enable debug logging | ### Generation parameters These fields override the corresponding values from `.kit.yml` / `KIT_*` environment variables. Leaving a field at its zero/nil value lets the precedence chain resolve a value (`KIT_*` env → config file → per-model defaults from `modelSettings`/`customModels` → an 8192 SDK floor for `MaxTokens` (matching the CLI `--max-tokens` default) and provider-level defaults for samplers). | Field | Type | Default | Description | |-------|------|---------|-------------| | `MaxTokens` | `int` | auto-resolved | Max output tokens per response. `0` = auto-resolve; non-zero suppresses automatic right-sizing (same semantics as `--max-tokens`). | | `ThinkingLevel` | `string` | auto-resolved | Reasoning effort: `"off"`, `"none"`, `"minimal"`, `"low"`, `"medium"`, `"high"`. `""` falls through to config/env/per-model/`"off"`. | | `Temperature` | `*float32` | — | Sampling randomness. Pointer type so explicit `0.0` is distinguishable from "unset". | | `TopP` | `*float32` | — | Nucleus sampling cutoff. `nil` leaves provider/per-model default. | | `TopK` | `*int32` | — | Top-K sampling limit. `nil` leaves provider/per-model default. | | `FrequencyPenalty` | `*float32` | — | OpenAI-family frequency penalty. `nil` leaves provider default. | | `PresencePenalty` | `*float32` | — | OpenAI-family presence penalty. `nil` leaves provider default. | Pointer-typed fields (`Streaming` and the samplers) are populated via tiny helpers: ```go func ptrBool(v bool) *bool { return &v } func ptrFloat32(v float32) *float32 { return &v } ``` These fields eliminate the need for `viper.Set()` calls before `kit.New()` when embedding Kit as a library. ### Provider configuration | Field | Type | Default | Description | |-------|------|---------|-------------| | `ProviderAPIKey` | `string` | — | API key used to authenticate with the provider. `""` falls back to config / provider-specific env var (e.g. `ANTHROPIC_API_KEY`). When set, it takes precedence over config and env values on this instance's store. | | `ProviderURL` | `string` | — | Override the provider endpoint (e.g. LiteLLM, vLLM, Azure OpenAI, internal proxy). `""` = provider default. | | `TLSSkipVerify` | `bool` | `false` | Disable TLS certificate verification on the provider HTTP client. Only effective when `true`; to force-disable, use config file or env var instead. For self-signed dev certs only. | ### Session | Field | Type | Default | Description | |-------|------|---------|-------------| | `SessionPath` | `string` | — | Open a specific session file | | `SessionDir` | `string` | — | Base directory for session discovery | | `Continue` | `bool` | `false` | Resume most recent session | | `NoSession` | `bool` | `false` | Ephemeral mode (no persistence) | | `SessionManager` | `SessionManager` | — | Custom session backend (advanced) | ### Tools & extensions | Field | Type | Default | Description | |-------|------|---------|-------------| | `Tools` | `[]Tool` | — | Replace the entire default tool set | | `ExtraTools` | `[]Tool` | — | Additional tools alongside core/MCP/extension tools | | `DisableCoreTools` | `bool` | `false` | Use no core tools (0 tools, for chat-only) | | `NoExtensions` | `bool` | `false` | Disable Yaegi extension loading | | `NoContextFiles` | `bool` | `false` | Disable automatic AGENTS.md loading | ### Skills & configuration | Field | Type | Default | Description | |-------|------|---------|-------------| | `SkipConfig` | `bool` | `false` | Skip `.kit.yml` file loading (viper defaults + env vars still apply) | | `Skills` | `[]string` | — | Explicit skill files/dirs to load | | `SkillsDir` | `string` | — | Override default skills directory | | `NoSkills` | `bool` | `false` | Disable skill loading entirely | These fields only control the **initial** skill and context-file set picked up by `New()`. To add, remove, or replace skills and `AGENTS.md`-style context files at runtime (e.g. per user or per session), use the `AddSkill` / `LoadAndAddSkill` / `RemoveSkill` / `SetSkills` and `AddContextFile` / `AddContextFileContent` / `RemoveContextFile` / `SetContextFiles` methods on `*kit.Kit`. See [Runtime skills and context files](/sdk/overview#runtime-skills-and-context-files). ### Compaction & MCP | Field | Type | Default | Description | |-------|------|---------|-------------| | `AutoCompact` | `bool` | `false` | Auto-compact when near context limit | | `CompactionOptions` | `*CompactionOptions` | — | Configuration for auto-compaction | | `MCPAuthHandler` | `MCPAuthHandler` | — | OAuth handler for remote MCP servers. `nil` disables OAuth (servers returning 401 fail with the authorization-required error). See [MCP OAuth](#mcp-oauth-authorization) below. | | `MCPTokenStoreFactory` | `func` | — | Custom OAuth token storage for MCP servers (default: JSON file in `$XDG_CONFIG_HOME/.kit/mcp_tokens.json`). | | `InProcessMCPServers` | `map[string]*MCPServer` | — | In-process mcp-go servers (no subprocess) | | `MCPTaskMode` | `map[string]MCPTaskMode` | — | Per-server override for task-augmented `tools/call`. Keys are server names; missing entries fall back to the `tasksMode` field of the matching `MCPServerConfig`. See [MCP Tasks](#mcp-tasks). | | `MCPTaskTimeout` | `time.Duration` | `15m` | Maximum wall-clock to wait for a task to reach a terminal state. Independent of any per-call context deadline. | | `MCPTaskTTL` | `time.Duration` | — | TTL hint sent in `TaskParams` for every task-augmented call. Zero omits the field and lets the server pick. | | `MCPTaskPollInterval` | `time.Duration` | `1s` | Fallback interval between `tasks/get` requests when the server does not suggest one. | | `MCPTaskMaxPollInterval` | `time.Duration` | `5s` | Cap on the polling interval (a server-supplied `pollInterval` can otherwise grow without bound). | | `MCPTaskProgress` | `MCPTaskProgressHandler` | — | Optional callback invoked once when a task is accepted and on every observed status transition. The final invocation always carries a terminal status. | ## MCP OAuth Authorization When a remote MCP server (SSE or Streamable HTTP) 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 is deliberately inert when `MCPAuthHandler` is `nil`: it does **not** auto-construct a default handler, bind a local TCP port, or open a browser. This keeps library, daemon, and web-app embedders free of surprise I/O. Consumers opt in by passing a handler explicitly. | Building block | When to use | |---|---| | `MCPAuthHandler = nil` (default) | OAuth disabled. Remote MCP servers requiring auth fail with a clear error. Correct for libraries, daemons, and web apps. | | `kit.NewCLIMCPAuthHandler()` | CLI/TUI apps. Opens the system browser, prints status to stderr (or via `NotifyFunc`), runs a localhost callback server. Used by the `kit` binary. | | `kit.NewDefaultMCPAuthHandler()` + `OnAuthURL` | Custom UX. Use the SDK's port reservation and callback server; plug in your own presentation via the `OnAuthURL(serverName, authURL)` closure. | | Implement `kit.MCPAuthHandler` directly | Full 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:** ```go 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.):** ```go authHandler, _ := kit.NewDefaultMCPAuthHandler() authHandler.OnAuthURL = func(serverName, authURL string) { // No browser or terminal assumptions — render however you like. myUI.ShowAuthPrompt(serverName, authURL) } defer authHandler.Close() host, _ := kit.New(ctx, &kit.Options{ MCPAuthHandler: authHandler, }) ``` **Fully custom handler (no local port binding at all):** ```go type WebAuthHandler struct { redirectURI string callbacks chan string } func (h *WebAuthHandler) RedirectURI() string { return h.redirectURI } func (h *WebAuthHandler) HandleAuth(ctx context.Context, serverName, authURL string) (string, error) { // Push the URL to the user's existing browser session via your web app, // then block on the callback that your HTTP handler pushes onto the channel. h.pushToUserSession(serverName, authURL) select { case callbackURL := <-h.callbacks: return callbackURL, nil case <-ctx.Done(): return "", ctx.Err() } } ``` ::: warning `DefaultMCPAuthHandler` with no `OnAuthURL` set will silently drop the authorization URL and hang until the 2-minute callback timeout fires. Always set `OnAuthURL`, or use a higher-level wrapper like `CLIMCPAuthHandler`. ::: ## MCP Tasks The [MCP Tasks utility](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks) turns a synchronous `tools/call` into a pollable async job: the server returns a `taskId` with status `working` immediately, and the client polls `tasks/get` / `tasks/result` until the task reaches a terminal state. Kit advertises task support during `initialize` and, by default, augments `tools/call` with task metadata only when the server advertises `tasks/toolCalls` capability — so any existing MCP server keeps its previous synchronous behaviour bit-for-bit. Long-running tools (builds, deployments, batch jobs, sub-agent runs) get HTTP/SSE timeout-resistance and clean cancellation "for free" once both sides opt in. ### Per-server mode ```go import "time" host, _ := kit.New(ctx, &kit.Options{ MCPTaskMode: map[string]kit.MCPTaskMode{ "build-server": kit.MCPTaskModeAlways, // force task-augmented calls "chat-server": kit.MCPTaskModeNever, // force synchronous calls // any server not in the map honours its `tasksMode` config field // (default "auto") }, }) ``` | Mode | Behaviour | |---|---| | `MCPTaskModeAuto` (default) | Augment `tools/call` with `TaskParams` only when the server advertised `tasks/toolCalls`. | | `MCPTaskModeNever` | Always issue `tools/call` synchronously, ignoring server capability. | | `MCPTaskModeAlways` | Always opt in, even when the server didn't advertise the capability. The server may still respond synchronously. | ### Progress callbacks ```go host, _ := kit.New(ctx, &kit.Options{ MCPTaskTimeout: 15 * time.Minute, // total wall-clock cap MCPTaskTTL: 30 * time.Minute, // server retention hint MCPTaskProgress: func(p kit.MCPTaskProgress) { log.Printf("%s/%s: %s %s", p.Server, p.TaskID, p.Status, p.Message) }, }) ``` The handler fires once when a task is accepted and again on every observed status transition. The final call always carries a terminal status (`MCPTaskStatusCompleted`, `MCPTaskStatusFailed`, or `MCPTaskStatusCancelled`). Do not block in the handler — dispatch long work on a goroutine. ### Inspecting and cancelling tasks ```go tasks, _ := host.ListMCPTasks(ctx, "build-server") for _, t := range tasks { fmt.Printf("%s: %s (%s)\n", t.TaskID, t.Status, t.StatusMessage) } t, _ := host.GetMCPTask(ctx, "build-server", taskID) if !t.Status.IsTerminal() { _, _ = host.CancelMCPTask(ctx, "build-server", taskID) } ``` `Kit.ListMCPTasks`, `Kit.GetMCPTask`, and `Kit.CancelMCPTask` work against any loaded MCP server that advertises the corresponding capability. `MCPTaskStatus.IsTerminal()` is the canonical check for completion. Context cancellation also works end-to-end: cancelling the `ctx` passed to a tool execution triggers a best-effort `tasks/cancel` before the call returns. ## Precedence For any given generation or provider field, the effective value is resolved in this order (highest priority first): 1. `Options.X` (SDK caller) 2. `KIT_X` environment variable 3. `.kit.yml` (project-local then `~/.kit.yml`) 4. Per-model defaults (`modelSettings[provider/model]` or `customModels[...].params`) 5. Provider-level defaults (e.g. Anthropic's own temperature default) 6. SDK last-resort floor (currently: `MaxTokens = 8192`, matching the CLI `--max-tokens` default) Sampling params that remain `nil` after the SDK resolution step are left out of the provider call entirely, so the LLM library applies its own default. ## Tool configuration **`Tools`** replaces ALL default tools (core + MCP + extension). **`ExtraTools`** adds tools alongside the defaults. Use `Tools` to restrict capabilities; use `ExtraTools` to extend them. Create custom tools with `kit.NewTool` — no external dependencies needed: ```go type LookupInput struct { ID string `json:"id" description:"Record ID to look up"` } lookupTool := kit.NewTool("lookup", "Look up a record by ID", func(ctx context.Context, input LookupInput) (kit.ToolOutput, error) { record := db.Find(input.ID) return kit.TextResult(record.String()), nil }, ) host, _ := kit.New(ctx, &kit.Options{ ExtraTools: []kit.Tool{lookupTool}, }) ``` See [Overview](/sdk/overview#custom-tools) for full custom tool documentation.