A minimal Claude-Code-style coding agent CLI. Talks to any OpenAI-compatible endpoint (Ollama, llama.cpp, LM Studio, or OpenAI) with tool calling.
Requires uv and Python 3.14+.
uv syncPull a tool-capable local model (example with Ollama):
ollama pull qwen2.5-coder:14b
ollama serveuv run coding-agent chat --model qwen2.5-coder:14bOr:
uv run python -m coding_agent chat --model qwen2.5-coder:14bFlags:
| Flag | Meaning |
|---|---|
--model |
Model name on your server (default: qwen2.5-coder:14b) |
--base-url |
OpenAI-compatible base URL (default: http://localhost:11434/v1) |
--api-key |
API key (default: ollama; ignored by most local servers) |
--yolo |
Skip confirmation prompts on writes/edits/shell |
--debug |
Dump full messages/tools/tool_calls for each model request/response |
Type /exit or /quit (or Ctrl-C) to leave the session. Use ↑ / ↓ to recall
previous prompts.
Captured against a local Ollama qwen2.5-coder:14b (with --yolo so writes/shell
would not prompt — this turn only used a read-only search):
$ uv run coding-agent chat --model qwen2.5-coder:14b --yolo
╭─────────────────────────────────── ready ───────────────────────────────────╮
│ coding-agent · model=qwen2.5-coder:14b · endpoint=http://localhost:11434/v1 │
│ --yolo enabled: writes/edits/shell run without confirmation │
╰─────────────────────────────────────────────────────────────────────────────╯
you> Find MAX_TOOL_ITERATIONS and DEFAULT_MODEL in src/coding_agent/config.py
by searching or reading files, then report both values. Use tools.
⚙ search_code pattern='MAX_TOOL_ITERATIONS|DEFAULT_MODEL' path='src/coding_agent/config.py'
╭───────────── search_code ─────────────╮
│ 3:MAX_TOOL_ITERATIONS = 12 │
│ 6:DEFAULT_MODEL = "qwen2.5-coder:14b" │
╰───────────────────────────────────────╯
╭─────────────────────────────────── agent ────────────────────────────────────╮
│ MAX_TOOL_ITERATIONS is set to 12 and DEFAULT_MODEL is set to │
│ "qwen2.5-coder:14b". │
╰────────────────────────────────── ⏱ 11.3s ───────────────────────────────────╯
you> /exit
What happened in that turn:
- Your prompt was appended to the conversation and sent to the model with the tool schemas.
- The model called
search_code(shown as the collapsed⚙line). - The tool result was fed back into the loop.
- The model answered in plain text; the green panel is the final reply, with total wall time in the subtitle.
user input
→ append to conversation history
→ call model with [system prompt + history + tool schemas]
→ model returns text OR tool_calls
→ if tool_calls: execute each, append results, loop
→ if text: print it, wait for next user input
Tools: read_file, list_dir, search_code (read-only); write_file,
edit_file, run_shell (gated behind confirmation unless --yolo).
Package layout lives under src/coding_agent/ — agent loop, CLI, prompts, and
tools are separate modules so you can extend them independently.
uv sync --group dev
uv run ruff check src tests # lint
uv run ruff format src tests # format
uv run mypy # type check
uv run pytest # testsOne-shot check (format check + lint + types + tests):
uv run ruff format --check src tests && uv run ruff check src tests && uv run mypy && uv run pytest