Tools¶
Keen Code provides a set of built-in tools that the LLM can use to interact with the codebase. Tools are registered in a central registry and exposed to the LLM with their schemas.
Tool Registry¶
// internal/tools/tool.go
type Tool interface {
Name() string
Description() string
InputSchema() map[string]any
Execute(ctx context.Context, input any) (any, error)
}
type Registry struct {
tools map[string]Tool
}
The registry manages all available tools and converts them to provider-specific tool formats (Anthropic, OpenAI, etc.).
Available Tools¶
| Tool | Purpose | Key Parameters |
|---|---|---|
read_file |
Read file contents | path, offset, limit |
write_file |
Create/overwrite files | path, content |
edit_file |
Targeted string replacement | path, oldString, newString |
glob |
Find files by pattern | pattern, path |
grep |
Search file contents | pattern, path, include |
bash |
Execute shell commands | command, isDangerous, summary |
web_fetch |
Fetch content from a URL | url |
call_mcp_tool |
Call a tool on an MCP server | server, tool, arguments |
read_file¶
Reads a UTF-8 text file with permission checks and validation.
type ReadFileTool struct {
guard *filesystem.Guard
permissionRequester PermissionRequester
}
Parameters:
- path (string, required): Absolute or relative path to the file
- offset (integer, optional): 1-based line number to start reading from (defaults to 1)
- limit (integer, optional): Maximum number of lines to return (defaults to 2000)
Validation: - File must be valid UTF-8 text - File must be under 10MB - Binary files are rejected
Returns:
{
"path": "/absolute/path/to/file",
"content": "file contents...",
"bytes_read": 1234
}
write_file¶
Creates a new file or overwrites existing content.
type WriteFileTool struct {
guard *filesystem.Guard
diffEmitter DiffEmitter
permissionRequester PermissionRequester
}
Parameters:
- path (string, required): Target file path
- content (string, required): Content to write
Behavior:
- Creates parent directories if needed
- Overwrites existing files completely
- Emits diff for display via DiffEmitter
Returns:
{
"path": "/absolute/path/to/file",
"bytes_written": 1234,
"created": true
}
edit_file¶
Performs targeted string replacement in existing files.
type EditFileTool struct {
guard *filesystem.Guard
diffEmitter DiffEmitter
permissionRequester PermissionRequester
}
Parameters:
- path (string, required): Target file path
- oldString (string, required): Exact text to find and replace
- newString (string, required): Replacement text
- shouldReplaceAll (boolean, optional): Replace all occurrences (default: false)
Behavior:
- File must already exist
- oldString must match exactly (including whitespace)
- Uses go-udiff for unified diff output
- Emits diff via DiffEmitter
Returns:
{
"success": true,
"path": "/absolute/path/to/file",
"replacementCount": 1
}
glob¶
Finds files matching a glob pattern.
type GlobTool struct {
guard *filesystem.Guard
permissionRequester PermissionRequester
}
Parameters:
- pattern (string, required): Glob pattern (e.g., *.go, **/*.md)
- path (string, optional): Base directory (defaults to working directory)
Limits: - Maximum 1000 files returned
Returns:
{
"pattern": "*.go",
"base_path": "/project",
"files": ["/project/main.go", "/project/pkg/foo.go"],
"count": 2
}
grep¶
Searches file contents using regular expressions.
type GrepTool struct {
guard *filesystem.Guard
permissionRequester PermissionRequester
}
Parameters:
- pattern (string, required): Regex pattern (Go/RE2 syntax)
- path (string, optional): Base directory
- include (string, optional): Glob filter for file types
- output_mode (string, optional): "file" or "content" (default)
Limits: - Maximum 1000 matches
Returns (content mode):
{
"pattern": "func foo",
"base_path": "/project",
"output_mode": "content",
"matches": [
{"file": "/project/main.go", "line_number": 10, "line": "func foo() {"},
{"file": "/project/main.go", "line_number": 25, "line": "func foo() error {"}
],
"count": 2
}
bash¶
Executes shell commands with timeout and output limits.
type BashTool struct {
guard *filesystem.Guard
permissionRequester PermissionRequester
}
Parameters:
- command (string, required): Bash command to execute
- isDangerous (boolean, optional): Always prompts for permission if true
- summary (string, optional): Brief description for the UI
Limits: - Timeout: 180 seconds - Output: 10MB max (truncated if exceeded)
Dangerous commands (always prompt):
- File removal (rm, rm -rf)
- Git operations that modify repo (git commit, git push, git reset, git rebase)
- Process termination (kill)
- System modifications
Returns:
{
"command": "go test ./...",
"exit_code": 0,
"stdout": "PASS\nok github.com/user/keen-code 0.015s",
"stderr": "",
"summary": "Run Go tests"
}
web_fetch¶
Fetches content from a URL and returns it as text.
type WebFetchTool struct{}
Parameters:
- url (string, required): The URL to fetch
Behavior: - HTML pages are automatically converted to Markdown for readability - Other content types (JSON, plain text, XML) are returned as-is - JavaScript-rendered pages (SPAs) return the pre-JS skeleton only
Limits: - Timeout: 30 seconds - Maximum response size: 128KB (truncated if exceeded)
Returns:
{
"url": "https://example.com",
"status_code": 200,
"content": "markdown or raw content..."
}
call_mcp_tool¶
Calls a tool on a connected MCP (Model Context Protocol) server.
type CallMCPTool struct {
manager keenmcp.Runtime
permissionRequester PermissionRequester
}
Parameters:
- server (string, required): The MCP server name as configured
- tool (string, required): The exact tool name to call on the server
- arguments (object, optional): Key-value arguments matching the tool's input schema
- checkCache (boolean, optional): Reserved for future caching; set to false or omit
Behavior:
- Requires user permission before execution
- Server name must match a configured MCP server
- Arguments must match the tool's input schema exactly
- Skill file at ~/.keen/skills/mcp:<server>/SKILL.md describes available tools
- Schema file at ~/.keen/skills/mcp:<server>/schemas/<tool>.json describes required arguments
Returns:
{
"server": "server-name",
"tool": "tool-name",
"content": "tool output text"
}
DiffEmitter¶
The DiffEmitter interface allows tools to emit diff output for display:
// internal/tools/diff.go
type DiffEmitter interface {
EmitDiff(lines []EditDiffLine)
}
type EditDiffLine struct {
Kind EditDiffLineKind
OldLineNum int
NewLineNum int
Content string
}
const (
DiffLineContext EditDiffLineKind = iota
DiffLineAdded
DiffLineRemoved
DiffLineHunk
)
Permission Integration¶
All tools integrate with the permission system through PermissionRequester:
// internal/tools/permission.go
type PermissionRequester interface {
RequestPermission(ctx context.Context, toolName, path, resolvedPath string, isDangerous bool) (bool, error)
}
Tools check permissions before execution and may request user approval for:
- Paths outside the working directory
- Dangerous operations (marked with isDangerous=true)
- First-time access to certain paths