Skip to main content

Krodo — a local-first, multi-provider coding agent CLI

Project description

Krodo

English | 中文

CI License: Apache-2.0 Python 3.12+ Status: Pre-alpha PyPI

A local-first, multi-provider coding agent CLI, built with Python 3.12+.

Status: 🚧 Pre-alpha (v0.1.1) — Phase 1 feature-complete & on PyPI (REPL + headless + pipe, 11 tools, JSONL sessions, three approval modes). Phase 2 (TUI, MCP client, tree-sitter symbol index) in planning.

Krodo is an open-source coding agent inspired by Claude Code, Codex CLI, and Aider. It runs locally, talks to your codebase through tools (read / edit / shell / git / grep), and supports any LLM provider via LiteLLM — Anthropic, OpenAI, Gemini, DeepSeek, Qwen, plus local models via Ollama / vLLM.

Why another coding agent

  • Local-first: your code never leaves your machine except for LLM API calls.
  • Multi-provider from day 1: switch between Claude, GPT, Gemini, DeepSeek, Qwen, or local models with a single config flag.
  • Three CLI shapes, one core: krodo REPL, krodo "<prompt>" headless, krodo tui (Phase 2) — all share the same agent loop.
  • Safety as a default: three approval modes (read_only / auto_edit / full_auto), path firewall, dangerous-command blocklist, automatic git checkpoint before every write.
  • Modular monolith: clean Protocol-based interfaces between core / llm / tools / sandbox / memory / obs. Easy to read, easy to contribute to.

For full design rationale, see docs/architecture.md.

Roadmap

Phase Scope Status
0 Single-file prototype validating the ReAct loop ✅ done
1 M1 Walking skeleton (3 tools, CLI, agent loop) ✅ done
1 M2 Full tools (11 tools) + three approval modes + pattern trust ✅ done
1 M3 Context management (token budget + dual compression) + 7 recovery scenarios ✅ done
1 M4 .krodoignore + git checkpoint + krodo undo + diff preview ✅ done
1 M5 Persistence + memory: JSONL sessions, krodo resume, AGENTS.md, config files ✅ done
1 M6 Streaming + cost tracking + pipe stdin + REPL slash commands + approval persistence ✅ done
1 M7 Brand rename (Coda → krodo) + mypy strict clean + docs quartet + GitHub release + dogfood PR ✅ done
2 tree-sitter symbol index, repo-map, Textual TUI, MCP client
3 OS-level sandbox, evaluation harness, OpenTelemetry / Langfuse
4 Production-grade: Rust hot paths, single-binary distribution, LiteLLM Proxy

Quick start

Try the v0.1.1 release (Phase 1 feature-complete)

uv tool install krodo                 # or: pipx install krodo
export ANTHROPIC_API_KEY=sk-ant-...   # or OPENAI_API_KEY / ZAI_API_KEY / ...

mkdir -p /tmp/krodo-sandbox

# Headless: run one task and exit
krodo --root /tmp/krodo-sandbox "create hello.py that prints Hello Krodo, then run it"

# REPL: omit the prompt to enter interactive multi-turn mode
krodo --root /tmp/krodo-sandbox
# you> create a simple mario game
# (assistant works, then…)
# you> now add a sound effect when collecting coins
# you> exit          # or Ctrl-D / Ctrl-C twice

# Pipe: stdin becomes the prompt…
echo "create hello.py that prints Hello Krodo" | krodo --root /tmp/krodo-sandbox

# …or extra context when a prompt is given
git diff | krodo "review this change for bugs"

Assistant text streams token-by-token, and every session summary ends with a cost line like tokens : 12.3k in / 4.1k out | cost $0.0231.

In REPL mode the conversation history (including everything the agent did in the previous turn) is carried over, so follow-ups like "now add X" or "fix the bug from before" work naturally. Exit with exit / quit / :q, Ctrl-D, or two consecutive Ctrl-C presses at the prompt.

REPL slash commands

Slash commands are handled locally — they are never sent to the LLM:

