From 5770a06724d5c0e1626bb8c18ee2f34375578542 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 17 Jun 2026 11:22:47 +0200 Subject: [PATCH 1/6] feat(sdk): Add a Lookup map core tool names to init functions & list name function The map can be used to easily map core tool names onto their respective init functions. The list function ListAllCoreToolNames() list all available core tools. It is available at any time and can be used to validate a user or extrenally supplied tool list. It differs from kit.GetToolNames() in that the latter only list tools registered with the agent. Signed-off-by: Egbert Eich --- internal/core/tools.go | 21 +++++++++++++++++++++ pkg/kit/tools.go | 1 + 2 files changed, 22 insertions(+) diff --git a/internal/core/tools.go b/internal/core/tools.go index b4712921..706836b4 100644 --- a/internal/core/tools.go +++ b/internal/core/tools.go @@ -8,6 +8,8 @@ import ( "context" "encoding/json" "fmt" + "maps" + "slices" "charm.land/fantasy" ) @@ -64,6 +66,25 @@ func parseArgs(input string, target any) error { return nil } +type initTool func(...ToolOption) fantasy.AgentTool + +var coreTools = map[string]initTool{ + "bash": NewBashTool, + "read": NewReadTool, + "write": NewWriteTool, + "edit": NewEditTool, + "grep": NewGrepTool, + "find": NewFindTool, + "ls": NewLsTool, + "subagent": NewSubagentTool, +} + +// ListAllCoreToolNames always returns the full list of available core +// tools. It can be used to validate a user provided tool list. +func ListAllCoreToolNames() []string { + return slices.Collect(maps.Keys(coreTools)) +} + // CodingTools returns the default set of core tools for a coding agent: // bash, read, write, edit. func CodingTools(opts ...ToolOption) []fantasy.AgentTool { diff --git a/pkg/kit/tools.go b/pkg/kit/tools.go index 3d3a1f23..d498265c 100644 --- a/pkg/kit/tools.go +++ b/pkg/kit/tools.go @@ -344,6 +344,7 @@ func NewFindTool(opts ...ToolOption) Tool { return core.NewFindTool(opts...) } func NewLsTool(opts ...ToolOption) Tool { return core.NewLsTool(opts...) } // --- Tool bundles --- +func ListAllCoreToolNames() []string { return core.ListAllCoreToolNames() } // AllTools returns all available core tools. func AllTools(opts ...ToolOption) []Tool { return core.AllTools(opts...) } From 75252618198398cd17c4c9797ba166a9ca989467 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 17 Jun 2026 20:53:43 +0200 Subject: [PATCH 2/6] feat(sdk): Add `CoreToolList` to `kit.Options` and `agent.AgentConfig` This allows a higher level to pass a list of tool names to kit. The argument is passed to `kit.New()` is validated there, all valid tool names are then passed down to `agent.NewAgent()`. To maintain backward compatibility, if the list passed to `kit.New()` is empty, all available tools will be enabled. To disable all core tools, use `DisableCoreTools`. Signed-off-by: Egbert Eich --- internal/agent/agent.go | 14 ++++---- internal/agent/factory.go | 8 ++--- internal/config/config.go | 7 ++++ internal/core/tools.go | 8 +++++ internal/kitsetup/setup.go | 10 +++--- pkg/kit/kit.go | 18 +++++++++-- pkg/kit/tools.go | 66 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 112 insertions(+), 19 deletions(-) diff --git a/internal/agent/agent.go b/internal/agent/agent.go index eef5fe41..099e2b73 100644 --- a/internal/agent/agent.go +++ b/internal/agent/agent.go @@ -42,10 +42,10 @@ type AgentConfig struct { // CodingTools or tools with a custom WorkDir). CoreTools []fantasy.AgentTool - // DisableCoreTools, when true, prevents loading any core tools. - // If both DisableCoreTools is true and CoreTools is empty, the agent + // CoreToolList lists core tool names to add. Overridden by CoreTools. + // If both CoreToolList is true and CoreTools is empty, the agent // will have no tools (useful for simple chat completions). - DisableCoreTools bool + CoreToolList []string // ToolWrapper is an optional function that wraps the combined tool list // before it is passed to the LLM agent. Used by the extensions system @@ -287,10 +287,10 @@ func NewAgent(ctx context.Context, agentConfig *AgentConfig) (*Agent, error) { } // Register core tools (direct AgentTool implementations, no MCP overhead). - // Use caller-provided tools if set, otherwise default to all core tools. - // DisableCoreTools allows explicitly having zero tools (for chat-only mode). + // Use caller-provided tools if set, otherwise default to core tools + // listed in CoreToolList. var coreTools []fantasy.AgentTool - if agentConfig.DisableCoreTools && len(agentConfig.CoreTools) == 0 { + if len(agentConfig.CoreToolList) == 0 && len(agentConfig.CoreTools) == 0 { // Explicitly zero tools - chat-only mode coreTools = nil } else if len(agentConfig.CoreTools) > 0 { @@ -298,7 +298,7 @@ func NewAgent(ctx context.Context, agentConfig *AgentConfig) (*Agent, error) { coreTools = agentConfig.CoreTools } else { // Default: load all core tools - coreTools = core.AllTools() + coreTools = core.ListedTools(agentConfig.CoreToolList) } // Build the initial tool list: core tools + extension tools (no MCP yet). diff --git a/internal/agent/factory.go b/internal/agent/factory.go index cb3d692f..7887db00 100644 --- a/internal/agent/factory.go +++ b/internal/agent/factory.go @@ -45,10 +45,10 @@ type AgentCreationOptions struct { // CoreTools overrides the default core tool set. If empty, core.AllTools() // is used. CoreTools []fantasy.AgentTool - // DisableCoreTools, when true, prevents loading any core tools. - // If both DisableCoreTools is true and CoreTools is empty, the agent + // CoreToolList lists core tool names to add. Overridden by CoreTools. + // If both CoreToolList is true and CoreTools is empty, the agent // will have no tools (useful for simple chat completions). - DisableCoreTools bool + CoreToolList []string // ToolWrapper wraps the combined tool list before agent creation. ToolWrapper func([]fantasy.AgentTool) []fantasy.AgentTool // ExtraTools are additional tools to include (e.g. from extensions). @@ -74,7 +74,7 @@ func CreateAgent(ctx context.Context, opts *AgentCreationOptions) (*Agent, error AuthHandler: opts.AuthHandler, TokenStoreFactory: opts.TokenStoreFactory, CoreTools: opts.CoreTools, - DisableCoreTools: opts.DisableCoreTools, + CoreToolList: opts.CoreToolList, ToolWrapper: opts.ToolWrapper, ExtraTools: opts.ExtraTools, OnMCPServerLoaded: opts.OnMCPServerLoaded, diff --git a/internal/config/config.go b/internal/config/config.go index 511d74f7..343bf209 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -516,6 +516,13 @@ mcpServers: # tags: [example] # Kit extension # when: on-demand # Kit extension +# Internal Core tools +# no-core-tools: false # true: disable all core tools +# include-core-tools: # list of core tool names to include +# exclude-core-tools: # list of core tool name to exclude + # include-/exclude-core-tools are mutually exclusive + # no-core-tools has precedence + # API Configuration (can also use environment variables) # provider-api-key: "your-api-key" # API key for OpenAI, Anthropic, or Google # provider-url: "https://api.openai.com/v1" # Base URL for OpenAI, Anthropic, or Ollama diff --git a/internal/core/tools.go b/internal/core/tools.go index 706836b4..662184f7 100644 --- a/internal/core/tools.go +++ b/internal/core/tools.go @@ -121,6 +121,14 @@ func SubagentTools(opts ...ToolOption) []fantasy.AgentTool { } } +func ListedTools(toolList []string, opts ...ToolOption) []fantasy.AgentTool { + var result = []fantasy.AgentTool{} + for _, t := range toolList { + result = append(result, coreTools[t](opts...)) + } + return result +} + // AllTools returns all available core tools. func AllTools(opts ...ToolOption) []fantasy.AgentTool { return append(SubagentTools(opts...), NewSubagentTool(opts...)) diff --git a/internal/kitsetup/setup.go b/internal/kitsetup/setup.go index 52a576ab..3c327047 100644 --- a/internal/kitsetup/setup.go +++ b/internal/kitsetup/setup.go @@ -30,13 +30,13 @@ type AgentSetupOptions struct { UseBufferedLogger bool // Quiet suppresses output. Replaces the cmd package's quietFlag variable. Quiet bool - // CoreTools overrides the default core tool set. If empty, core.AllTools() + // CoreTools overrides the default core tool set. If empty, CoreToolList // is used. Allows SDK users to pass custom tools (e.g. with WithWorkDir). CoreTools []fantasy.AgentTool - // DisableCoreTools, when true, prevents loading any core tools. - // If both DisableCoreTools is true and CoreTools is empty, the agent + // CoreToolList lists core tool names to add. Overridden by CoreTools. + // If both CoreToolList is true and CoreTools is empty, the agent // will have no tools (useful for simple chat completions). - DisableCoreTools bool + CoreToolList []string // ExtraTools are additional tools added alongside core, MCP, and extension // tools. They do not replace the defaults — they extend them. ExtraTools []fantasy.AgentTool @@ -255,7 +255,7 @@ func SetupAgent(ctx context.Context, opts AgentSetupOptions) (*AgentSetupResult, AuthHandler: opts.AuthHandler, TokenStoreFactory: opts.TokenStoreFactory, CoreTools: opts.CoreTools, - DisableCoreTools: opts.DisableCoreTools, + CoreToolList: opts.CoreToolList, ToolWrapper: toolWrapper, ExtraTools: extraTools, OnMCPServerLoaded: opts.OnMCPServerLoaded, diff --git a/pkg/kit/kit.go b/pkg/kit/kit.go index 6f61d643..d8abbf98 100644 --- a/pkg/kit/kit.go +++ b/pkg/kit/kit.go @@ -996,6 +996,10 @@ type Options struct { // are still applied. Use this for fully programmatic configuration. SkipConfig bool + // List of tools to include, when empty, include all available core + // tools. + CoreToolList []string + // DisableCoreTools, when true, prevents loading any core tools. // Use with Tools or ExtraTools to provide only custom tools. // If both DisableCoreTools is true and Tools is empty, the agent @@ -1266,7 +1270,7 @@ func New(ctx context.Context, opts *Options) (*Kit, error) { mcpConfig *config.Config debug bool noExtensions bool - disableCoreTools bool + toolList []string maxSteps int streaming bool hasCustomSystemPrompt bool @@ -1497,7 +1501,15 @@ func New(ctx context.Context, opts *Options) (*Kit, error) { modelString = v.GetString("model") debug = v.GetBool("debug") noExtensions = opts.NoExtensions || v.GetBool("no-extensions") - disableCoreTools = opts.DisableCoreTools || v.GetBool("no-core-tools") + toolList = opts.CoreToolList + if toolList == nil { + var err error + toolList, err = CoreToolFilterHelper(v) + if err != nil { + return err + } + } + toolList = handleCoreToolList(toolList, opts.DisableCoreTools || v.GetBool("no-core-tools")) maxSteps = v.GetInt("max-steps") streaming = v.GetBool("stream") @@ -1580,7 +1592,7 @@ func New(ctx context.Context, opts *Options) (*Kit, error) { MCPConfig: mcpConfig, Quiet: opts.Quiet, CoreTools: opts.Tools, - DisableCoreTools: disableCoreTools, + CoreToolList: toolList, ExtraTools: extraTools, ToolWrapper: hookToolWrapper(beforeToolCall, afterToolResult), ProviderConfig: providerConfig, diff --git a/pkg/kit/tools.go b/pkg/kit/tools.go index d498265c..b4229881 100644 --- a/pkg/kit/tools.go +++ b/pkg/kit/tools.go @@ -5,12 +5,15 @@ import ( "context" "encoding/json" "fmt" + "log" + "slices" "strings" "sync" "charm.land/fantasy" "github.com/mark3labs/kit/internal/core" + "github.com/spf13/viper" ) // Tool is the interface that all Kit tools implement. @@ -23,6 +26,32 @@ type ToolOption = core.ToolOption // If empty, os.Getwd() is used at execution time. var WithWorkDir = core.WithWorkDir +// --- Core Tool Validation --- +// processes a list of tool names, if disableCoreTools is true, return an +// empty list. Otherwise if coreTools is not empty, it will return a list of +// all valid names ie those found in ListAllCoreToolNames(), +// otherwise, it will return all of ListAllCoreToolNames(). +func handleCoreToolList(coreTools []string, disableCoreTools bool) []string { + var result []string + if disableCoreTools { + return result + } + allTools := ListAllCoreToolNames() + if len(coreTools) > 0 { + for _, tool := range allTools { + for _, t := range coreTools { + if t == tool { + result = append(result, t) + continue + } + } + } + return result + } else { + return allTools + } +} + // --- Custom tool creation --- // ToolOutput is the return value from custom tool handlers created with @@ -361,3 +390,40 @@ func ReadOnlyTools(opts ...ToolOption) []Tool { return core.ReadOnlyTools(opts.. // creating child Kit instances (in-process subagents) to prevent infinite // recursion. func SubagentTools(opts ...ToolOption) []Tool { return core.SubagentTools(opts...) } + +// --- Tool helper --- +func CoreToolFilterHelper(v *viper.Viper) ([]string, error) { + // Core tool filtering + includeTools := v.GetStringSlice("include-core-tools") + excludeTools := v.GetStringSlice("exclude-core-tools") + if len(includeTools) > 0 && len(excludeTools) > 0 { + return nil, fmt.Errorf("cannot use both include-core-tools and exclude-core-tools options") + } + + var coreToolList []string + if len(includeTools) > 0 || len(excludeTools) > 0 { + allCoreTools := ListAllCoreToolNames() + if len(includeTools) > 0 { + for _, t := range includeTools { + if !slices.Contains(allCoreTools, t) { + log.Printf("Warning: invalid core tool: %s", t) + continue + } + } + coreToolList = includeTools + } else { + for _, t := range excludeTools { + if !slices.Contains(allCoreTools, t) { + log.Printf("Warning: invalid core tool: %s", t) + continue + } + } + for _, t := range allCoreTools { + if !slices.Contains(excludeTools, t) { + coreToolList = append(coreToolList, t) + } + } + } + } + return coreToolList, nil +} From da5b03f3855ed75f3d2ab69998fbafd800ffa7e0 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Fri, 19 Jun 2026 11:57:11 +0200 Subject: [PATCH 3/6] test(sdk): Add test functions TestToolList & TestDisableCoreTools `TestCoreToolList()` tests: - adding an empty `Options.CoreToolList` in which case all core tools should be available. - adding two valid tool names and an invalid one in which case the valid ones are registered while the invalid one has been dropped. `TestDisableCoreTools()` tests: - adding an empty `Options.CoreToolList`, - adding a subset of vaild tool names. In both cases, no tools should be registered. `TestCoreToolListOption()` tests: - whether `exclude-core-tools` and `include-core-tools` are mutually exclusive, - whether the option `include-core-tools` works, - whether the option `exclude-core-tools` works. Signed-off-by: Egbert Eich --- pkg/kit/kit_test.go | 190 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/pkg/kit/kit_test.go b/pkg/kit/kit_test.go index 81256549..3ce8728b 100644 --- a/pkg/kit/kit_test.go +++ b/pkg/kit/kit_test.go @@ -3,6 +3,7 @@ package kit_test import ( "context" "os" + "slices" "strings" "testing" @@ -472,3 +473,192 @@ func TestNewSystemPromptInline(t *testing.T) { t.Errorf("composed system-prompt missing inline content; got %q", composed) } } + +// TestDisableCoreTools verifies that setting Options.DisableCoreTools to true +// does not set any tools even when tools are explicitly listed in the kit.Options.ToolList. +func TestDisableCoreTools(t *testing.T) { + if os.Getenv("ANTHROPIC_API_KEY") == "" { + t.Skip("Skipping test: ANTHROPIC_API_KEY not set") + } + + ctx := context.Background() + t.Run("DisableCoreTools true with empty CoreToolList", func(t *testing.T) { + defer resetViper() + host, err := kit.New(ctx, &kit.Options{ + Model: "anthropic/claude-sonnet-4-5-20250929", + Quiet: true, + NoSession: true, + NoExtensions: true, + DisableCoreTools: true, + }) + if err != nil { + t.Fatalf("Failed to create Kit with DisableCoreTools: %v", err) + } + defer func() { _ = host.Close() }() + + tools := host.GetToolNames() + if len(tools) != 0 { + t.Errorf("Expected 0 tool when DisableCoreTools is true, got %d: %v", len(tools), tools) + } + }) + t.Run("DisableCoreTools true with populated CoreToolList", func(t *testing.T) { + defer resetViper() + host, err := kit.New(ctx, &kit.Options{ + Model: "anthropic/claude-sonnet-4-5-20250929", + Quiet: true, + NoSession: true, + NoExtensions: true, + DisableCoreTools: true, + CoreToolList: []string{"subagent", "bash"}, + }) + if err != nil { + t.Fatalf("Failed to create Kit with DisableCoreTools and Tool list: %v", err) + } + defer func() { _ = host.Close() }() + + tools := host.GetToolNames() + if len(tools) != 0 { + t.Errorf("Expected 0 tool when DisableCoreTools is true, got %d: %v", len(tools), tools) + } + }) +} + +func TestCoreToolList(t *testing.T) { + if os.Getenv("ANTHROPIC_API_KEY") == "" { + t.Skip("Skipping test: ANTHROPIC_API_KEY not set") + } + + ctx := context.Background() + t.Run("Test wether empty CoreToolList adds all tools", func(t *testing.T) { + defer resetViper() + host, err := kit.New(ctx, &kit.Options{ + Quiet: true, + NoSession: true, + NoExtensions: true, + }) + if err != nil { + t.Fatalf("Failed to create Kit with DisableCoreTools: %v", err) + } + defer func() { _ = host.Close() }() + + tools := host.GetToolNames() + if len(tools) != len(kit.ListAllCoreToolNames()) { + t.Errorf("Expected %d tool when DisableCoreTools is true, got %d: %v", + len(kit.ListAllCoreToolNames()), len(tools), tools) + } + }) + t.Run("Test ToolList populated with two valid and one invalid tool name", func(t *testing.T) { + defer resetViper() + host, err := kit.New(ctx, &kit.Options{ + Quiet: true, + NoSession: true, + NoExtensions: true, + DisableCoreTools: true, + CoreToolList: []string{"subagent", "bash", "deadbeef"}, + }) + if err != nil { + t.Fatalf("Failed to create Kit with DisableCoreTools and Tool list: %v", err) + } + defer func() { _ = host.Close() }() + + tools := host.GetToolNames() + if len(tools) != 0 { + t.Errorf("Expected 2 tools with 2 valid and 1 invalid tool name, got %d: %v", len(tools), tools) + } + for _, s := range tools { + if s != "subagent" && s != "bash" { + t.Errorf("Expected tool to be 'bash' or 'subagent' but got %s", s) + } + } + }) +} + +func TestCoreToolListOption(t *testing.T) { + if os.Getenv("ANTHROPIC_API_KEY") == "" { + t.Skip("Skipping test: ANTHROPIC_API_KEY not set") + } + ctx := context.Background() + t.Run("Test whether exclude-core-tools and include-core-tools combined generates failure", func(t *testing.T) { + cfgFile := t.TempDir() + "/.kit.yml" + txt := []byte(`include-core-tools: + - "subagent" +exclude-core-tools: + - "bash"`) + if err := os.WriteFile(cfgFile, txt, 0o644); err != nil { + t.Fatalf("failed to write config: %v", err) + } + host, err := kit.New(ctx, &kit.Options{ + Model: "anthropic/claude-sonnet-4-5-20250929", + Quiet: true, + NoSession: true, + ConfigFile: cfgFile, + }) + if err != nil { + if err.Error() != "cannot use both include-core-tools and exclude-core-tools options" { + t.Errorf("kit.New: unexpected error %v", err) + } + } else { + defer func() { _ = host.Close() }() + t.Errorf("kit.New was expected to fail with both include-core-tools and exclude-core-tools specified") + } + }) + t.Run("Test whether include-core-tools works", func(t *testing.T) { + cfgFile := t.TempDir() + "/.kit.yml" + txt := []byte(`include-core-tools: + - "subagent" + - "deadbeef" + - "bash"`) + if err := os.WriteFile(cfgFile, txt, 0o644); err != nil { + t.Fatalf("failed to write config: %v", err) + } + host, err := kit.New(ctx, &kit.Options{ + Model: "anthropic/claude-sonnet-4-5-20250929", + Quiet: true, + NoSession: true, + ConfigFile: cfgFile, + }) + if err != nil { + t.Fatalf("kit.New failed: %v", err) + } + defer func() { _ = host.Close() }() + tools := host.GetToolNames() + for _, tool := range tools { + if tool != "bash" && tool != "subagent" { + t.Errorf("include-core-tools expected to have only 'bash' and 'subagent' tools but have %s", tool) + } + } + }) + t.Run("Test whether exclude-core-tools works", func(t *testing.T) { + cfgFile := t.TempDir() + "/.kit.yml" + txt := []byte(`exclude-core-tools: + - "subagent" + - "deadbeef" + - "bash"`) + if err := os.WriteFile(cfgFile, txt, 0o644); err != nil { + t.Fatalf("failed to write config: %v", err) + } + host, err := kit.New(ctx, &kit.Options{ + Model: "anthropic/claude-sonnet-4-5-20250929", + Quiet: true, + NoSession: true, + ConfigFile: cfgFile, + }) + if err != nil { + t.Fatalf("kit.New failed: %v", err) + } + defer func() { _ = host.Close() }() + var registeredTools []string + for _, tool := range kit.ListAllCoreToolNames() { + if tool != "bash" && tool != "subagent" { + registeredTools = append(registeredTools, tool) + } + } + tools := host.GetToolNames() + for _, tool := range tools { + if slices.Contains(registeredTools, tool) { + continue + } + t.Errorf("exclude-core-tools added unexpected %s tool", tool) + } + }) +} From 8332c76a6a1357d30c82048f2ea4f30530efba73 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Sat, 20 Jun 2026 06:51:37 +0200 Subject: [PATCH 4/6] doc(sdk): document kit.Options element CoreToolList `CoreToolList` allows to specify a list of core tool names to include. If this list is empty, include all available tools (default). `DisableCoreTools` if set to `true` has precedence. Signed-off-by: Egbert Eich --- README.md | 5 +++++ pkg/kit/README.md | 2 ++ skills/kit-sdk/SKILL.md | 1 + www/pages/sdk/options.md | 1 + 4 files changed, 9 insertions(+) diff --git a/README.md b/README.md index 61fa3df0..489f2b6e 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,9 @@ temperature: 0.7 stream: true thinking-level: off # off, none, minimal, low, medium, high no-core-tools: false # set to true to disable all built-in core tools +exclude-core-tools: # List of core tools to exclude, mutually exclusive to `include-core-tools` +#include-core-tools: +# - "bash" # List of core tools to exclude, mutually exclusive to `exclude-core-tools` # Skills — all keys are optional no-skills: false # set to true to disable all skill loading @@ -657,6 +660,8 @@ host, err := kit.New(ctx, &kit.Options{ DisableCoreTools: true, // Disable all built-in core tools; also controllable via // --no-core-tools flag, KIT_NO_CORE_TOOLS env var, // or no-core-tools: true in .kit.yml + CoreToolList []string, // List of core tool names to register. If empty (default), include all. + // DisableCoreTools has precedence. // Configuration SkipConfig: true, // Skip .kit.yml files (viper defaults + env vars still apply) diff --git a/pkg/kit/README.md b/pkg/kit/README.md index ecc2e9fe..9387f5c5 100644 --- a/pkg/kit/README.md +++ b/pkg/kit/README.md @@ -102,6 +102,7 @@ host, err := kit.New(ctx, &kit.Options{ Tools: []kit.Tool{kit.NewBashTool()}, // Replace default tool set ExtraTools: []kit.Tool{myTool}, // Add alongside defaults DisableCoreTools: true, // Use no core tools (0 tools) + CoreToolList []string, // List of core tools to include, if empty (default) use all. // Configuration SkipConfig: true, // Skip .kit.yml files (viper defaults + env vars still apply) @@ -420,6 +421,7 @@ Key `Options` fields for SDK usage: | `Tools` | Replace core tools with custom set | | `ExtraTools` | Add tools alongside defaults | | `DisableCoreTools` | Use no core tools (0 tools, for chat-only) | +| `CoreToolList` | List of core tools to include, if empty (default) use all. | | `NoSession` | Ephemeral mode (no session persistence) | | `SessionPath` | Open specific session file | | `Continue` | Resume most recent session | diff --git a/skills/kit-sdk/SKILL.md b/skills/kit-sdk/SKILL.md index e578fbcd..ece7f291 100644 --- a/skills/kit-sdk/SKILL.md +++ b/skills/kit-sdk/SKILL.md @@ -108,6 +108,7 @@ host, err := kit.New(ctx, &kit.Options{ 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) + CoreToolList []string, // List of core tools to include, if empty (default) include all // Configuration SkipConfig: true, // Skip .kit.yml files (viper defaults + env vars still apply) diff --git a/www/pages/sdk/options.md b/www/pages/sdk/options.md index d36e6e67..7f6e206d 100644 --- a/www/pages/sdk/options.md +++ b/www/pages/sdk/options.md @@ -57,6 +57,7 @@ host, err := kit.New(ctx, &kit.Options{ 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) + CoreToolList: []string, // List of core tools to include, if empty (default) include all // Configuration SkipConfig: true, // Skip .kit.yml files (viper defaults + env vars still apply) From ff9a97002171bf8c1de94354424c0b04f293e81f Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Fri, 19 Jun 2026 07:22:49 +0200 Subject: [PATCH 5/6] feat(kit): Add option for mutually exclusive include/exclude-core-tools lists These options allow to add a list of core (`enable-core-tools`) or core tools to exclude (`disable-core-tools`). If neither list is set, default to enable all core tools. Signed-off-by: Egbert Eich --- cmd/root.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index f1aa5daf..e57275cf 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -69,9 +69,11 @@ var ( mainGPU int32 // Extensions control - noExtensionsFlag bool - noCoreToolsFlag bool - extensionPaths []string + noExtensionsFlag bool + noCoreToolsFlag bool + includeCoreToolsFlag []string + excludeCoreToolsFlag []string + extensionPaths []string // Skills control noSkillsFlag bool @@ -286,6 +288,10 @@ func init() { BoolVar(&noExtensionsFlag, "no-extensions", false, "disable all extensions") rootCmd.PersistentFlags(). BoolVar(&noCoreToolsFlag, "no-core-tools", false, "disable all built-in core tools (bash, read, write, edit, grep, find, ls, subagent)") + rootCmd.PersistentFlags(). + StringSliceVar(&includeCoreToolsFlag, "include-core-tools", nil, "comma-separated list of core tools to include") + rootCmd.PersistentFlags(). + StringSliceVar(&excludeCoreToolsFlag, "exclude-core-tools", nil, "comma-separated list of core tools to exclude") rootCmd.PersistentFlags(). StringSliceVarP(&extensionPaths, "extension", "e", nil, "load additional extension file(s)") @@ -346,6 +352,8 @@ func init() { _ = viper.BindPFlag("tls-skip-verify", rootCmd.PersistentFlags().Lookup("tls-skip-verify")) _ = viper.BindPFlag("no-extensions", rootCmd.PersistentFlags().Lookup("no-extensions")) _ = viper.BindPFlag("no-core-tools", rootCmd.PersistentFlags().Lookup("no-core-tools")) + _ = viper.BindPFlag("include-core-tools", rootCmd.PersistentFlags().Lookup("include-core-tools")) + _ = viper.BindPFlag("exclude-core-tools", rootCmd.PersistentFlags().Lookup("exclude-core-tools")) _ = viper.BindPFlag("extension", rootCmd.PersistentFlags().Lookup("extension")) _ = viper.BindPFlag("prompt-template", rootCmd.PersistentFlags().Lookup("prompt-template")) _ = viper.BindPFlag("no-prompt-templates", rootCmd.PersistentFlags().Lookup("no-prompt-templates")) @@ -829,6 +837,10 @@ func runNormalMode(ctx context.Context) error { fmt.Fprintf(os.Stderr, "Warning: Failed to create OAuth handler: %v\n", authErr) } + coreToolList, err := kit.CoreToolFilterHelper(viper.GetViper()) + if err != nil { + return err + } // appInstancePtr is used to break the circular dependency between // kit.New (which needs the OnMCPServerLoaded callback) and app.New // (which is needed by the callback to send events to the TUI). @@ -843,6 +855,7 @@ func runNormalMode(ctx context.Context) error { AutoCompact: autoCompactFlag, MCPAuthHandler: authHandler, DisableCoreTools: viper.GetBool("no-core-tools"), + CoreToolList: coreToolList, NoSkills: noSkillsFlag, Skills: skillsPaths, SkillsDir: skillsDir, From 9ae4cec8b8d835f3387ab3cf81cf0da263eea0d5 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Sat, 20 Jun 2026 06:45:39 +0200 Subject: [PATCH 6/6] doc(kit): add documentation for --include-core-tools & --exclude-core-tools Document the mutually exclusive options * `--include-core-tools` which specifies a list of core tools to include * `--exclude-core-tools` which specifies a list of core tools to not include Signed-off-by: Egbert Eich --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 489f2b6e..06b8020f 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,9 @@ mcpServers: --extension, -e Load additional extension file(s) (repeatable) --no-extensions Disable all extensions --no-core-tools Disable all built-in core tools (bash, read, write, edit, grep, find, ls, subagent) +--include-core-tools +--exclude-core-tools Mutually exclusive lists of core tool names to include or not to include in agent + --prompt-template Load a specific prompt template by name --no-prompt-templates Disable prompt template loading