> ## Content Index
> Fetch the complete content index at: https://wuu73.org/aiguide-ghost/llms.txt
> Use this file to discover other available public pages before exploring further.

# Zaica: The Focused Coding Agent
- URL: https://wuu73.org/aiguide-ghost/coding-agents-zaica/
- Published: 2026-05-29T00:23:00.000Z
- Updated: 2026-05-29T00:23:00.000Z
- Description: Part of Agent Harness Field Guide.
- Author: WUU73
- Tags: Deep Dives, Agent Harness Field Guide, #Deep Dive Child, #Import 2026-09-12 06:38

Zig 0.15 • \~9,100 Lines • 6 Providers • Chain Mode • MIT

A single static binary with zero runtime that delivers multi-provider LLM coding assistance, chain-mode structured workflows, parallel sub-agent dispatch, reactive state management, and a hand-crafted terminal REPL — all in \~9,100 lines of Zig.

Shameless Plug[While we're deep-diving into complex CLI tools... let's be honest. Are you tired of pretending you enjoy memorizing 400 arcane tmux key combos? Do you lie awake at night dreading the moment you have to edit a cryptic dotfile just to change a font size? Same. It's the AI age, we shouldn't be computing like it's 1995.**ButtonsCLI**: The terminal for](https://buttonscli.com/?ref=wuu73.org)

(Alright, ad over. Back to the serious technical analysis.)

## What is Zaica?

Zaica (pronounced "ZAI-tsah") is a Zig AI coding assistant that runs in your terminal, calls tools autonomously, and streams responses in real-time. It is built from scratch in **Zig 0.15** with **zero runtime dependencies** beyond the standard library, plus two optional dependencies: `vaxis` (terminal UI library) and `zefx` (a custom reactive state management library, both authored by the same developer).

The binary is distributed via **Homebrew** for macOS (aarch64 + x86\_64) and Linux (aarch64 + x86\_64), with pre-built binaries on GitHub releases. It uses `std.http.Client` directly — no HTTP library dependency.

📌

#### Key differentiator

Zaica is the **most focused coding agent** in the Zig category. While Wintermolt is a sprawling multi-feature platform, Zaica stays laser-focused on the coding loop: chat, tools, chains, skills, sessions — and does each one with exceptional polish.

## Architecture overview

| Module          | Files | Lines   | What it does                                                                            |
| --------------- | ----- | ------- | --------------------------------------------------------------------------------------- |
| src/main.zig    | 1     | \~100   | Entry point — 3 modes: single-shot, REPL, chain                                         |
| src/repl.zig    | 1     | 2,153   | Full interactive REPL with manual line editing, UTF-8/Cyrillic, escape sequence parsing |
| src/node.zig    | 1     | 731     | Generic agentic loop — LLM call → parse → execute tools → repeat                        |
| src/tools.zig   | 1     | 631     | 7 tools with risk levels, permissions, output truncation                                |
| src/chain.zig   | 1     | 528     | Multi-step pipeline orchestrator (.chain.md files)                                      |
| src/state.zig   | 1     | 600     | Reactive state graph using zefx (Events, Stores, watchers)                              |
| src/session.zig | 1     | 544     | JSONL session persistence and resume                                                    |
| src/skills.zig  | 1     | 400     | Markdown-based knowledge injection system                                               |
| src/io.zig      | 1     | 394     | Terminal I/O, scroll region, status bar, spinner                                        |
| src/config/     | 9     | \~1,500 | Layered JSON config system (6-layer priority chain)                                     |
| src/client/     | 4     | \~1,200 | HTTP streaming, SSE parser, message types, chat API                                     |

## The agentic loop (node.zig)

The central abstraction is the **Node** in `src/node.zig` (731 lines). It is the generic agentic loop used by both the REPL and sub-agents:

1. **LLM call** — sends accumulated message history to the provider with streaming enabled
2. **Parse response** — accumulates SSE deltas into content text and tool call fragments
3. **Execute tools** — runs each tool call (parallel in terminal mode, sequential in silent mode)
4. **Append results** — tool results become `tool_result` messages in history
5. **Repeat** — up to the iteration limit, or until no more tool calls

**Parallel tool execution** is a key feature: in terminal mode, tools run in parallel using `std.Thread.spawn` — each tool executes in its own OS thread with a done-flag atomic (`std.atomic.Value(bool)`) tracking completion. In **silent mode** (sub-agents, chain mode), tools run **sequentially** to avoid "threads-inside-threads."

📌

#### Key file

`src/node.zig` — the `Node` struct with `run()` as the main loop entry point, `executeToolsParallel()` for parallel dispatch

## Wyhash loop detection

Zaica implements a sophisticated loop detection system in `src/node.zig` using a **Wyhash-based ring buffer** of tool call signatures (tool name + args hash). It detects repeating patterns of length 1, 2, or 3 within a 10-call window with a **3-tier escalation**:

- **Tier 1** — Warning message to the LLM: "You seem to be repeating the same actions"
- **Tier 2** — Stronger "STOP" warning with explicit instruction to change approach
- **Tier 3** — Force break the loop with a summary instruction

This is significantly more nuanced than simple tool-name deduplication. The same tool called with different arguments or producing different output gets a **different hash**.

## 6 provider support

All providers use the OpenAI-compatible `/chat/completions` endpoint format except Anthropic, which uses the `.anthropic_native` tool format. The wire format enum (`ToolFormat`) is defined in `src/config/types.zig` with three variants: `openai_compatible`, `anthropic_native`, and `gemini_native`.

| Provider          | Base URL          | Default Model              | API Key Env Var      |
| ----------------- | ----------------- | -------------------------- | -------------------- |
| **GLM** (default) | api.z.ai          | glm-4.7-flash              | GLM\_API\_KEY        |
| **Anthropic**     | api.anthropic.com | claude-sonnet-4-5-20250929 | ANTHROPIC\_API\_KEY  |
| **OpenAI**        | api.openai.com    | gpt-4o                     | OPENAI\_API\_KEY     |
| **OpenRouter**    | openrouter.ai     | openrouter/aurora-alpha    | OPENROUTER\_API\_KEY |
| **DeepSeek**      | api.deepseek.com  | deepseek-chat              | DEEPSEEK\_API\_KEY   |
| **Ollama**        | localhost:11434   | llama3                     | (none required)      |

The HTTP client (`src/client/http.zig`, 388 lines) uses Zig 0.15's `std.http.Client` API directly. It **disables compression** (`.accept_encoding = .omit`) because SSE needs a raw byte stream.

The SSE parser (`src/client/sse.zig`, 408 lines) parses each `data: {json}` line and returns a tagged union with variants: `.content`, `.reasoning`, `.tool_call_delta`, `.done` (carrying token usage), and `.api_error`.

## The 7 tools

Zaica ships with exactly 7 tools, each with a declared risk level:

| Tool            | Risk      | Description                                           |
| --------------- | --------- | ----------------------------------------------------- |
| read\_file      | safe      | Read file contents (10 MB limit)                      |
| list\_files     | safe      | List directory entries                                |
| search\_files   | safe      | Grep pattern search (/usr/bin/grep -rn)               |
| write\_file     | write     | Create or overwrite files                             |
| execute\_bash   | dangerous | Run bash commands (configurable timeout, default 30s) |
| dispatch\_agent | dangerous | Spawn a parallel sub-agent for complex subtasks       |
| load\_skill     | safe      | Load a skill's full content on demand                 |

**Tool output truncation** uses a **head/tail strategy** — keeping the first half and last half of the output, with a truncation warning marker in the middle. This aligns with the "Attractor coding-agent-loop-spec." Per-type limits: `read_file` caps at 50,000 chars; `execute_bash` at 30,000 chars / 256 lines.

## 3-tier permission system

Zaica's permission model is elegantly simple:

- **`[y]es all`** — all tools allowed
- `**[s]afe only**` — only read-only tools (`read_file`, `list_files`, `search_files`)
- **`[n]o`** — nothing allowed

The ask happens **once per session**. The `--yolo` / `--dangerously-skip-permissions` CLI flag grants all tools automatically.

**Bash execution** wraps commands in a safety wrapper that: redirects stdin from `/dev/null` (interactive programs get EOF and exit immediately), sets a timer that kills the process tree with `pkill -9 -P $PID` then `kill -9 $PID`, detects SIGKILL (exit code 137) to report timeout, and caps output at 1 MB.

## Chain mode: structured workflows

Chain mode (`src/chain.zig`, 528 lines) is one of zaica's most distinctive features. It allows you to define **multi-step pipelines** in `.chain.md` markdown files with YAML frontmatter:

Each step has: **name**, **prompt** (with `{task}` and `{previous}` variable substitution), optional **tool filter**, and **max\_iterations**.

📌

#### Example: review.chain.md

4 steps: **scout** (read-only tools, 15 iterations) → **planner** (3 iterations) → **coder** (full tools) → **reviewer** (5 iterations). The chain determines the **maximum risk level** across all steps for a single permission prompt.

## Reactive state management (zefx)

Instead of imperative state management, zaica uses a custom **Effector-inspired reactive state machine** (`lib/zefx/`). Events trigger Store reducers, which trigger watchers. This gives a declarative data flow:

`tokens_received` event → `prompt_tokens` / `completion_tokens` stores → `total_tokens` derived store → status bar watcher.

The engine uses a **two-phase flush** (pure reducers first, then effects) ensuring watchers always see consistent state. This is a genuinely novel approach in a coding agent — no other agent in this set uses a reactive state graph for UI state.

## Terminal-level control

Unlike Python agents that rely on libraries like `rich` or `prompt_toolkit`, zaica does **raw `/dev/tty` access** with manual `tcsetattr` for cooked/uncooked/stream modes, manual escape sequence parsing (CSI, CSI u), and direct ioctl for terminal size.

It supports full **UTF-8 and Cyrillic input** including Cyrillic keyboard layout mapping for Ctrl keys. The REPL (`src/repl.zig`, 2,153 lines) implements manual line editing with history — no readline dependency.

## Skills system

Skills are `SKILL.md` files with JSON frontmatter in `.zaica/skills/<name>/` (project-local) or `~/.config/zaica/skills/<name>/` (user-global).

- **"Always-on" skills** are injected directly into the system prompt
- **Other skills** appear as an XML summary that the LLM can load on demand via `load_skill`
- **Skills can declare** required binaries/env vars; missing ones are reported to the LLM

## Session management

Sessions are stored as **JSONL files** in `~/.config/zaica/sessions/<timestamp>.jsonl`. Each line is a typed JSON object: `meta`, `text`, `tool_use`, `tool_result`, or `summary`.

Supports listing, loading, resuming (`-c` / `--continue`), and targeting specific sessions (`--session <id>`).

## 6-layer config system

The config module (`src/config/`, 9 files, \~1,500 lines) implements a **6-layer priority chain**:

1. **Comptime defaults** — hardcoded at compile time
2. **Provider presets** — per-provider default models/settings
3. **`~/.config/zaica/config.json`** — user config
4. **`.zaica.json`** — project-level config
5. **`ZAICA_*` env vars** — environment overrides
6. **CLI flags** — highest priority

API key resolution follows a 4-tier chain: CLI flag → `ZAICA_API_KEY` → `{PROVIDER}_API_KEY` → `~/.config/zaica/auth.json`.

## Unique engineering decisions

### Comptime JSON schemas

Tool parameter schemas are **comptime string literals** — zero allocation, validated at compile time. The request body is hand-written JSON with no serialization library — tool parameters are raw JSON schema strings written directly (not escaped).

### ChatMessage as tagged union

`.text`, `.tool_use`, `.tool_result` — type-safe message history enforced by the Zig compiler. No possibility of a malformed message state at runtime.

### Error-as-string pattern

Tool errors are returned as string descriptions (not Zig error unions) so the LLM can reason about them. `"Error opening /path: error.FileNotFound"` becomes context for the next LLM call.

### Head/tail output truncation

Unlike agents that truncate at a fixed boundary, zaica preserves the beginning and end of large outputs (where the most useful information typically is), with a clear truncation warning in the middle.

### Multi-agent parallel dispatch

The `dispatch_agent` tool spawns sub-agents via `std.Thread.spawn` running independent agentic loops with full tool access — built-in parallelism that most single-threaded Python agents lack.

### Terminal resilience

Forces cooked mode on startup, `\n` → `\r\n` translation regardless of OPOST, manual escape sequence parsing — the terminal works correctly even on unusual configurations.

## Strengths

- **Code quality** — \~9,100 lines with extensive test coverage across all modules
- **Focus** — stays tight on the coding agent experience without feature creep
- **Reactive state graph** — the zefx engine is genuinely novel UI architecture
- **Chain mode** — structured workflows with per-step tool filtering
- **Loop detection** — Wyhash-based 3-tier escalation is the best in this set
- **Terminal craftsmanship** — raw /dev/tty, Cyrillic, manual line editing
- **Parallel sub-agents** — OS-thread-based dispatch for independent agent loops

## Tradeoffs

⚠️

#### Where Zaica gives things up

- **Only 5 core tools** — read\_file, list\_files, search\_files, write\_file, execute\_bash. This is the minimal set for a coding agent, but less than the 16+ tools in Wintermolt or the 40+ in Claude Code.
- **No MCP support** — unlike Wintermolt (and many TypeScript agents), zaica doesn't implement the Model Context Protocol for extending its tool surface.
- **No persistence layer** — sessions are JSONL files, not a SQLite database. No semantic search, no RAG, no cross-session memory beyond the session file itself.
- **GLM is the default provider** — the default model is `glm-4.7-flash` from Z.AI, not one of the more commonly tested models. This is an unusual default.
- **Hardcoded grep path** — `search_files` spawns `/usr/bin/grep` directly, which may not exist on all systems (e.g., BSD grep vs GNU grep paths).
- **Smaller ecosystem** — no chat bridges, no web UI, no menu bar app, no gateway. It's a terminal-only experience.

## Key files to read

📌

#### Core runtime

`src/node.zig` (generic agentic loop, 731 lines), `src/repl.zig` (full REPL, 2,153 lines), `src/tools.zig` (7 tools + permissions, 631 lines), `src/chain.zig` (structured workflows, 528 lines)

#### State and sessions

`src/state.zig` (reactive state graph, 600 lines), `src/session.zig` (JSONL persistence, 544 lines), `src/skills.zig` (knowledge injection, 400 lines), `src/io.zig` (terminal I/O, 394 lines)

#### Config and client

`src/config/` (9 files, layered JSON, \~1,500 lines), `src/client/http.zig` (streaming HTTP, 388 lines), `src/client/sse.zig` (SSE parser, 408 lines), `src/client/message.zig` (ChatMessage union, 316 lines)

#### Reactive engine

`lib/zefx/` (custom reactive state machine, Effector-inspired)

## Verdict

### Best designed, if you value code craftsmanship

Zaica is the most carefully crafted coding agent in the Zig category. At \~9,100 lines, it delivers a complete agentic experience with exceptional attention to terminal control, type safety (tagged unions throughout), and reactive state management.

### Most focused on the coding loop

While Wintermolt goes wide with 7 modes and dozens of features, zaica goes deep on the core loop: chat, tools, chains, skills, sessions. The chain mode with structured workflows is genuinely unique — no other agent in this set offers it.