A context-aware terminal-living code architect agent inspired by Claude Code. Runs entirely on local hardware via Ollama — no cloud API keys required.
Cazagent ships as two complementary implementations:
| Implementation | Location | Status | Description |
|---|---|---|---|
| TypeScript Chatbot (primary) | chatbot/ |
Active | A Claude Code-style interactive terminal UI built on claude-code-kit (React + Ink). |
| Python CLI (legacy) | legacy/ |
Maintenance | The original single-shot CLI with sandboxed execution, persistent memory, and self-optimizing handbook. |
Both share the same Ollama backend, model tiers, and routing philosophy.
- What it does
- Requirements
- Installation
- Usage
- Configuration
- Architecture
- Testing
- Troubleshooting
- Safety notes
- License
- Credits
- Routes each request between a fast terminal-operator model (
MODEL_FAST) and a heavier code-architect model (MODEL_BRAIN) using a lightweight classifier (MODEL_ROUTER). - Executes commands inside a restricted working directory with a dangerous-pattern blocklist, human confirmation gate, and hard timeout (Python CLI); or via tool-calling with a smart permission system (TypeScript chatbot).
- Auto-debugs — reads command stdout/stderr/exit code and emits corrected commands in an agentic loop.
- Persists memory across sessions in three compressed files (plan, context, history) injected into every prompt (both implementations).
- Self-optimizes via Review Mode: when the agent fails, it analyzes the failure and rewrites its own operational handbook with a new guardrail (both implementations).
- Ships 17 built-in tools for a full Claude Code-like agentic experience (TypeScript chatbot): file/shell (Bash, Read, Edit, Write, Glob, Grep), SubAgent delegation, parallel agents (up to 10 concurrent), task tracking (TaskCreate/Update/Get/List), web access (WebFetch, WebSearch), Jupyter notebook editing, and git worktree management.
- Claude Code-style UI — streaming responses, tool-call cards, permission prompts, status line, and welcome screen (TypeScript chatbot).
-
Node.js 18+ and pnpm (TypeScript chatbot)
-
Python 3.10+ (Python CLI)
-
Ollama running locally
-
The models configured in
chatbot/src/config.tsorlegacy/config.py:Constant Default model Purpose MODEL_ROUTERphi4-miniClassifies each prompt as FASTorBRAINMODEL_FASTqwen2.5-coder:7b-instruct-q8_0Terminal commands, git, file listing, system queries MODEL_BRAINgemma-4-12B-agentic-fable5-composer2.5-v2-q6_kCode writing, refactoring, bug fixes, architecture Pull them via
ollama pull <model>.
The chatbot is a pnpm workspace package that depends on the vendored claude-code-kit monorepo in lib/claude-code-kit-0.3.1.
git clone <repo-url> cazagent
cd cazagent
# Install dependencies for the library + chatbot workspace
cd lib/claude-code-kit-0.3.1
pnpm install
# Build the library packages once (generates dist/ used by the chatbot)
pnpm -r buildThe chatbot's package.json references the library via workspace:* symlinks, so after pnpm install the @claude-code-kit/* packages resolve to lib/claude-code-kit-0.3.1/packages/*.
git clone <repo-url> cazagent
cd cazagent
pip install -r legacy/requirements.txtStart the interactive UI from the lib/claude-code-kit-0.3.1 directory (so pnpm can resolve the workspace):
cd lib/claude-code-kit-0.3.1
pnpm --filter cazagent-chatbot startYou'll see a welcome screen, a status line at the bottom, and a prompt. Type a message and press Enter. The agent will:
- Route your prompt to
FASTorBRAIN(if auto-router is ON). - Stream the assistant's response token-by-token.
- Call tools as needed — 17 built-in tools across file/shell, SubAgent, parallel agents (up to 10 concurrent), task tracking, web, notebook, and git worktree. Read-only tools run automatically; write tools prompt for permission.
Run the precompiled binary from releases/v0.1.0/ — no install or build step required, only Node.js 18+ and a running Ollama.
cd /path/to/your/project
node /path/to/cazagent/releases/v0.1.0/cazagent.mjsThe agent operates in your current working directory, so .agent_workspace/ (the evolved handbook + memory) is created in the project you cd into — not inside the release folder. To override the working directory non-interactively, set CAZAGENT_CWD:
CAZAGENT_CWD=/path/to/your/project node /path/to/cazagent/releases/v0.1.0/cazagent.mjsThe UI, commands, status line, and model-switching behavior are identical to the from-source variant described below.
Type these in the prompt:
| Command | Description |
|---|---|
/clear |
Clear conversation history. Type twice to confirm — the first press asks "Are you sure?", the second clears. Any other input cancels. |
/model <name> |
Switch to a specific Ollama model. Disables auto-routing. Example: /model deepseek-coder:1.3b-instruct |
/model |
Show the current effective model and auto-router state. |
/models |
List all installed Ollama models (with tool-support annotation). |
/router on |
Enable automatic FAST/BRAIN routing (default). |
/router off |
Disable routing and use the currently selected model for all prompts. |
/review [desc] |
Trigger Review Mode — analyze the last failure (or desc) and rewrite the handbook. Re-creates the agent with the evolved prompt. |
/rollback |
Restore the previous handbook from instructions.bak.txt (undo a Review Mode rewrite). |
/show-handbook |
Print the current evolved handbook to the screen. |
/reset-handbook |
Reset the handbook to factory defaults. Type twice to confirm — same double-press flow as /clear. |
/show-memory |
Print the plan/context/history memory files to the screen. |
/reset-memory |
Reset memory (plan/context/history) to factory defaults. Type twice to confirm — same double-press flow as /clear. |
/help |
Show the command list. |
Note:
/model <name>,/router on, and/router offall clear the conversation history (the agent is re-created with the new model/routing state).
Keyboard shortcuts:
Ctrl+C— cancel an in-flight response.Ctrl+D— quit the chatbot.
The bottom status line reflects the current routing state. The final segment is the working directory name (WORKING_DIRECTORY_LABEL = basename(WORKING_DIRECTORY)), so it shows Cazagent only when the chatbot is launched from a directory of that name.
| State | Status line |
|---|---|
| Auto-route ON, before first prompt | ollama · auto · <cwd-name> |
| Auto-route ON, tier = FAST | ollama · FAST · qwen2.5-coder:7b-instruct-q8_0 · <cwd-name> |
| Auto-route ON, tier = BRAIN | ollama · BRAIN · gemma-4-12B-... · <cwd-name> |
| Auto-route OFF, manual model | ollama · <model> · <cwd-name> |
When auto-routing is ON and no prompt has been submitted yet, no specific model is shown — the router picks one per-prompt.
- Auto-router ON (default): Each prompt is classified by
MODEL_ROUTERasFASTorBRAIN, and the corresponding tier model is used for that turn only. /model <name>: Pins the session to a single model and turns auto-routing OFF. To return to automatic routing, run/router on./router on|off: Toggles routing without changing the selected model. Turning routing back ON resumes per-prompt classification.
# Ask a question / give a task
python legacy/main.py ask "find all large files over 100MB"
# Skip the per-command confirmation gate (autonomous loop)
python legacy/main.py ask "list files" --no-confirm
# Override the routed model (disables auto-routing)
python legacy/main.py ask "refactor this" --model gemma-4-12B-agentic-fable5-composer2.5-v2
# Run commands inside a Docker container instead of the local sandbox
python legacy/main.py ask "scan this directory" --docker
# Manual Review Mode — evolve the handbook from a known failure
python legacy/main.py review "the agent kept trying to use sudo"
# Run Review Mode with a specific model
python legacy/main.py review "looped on a bad command" --model gemma-4-12B-agentic-fable5-composer2.5-v2-q6_k
# Restore the previous handbook (undo a bad Review Mode rewrite)
python legacy/main.py rollback
# Inspect state
python legacy/main.py show-handbook
python legacy/main.py show-memory
# Reset to factory defaults
python legacy/main.py reset memory
python legacy/main.py reset handbook
python legacy/main.py reset allAt startup ask and review hit Ollama's /api/tags endpoint to confirm the
server is running and the required models are installed, exiting with a friendly
error (and a ollama pull hint) instead of a raw connection traceback.
Edit chatbot/src/config.ts:
| Constant | Default | Purpose |
|---|---|---|
OLLAMA_BASE_URL |
http://localhost:11434 |
Ollama native API base |
OLLAMA_OPENAI_BASE_URL |
${OLLAMA_BASE_URL}/v1 |
OpenAI-compatible endpoint (consumed by OpenAIProvider) |
OLLAMA_TAGS_URL |
${OLLAMA_BASE_URL}/api/tags |
Lists installed models + capabilities |
OLLAMA_GENERATE_URL |
${OLLAMA_BASE_URL}/api/generate |
Used by the router for fast classification |
MODEL_ROUTER / MODEL_FAST / MODEL_BRAIN |
see Requirements | Ollama model names |
DEFAULT_MODEL |
MODEL_FAST |
Used when auto-routing is disabled and no model is manually selected |
AGENT_OPTIONS.temperature |
0.1 |
Sampling temperature |
AGENT_OPTIONS.maxTurns |
20 |
Cap on the model→tool→feedback loop |
MAX_HISTORY_ENTRIES |
30 |
Max verbatim entries in history.md before oldest are folded into a summary |
MAX_HISTORY_CHARS |
8000 |
Max characters of history.md injected into the prompt each turn |
ROUTER_PROMPT |
(see file) | Zero-shot classifier prompt (rules + user input) |
WORKING_DIRECTORY |
process.cwd() (override via CAZAGENT_CWD) |
Directory the agent operates in |
Edit legacy/config.py:
MODEL_ROUTER/MODEL_FAST/MODEL_BRAIN— Ollama model namesOLLAMA_OPTIONS_ROUTER/OLLAMA_OPTIONS_FAST/OLLAMA_OPTIONS_BRAIN— per-tiertemperatureandkeep_alive(how long models stay resident). BRAIN runs hotter and stays resident longer than FAST.OLLAMA_TIMEOUT— HTTP timeout for Ollama API callsREQUIRE_CONFIRMATION— human gate before each sandboxed command (overridable per-run withask --no-confirm)MAX_AGENT_ITERATIONS— cap on the model→execute→feedback loopMAX_HISTORY_ENTRIES/MAX_HISTORY_CHARS— history.md compaction thresholds (oldest entries are folded into a summary once exceeded)COMMAND_TIMEOUT— per-command execution timeout in seconds
chatbot/
├── src/
│ ├── index.tsx Entry point — render(<App/>) + ThemeProvider
│ ├── App.tsx Root component: boot → error → chat view; commands; status line
│ ├── chat-hook.ts useChat() — conversation state, routing, streaming, permissions
│ ├── router.ts routePrompt() / modelForTier() — classifies prompt as FAST/BRAIN (port of router.py)
│ ├── ollama.ts checkOllama(), listOllamaModels(), createOllamaProvider()
│ ├── system-prompt.ts SYSTEM_PROMPT (function-call tools) + REVIEW_PROMPT (Review Mode)
│ ├── handbook.ts Self-optimizing operational handbook + Review Mode (port of handbook.py)
│ ├── memory.ts Filesystem-backed plan/context/history memory (port of memory.py)
│ ├── parallel-agents.ts ParallelAgents tool — up to 10 concurrent subagents via Promise.all()
│ ├── config.ts Model + runtime configuration (port of config.py)
│ └── smoke-test.ts Non-interactive end-to-end test
├── package.json Workspace package (depends on @claude-code-kit/*)
├── tsconfig.json Self-contained TS config (moduleResolution: bundler)
└── tsup.config.ts ESM bundler config (used by `pnpm build`)
Key flows:
- Boot —
Appchecks Ollama health, lists models, and picks an initial model: it prefersDEFAULT_MODELif present (matched by name); otherwise falls back to the first tool-capable model, then the first available model. It also initializes the handbook (initHandbook()) and persistent memory (initWorkspace()), and usesloadHandbook()as the system prompt. - Submit —
useChat.submit()optionally routes the prompt viaroutePrompt(), callsagent.setModel(), prepends the compressed memory block (getCompactState()) to the user message, then iteratesagent.run()(an async generator). - Events —
textchunks stream into the UI (with memory-update tags stripped);tool_call/tool_resultrender as cards;errorsurfaces inline;donefinalizes the assistant message, applies any<plan_update>/<context_update>blocks to disk, and appends a timestamped entry tohistory.md. On run errors, a failure log is captured for/review. - Permissions — read-only tools (Read/Glob/Grep/TaskGet/TaskList) and "always allow" tools run silently; write tools (Bash/Edit/Write/Agent/ParallelAgents/TaskCreate/TaskUpdate/NotebookEdit/EnterWorktree/ExitWorktree) surface a permission prompt. Bash commands render a command preview; Edit/Write show the target file path.
Built-in tools (17):
| Category | Tools | Source |
|---|---|---|
| File & Shell | Bash, Read, Edit, Write, Glob, Grep | @claude-code-kit/tools |
| SubAgent | Agent (single delegated execution) | createSubagentTool() |
| Parallel Agents | ParallelAgents (up to 10 concurrent subagents) | parallel-agents.ts |
| Task Management | TaskCreate, TaskUpdate, TaskGet, TaskList | createTaskTool() |
| Web | WebFetch (SSRF-protected), WebSearch | @claude-code-kit/tools |
| Notebook | NotebookEdit (Jupyter .ipynb) |
@claude-code-kit/tools |
| Git Worktree | EnterWorktree, ExitWorktree | @claude-code-kit/tools |
The SubAgent and ParallelAgents tools share the same agentFactory: each spawns a new Agent with MODEL_BRAIN, the current handbook, and the basic toolset (no SubAgent/Task/ParallelAgents tools — prevents infinite recursion). The ParallelAgents tool runs all subagents concurrently via Promise.all() with a shared 5-minute timeout and abort scope. Task tools hold in-memory state via useRef, so the task list survives agent recreation (model switch, Review Mode, etc.).
Built on:
@claude-code-kit/agent— headless agent loop,OpenAIProvider, tool registry, permissions@claude-code-kit/ui—REPL,WelcomeScreen,Spinner,StatusLine,MessageList,PermissionRequest@claude-code-kit/ink-renderer— React reconciler for the terminal (Flexbox via Yoga)@claude-code-kit/tools—bashTool,readTool,editTool,writeTool,globTool,grepTool,webFetchTool,webSearchTool,notebookEditTool,enterWorktreeTool,exitWorktreeTool,createSubagentTool(),createTaskTool()
legacy/
├── main.py Entry point + CLI + agentic loop
├── router.py Intent classifier (FAST vs BRAIN tier)
├── context.py Gathers terminal/git context for the prompt
├── memory.py Filesystem-backed plan/context/history memory
├── executor.py Secure execution bridge (sandbox + blocklist)
├── handbook.py Self-optimizing system prompt (Review Mode)
├── prompts.py Prompt templates (system, router, review)
├── retry.py Exponential-backoff retry wrapper for transient Ollama errors
├── config.py Model + runtime configuration
├── tests/ Unit tests (test_executor, test_handbook, test_main, test_memory, test_retry)
└── requirements.txt
Runtime state lives in .agent_workspace/:
instructions.txt— the evolved handbook (system prompt)instructions.bak.txt— previous handbook (for rollback)plan.md,context.md,history.md— persistent memorysandbox/— restricted working directory for executed commands
The TypeScript chatbot ports the core routing + agent loop from Python. The following Python files have their primary functionality migrated:
| Python file | TypeScript replacement | Status |
|---|---|---|
legacy/config.py |
chatbot/src/config.ts |
Migrated (models, endpoints, router prompt) |
legacy/router.py |
chatbot/src/router.ts |
Migrated (routePrompt / modelForTier) |
legacy/prompts.py (system prompt) |
chatbot/src/system-prompt.ts |
Migrated (adapted for function-call tools) |
legacy/main.py (agent loop) |
chatbot/src/App.tsx + chat-hook.ts |
Migrated (interactive REPL replaces single-shot CLI) |
legacy/context.py |
— | Not migrated (chatbot uses working-directory scoping instead) |
legacy/memory.py |
chatbot/src/memory.ts |
Migrated (plan/context/history persistence + <plan_update>/<context_update> tag protocol + history compaction) |
legacy/executor.py |
— | Not migrated (chatbot uses @claude-code-kit/tools bashTool + permission system) |
legacy/handbook.py |
chatbot/src/handbook.ts |
Migrated (Review Mode + handbook evolution; /review, /rollback, /show-handbook, /reset-handbook commands) |
cd lib/claude-code-kit-0.3.1
# Type-check
pnpm --filter cazagent-chatbot typecheck
# Non-interactive smoke test (requires Ollama running)
pnpm --filter cazagent-chatbot exec tsx src/smoke-test.tsThe smoke test verifies tool-schema generation and end-to-end tool calling with qwen2.5:7b-instruct. Expected output ends with RESULT: PASS (tool calls executed successfully).
python -m unittest discover -s legacy/tests -vEnsure Ollama is running:
ollama serveVerify the endpoint responds:
curl http://localhost:11434/api/tagsIf Ollama is on a different host, edit OLLAMA_BASE_URL in chatbot/src/config.ts or OLLAMA_URL in legacy/config.py.
Pull the required models:
ollama pull phi4-mini
ollama pull qwen2.5-coder:7b-instruct-q8_0
ollama pull gemma-4-12B-agentic-fable5-composer2.5-v2-q6_kOr list what's available:
ollama listThe name must match exactly what ollama list shows (including tags like :latest or :7b-instruct-q8_0). Run /models inside the chatbot to see valid names.
The router is a lightweight phi4-mini model with a temperature of 0.1. If it mis-routes:
- Run
/router offand use/model <name>to pin a specific model. - Edit
ROUTER_PROMPTinchatbot/src/config.tsto tune the classifier instructions.
This is a VS Code TS-server resolution issue. The tsc --noEmit typecheck passes correctly via pnpm's symlinks. To fix VS Code:
- Ensure
chatbot/tsconfig.jsonis self-contained (does notextendsthe library tsconfig) — VS Code's TS server doesn't always pick upmoduleResolution: "bundler"throughextends. - Run "TypeScript: Restart TS Server" in VS Code.
- If it persists, run
pnpm -r buildfromlib/claude-code-kit-0.3.1/to regeneratedist/*.d.tsfiles.
This happens if tsconfig.json uses paths to map @claude-code-kit/* to .d.ts files — tsx respects paths and tries to import from declaration files. Keep tsconfig.json free of paths mappings; rely on pnpm's workspace:* symlinks instead.
The model may not support function calling well. The smoke test tries qwen2.5:7b-instruct first, then llama3.1:latest, then DEFAULT_MODEL. Ensure at least one tool-capable model is installed:
ollama list # look for models with "tools" capabilityThe sandbox is not a true OS-level isolation boundary. The dangerous-pattern blocklist catches obvious foot-guns (rm -rf /, sudo, fork bombs, etc.) and commands run in a restricted working directory with sanitized environment variables. For untrusted models, swap execute_command() for a Docker backend that mounts the sandbox in a container.
In the TypeScript chatbot, write tools (Bash/Edit/Write/Agent/ParallelAgents/TaskCreate/TaskUpdate/NotebookEdit/EnterWorktree/ExitWorktree) always prompt for permission before executing. You can choose:
- Allow once — runs this one call, prompts again next time.
- Always allow — adds the tool to an allowlist for the session.
- Deny — blocks the call and returns an error to the agent.
Read-only tools (Read/Glob/Grep/TaskGet/TaskList/WebFetch/WebSearch) never prompt.
This project is licensed under the MIT License - see the LICENSE file for details.
Built with Trae IDE — an AI-powered development environment that helped architect and refine this project.
Special thanks to:
-
claude-code-kit (MIT License, Copyright 2026 Minnzen) for the foundational agent framework and terminal UI components
-
Ollama for enabling local LLM inference