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: run in 07-event-driven/src/mybot/server/worker.py:17 is 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, and 07-event-driven/src/mybot/provider/web_read/base.py mutually 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.py files (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.py and 10‑websocket/src/mybot/server/channel_worker.py have max indentation depth 7, making control flow hard to follow; guard‑clause refactor is recommended.

How To Use It

StepCommand (from README)
1. Copy configcp default_workspace/config.example.yaml default_workspace/config.user.yaml
2. Edit keysEdit config.user.yaml – add LiteLLM‑compatible model and api_key entries.
3. Install depspip install -e . (or uv pip install -e .) from the repo root; the presence of pyproject.toml indicates pip/uv.
4. Run a stepcd 00-chat-loop && python -m src.mybot.cli.main (the CLI main.py is the entry point for the chat loop).
5. ProgressEach 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

  • HIGHAdd a test suite; evidence: 747 source files, no test files. Any change ships with no signal that existing behaviour still holds.
  • HIGHCommit a lockfile; evidence: 00-chat-loop/pyproject.toml has no lockfile. An unlocked range may ship different transitive code.
  • HIGHAdd a CI workflow; evidence: 747 source files, no CI configuration. Every merge runs untested.
  • MEDIUMEnable Dependabot/Renovate; evidence: 19 manifest(s), no update bot configured.
  • LOWAdd 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.py participate in a circular import.
  • Deep nesting09‑channels/src/mybot/server/channel_worker.py, 09‑channels/src/mybot/server/delivery_worker.py, 10‑websocket/src/mybot/server/channel_worker.py have 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.