The Problem
Building an AI agent from scratch quickly becomes repetitive: the same chat‑loop logic, tool‑registration, and persistence boiler‑plate appear in every step. The repository bundles 18 progressive tutorials, but the duplicated code and missing test/ CI infrastructure make it hard to trust that changes in one step won’t break another.
What This Does
The repo is a step‑by‑step tutorial (18 steps, labelled 00‑chat_loop through 17‑memory) that teaches how to build a minimal OpenClaw‑style agent.
- Phase 1 (steps 0‑6) adds tools, skills, persistence, slash‑commands, compaction, and web‑search.
- Phase 2 (steps 7‑10) refactors to an event‑driven architecture, adds hot‑reload, channels, and a WebSocket endpoint.
- Phase 3 (steps 11‑15) introduces cron‑heartbeat, multi‑layer prompts, post‑message back, and multi‑agent dispatch/routing.
- Phase 4 (steps 16‑17) tackles concurrency control and long‑term memory.
Each step lives in its own sub‑directory (e.g. 00-chat-loop/, 01-tools/, …) with its own pyproject.toml and a small runnable code base. The top‑level README lists a reference implementation pickle‑bot and instructions for copying default_workspace/config.example.yaml into config.user.yaml to supply API keys.
How It Is Wired
- Entry point:
runin07-event-driven/src/mybot/server/worker.py:17is the sole top‑level start function; it reaches 118 other functions and is called from nowhere else in the repo. - Call graph highlights:
new_session– called from 8 places (e.g.chat → chat_command → setup_logging).publish– called from 8 places, feeds the event bus (07-event-driven/src/mybot/core/eventbus.py).set_runtime– called from 7 places, configures the LLM provider.Agent– called from 7 places, the core agent class (00-chat-loop/src/mybot/core/agent.py).tool– called from 6 places, registers builtin tools (01-tools/src/mybot/tools/base.py).- Key files that route the most traffic:
03-persistence/src/mybot/core/history.py– reads/writes conversation history, called from 7 other files.08-config-hot-reload/src/mybot/utils/config.py– loads & merges config, 15 functions, 6 classes.12-cron-heartbeat/src/mybot/core/events.py– defines the event bus subtypes (is_cron,is_agent, …).- Import cycle (high/soundness):
06-web-tools/src/mybot/provider/web_read/base.py,06-web-tools/src/mybot/provider/web_search/base.py, and07-event-driven/src/mybot/provider/web_read/base.pymutually import each other, breaking a clean dependency order. - Duplicated code (high/clarity): 4 217 repeated 6‑line blocks across 590 files, mainly in the
*‑chat.pyfiles (00‑chat-loop/…,01‑tools/…,02‑skills/…,03‑persistence/…). The fix is to extract shared helpers and DRY the logic. - Deep nesting (medium/cognitive_load):
09-channels/src/mybot/server/channel_worker.pyand10‑websocket/src/mybot/server/channel_worker.pyhave max indentation depth 7, making control flow hard to follow; guard‑clause refactor is recommended.
How To Use It
| Step | Command (from README) |
|---|---|
| 1. Copy config | cp default_workspace/config.example.yaml default_workspace/config.user.yaml |
| 2. Edit keys | Edit config.user.yaml – add LiteLLM‑compatible model and api_key entries. |
| 3. Install deps | pip install -e . (or uv pip install -e .) from the repo root; the presence of pyproject.toml indicates pip/uv. |
| 4. Run a step | cd 00-chat-loop && python -m src.mybot.cli.main (the CLI main.py is the entry point for the chat loop). |
| 5. Progress | Each subsequent step adds its own main.py; e.g. cd 01-tools && python -m src.mybot.cli.main to see the tool‑augmented agent. |
No Dockerfile or Makefile is present, so a local Python environment is the intended deployment model.
Real‑World Use
A product team could start at step 03‑persistence to prototype an agent that logs every user turn to a local SQLite file (history.py). Adding step 06‑web‑tools lets the agent fetch live web search results via web_search and web_read providers, demonstrating a lightweight “assistant‑plus‑internet” workflow. When the team outgrows a single process, they can migrate to step 12‑cron‑heartbeat for scheduled background tasks or step 15‑agent‑dispatch to split work across specialized agents.
Code Health & Issues
- HIGH – Add a test suite; evidence: 747 source files, no test files. Any change ships with no signal that existing behaviour still holds.
- HIGH – Commit a lockfile; evidence:
00-chat-loop/pyproject.tomlhas no lockfile. An unlocked range may ship different transitive code. - HIGH – Add a CI workflow; evidence: 747 source files, no CI configuration. Every merge runs untested.
- MEDIUM – Enable Dependabot/Renovate; evidence: 19 manifest(s), no update bot configured.
- LOW – Add convention files; evidence: missing
.editorconfig,.gitattributes, formatter config.
Measured static‑analysis findings (from the pipeline):
- Duplicated code blocks – 4 217 repeated 6‑line blocks across 590 files (files:
00‑chat-loop/src/mybot/cli/chat.py,01‑tools/…,02‑skills/…,03‑persistence/…). - Import cycle – modules
06‑web-tools/src/mybot/provider/web_read/base.py,06‑web-tools/src/mybot/provider/web_search/base.py,07‑event-driven/src/mybot/provider/web_read/base.pyparticipate in a circular import. - Deep nesting –
09‑channels/src/mybot/server/channel_worker.py,09‑channels/src/mybot/server/delivery_worker.py,10‑websocket/src/mybot/server/channel_worker.pyhave max indentation depth 7.
The Bottom Line
This repo is a valuable, well‑structured tutorial for anyone wanting to understand the incremental building blocks of a capable AI agent. The step‑wise layout, clear README, and reference implementation make it easy to follow and experiment. However, the absence of tests, CI, and a lockfile means production use demands you add those safeguards yourself. It’s best suited for learning, prototyping, or as a sandbox for custom agent extensions rather than as a ready‑to‑ship product.