with one click
kodelet
// Kodelet CLI usage guide, commands, configuration, and workflows. Use when users ask about kodelet features, commands, configuration options, or how to accomplish tasks with kodelet.
// Kodelet CLI usage guide, commands, configuration, and workflows. Use when users ask about kodelet features, commands, configuration options, or how to accomplish tasks with kodelet.
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | kodelet |
| description | Kodelet CLI usage guide, commands, configuration, and workflows. Use when users ask about kodelet features, commands, configuration options, or how to accomplish tasks with kodelet. |
Kodelet is a lightweight agentic SWE Agent that runs as an interactive CLI tool. It performs software engineering and production operations tasks using AI assistance.
# Using install script
curl -sSL https://raw.githubusercontent.com/jingkaihe/kodelet/main/install.sh | bash
# Force standalone binary install
curl -sSL https://raw.githubusercontent.com/jingkaihe/kodelet/main/install.sh | bash -s -- --binary
Execute single commands quickly:
# Basic query
kodelet run "your query"
# Continue most recent conversation
kodelet run --follow "continue the task"
kodelet run -f "quick follow-up"
# Resume specific conversation
kodelet run --resume CONVERSATION_ID "more questions"
# Don't save conversation
kodelet run --no-save "temporary query"
# Output only the final result (no intermediate output or usage stats)
kodelet run --result-only "what is 2+2"
# Disable all tools (for simple query-response usage)
kodelet run --no-tools "what is the capital of France?"
For extended conversations and complex tasks, use the Agent Client Protocol (ACP) with a compatible client like toad:
toad acp 'kodelet acp' # Start interactive chat via ACP
The ACP mode provides a rich interactive experience with features like:
Kodelet automatically loads project-specific context from AGENTS.md in your current directory. This file should contain:
Bootstrap your context file:
kodelet run -r init
Reusable prompt templates with variable substitution, bash command execution, and tool/command restrictions.
Built-in recipes:
kodelet recipe list # List all available recipes
kodelet recipe show init # View recipe content
# Repository initialization
kodelet run -r init # Bootstrap AGENTS.md with project context
Recipe capabilities:
{{.variable_name}}{{bash "git" "branch" "--show-current"}}allowed_toolsallowed_commandsworkflow: trueCustom recipes:
Create templates in ./recipes/ or ~/.kodelet/recipes/:
---
name: My Custom Recipe
description: Brief description
arguments:
project:
description: The project name to analyze
default: "default-value"
focus_area:
description: Area to focus the analysis on
allowed_tools:
- file_read
- grep_tool
- bash
allowed_commands:
- "git *"
- "cat *"
---
## Context:
Current branch: {{bash "git" "branch" "--show-current"}}
Project: {{.project}}
## Task:
Please analyze {{.focus_area}}
Usage:
kodelet run -r my-recipe --arg project="Kodelet" --arg focus_area="security"
kodelet run -r my-recipe "additional context or instructions"
Model-invoked capabilities that package domain expertise. Unlike fragments (user-invoked), skills are automatically invoked when relevant to your task.
Skill locations:
./.kodelet/skills/<name>/SKILL.md - Repository-local (higher precedence)~/.kodelet/skills/<name>/SKILL.md - User-globalManaging skills:
# Install plugin-provided skills and recipes
kodelet plugin add orgname/skills # Install locally
kodelet plugin add orgname/skills@v0.1.0 # Install a specific ref
kodelet plugin add orgname/skills -g # Install globally
# Inspect installed plugins and bundled skills
kodelet plugin list
kodelet plugin show orgname/skills
Creating a skill:
---
name: my-skill
description: Brief description for model decision-making
---
# My Skill
## Instructions
Step-by-step guidance for the agent...
Configuration:
skills:
enabled: true # Default: true
allowed: # Empty = all skills enabled
- pdf
- xlsx
Disabling skills:
kodelet run --no-skills "query"
Recipes marked with workflow: true can be invoked by the subagent tool, enabling the model to delegate specialized tasks like PR creation or issue resolution.
Built-in workflows:
github/pr - Create pull requests with AI-generated descriptionsinit - Bootstrap AGENTS.md for repositorycommit - Generate commit messageWorkflow recipe example:
---
name: My Workflow
description: A workflow that can be invoked by the subagent
workflow: true
arguments:
target:
description: Target branch
default: "main"
---
Instructions for the workflow...
Disabling workflows:
kodelet run --no-workflows "query"
kodelet acp --no-workflows
Disabling subagent:
Removes the subagent tool and subagent-related context from the system prompt. Other tools like web_fetch remain available.
kodelet run --disable-subagent "query"
kodelet acp --disable-subagent
Also configurable via disable_subagent: true in config or KODELET_DISABLE_SUBAGENT=true.
Disabling LLM conversation summaries: Uses the first user message for persisted conversation titles instead of calling the weak model.
kodelet run --conversation-summary-mode first_message "query"
Also configurable via conversation_summary_mode: first_message in config or KODELET_CONVERSATION_SUMMARY_MODE=first_message.
Hooks allow external scripts to observe and control agent behavior for audit logging, security controls, and monitoring.
Hook locations (in precedence order):
.kodelet/hooks/ - Repository-local standalone (highest precedence).kodelet/plugins/<org@repo>/hooks/ - Repository-local plugin hooks~/.kodelet/hooks/ - User-global standalone~/.kodelet/plugins/<org@repo>/hooks/ - User-global plugin hooks (lowest precedence)Plugin hooks are prefixed with org/repo/ (e.g., jingkaihe/hooks/audit-logger).
Hook protocol:
./hook hook - Discovery: returns the event type stringecho '<json_payload>' | ./hook run - Execution: receives JSON payload via stdin, returns JSON resultPayload Types (TypeScript):
type HookType = "before_tool_call" | "after_tool_call" | "user_message_send" | "agent_stop";
type InvokedBy = "main" | "subagent";
interface BasePayload {
event: HookType;
conv_id: string;
cwd: string;
invoked_by: InvokedBy;
recipe_name?: string; // Present when invoked via a recipe
}
// before_tool_call: Can block or modify tool input
interface BeforeToolCallPayload extends BasePayload {
event: "before_tool_call";
tool_name: string;
tool_input: Record<string, unknown>;
tool_user_id: string;
}
interface BeforeToolCallResult {
blocked: boolean;
reason?: string;
input?: Record<string, unknown>;
}
// after_tool_call: Can modify tool output
interface AfterToolCallPayload extends BasePayload {
event: "after_tool_call";
tool_name: string;
tool_input: Record<string, unknown>;
tool_output: { toolName: string; success: boolean; error?: string; timestamp: string };
tool_user_id: string;
}
interface AfterToolCallResult {
output?: { toolName: string; success: boolean; error?: string; timestamp: string };
}
// user_message_send: Can block message
interface UserMessageSendPayload extends BasePayload {
event: "user_message_send";
message: string;
}
interface UserMessageSendResult {
blocked: boolean;
reason?: string;
}
// agent_stop: Can return follow-up messages
interface AgentStopPayload extends BasePayload {
event: "agent_stop";
messages: Array<{ role: "user" | "assistant"; content: string }>;
}
interface AgentStopResult {
follow_up_messages?: string[];
}
Example hook (only acts for main agent):
#!/bin/bash
if [ "$1" == "hook" ]; then echo "agent_stop"; exit 0; fi
if [ "$1" == "run" ]; then
payload=$(cat)
invoked_by=$(echo "$payload" | jq -r '.invoked_by')
if [ "$invoked_by" != "main" ]; then exit 0; fi
if [ -f "./cleanup-needed.txt" ]; then
echo '{"follow_up_messages":["Please clean up temporary files."]}'
fi
exit 0
fi
Disabling hooks:
kodelet run --no-hooks "query"
AI Commit Messages:
git add .
# Recommended: fast, non-interactive, no conversation saved
kodelet commit --no-confirm
# Include a ticket prefix
kodelet commit --prefix TICKET-123
# Other options
kodelet commit # Interactive with confirmation
kodelet commit --no-confirm # Skip confirmation only
Pull Requests:
kodelet pr # Create PR with AI-generated description
kodelet pr --target main # Specify target branch
kodelet pr --draft # Create draft PR
Vision-enabled analysis with multi-modal models:
# Single image
kodelet run --image /path/to/screenshot.png "What's wrong with this UI?"
# Multiple images
kodelet run --image ./diagram.png --image ./mockup.jpg "Compare these designs"
Supported: JPEG, PNG, GIF, WebP | Max: 5MB per image, 10 images per message Provider Support: All providers (Anthropic, OpenAI, Google) if the model supports multi-modal
Extend kodelet with executable tools in any language:
Directory structure:
./.kodelet/tools/ - Repository-local standalone tools./.kodelet/plugins/<org@repo>/tools/ - Repository-local plugin tools~/.kodelet/tools/ - User-global standalone tools~/.kodelet/plugins/<org@repo>/tools/ - User-global plugin toolsIf the same tool name appears in multiple locations, precedence is local standalone > local plugin > global standalone > global plugin.
Direct CLI invocation: Custom tools can be inspected and run directly without going through the agent:
# List discovered tools
kodelet custom-tool list
# Show description, executable path, and JSON schema
kodelet custom-tool describe hello
# Invoke a tool using flags generated from its input_schema
kodelet custom-tool invoke hello --name Ada --age 36
# Short alias
kodelet cti hello --name Ada --age 36
# Show dynamic per-tool help
kodelet custom-tool invoke hello --help
# Pass nested or advanced JSON that does not map cleanly to flags
kodelet custom-tool invoke hello --name Ada --input-json '{"config":{"verbose":true}}'
kodelet custom-tool invoke <tool> --help is generated at runtime from the tool's input_schema. Strings, integers, numbers, booleans, and string/integer arrays are exposed as flags automatically. Use --input-json for nested or complex properties; when both flags and --input-json are provided, the JSON values are merged on top of the flag-derived input.
Flags after the tool name are reserved for the tool's schema-derived input. For runtime overrides such as timeout, use config or an environment variable instead of expecting a built-in invoke flag.
Runtime configuration:
Custom tools use custom_tools.timeout (120s by default). Individual tools can override timeout and inject environment variables with custom_tools.tools.<tool-name>:
custom_tools:
tools:
seer:
timeout: 30m
envs:
SEER_MODEL: gpt-5.5
ANTHROPIC_API_KEY:
Bare or null env values inherit from Kodelet's current process environment, so ANTHROPIC_API_KEY: behaves like ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY when that variable is set. Use KEY: "" to intentionally pass an empty string.
Tool binaries may also optionally implement ./my-tool config and return defaults such as {"timeout":"30m"}. Explicit custom_tools.tools.<tool-name>.timeout wins over the optional tool config.
For one-off runs, override the global custom tool timeout per process with KODELET_CUSTOM_TOOLS_TIMEOUT:
KODELET_CUSTOM_TOOLS_TIMEOUT=300s kodelet custom-tool invoke my-tool ...
This environment variable also applies when kodelet run ... invokes a custom tool through the agent.
Generate custom tools:
Install the custom-tool skill from the jingkaihe/skills plugin, then ask for the tool in natural language:
kodelet plugin add jingkaihe/skills
kodelet run "Create a Kodelet custom tool that fetches weather without an API key and save it locally."
Tool protocol:
./my-tool description # Returns JSON schema
./my-tool config # Optional runtime defaults
./my-tool run # Executes with JSON input from stdin
Model Context Protocol for external integrations. Configure in config.yaml:
mcp:
servers:
fs:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/path"]
tool_white_list: ["list_directory"]
# List conversations
kodelet conversation list
kodelet conversation list --search "keyword"
# View conversation
kodelet conversation show <id>
kodelet conversation show <id> --format markdown
kodelet conversation show <id> --format json
kodelet conversation show <id> --stats-only # Header/stats only, no messages
kodelet conversation show <id> --no-header # Messages only, no header
# Stream conversation (real-time)
kodelet conversation stream <id>
kodelet conversation stream <id> --include-history # Show history, then stream new
kodelet conversation stream <id> --history-only # Show history and exit
# Delete conversation
kodelet conversation delete <id>
# Fork conversation (experimental branching)
# 1. Ensure clean git status
# 2. Fork the conversation to try different approaches
# 3. If it doesn't work: git reset --hard and continue with original
kodelet conversation fork <id>
Output formats for conversation show:
| Format | Description |
|---|---|
--format text | Human-readable output (default) |
--format markdown | Markdown transcript with markdown-rendered tool calls/results |
--format json | Structured JSON with id, provider, summary, usage, messages |
--format raw | Full ConversationRecord dump as JSON (includes rawMessages, toolResults, metadata, etc.) |
Flags:
--stats-only: Show header/stats without messages--no-header: Show messages only (for text/json formats)Kodelet uses layered configuration:
~/.kodelet/config.yaml./kodelet-config.yaml (overrides global)Example config.yaml:
aliases:
haiku-45: claude-haiku-4-5-20251001
opus-47: claude-opus-4-7
sonnet-46: claude-sonnet-4-6
max_tokens: 16000
model: sonnet-46
profile: default
reasoning_effort: medium
weak_model: haiku-45
weak_model_max_tokens: 8192
conversation_summary_mode: llm
profiles:
hybrid:
max_tokens: 16000
model: sonnet-46
reasoning_effort: medium
subagent_args: "--profile openai-subagent"
weak_model: haiku-45
weak_model_max_tokens: 8192
openai-subagent:
disable_fs_search_tools: true
tool_mode: patch
model: gpt-5.5
openai:
api_mode: responses
provider: openai
reasoning_effort: high
openai:
disable_fs_search_tools: true
max_tokens: 16000
model: gpt-5
provider: openai
reasoning_effort: medium
tool_mode: patch
weak_model: gpt-5
anthropic:
max_tokens: 64000
model: opus-47
reasoning_effort: max
weak_model: sonnet-46
weak_model_max_tokens: 8192
Models:
claude-sonnet-4-6 - Recommended for standard tasksclaude-haiku-4-5-20251001 - Lightweight tasksclaude-opus-4-1-20250805 - Complex reasoningFeatures:
Setup:
# Option 1: Using anthropic-login (no environment variable needed)
kodelet anthropic-login
# Option 2: Using environment variable
export ANTHROPIC_API_KEY="sk-ant-api..."
# Use the provider
kodelet run --provider anthropic "query"
Models:
gpt-5 - Latest GPT modelFeatures:
Setup:
export OPENAI_API_KEY="sk-..."
kodelet run --provider openai --model gpt-5 "query"
Headless mode outputs structured JSON stream:
# Stream JSON output
kodelet run --headless "analyze this codebase"
kodelet run --headless --include-history "continue analysis"
# Real-time conversation stream
kodelet conversation stream CONVERSATION_ID
kodelet conversation stream CONVERSATION_ID --include-history
Partial Message Streaming (--stream-deltas):
Enables real-time token streaming in headless mode, outputting text as it's generated:
# Stream partial text deltas
kodelet run --headless --stream-deltas "explain how TCP works"
# Show only text deltas in real-time
kodelet run --headless --stream-deltas "write a poem" | \
jq -r 'select(.kind == "text-delta") | .delta' | tr -d '\n'
# Show thinking in real-time
kodelet run --headless --stream-deltas "solve this puzzle" | \
jq -r 'select(.kind == "thinking-delta") | .delta' | tr -d '\n'
Delta Event Types:
| Kind | Description |
|---|---|
text-delta | Partial text content chunk |
thinking-delta | Partial thinking content chunk |
thinking-start | Thinking block begins |
thinking-end | Thinking block ends |
content-end | Content block ends |
Example Delta Output:
{"kind":"thinking-start","conversation_id":"abc123","role":"assistant"}
{"kind":"thinking-delta","delta":"Let me analyze...","conversation_id":"abc123","role":"assistant"}
{"kind":"thinking-end","conversation_id":"abc123","role":"assistant"}
{"kind":"text-delta","delta":"The answer","conversation_id":"abc123","role":"assistant"}
{"kind":"text-delta","delta":" is 42.","conversation_id":"abc123","role":"assistant"}
{"kind":"content-end","conversation_id":"abc123","role":"assistant"}
{"kind":"text","content":"The answer is 42.","conversation_id":"abc123","role":"assistant"}
Note: Complete messages are still emitted after delta streams for clients that ignore deltas.
StreamEntry JSON format (complete messages):
{"kind":"text","role":"user","content":"What files are here?","conversation_id":"conv_123"}
{"kind":"thinking","role":"assistant","content":"User wants to see files..."}
{"kind":"tool-use","tool_name":"bash","input":"{\"command\":\"ls\"}","tool_call_id":"call_456"}
{"kind":"tool-result","tool_name":"bash","result":"file1.txt\nfile2.go"}
{"kind":"text","role":"assistant","content":"Here are the files..."}
Processing with jq:
# Extract text only
kodelet run --headless "query" | jq -r 'select(.kind == "text") | .content'
# Monitor tool usage
kodelet conversation stream ID | jq 'select(.kind == "tool-use") | .tool_name'
Browser-based interface:
kodelet serve # Start on localhost:8080
kodelet serve --host 0.0.0.0 --port 3000
kodelet serve --cors-origins https://app.example.com,https://admin.example.com
Access with the tokenized URL printed by kodelet serve for conversation
management and chat interface. Loopback CORS origins are allowed by default;
use --cors-origins for additional browser origins.
Kodelet implements the Agent Client Protocol (ACP) for integration with compatible IDEs like Zed and JetBrains:
kodelet acp # Start ACP agent mode (stdin/stdout JSON-RPC)
Zed configuration (settings.json):
{
"agent": {
"command": "kodelet",
"args": ["acp"]
}
}
Features:
For detailed protocol documentation, see docs/ACP.md.
Steer autonomous conversations:
kodelet steer --follow "great job, but please add tests"
kodelet steer --conversation-id ID "needs improvement on error handling"
Tab completion for bash, zsh, fish:
# Bash
echo 'source <(kodelet completion bash)' >> ~/.bashrc
# Zsh
echo 'source <(kodelet completion zsh)' >> ~/.zshrc
# Fish
kodelet completion fish > ~/.config/fish/completions/kodelet.fish
Control which bash commands kodelet can execute:
# config.yaml
allowed_commands:
- "ls *"
- "pwd"
- "git status"
- "npm *"
Or via environment:
export KODELET_ALLOWED_COMMANDS="ls *,pwd,git status"
Set the maximum timeout the agent can request for a bash command. Defaults to 120s.
bash:
timeout: 5m
Or via environment:
export KODELET_BASH_TIMEOUT=5m
Limit available tools:
kodelet run --allowed-tools "file_read,grep_tool,bash" "analyze code"
AGENTS.md) for project-specific conventions--follow flag to continue conversations efficientlygit diff main | kodelet run "review these changes for issues"
kodelet run "analyze error logs and suggest fixes"
kodelet run --follow "implement the suggested fix"
kodelet run "refactor user authentication to use middleware pattern"
kodelet run "add comprehensive docstrings to all functions in this file"
kodelet run "write unit tests for the payment processing module"
kodelet version # Show version and build info
Note: This guide focuses on end-user usage. For development information, build processes, and contribution guidelines, see the project's GitHub repository and development documentation.