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.