[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-93345":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":24,"readmeContent":25,"aiSummary":26,"trendingCount":16,"starSnapshotCount":16,"syncStatus":27,"lastSyncTime":28,"discoverSource":29},93345,"waku-agent","ShenSeanChen\u002Fwaku-agent","ShenSeanChen","Waku Waku! Waku agent is your personal AI agent, on your own laptop, in code you can read in an afternoon — harness + loop + memory + eval","",null,"Python",216,54,1,4,0,28,62.02,"MIT License",false,"main",true,[],"2026-07-22 04:02:08","# waku-agent\n\n**Your own AI assistant. On your laptop. In code you can read in an afternoon.**\n\nMeet **Waku** — a local-first personal assistant that shows the four pillars behind every\nserious agent: **Harness · Loop · Memory · Eval\u002FLLM-Ops**. No frameworks hiding the good parts.\nBuilt for [Sean's AI Stories](https:\u002F\u002Fwww.youtube.com\u002F@SeanAIStories).\n\n- **Local-first.** Your memory is one SQLite file. Open it. Read it. It's yours.\n- **Memory is the hero.** Semantic + episodic + procedural — with a gate that decides *whether*\n  to remember, and a pass that decides *what* to keep.\n- **The loop is ~95 lines** of plain Python. Step through it.\n- **Watch it think.** A local dashboard lights up every message as it flows through the harness.\n- **Eval built in.** Deterministic tests *and* LLM-as-judge, side by side, with a release gate.\n\n![waku-agent architecture — the whiteboard](docs\u002Farchitecture-whiteboard.png)\n\n> The system-design whiteboard from the [Sean's AI Stories](https:\u002F\u002Fwww.youtube.com\u002F@SeanAIStories)\n> series. For the **code-accurate** version (every box → a file it maps to), see\n> [The whiteboard maps to the code](#the-whiteboard-maps-to-the-code) below.\n>\n> **▶ Watch the 20-min code walkthrough:** [You Can Build Your Own Local AI Agent](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=rvRyBhILrls&list=PLE9hy4A7ZTmpGq7GHf5tgGFWh2277AeDR&index=42) — every part of this repo, live: the loop, the memory pillars, the evals, the Telegram gateway, and the \"Waku Waku\" voice wake word.\n>\n> ---\n\n## Watch & follow\n\n- **Video walkthrough:** [You Can Build Your Own Local AI Agent In 20 Min](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=rvRyBhILrls&list=PLE9hy4A7ZTmpGq7GHf5tgGFWh2277AeDR&index=42)\n- **YouTube:** [Sean's AI Stories](https:\u002F\u002Fwww.youtube.com\u002F@SeanAIStories)\n- **X:** [@ShenSeanChen](https:\u002F\u002Fx.com\u002FShenSeanChen)\n- **LinkedIn:** [shen-sean-chen](https:\u002F\u002Flinkedin.com\u002Fin\u002Fshen-sean-chen)\n- **Instagram:** [@sean_ai_stories](https:\u002F\u002Fwww.instagram.com\u002Fsean_ai_stories)\n- **Discord:** [Sean's Discord](https:\u002F\u002Fdiscord.gg\u002FtvECErKcFr) · [AutoManus Discord](https:\u002F\u002Fdiscord.gg\u002F5HhcNjCR)\n\n## Support\n\n- ☕️ **Buy me a coffee:** [Cafe Latte](https:\u002F\u002Fbuy.stripe.com\u002F5kA176bA895ggog4gh)\n- 🚀 **Launch Full-Stack App Template:** [launch-mvp-stripe-nextjs-supabase](https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Flaunch-mvp-stripe-nextjs-supabase) — NextJS + Supabase + Stripe, everything you need to ship a SaaS\n- 💻 **My AI startup:** [AutoManus.io](https:\u002F\u002Fautomanus.io) — an AI sales lead manager for made-to-order product sales. We embed where conversations happen (WhatsApp, email, web chat) to capture inbound, automate follow-ups, and kill CRM busywork. Pre-seed backed by Character VC.\n\n## Quickstart\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Fwaku-agent && cd waku-agent\nuv venv && uv pip install -e .          # create the env + install the `waku` command\ncp .env.example .env                    # pick a provider, paste ONE key\nuv run waku                             # talk to your Waku in the terminal\nuv run waku dashboard                   # …or the browser cockpit → localhost:7777\n```\n\n`uv run waku …` needs **no venv activation**. Three ways to run it:\n\n| Command | When |\n|---|---|\n| `uv run waku dashboard` | quick start, zero activation (recommended) |\n| `source .venv\u002Fbin\u002Factivate` → `waku dashboard` | activate once, bare `waku` all session |\n| `uv tool install .` → `waku dashboard` | install `waku` **globally**, forever |\n\n`waku` and `waku dashboard` are two doors into the **same** Waku. The dashboard is a tiny web\nserver on *your* machine — chat in the browser, that process runs the turn. Nothing leaves your\nlaptop. Set `TELEGRAM_BOT_TOKEN` and it starts your bot too. (`make dashboard` works as well.)\n\n**Now try it.** *\"Remember that Alex prefers morning meetings.\"* Quit. Restart.\n*\"Book a catch-up with Alex on Friday.\"* → it remembers, and books 9am. Your memory is one\nfile: `.waku\u002Fstate.db`.\n\n**Use the model you already pay for.** Anthropic (default), OpenAI, Gemini, DeepSeek, MiniMax,\nKimi, GLM, or OpenRouter (one key, hundreds of hosted models) — set `WAKU_PROVIDER=`, paste the key,\ndone. One dialect in the loop; a [~60-line adapter](waku\u002Floop\u002Fmodels.py) handles the rest.\n\n## Watch the harness run — the dashboard\n\n```bash\nwaku dashboard          # starts a local server → http:\u002F\u002Flocalhost:7777\n```\n\nA small web server you own (`127.0.0.1`, no cloud). The browser is just the UI — the same\nprocess runs every turn. This is the fastest way to *get* the system.\n\nA chat dock sits on every tab. Type or **speak**, and watch it flow through the harness on the\nOverview diagram: gate lights up → loop calls a tool → reply comes back → memory updates. The\nfrontend is plain static files. No build step.\n\nEach tab is one pillar, linked to the real files:\n\n| Tab | What you see |\n|---|---|\n| **Overview** | cost, latency, the gate skip\u002Fretrieve split, the clickable architecture map |\n| **Gateway** | one conversation across every channel, each message tagged by source (dashboard \u002F telegram \u002F voice \u002F cli) |\n| **Loop** | every turn with its gate decision, tool calls, tokens, and cost |\n| **Memory** | sub-tabs per pillar — semantic facts, episodes, editable skills + SOUL, consolidation |\n| **Tools** | the agent's available tools (grouped by origin), its results, and MCP connectors |\n| **Data** | a live SQLite browser: per-table tabs, schema, and a read-only SQL console over `state.db` |\n| **Ops** | eval verdict + history, the gate decisions, slowest turns, and inline JSONL traces |\n\nThe sidebar and chat dock are drag-resizable and hideable, and the chat has *New chat* +\nhistory like any chat app.\n\n## Things to try (each shows off a pillar)\n\nType these in the chat dock (or `make run`) and watch the dashboard light up:\n\n| Try this | What it shows | Where to watch |\n|---|---|---|\n| *\"Schedule a tennis game with Raj this Saturday at 8am\"* | the Loop calls a tool (`create_event`) | the **LOOP** box pulses; **Loop** tab shows `iter 2` |\n| *\"What's on my calendar today?\"* | reading the calendar (`list_events`) | it answers from `state.db`, no made-up events |\n| *\"When am I swimming with Sergey?\"* then *\"what's 12 × 8?\"* | the **retrieval gate** — retrieve vs skip | Overview gate bar; **Ops** shows the per-turn decision |\n| *\"Remember that Raj prefers evening games\"* | memory self-management (`save_note`) | **Memory ▸ Semantic** gains a fact; `MEMORY.md` updates |\n| *\"Search for the World Cup games still left to play and add each one to my calendar\"* | **multi-tool loop engineering** | **Loop** tab shows `iter 8`: `search_web` × N → `create_event` × N |\n| chat from `make run` **and** the browser | one brain, many gateways | the **Gateway** tab tags each message `cli` \u002F `dashboard` |\n\n**The money shot** is the World Cup one. In one turn, Waku searches the web a few times, reasons\nover the results, and books every remaining match — **8 loop iterations**, live. Needs a free\n`TAVILY_API_KEY` (paste it in **Settings**). Watch the **LOOP** box pulse per cycle. That's loop\nengineering, on tape.\n\n## How is this different from ChatGPT \u002F Claude Desktop?\n\nThose are products you *use*. This is a codebase you *own* — the loop, the memory schema, the\ngate, the eval harness, all yours to read and change. Understand this repo, and you understand\nwhat the products do under the hood.\n\nVersus the big open-source assistants (OpenClaw, Hermes)? Same architecture, 1\u002F100th the code.\nProducts vs. a readable blueprint.\n\n## The whiteboard gallery — editable system-design charts\n\nEvery whiteboard from the videos lives in [`docs\u002Fwhiteboards\u002F`](docs\u002Fwhiteboards) as an\n**editable `.excalidraw` source** — download one, drop it on [excalidraw.com](https:\u002F\u002Fexcalidraw.com),\nand remix it for your own team:\n\n| Chart | What it explains |\n|---|---|\n| [`k3-architecture.excalidraw`](docs\u002Fwhiteboards\u002Fk3-architecture.excalidraw) | Kimi K3: the 16-of-896 MoE, KDA + AttnRes attention, why agent loops get cheap |\n| [`pi-architecture.excalidraw`](docs\u002Fwhiteboards\u002Fpi-architecture.excalidraw) | pi (72K-star coding agent): 4-tool core, extensions, one EventStream |\n| [`architecture-whiteboard.png`](docs\u002Farchitecture-whiteboard.png) | Waku itself — the chart this whole repo implements |\n\nNew charts land here with every video. If they help you,\n[a star](https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Fwaku-agent) keeps them coming — and\n[sponsoring](https:\u002F\u002Fgithub.com\u002Fsponsors\u002FShenSeanChen) gets new whiteboards early.\n\n## The whiteboard maps to the code\n\nThis diagram renders straight from the README (it's [Mermaid](https:\u002F\u002Fmermaid.js.org\u002F) text, not an\nimage — edit it in a PR):\n\n```mermaid\nflowchart LR\n  GW[\"Gateway\u003Cbr\u002F>cli · telegram · voice · dashboard\"] --> WM[\"Working memory\u003Cbr\u002F>SOUL.md + memory + history\"]\n  WM --> LLM\n  subgraph LOOP[\"The Loop — loop\u002Fagent.py\"]\n    LLM[\"LLM\"] -->|tool call| TOOLS[\"Tools\u003Cbr\u002F>create_event · list_events\u003Cbr\u002F>search_web · save_note · …\"]\n    TOOLS -->|result| LLM\n  end\n  LLM -->|reply| REPLY[\"Reply\"] --> GW\n  GATE{{\"Retrieval gate\u003Cbr\u002F>does this turn need memory?\"}} -. only if needed .-> WM\n  MEM[(\"Memory — state.db\u003Cbr\u002F>SQLite + FTS5\u003Cbr\u002F>semantic · episodic · procedural\")] --> GATE\n  REPLY -. save chat .-> MEM\n  MEM -->|every N chats| CONS[\"Consolidate → facts\"] --> MEM\n  REPLY --> OPS[\"LLM Ops\u003Cbr\u002F>trace → eval → gate → release\"]\n  OPS -. improved prompt\u002Fconfig .-> WM\n  WM -.- WATERMARK[\"waku-agent · Sean's AI Stories · @ShenSeanChen\"]:::wm\n  classDef wm fill:none,stroke:none,color:#9aa0aa,font-size:11px;\n```\n\n> _Architecture of **waku-agent** — built on [Sean's AI Stories](https:\u002F\u002Fwww.youtube.com\u002F@SeanAIStories)\n> ([@ShenSeanChen](https:\u002F\u002Fgithub.com\u002FShenSeanChen)). Code is MIT; **this diagram is licensed CC BY-NC-SA 4.0** —\n> reuse it with credit to the channel, not for commercial resale._\n\nEvery box is one module (full version with every file path: [docs\u002Farchitecture.md](docs\u002Farchitecture.md)):\n\n| Diagram box | Module |\n|---|---|\n| Gateway Interface (CLI \u002F voice \u002F Telegram \u002F web) | [`waku\u002Fgateway\u002F`](waku\u002Fgateway) |\n| Ephemeral Agent Run → Working Memory | [`waku\u002Fruntime\u002Fsession.py`](waku\u002Fruntime\u002Fsession.py) |\n| The Loop (LLM ↔ tools, end-loop guardrails) | [`waku\u002Floop\u002Fagent.py`](waku\u002Floop\u002Fagent.py) |\n| Agentic Tools (schedule \u002F note \u002F message) | [`waku\u002Ftools\u002F`](waku\u002Ftools) |\n| Procedural Memory (SKILL.md, \"how to act\") | [`waku\u002Fmemory\u002Fprocedural\u002F`](waku\u002Fmemory\u002Fprocedural) + [`skills\u002F`](skills) |\n| Semantic Memory (durable facts, profile) | [`waku\u002Fmemory\u002Fsemantic\u002F`](waku\u002Fmemory\u002Fsemantic) |\n| Episodic Memory (dated events, past chats) | [`waku\u002Fmemory\u002Fepisodic\u002F`](waku\u002Fmemory\u002Fepisodic) |\n| \"Should we even retrieve?\" gate | [`waku\u002Fmemory\u002Fretrieval_gate.py`](waku\u002Fmemory\u002Fretrieval_gate.py) |\n| Consolidate after N chats → summarizer | [`waku\u002Fmemory\u002Fconsolidation.py`](waku\u002Fmemory\u002Fconsolidation.py) |\n| Trace (1 trace per run) | [`waku\u002Fops\u002Ftracing.py`](waku\u002Fops\u002Ftracing.py) |\n| Eval: deterministic vs LLM-as-judge | [`evals\u002Fdeterministic\u002F`](evals\u002Fdeterministic) vs [`evals\u002Fjudge\u002F`](evals\u002Fjudge) |\n| Gate → Release | [`waku\u002Fops\u002Frelease_gate.py`](waku\u002Fops\u002Frelease_gate.py) |\n\n**A note on `MEMORY.md` vs `state.db`.** Some assistants (e.g. Hermes) keep long-term memory as a\nsingle `MEMORY.md` markdown file. Waku keeps the *queryable* source in `state.db` (the `facts` and\n`episodes` tables, keyword-searchable via FTS5) **and** regenerates a human-readable\n`.waku\u002FMEMORY.md` mirror after every turn — so you get both: a real file you can open, backed by a\nsturdy database. The dashboard's **Memory** tab is the friendly view; the **Database** tab shows the\nraw `state.db` tables.\n\n## The Loop — reason → act → repeat\n\nYes, there's a real agent loop, and it's [~95 lines of plain Python](waku\u002Floop\u002Fagent.py) —\nno LangGraph, no hidden control flow:\n\n```\nwhile not done:\n    response = llm(messages, tools)      # reason\n    if response wants tools:\n        results = run(tool_calls)        # act\n        messages += results              # observe\n    else:\n        done                             # reply to the human\n```\n\nTwo guardrails end every turn: the model stops asking for tools (natural end), or it hits\n`max_iterations` (hard stop — it never spins forever). That's \"loop engineering\": the exit\nconditions, the tool round-trip, and feeding results back as working memory.\n\n**How to show it on camera:**\n1. Type *\"schedule a swim with Sergey Saturday at 5pm\"* in the chat dock and watch the **LOOP**\n   box on the Overview diagram light up: reason → `create_event` → reason → reply.\n2. Open the **Loop** tab — every turn is listed with its gate decision, each tool call, the\n   **iteration count**, tokens, and dollar cost. A tool-using turn shows `iter 2` (reason,\n   act, then reason again to reply); a plain answer shows `iter 1`.\n3. Open the **Ops** tab (or `.waku\u002Ftraces\u002F\u003Ctoday>.jsonl`) to read that same turn as raw\n   events in order: `turn_start → gate → llm → tool → llm → turn_end`. That's the loop, on tape.\n\n**The multi-tool loop (the money shot).** One tool is a loop; *chaining* tools is where loop\nengineering earns its name. Try:\n\n> *\"Search for the World Cup games still left to play and add each one to my calendar.\"*\n\nThe agent loops across two tools: [`search_web`](waku\u002Ftools\u002Fsearch.py) reads the web, it\nreasons over the results, then calls [`create_event`](waku\u002Ftools\u002Fcalendar.py) once per match —\nseveral iterations in a single turn. You'll see `iter 4`, `iter 5`… on the Loop tab and the\nLOOP box pulse for each cycle. `search_web` works keyless via DuckDuckGo but that endpoint\nrate-limits bots, so for a clean take set a free `TAVILY_API_KEY` (see [`.env.example`](.env.example)).\n\n## The two hero moments\n\n**1. The retrieval gate.** Most agents hit their memory store on every turn. That's\nslow, and worse — irrelevant memories bias answers. Here a cheap model first answers\none question: *does this message need memory at all?* Watch it in the terminal:\n\n```\nyou > what's 2+2?\n  gate · skip — pure math\nyou > when am I meeting Alex?\n  gate · retrieve — references user's plans\n```\n\n**2. Deterministic eval vs LLM-as-judge.** *\"Did it create the right calendar event?\"*\nis a unit test — 0 or 1, no model judges it (`make eval`). *\"Was the reply helpful?\"*\nis a judged score with a threshold (`make eval-judge`). Conflating the two is the most\ncommon eval mistake; here they're separate suites you can diff. `make gate` runs both\nas a release gate.\n\n## Eval, tracing & catching bugs\n\nThree commands, two kinds of eval — the LLM-Ops half of the system:\n\n```bash\nmake eval          # deterministic: \"did the right tool fire?\" — 0 or 1, no model judges it\nmake eval-judge    # LLM-as-judge: \"was the reply helpful?\" — a scored %, needs a key\nmake gate          # the release gate: deterministic must pass 100%, judge must clear threshold\n```\n\nDeterministic tests are plain pytest in [`evals\u002Fdeterministic\u002F`](evals\u002Fdeterministic); judged\nones use DeepEval in [`evals\u002Fjudge\u002F`](evals\u002Fjudge). Keeping them apart is the whole point —\nconflating \"did it do the thing\" (a unit test) with \"was it any good\" (a scored judgement) is\nthe most common eval mistake.\n\n**Where the results show:** the terminal, and the dashboard's **Ops** tab — the release-gate\nverdict, an **eval-history** table (one row per `make gate`, so you can see it grow), the actual\nper-turn gate decisions, and the raw traces inline.\n\n**The bug workflow (this is the discipline you show on camera):** when you catch a bug by using\nthe thing live, you fix it AND add a deterministic case so it can never come back. A real example\nfrom this repo: the agent didn't know the current *time* and asked for it before scheduling\n\"in 30 minutes\" → fixed in [`session.py`](waku\u002Fruntime\u002Fsession.py), locked forever by\n[`test_working_memory.py`](evals\u002Fdeterministic\u002Ftest_working_memory.py). Run `make gate` → green →\nthe eval history records the run.\n\n**Spend is permanent:** every LLM call's tokens are appended to `.waku\u002Fusage.jsonl` — an\nappend-only ledger that a demo reset never wipes. The **Ops** tab shows the all-time cost, tokens,\nand a per-day \u002F per-provider breakdown (dollar cost is estimated from tokens, which are the ground\ntruth). So the number you show on camera is your real running total, not a per-session guess.\n\n**Tracing is always on:** every turn appends readable lines to `.waku\u002Ftraces\u002F\u003Cdate>.jsonl`\n(zero setup) — a trace is just \"what happened, in order.\" For span-waterfall views:\n\n```bash\npip install -e '.[tracing]'\nmake trace                                            # Phoenix at localhost:6006\nOTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Flocalhost:4317 make run\n```\n\nLangfuse cloud speaks the same OTel toggle.\n\n## Recording a clean demo\n\n```bash\npython scripts\u002Fdemo_seed.py --yes      # resets .waku to a tidy, curated state (--yes required)\n```\n\nIt backs up your current `.waku` first, then seeds a few clean facts, one episode, and one\nevent — Sergey's standing **Saturday 5 PM swim**. The chat log and traces start **empty**, so\nwhen you type live the Loop, traces, and Gateway inbox fill up in front of the viewer. The\nmemory\u002FData\u002FTools tabs already have tidy content to explain. Edit the seed lists at the top of\nthe script to taste.\n\n## Talk to it\n\n```bash\nuv pip install -e '.[voice]'\nwaku voice        # hands-free: always-listening for \"waku waku\"\n```\n\n**Hands-free by default.** `waku voice` listens for the wake word **\"waku waku\"** — a tiny\nWhisper model scans the mic; when it hears the phrase, the big model takes over for your\ncommand and speaks the reply. Change or disable it:\n\n```bash\nWAKU_WAKE_WORD=\"hey waku\"  waku voice     # any phrase, no training\nWAKU_WAKE_WORD=\"\"          waku voice     # push-to-talk instead (Enter, speak, Enter)\n```\n\nThe matcher is ~15 transparent lines with a deterministic eval; it accepts cross-script\nvariants (`\"waku waku,わくわく\"`). A trained openWakeWord model is the efficient v2 upgrade.\n\n**A beautiful voice.** Out of the box it uses macOS `say` — and Waku auto-picks the nicest\nvoice you have, preferring a downloaded Premium\u002FEnhanced one (System Settings ▸ Accessibility\n▸ Spoken Content ▸ System Voice) over the robotic built-ins. For the real neural upgrade,\ninstall [Kokoro](https:\u002F\u002Fgithub.com\u002Fhexgrad\u002Fkokoro) — a fully local, offline British-butler\nvoice that's picked up automatically, no env var needed:\n\n```bash\nuv pip install '.[voice-neural]'          # neural Kokoro (bm_george); pulls torch (~2GB)\n```\n\nOverride either engine with `WAKU_VOICE` (a `say` voice name, or a Kokoro voice like `bf_emma`).\n\n## Phone to laptop\n\n```bash\npip install -e '.[telegram]'\n# message @BotFather, \u002Fnewbot, put the token in .env, then:\nmake telegram\n```\n\nText your bot from anywhere and your laptop runs the turn — long-polling, so no\npublic URL or webhook. Set `TELEGRAM_ALLOWED_USER` to lock it to just you.\n\n## Brief me on my week (Apple Calendar + Mail)\n\n```bash\nWAKU_APPLE_TOOLS=1 make brief      # macOS; grant the permission prompts once\n```\n\nWaku reads your **real** Calendar.app (including events invited by email) and\nrecent Apple Mail, cross-references your memory, and writes a focus-first briefing\nwith clickable `message:\u002F\u002F` links. Cron it for a morning greeting:\n\n```\n30 7 * * *  cd ~\u002Fwaku-agent && make brief\n```\n\nIt runs through the normal harness, so it animates on the dashboard like any turn.\n\n## It manages its own memory\n\nThe agent has tools to keep itself useful — no black box:\n- **manage_memory** — correct or forget a fact when you say it's wrong.\n- **update_soul** — save a standing preference you give it (lives in `SOUL.md`).\n- **create_skill** — when you teach it a repeatable workflow, it offers to save it\n  as a skill (written to `.waku\u002Fskills\u002F`, live the same session).\n\nYou can also edit any of this by hand on the dashboard's Memory tab (edit\u002Fdelete\nfacts, rewrite `SOUL.md`) or in Settings (switch provider\u002Fmodel, paste keys — BYOK,\nkept in your local `.env`, never sent to the browser).\n\n## Connect MCP servers\n\n```bash\npip install -e '.[mcp]'\n```\n\nCreate `.waku\u002Fmcp.json` and any Model Context Protocol server's tools appear to\nthe agent, namespaced `\u003Cserver>_\u003Ctool>` (and in the dashboard's Tools ▸ MCP tab):\n\n```json\n{\"servers\": [{\"name\": \"fs\", \"command\": \"npx\",\n  \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-filesystem\", \"\u002Ftmp\"]}]}\n```\n\n**Node-free demo** — a tiny self-contained Python MCP server ships in the repo:\n\n```bash\ncp examples\u002Fmcp.demo.json .waku\u002Fmcp.json   # points at examples\u002Fmcp_demo_server.py\nmake dashboard                               # demo_word_count \u002F demo_reverse_text appear in Tools\n```\n\nSame pattern scales to any server, yours or a vendor's — no changes to Waku's code.\n\n## Add skills — yours or the community's\n\nSkills are procedural memory: markdown instructions loaded only when relevant.\n\n```bash\npython -m waku skill install https:\u002F\u002Fgithub.com\u002F\u003Csomeone>\u002F\u003Crepo>\u002Fblob\u002Fmain\u002Fskills\u002F\u003Cskill>\u002FSKILL.md\n```\n\n**Contribute one — it's just a markdown file.** Copy [`skills\u002FTEMPLATE.md`](skills\u002FTEMPLATE.md),\nPR it into [`skills\u002Fcommunity\u002F`](skills\u002Fcommunity). CI validates the frontmatter.\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Every command\n\nThe `waku` command is installed with the package; the `make` targets are equivalent aliases.\n\n| Command | Does |\n|---|---|\n| `waku` | chat in the terminal |\n| `waku dashboard` | the live cockpit at localhost:7777 (+ Telegram if `TELEGRAM_BOT_TOKEN` is set) |\n| `waku voice` | talk to it — hands-free \"waku waku\" (or push-to-talk) |\n| `waku telegram` | message it from your phone (standalone) |\n| `waku brief` | morning briefing from Calendar + Mail + memory |\n| `make trace` | deep trace waterfalls (Phoenix) at localhost:6006 |\n| `make eval` | deterministic evals (0\u002F1, no judge) |\n| `make eval-judge` | LLM-as-judge evals (scored %) |\n| `make gate` | the release gate — both eval suites must pass |\n\n## Roadmap — the whiteboard boxes beyond the flagship task\n\nThese live in [`waku\u002Ftools\u002Fexperimental.py`](waku\u002Ftools\u002Fexperimental.py), OFF by default —\n`WAKU_EXPERIMENTAL=1` registers them.\n\n**Sub-Agents is now LIVE.** `delegate_task` hands a coding job to\n[pi](https:\u002F\u002Fgithub.com\u002Fearendil-works\u002Fpi) — Mario Zechner's minimal open-source coding agent —\nthrough its headless print mode (`pi -p \"task\"`). Waku stays the orchestrator (memory, context,\nevals); pi is the specialist contractor (read\u002Fbash\u002Fedit\u002Fwrite). Try it:\n\n```bash\nnpm install -g --ignore-scripts @earendil-works\u002Fpi-coding-agent\nWAKU_EXPERIMENTAL=1 uv run waku\n# \"have pi fix the failing test in ~\u002Fmy-project\"\n```\n\nThe full pi transcript lands in `.waku\u002Foutbox\u002Fdelegate-*.log`; tune the budget with\n`WAKU_DELEGATE_TIMEOUT` (default 300s).\n\nThe rest are still deliberate **skeletons** — the intent is drawn so the diagram maps to\nsomething, but nothing is over-promised (they report \"coming soon\", and the dashboard's\n**Tools** tab lists them under **Coming soon**):\n\n| Whiteboard box | Tool | Status |\n|---|---|---|\n| Sub-Agents | `delegate_task` | **live** — delegates coding tasks to pi |\n| Terminal tool | `run_command` | skeleton — needs a real sandbox + safety surface first |\n| Browser tool | `browse_web` | skeleton — `search_web` already covers read-only lookups |\n| Cron Job | `schedule_task` | skeleton — `make brief` + a system cron line covers it today |\n\nThe point of a teaching repo is a readable core; these come alive one at a time, tested.\n\n## Upgrade paths (when you outgrow the defaults)\n\n| Default (zero setup) | Upgrade | How |\n|---|---|---|\n| SQLite FTS5 keyword memory | Supabase pgvector semantic search | `WAKU_SEMANTIC_STORE=supabase` + [sql\u002Finit_supabase.sql](sql\u002Finit_supabase.sql) — the exact schema from [launch-rag](https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Flaunch-rag)\u002F[launch-agentic-rag](https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Flaunch-agentic-rag) |\n| Mock calendar (ICS + SQLite) | Apple \u002F Google Calendar | `WAKU_APPLE_CALENDAR=1` (macOS), or swap `waku\u002Ftools\u002Fcalendar.py` — the tool schema stays |\n| Hand-built memory pillars | mem0 \u002F Letta \u002F Zep | production frameworks that automate what this repo teaches |\n\n## Related repos (the building blocks)\n\n[launch-rag](https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Flaunch-rag) ·\n[launch-agentic-rag](https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Flaunch-agentic-rag) ·\n[launch-agent-skills](https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Flaunch-agent-skills) ·\n[launch-mcp-demo](https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Flaunch-mcp-demo) ·\n[launch-DeepResearch-Backend](https:\u002F\u002Fgithub.com\u002FShenSeanChen\u002Flaunch-DeepResearch-Backend)\n\n## Community\n\nStar the repo, join the [Discord](https:\u002F\u002Fdiscord.gg\u002F7Ntxzm3eJ), and grab a\n[good first issue](docs\u002Fgood-first-issues.md) — gateway adapters (WhatsApp, Discord),\nmemory backends, and community skills are all designed to be first PRs.\n\nMIT — see [LICENSE](LICENSE). Built by [@ShenSeanChen](https:\u002F\u002Fgithub.com\u002FShenSeanChen)\n([YouTube](https:\u002F\u002Fwww.youtube.com\u002F@SeanAIStories) · [X](https:\u002F\u002Fx.com\u002FShenSeanChen)).\n","Waku-agent 是一个轻量级、本地运行的个人AI智能体框架，专为可理解性与教学示范设计。它以约95行核心Python代码实现完整Agent循环，集成语义\u002F情景\u002F程序记忆（SQLite本地存储）、实时交互监控看板、内置确定性测试与LLM评估机制。项目强调透明性——所有组件一一对应白板架构图，内存结构开放可查，无黑盒框架封装。适用于AI学习者理解Agent基础原理、本地私有化AI助手开发、或作为教学\u002F原型验证的最小可行Agent基座。",2,"2026-07-17 02:30:03","CREATED_QUERY"]