The Problem
Building a personal AI agent typically means either fighting heavyweight frameworks that obscure the core loop, or gluing together scattered scripts with no memory, no evals, and no way to verify changes. You end up with a black box you cannot debug or trust.
What This Does
waku-agent is a local-first personal assistant built on four explicit pillars: Harness · Loop · Memory · Eval. The core agent loop lives in about 95 lines of plain Python in waku/loop/. Memory is a single SQLite file (.waku/state.db) with semantic, episodic, and procedural stores, gated by a retrieval pass in waku/memory/retrieval_gate.py. A local dashboard in waku/ops/dashboard.py (1,211 lines) visualizes every message as it flows through the system. Evals live in evals/, with both deterministic tests (evals/deterministic/) and an LLM-as-judge setup in evals/judge/.
How It Is Wired
Execution starts at main in waku/__main__.py, which reaches 82 functions. The CLI routes into respond in waku/app.py, the central turn handler called from 20 places. From there, the loop calls waku/loop/models.py for inference, which routes through load_settings (called from 28 places) and make_waku (called from 27 places) — the two highest-blast-radius functions.
The memory path is concrete: handle in waku/gateway/telegram.py → respond → export_markdown, which writes to MEMORY.md and executes a SQL SELECT against the SQLite DB. The dashboard's chat function in waku/ops/dashboard.py manages sessions and calls _get_agent, which touches the database, filesystem, external commands, and the network.
waku/config.py is the module hub — 21 modules depend on it, none of which it imports. It is stable but any churn there ripples widely. The import graph shows zero circular dependencies across 85 modules, which is clean for a codebase this size.
How To Use It
git clone https://github.com/moses-y/waku-agent && cd waku-agent
uv venv && uv pip install -e .
cp .env.example .env
uv run waku
Configuration lives in .env — pick one provider key (Anthropic, OpenAI, Gemini, DeepSeek). Run uv run waku dashboard for the browser UI at localhost:7777, or set TELEGRAM_BOT_TOKEN to enable the Telegram gateway.
Real-World Use
A personal research assistant that remembers context across sessions. Say: "Remember that Alex prefers morning meetings." Quit, restart, then: "Book a catch-up with Alex on Friday." It retrieves the preference from the SQLite memory store and books the slot via the calendar tool in waku/tools/calendar.py, which syncs to Apple Calendar.
Code Health & Issues
Static analysis found 46 issues (14 high, 32 medium) across 7 kinds. The notable ones:
- High - cognitive load -
waku/ops/dashboard.pyat 1,211 lines with max indentation depth of 9;waku/app.pyandwaku/loop/models.pyhave deep nesting. Flatten with guard clauses. - Medium - broad exception handling -
waku/ops/dashboard.py,waku/gateway/voice.py,waku/loop/agent.pycatchExceptionindiscriminately. - Medium - hub module -
waku/config.pyhas 21 dependents; keep it stable and small. - Medium - empty catch blocks - three JS files (
compare.js,main.js,render.js) silently discard errors. - Medium - file handle leak -
waku/memory/retrieval_gate.pyusesopen()without a context manager.
SDLC gaps: no lockfile (pyproject.toml declares openai >=1.50 and rich >=13.0, both 2 majors behind), no Dependabot, no dependency vulnerability scan in CI, and validate-skills.yml does not declare least-privilege GITHUB_TOKEN permissions. Tests and CI are present; no committed secrets found.
The Bottom Line
A genuinely readable agent architecture — the loop, memory pillars, and eval harness are all inspectable in an afternoon. The dashboard is overgrown and the dependency hygiene needs attention before production use. Ideal for engineers learning agent internals or building a local-first assistant they can trust and modify.