Command Action
:help List available commands
:sessions Show the 10 most recent sessions in this workspace
:undo Restore files to the previous checkpoint
:cost Show session token / cost totals
:resume <id> Switch to another session (history is replayed)
:q Quit (same as exit)

Resuming a previous session

Sessions are persisted automatically. You can pick up right where you left off:

# List recent sessions
krodo resume --list

# Resume by session ID (or unique prefix)
krodo resume a3f2b1

# Resume in a specific workspace
krodo resume --root /tmp/krodo-sandbox a3f2b1

krodo resume replays the stored conversation history into a fresh REPL, so the model remembers everything from the prior session — files edited, tools called, and dialogue.

Install (PyPI)

Krodo is on PyPI. Pick your favourite installer:

uv tool install krodo                # recommended (fast, isolated)
# or
pipx install krodo                   # equally good
# or
pip install krodo                    # works, but pip's global installs can clash

Verify:

krodo --version                      # krodo <version>
krodo --help

To run from source instead (for development):

git clone https://github.com/wadekun/krodo
cd krodo
uv sync                              # creates .venv with all deps + dev group
uv run krodo --help                  # `uv run` needed because not pip-installed

Available tools (11 total)

Tool Category Requires approval Description
read_file Read No Read a file (with optional offset/limit)
list_dir Read No List directory contents (depth-limited, noise-dirs skipped)
glob Read No Find files matching a pattern (**/*.py)
grep Read No Regex search; ripgrep when available, Python fallback
git_status Git No Show working tree status (git status --porcelain)
git_diff Git No Show unified diff (staged/unstaged, optional path filter)
write_file Write Yes Write or overwrite a file
edit_file Write Yes Targeted string replacement with uniqueness enforcement
apply_patch Write Yes Apply a unified diff atomically with rollback on failure
run_shell Shell Yes Execute a shell command inside the workspace sandbox
git_commit Git Yes Commit staged files (API keys auto-redacted from message)

Context & Recovery

Krodo enforces a token budget and offers dual compression strategies so that long sessions never overflow the model's context window.

Token budget (§3.4.1)

The budget is 80% of the model's context window. At 80% usage, compression is triggered. At 95%, hard truncation kicks in as a safety net. If the available budget hits zero, the next turn is refused with a clear message.

Total budget   = model_context_window × 0.80
Output reserve = total_budget × 0.15
Compress at    = 80% of budget (default)
Truncate at    = 95% of budget

Compression strategies

Select via KRODO_COMPRESS environment variable:

Strategy Env value Description
LLM summary (default) llm Calls the same LLM provider to summarise the oldest N dialogue rounds into a <SUMMARY>…</SUMMARY> block.
Algorithmic algorithmic Drops tool_result content, keeps tool-call metadata and file paths. Zero extra LLM cost — great for offline dev or large codebases.
# Use algorithmic compression (no extra LLM calls):
KRODO_COMPRESS=algorithmic krodo "..."

# Override the token ratio for Claude (default 1.1x, tiktoken undercounts):
KRODO_TOKEN_RATIO=1.15 krodo --model anthropic/claude-3-5-sonnet "..."

Error recovery (7 scenarios, §7.5)

# Scenario Recovery
1 LLM returns invalid tool-call JSON Re-inject schema + error; retry ×2, then abort
2 Tool execution timeout Kill subprocess; skip tool call with truncated partial result
3 Agent stall (3× same write-tool call) Abort turn; show last 3 calls to user
4 Compression-induced context loss Re-inject pinned file paths + last user message
5 File externally modified (SHA-256 conflict) Block write; ask agent to re-read the file first
6 Provider rate limit / 5xx Exponential back-off ×3 (1 s / 2 s / 4 s)
7 File permission denied (EACCES) Skip write; report path + permission bits

CLI flags

# Limit tool calls per turn (default 25):
krodo --max-tool-calls 5 "..."

# Set compression window (how many dialogue rounds to compress at once):
krodo --summary-window 3 "..."

Persistence & Memory

Session storage

Every session is automatically saved to .krodo/sessions/<session_id>.jsonl in your workspace. Each line is a JSON event (USER_MESSAGE, ASSISTANT_MESSAGE, TOOL_CALL, TOOL_RESULT, COMPRESSION, etc.) with a monotonic seq number so multi-process appends are safe.

Application logs go to .krodo/logs/<session_id>.log (pure structlog JSONL — separate from session events).

AGENTS.md — project memory

Place an AGENTS.md file anywhere in your project and Krodo will inject it automatically into every session as <project_memory>:

Tier Location Purpose
System ~/.config/krodo/AGENTS.md Personal conventions (applies to all workspaces)
Project <workspace>/AGENTS.md Project-specific rules (always included, never dropped)
Subdir <cwd>/AGENTS.md … up to workspace root Contextual docs for the directory you're working in

Each file is limited to 8K tokens; total budget is 12K tokens (subdirectory files are dropped first if the limit is hit).

Configuration files

Defaults can be set in .krodo/config.yaml (workspace) or ~/.config/krodo/config.toml (user-global). Precedence: CLI flag > env var > workspace > user > built-in default.

Quick example:

# .krodo/config.yaml — workspace-level default
model: deepseek/deepseek-v4-flash
approval: auto_edit
max_tool_calls: 15

Full field reference + 10 providers + per-provider API keys + troubleshooting (field-name gotchas, proxy caveats, error-pattern diagnosis): see Models & Providers.

Run krodo doctor after every config change to verify what's actually loaded.

.krodoignore & Git checkpoint

Two safety nets: a 4-tier ignore system and automatic git checkpointing before every write.

.krodoignore — 4-tier path filtering (§5.3)

Every read_file, list_dir, glob, and grep call passes through KrodoIgnore before touching the disk. Rules are merged from four sources in increasing specificity order:

Tier Source Overridable?
1 Hard-coded defaults (.env, *.pem, id_rsa, node_modules/, etc.) ❌ always active
2 Project .gitignore
3 Project .krodoignore (workspace root) adds custom patterns
4 User-level ~/.config/krodo/krodoignore personal overrides

When a path matches any rule, the tool returns:

PathIgnoredError: '<path>' is ignored (rule: '<pattern>' from <source>)

Example .krodoignore

# Exclude internal data directories from agent reads
data/raw/
reports/*.csv

# Exclude generated mock files
tests/fixtures/generated/

Git checkpoint (§5.4)

Before every write (write_file, edit_file, apply_patch) and write-heuristic shell command, Krodo creates a lightweight git stash create checkpoint:

  1. Collect affected paths.
  2. checkpoint_sha = git stash create — does not push to the stash stack; working tree is untouched.
  3. Emit a CHECKPOINT SessionEvent to .krodo/logs/<session>.jsonl.
  4. Execute the write.

On non-git workspaces, checkpointing degrades to a no-op (warning logged; writes proceed normally).

krodo undo

# Undo the last checkpoint in the most recent session:
krodo undo [--root <workspace>]

# Undo a specific session:
krodo undo --session <session_id> [--root <workspace>]

krodo undo reads the session JSONL, finds the most recent CHECKPOINT event, and runs git checkout <sha> -- <affected_paths> to restore only those paths. Other files are untouched.

Condition Behaviour
Non-git workspace Exit 1 with friendly error
No CHECKPOINT found Exit 1 with log path hint
affected_paths = workspace root (shell command scope) Prompts for confirmation before restoring

CLI subcommand semantics

Krodo has three named subcommands — resume, undo, and doctor — alongside a free-form headless prompt. The parser resolves the two as follows:

Invocation Behaviour
krodo "create a mario game" Headless — prompt is "create a mario game"
krodo Interactive REPL
krodo resume Resume subcommand (most recent session)
krodo resume abc123 Resume subcommand with session ID abc123
krodo resume --root /path Resume subcommand; --root goes to resume
krodo --root /path resume Resume subcommand; global --root inherited as default
krodo undo Undo subcommand
krodo doctor Doctor subcommand

Key rules:

  • The first non-option token is checked against registered subcommand names. If it matches, the token triggers subcommand dispatch — it is never treated as the headless prompt.
  • Global flags (--root, --model, --approval, etc.) can go before or after the subcommand token. When placed before, they are propagated to the subcommand as defaults; an explicit flag in the subcommand itself always wins.
  • Natural-language prompts should be quoted so they arrive as a single token. Without quotes, the first word could match a subcommand name:
    krodo "resume the work from yesterday"   # ✓ headless with full prompt
    krodo resume the work from yesterday     # ✗ routes to resume subcommand; "the" is unexpected arg
    

Local development

Krodo uses uv for dependency and venv management.

git clone https://github.com/wadekun/krodo
cd krodo
uv sync                       # install deps + create .venv
uv run pytest                 # run tests
uv run ruff check             # lint
uv run mypy src               # type-check

Set your LLM credentials in the environment (any subset, depending on the provider you use):

export ANTHROPIC_API_KEY=sk-ant-...
export OPENAI_API_KEY=sk-...
# or use the system keyring (recommended for shared machines, see docs/architecture.md §7.2)

Project layout

krodo/
  src/krodo/
    cli/        # Typer entry, REPL, headless exec
    core/       # Agent loop, Context, Budget, Compression, Recovery, Events
    llm/        # LLMProvider Protocol + LiteLLM adapter
    tools/      # File / shell / patch / search / git tools
    sandbox/    # Path firewall, command policy, approval modes
    memory/     # JSONL session store, krodo resume, AGENTS.md loader, config
    obs/        # structlog + OpenTelemetry + cost tracker
  tests/{unit,integration,e2e}/
  docs/
    architecture.md         # design baseline (read this first)
    reviews/                # past architecture review notes
  scripts/
    prototype.py            # Phase 0 single-file prototype (DEPRECATED — use krodo CLI)

Contributing

This is a learning + production project. Contributions welcome — Phase 1 is feature-complete and the CI gate is stable.

Ground rules:

  • All code goes through ruff + mypy --strict + pytest --cov (see CONTRIBUTING.md for the full CI gate).
  • All new tools come with 100% unit test coverage and an integration test against a recorded LLM response (vcrpy).
  • All changes that touch the agent loop must pass the regression matrix (Phase 2+).
  • See docs/architecture.md §11 for the seven engineering principles.

Documentation

Document What's in it
docs/QUICKSTART.md 5-minute install + first task
docs/MODELS.md Model & provider config, switching, troubleshooting
CONTRIBUTING.md Dev setup, CI gate, PR flow, commit conventions
SECURITY.md Threat model, sandbox boundaries, vulnerability reporting
CHANGELOG.md Milestone-by-milestone changes
docs/architecture.md Full design baseline (the source of truth)
AGENTS.md Auto-loaded project memory (loaded into every session)

License

Apache-2.0 © The Krodo Contributors

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

krodo-0.1.1.tar.gz (409.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

krodo-0.1.1-py3-none-any.whl (122.2 kB view details)

Uploaded Python 3

File details

Details for the file krodo-0.1.1.tar.gz.

File metadata

  • Download URL: krodo-0.1.1.tar.gz
  • Upload date:
  • Size: 409.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for krodo-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d09e00ce84154111a2a26891af5cc86e656a8d56fd9f948c1137e23d538db738
MD5 19bd54ef54ddb991d39705444cb842ea
BLAKE2b-256 e4dac70d91ae6c3011b29c263888be2b9a0658a203bceb4f26fa5c8800cb8428

See more details on using hashes here.

Provenance

The following attestation bundles were made for krodo-0.1.1.tar.gz:

Publisher: publish.yml on wadekun/krodo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file krodo-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: krodo-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 122.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for krodo-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cb276803b68231c9d4db82488bd8f9c56c8d32df93bd48d1dfa2725b5200bedd
MD5 b76c396965552bd5db14e9ecec229425
BLAKE2b-256 c6a79f37511ce39a18a0f91ed7763615c22fe971591ff51d3165ade72de4ccac

See more details on using hashes here.

Provenance

The following attestation bundles were made for krodo-0.1.1-py3-none-any.whl:

Publisher: publish.yml on wadekun/krodo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page