waku-agent 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. waku_agent-0.1.0/.env.example +192 -0
  2. waku_agent-0.1.0/.gitignore +31 -0
  3. waku_agent-0.1.0/CLAUDE.md +68 -0
  4. waku_agent-0.1.0/CODE_OF_CONDUCT.md +44 -0
  5. waku_agent-0.1.0/CONTRIBUTING.md +113 -0
  6. waku_agent-0.1.0/LICENSE +21 -0
  7. waku_agent-0.1.0/Makefile +56 -0
  8. waku_agent-0.1.0/PKG-INFO +576 -0
  9. waku_agent-0.1.0/README.md +516 -0
  10. waku_agent-0.1.0/SECURITY.md +43 -0
  11. waku_agent-0.1.0/evals/__init__.py +0 -0
  12. waku_agent-0.1.0/evals/coding.jsonl +2 -0
  13. waku_agent-0.1.0/evals/conftest.py +6 -0
  14. waku_agent-0.1.0/evals/dataset.jsonl +11 -0
  15. waku_agent-0.1.0/evals/deterministic/test_all_history.py +63 -0
  16. waku_agent-0.1.0/evals/deterministic/test_apple_calendar.py +44 -0
  17. waku_agent-0.1.0/evals/deterministic/test_apple_tools.py +129 -0
  18. waku_agent-0.1.0/evals/deterministic/test_browser_agent.py +71 -0
  19. waku_agent-0.1.0/evals/deterministic/test_cli_memory.py +52 -0
  20. waku_agent-0.1.0/evals/deterministic/test_coding_eval.py +95 -0
  21. waku_agent-0.1.0/evals/deterministic/test_compare_history.py +74 -0
  22. waku_agent-0.1.0/evals/deterministic/test_consolidation.py +237 -0
  23. waku_agent-0.1.0/evals/deterministic/test_dashboard_routes.py +107 -0
  24. waku_agent-0.1.0/evals/deterministic/test_delegate.py +214 -0
  25. waku_agent-0.1.0/evals/deterministic/test_discord_access.py +126 -0
  26. waku_agent-0.1.0/evals/deterministic/test_episodic_store_switch.py +299 -0
  27. waku_agent-0.1.0/evals/deterministic/test_experimental_toggle.py +73 -0
  28. waku_agent-0.1.0/evals/deterministic/test_gcal_oauth.py +207 -0
  29. waku_agent-0.1.0/evals/deterministic/test_google_calendar.py +211 -0
  30. waku_agent-0.1.0/evals/deterministic/test_history_window.py +48 -0
  31. waku_agent-0.1.0/evals/deterministic/test_judge.py +68 -0
  32. waku_agent-0.1.0/evals/deterministic/test_models.py +118 -0
  33. waku_agent-0.1.0/evals/deterministic/test_notion_episodes.py +194 -0
  34. waku_agent-0.1.0/evals/deterministic/test_packaging.py +124 -0
  35. waku_agent-0.1.0/evals/deterministic/test_pinned_models.py +185 -0
  36. waku_agent-0.1.0/evals/deterministic/test_providers.py +179 -0
  37. waku_agent-0.1.0/evals/deterministic/test_retrieval_gate.py +163 -0
  38. waku_agent-0.1.0/evals/deterministic/test_runtime_data_is_ignored.py +96 -0
  39. waku_agent-0.1.0/evals/deterministic/test_scoring.py +54 -0
  40. waku_agent-0.1.0/evals/deterministic/test_session_resume.py +65 -0
  41. waku_agent-0.1.0/evals/deterministic/test_session_rotation.py +89 -0
  42. waku_agent-0.1.0/evals/deterministic/test_shootout.py +66 -0
  43. waku_agent-0.1.0/evals/deterministic/test_show_trace.py +86 -0
  44. waku_agent-0.1.0/evals/deterministic/test_skill_encoding.py +99 -0
  45. waku_agent-0.1.0/evals/deterministic/test_speakable.py +26 -0
  46. waku_agent-0.1.0/evals/deterministic/test_static_assets.py +70 -0
  47. waku_agent-0.1.0/evals/deterministic/test_tool_trigger.py +127 -0
  48. waku_agent-0.1.0/evals/deterministic/test_trace_encoding.py +112 -0
  49. waku_agent-0.1.0/evals/deterministic/test_turn_meta.py +55 -0
  50. waku_agent-0.1.0/evals/deterministic/test_wake_word.py +39 -0
  51. waku_agent-0.1.0/evals/deterministic/test_working_memory.py +43 -0
  52. waku_agent-0.1.0/evals/deterministic/test_workspace.py +66 -0
  53. waku_agent-0.1.0/evals/helpers.py +87 -0
  54. waku_agent-0.1.0/evals/judge/anthropic_judge.py +47 -0
  55. waku_agent-0.1.0/evals/judge/test_response_quality.py +84 -0
  56. waku_agent-0.1.0/pyproject.toml +158 -0
  57. waku_agent-0.1.0/scripts/demo_seed.py +123 -0
  58. waku_agent-0.1.0/scripts/shootout.py +206 -0
  59. waku_agent-0.1.0/scripts/validate_skills.py +51 -0
  60. waku_agent-0.1.0/skills/TEMPLATE.md +23 -0
  61. waku_agent-0.1.0/skills/community/README.md +10 -0
  62. waku_agent-0.1.0/skills/community/meeting-prep/SKILL.md +39 -0
  63. waku_agent-0.1.0/skills/schedule-meeting/SKILL.md +25 -0
  64. waku_agent-0.1.0/skills/weekly-brief/SKILL.md +26 -0
  65. waku_agent-0.1.0/sql/init_supabase.sql +232 -0
  66. waku_agent-0.1.0/waku/__init__.py +10 -0
  67. waku_agent-0.1.0/waku/__main__.py +58 -0
  68. waku_agent-0.1.0/waku/app.py +103 -0
  69. waku_agent-0.1.0/waku/config.py +105 -0
  70. waku_agent-0.1.0/waku/db.py +107 -0
  71. waku_agent-0.1.0/waku/gateway/__init__.py +0 -0
  72. waku_agent-0.1.0/waku/gateway/cli.py +88 -0
  73. waku_agent-0.1.0/waku/gateway/discord.py +231 -0
  74. waku_agent-0.1.0/waku/gateway/telegram.py +148 -0
  75. waku_agent-0.1.0/waku/gateway/voice.py +360 -0
  76. waku_agent-0.1.0/waku/gateway/whatsapp.py +322 -0
  77. waku_agent-0.1.0/waku/loop/__init__.py +0 -0
  78. waku_agent-0.1.0/waku/loop/agent.py +114 -0
  79. waku_agent-0.1.0/waku/loop/models.py +326 -0
  80. waku_agent-0.1.0/waku/memory/__init__.py +186 -0
  81. waku_agent-0.1.0/waku/memory/consolidation.py +75 -0
  82. waku_agent-0.1.0/waku/memory/episodic/__init__.py +0 -0
  83. waku_agent-0.1.0/waku/memory/episodic/notion_store.py +164 -0
  84. waku_agent-0.1.0/waku/memory/episodic/store.py +57 -0
  85. waku_agent-0.1.0/waku/memory/procedural/__init__.py +0 -0
  86. waku_agent-0.1.0/waku/memory/procedural/installer.py +54 -0
  87. waku_agent-0.1.0/waku/memory/procedural/loader.py +91 -0
  88. waku_agent-0.1.0/waku/memory/retrieval_gate.py +55 -0
  89. waku_agent-0.1.0/waku/memory/semantic/__init__.py +0 -0
  90. waku_agent-0.1.0/waku/memory/semantic/store.py +78 -0
  91. waku_agent-0.1.0/waku/memory/semantic/supabase_store.py +58 -0
  92. waku_agent-0.1.0/waku/ops/README.md +66 -0
  93. waku_agent-0.1.0/waku/ops/__init__.py +0 -0
  94. waku_agent-0.1.0/waku/ops/arena.py +245 -0
  95. waku_agent-0.1.0/waku/ops/brief.py +35 -0
  96. waku_agent-0.1.0/waku/ops/browser_agent.py +162 -0
  97. waku_agent-0.1.0/waku/ops/catalog.py +211 -0
  98. waku_agent-0.1.0/waku/ops/coding_eval.py +183 -0
  99. waku_agent-0.1.0/waku/ops/compare_history.py +140 -0
  100. waku_agent-0.1.0/waku/ops/dashboard.py +901 -0
  101. waku_agent-0.1.0/waku/ops/judge.py +101 -0
  102. waku_agent-0.1.0/waku/ops/pricing.py +180 -0
  103. waku_agent-0.1.0/waku/ops/release_gate.py +92 -0
  104. waku_agent-0.1.0/waku/ops/scoring.py +59 -0
  105. waku_agent-0.1.0/waku/ops/settings_api.py +177 -0
  106. waku_agent-0.1.0/waku/ops/show_trace.py +177 -0
  107. waku_agent-0.1.0/waku/ops/static/README.md +62 -0
  108. waku_agent-0.1.0/waku/ops/static/index.html +60 -0
  109. waku_agent-0.1.0/waku/ops/static/js/compare.js +558 -0
  110. waku_agent-0.1.0/waku/ops/static/js/diagram.js +149 -0
  111. waku_agent-0.1.0/waku/ops/static/js/dock.js +146 -0
  112. waku_agent-0.1.0/waku/ops/static/js/main.js +182 -0
  113. waku_agent-0.1.0/waku/ops/static/js/memory.js +37 -0
  114. waku_agent-0.1.0/waku/ops/static/js/models.js +235 -0
  115. waku_agent-0.1.0/waku/ops/static/js/render.js +189 -0
  116. waku_agent-0.1.0/waku/ops/static/js/util.js +91 -0
  117. waku_agent-0.1.0/waku/ops/static/js/views.js +489 -0
  118. waku_agent-0.1.0/waku/ops/static/style.css +400 -0
  119. waku_agent-0.1.0/waku/ops/tracing.py +167 -0
  120. waku_agent-0.1.0/waku/ops/whiteboard/__init__.py +0 -0
  121. waku_agent-0.1.0/waku/ops/whiteboard/assets/github.png +0 -0
  122. waku_agent-0.1.0/waku/ops/whiteboard/assets/x.jpg +0 -0
  123. waku_agent-0.1.0/waku/ops/whiteboard/assets/youtube.png +0 -0
  124. waku_agent-0.1.0/waku/ops/whiteboard/build_k3_tutorial.py +178 -0
  125. waku_agent-0.1.0/waku/ops/whiteboard/build_pi_system.py +140 -0
  126. waku_agent-0.1.0/waku/ops/whiteboard/build_pi_vs_claude.py +105 -0
  127. waku_agent-0.1.0/waku/ops/whiteboard/style.py +379 -0
  128. waku_agent-0.1.0/waku/runtime/__init__.py +0 -0
  129. waku_agent-0.1.0/waku/runtime/session.py +127 -0
  130. waku_agent-0.1.0/waku/tools/__init__.py +77 -0
  131. waku_agent-0.1.0/waku/tools/apple.py +224 -0
  132. waku_agent-0.1.0/waku/tools/calendar.py +431 -0
  133. waku_agent-0.1.0/waku/tools/experimental.py +331 -0
  134. waku_agent-0.1.0/waku/tools/google_calendar.py +182 -0
  135. waku_agent-0.1.0/waku/tools/mcp_client.py +100 -0
  136. waku_agent-0.1.0/waku/tools/memory_admin.py +144 -0
  137. waku_agent-0.1.0/waku/tools/messages.py +39 -0
  138. waku_agent-0.1.0/waku/tools/notes.py +40 -0
  139. waku_agent-0.1.0/waku/tools/registry.py +58 -0
  140. waku_agent-0.1.0/waku/tools/search.py +99 -0
  141. waku_agent-0.1.0/waku/tools/workspace.py +120 -0
@@ -0,0 +1,192 @@
1
+ # ── Provider ────────────────────────────────────────────────────────────────
2
+ # Pick ONE provider and paste its key below. That's the whole setup.
3
+ # anthropic (default) · openai · gemini · deepseek · minimax · kimi · glm · openrouter · opencode_zen · opencode_go
4
+ # No paid key? openrouter's default models are $0 ":free" ids (rate-limited).
5
+ WAKU_PROVIDER=anthropic
6
+
7
+ # Keys — only the one for your chosen provider is needed.
8
+ # (Keep comments on their own line: python-dotenv reads inline text as the value.)
9
+ # anthropic → https://console.anthropic.com
10
+ ANTHROPIC_API_KEY=
11
+ # openai → https://platform.openai.com
12
+ OPENAI_API_KEY=
13
+ # gemini → https://aistudio.google.com
14
+ GEMINI_API_KEY=
15
+ # deepseek → https://platform.deepseek.com
16
+ DEEPSEEK_API_KEY=
17
+ # minimaxi → https://platform.minimaxi.com
18
+ MINIMAX_API_KEY=
19
+ # kimi → https://platform.moonshot.ai
20
+ MOONSHOT_API_KEY=
21
+ # glm → https://z.ai
22
+ ZHIPU_API_KEY=
23
+ # openrouter (one key, hundreds of hosted models) → https://openrouter.ai/keys
24
+ OPENROUTER_API_KEY=
25
+ # xai / grok → https://console.x.ai
26
+ XAI_API_KEY=
27
+ # opencode zen → https://opencode.ai/zen/v1
28
+ OPENCODE_ZEN_API_KEY=
29
+ # opencode go → https://opencode.ai/zen/go/v1
30
+ OPENCODE_GO_API_KEY=
31
+
32
+ # ── Models (optional) ───────────────────────────────────────────────────────
33
+ # Each provider has sensible defaults (see waku/loop/models.py PROVIDERS):
34
+ # anthropic: claude-sonnet-5 + claude-haiku-4-5 (gate/summarizer)
35
+ # openai: gpt-5.6 + gpt-5.6-luna
36
+ # gemini: gemini-3.5-flash + gemini-3.1-flash-lite
37
+ # deepseek: deepseek-v4-pro + deepseek-v4-pro
38
+ # minimax: MiniMax-M3 + MiniMax-M2
39
+ # kimi: kimi-k3 + kimi-k2.6 (gate/summarizer)
40
+ # (K3-only key? set WAKU_SMALL_MODEL=kimi-k3 too)
41
+ # glm: glm-5.2 + glm-5-turbo
42
+ # openrouter: nemotron-3-super:free + gemma-4-26b:free (both $0,
43
+ # rate-limited; Settings lists the live catalog, free first)
44
+ # openrouter's whole point is picking a different model, so WAKU_MODEL takes
45
+ # any "<vendor>/<model>" slug from https://openrouter.ai/models — e.g.
46
+ # WAKU_MODEL=meta-llama/llama-3.1-70b-instruct
47
+ # Override here if you want something else — they're just strings:
48
+ # WAKU_MODEL=
49
+ # WAKU_SMALL_MODEL=
50
+ # Advanced: point at any compatible endpoint / bring your own key var:
51
+ # WAKU_BASE_URL=
52
+ # WAKU_API_KEY=
53
+
54
+ # ── Waku home (optional) ──────────────────────────────────────────────────
55
+ # Where memory (state.db), calendar.ics, outbox/ and traces/ live.
56
+ # WAKU_HOME=.waku
57
+
58
+ # ── Loop guardrails (optional) ──────────────────────────────────────────────
59
+ # WAKU_MAX_ITERATIONS=10
60
+ # WAKU_MAX_TOKENS=2048
61
+ # Working memory window: how many recent turns enter the prompt (default 12).
62
+ # Older turns stay in state.db + consolidation; the retrieval gate brings them
63
+ # back when relevant. Caps context/cost/latency on long (esp. Telegram) threads.
64
+ # WAKU_HISTORY_TURNS=12
65
+
66
+ # ── Memory tuning (optional) ────────────────────────────────────────────────
67
+ # Consolidate chats into durable facts only after N new exchanges.
68
+ # WAKU_CONSOLIDATE_EVERY=6
69
+ # WAKU_RETRIEVAL_TOP_K=4
70
+
71
+ # ── Tracing (optional): pip install -e '.[tracing]' ────────────────────────
72
+ # JSONL traces are ALWAYS written to $WAKU_HOME/traces/. To also see them in
73
+ # a dashboard: run `make trace` (Phoenix on localhost:6006) and uncomment:
74
+ # OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
75
+ # (Langfuse cloud speaks OTel too — use their endpoint + auth headers instead.)
76
+
77
+ # ── Apple ecosystem (optional, macOS) ───────────────────────────────────────
78
+ # Sync created events into Calendar.app (a dedicated "Waku" calendar):
79
+ # WAKU_APPLE_CALENDAR=1
80
+ # Give the agent read/write tools for Calendar, Mail, Reminders, Notes — so it
81
+ # can brief you on your real week ("brief me"). First use triggers the macOS
82
+ # Automation permission prompts for each app.
83
+ # WAKU_APPLE_TOOLS=1
84
+ # Limit calendar reads to named calendars (faster; comma-separated):
85
+ # WAKU_APPLE_CALENDARS=Work,Home
86
+
87
+ # ── Google Calendar writes (optional): pip install -e '.[gcal]' ────────────
88
+ # SQLite + calendar.ics remain the source of truth. This only mirrors events
89
+ # created by create_event; list_events stays local and requests use sendUpdates=none.
90
+ # Authenticate first with Application Default Credentials, then enable:
91
+ # WAKU_GOOGLE_CALENDAR=1
92
+ # WAKU_GOOGLE_CALENDAR_ID=primary
93
+
94
+ # ── Open files in your editor (optional) ────────────────────────────────────
95
+ # Dashboard "reveal" links open files in this editor when it's on PATH
96
+ # (falls back to cursor, then code, then Finder):
97
+ # WAKU_EDITOR=cursor
98
+
99
+ # ── Experimental tools (optional) ───────────────────────────────────────────
100
+ # delegate_task (LIVE): hand coding jobs to pi, the open-source coding agent —
101
+ # npm install -g --ignore-scripts @earendil-works/pi-coding-agent
102
+ # The terminal/browser/cron skeletons still just report "coming soon".
103
+ # WAKU_EXPERIMENTAL=1
104
+ # Max seconds pi may spend on one delegated task (default 300):
105
+ # WAKU_DELEGATE_TIMEOUT=300
106
+
107
+ # ── Web search (optional) ───────────────────────────────────────────────────
108
+ # The search_web tool works keyless via DuckDuckGo, but that endpoint often
109
+ # blocks automated requests. For reliable search (e.g. the "find the World Cup
110
+ # games left and add them to my calendar" loop demo), set a free Tavily key:
111
+ # sign up at https://tavily.com → copy the key here.
112
+ # TAVILY_API_KEY=
113
+
114
+ # ── MCP servers (optional): pip install -e '.[mcp]' ─────────────────────────
115
+ # Connect Model Context Protocol servers by creating .waku/mcp.json:
116
+ # {"servers": [{"name": "fs", "command": "npx",
117
+ # "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]}]}
118
+ # Their tools register as <server>_<tool> and appear to the agent automatically.
119
+
120
+ # ── Voice gateway (optional): pip install -e '.[voice]' ────────────────────
121
+ # Unset = push-to-talk (Enter, speak, Enter). Set a wake word — ANY phrase —
122
+ # and `make voice` becomes always-listening:
123
+ # WAKU_WAKE_WORD=waku waku
124
+ # What it says when it wakes:
125
+ # WAKU_WAKE_ACK=Yes?
126
+ # Stay in the conversation after answering (Siri-style) for N seconds before
127
+ # needing "waku waku" again:
128
+ # WAKU_FOLLOWUP_SECONDS=8
129
+ # STT model (tiny/base/small — bigger = more accurate, slower):
130
+ # WAKU_WHISPER_MODEL=base
131
+ # TTS engine: 'say' (macOS built-in, default) or 'kokoro' (neural British
132
+ # butler — first: pip install kokoro soundfile):
133
+ # WAKU_TTS=say
134
+ # WAKU_VOICE=Daniel
135
+ # (for kokoro use voices like bm_george / bm_fable)
136
+ # Mic sensitivity: lower if it never hears you, higher if it wakes on noise:
137
+ # WAKU_MIC_THRESHOLD=0.005
138
+
139
+ # ── Reliability (optional) ──────────────────────────────────────────────────
140
+ # Max seconds any single LLM call may take before erroring instead of hanging:
141
+ # WAKU_LLM_TIMEOUT=120
142
+
143
+ # ── Telegram gateway (optional): pip install -e '.[telegram]' ──────────────
144
+ # Create a bot: message @BotFather → /newbot. Find your numeric user id via
145
+ # @userinfobot to lock the bot to yourself.
146
+ # TELEGRAM_BOT_TOKEN=
147
+ # TELEGRAM_ALLOWED_USER=
148
+
149
+ # ── Discord gateway (optional): pip install -e '.[discord]' ────────────────
150
+ # Create a bot in the Discord Developer Portal and enable Message Content Intent.
151
+ #
152
+ # READ THIS: the bot answers out of YOUR memory, with YOUR tools, on YOUR key.
153
+ # Default posture is deny — DMs only, and NO server channel is answered until
154
+ # you name it below. Every message it answers is a billed agent turn, and its
155
+ # chat log feeds consolidation, so a stranger's message can become a permanent
156
+ # fact in your memory. Open it up one line at a time.
157
+ # DISCORD_BOT_TOKEN=
158
+ # DISCORD_ALLOWED_USER= # comma-separated ids. Empty = anyone may DM it.
159
+ # DISCORD_ALLOWED_CHANNEL= # comma-separated channel ids. Empty = no channel.
160
+ # DISCORD_REQUIRE_MENTION=1 # in a channel, only reply when @-mentioned
161
+ # DISCORD_MAX_TURNS_PER_HOUR=30 # hard spend ceiling across all users
162
+ # DISCORD_HOME=.waku-discord # a SEPARATE memory — use this for any shared server
163
+ # ── WhatsApp gateway (optional): pip install -e '.[whatsapp]' ──────────────
164
+ # Meta Cloud API access token (temporary: 24h, permanent via System User).
165
+ # See waku/gateway/whatsapp.py docstring for full setup guide.
166
+ # WHATSAPP_TOKEN=
167
+ # Phone Number ID from WhatsApp > Getting Started in your Meta app dashboard.
168
+ # WHATSAPP_PHONE_NUMBER_ID=
169
+ # App Secret from your app's Settings → Basic → App Secret.
170
+ # Required: Meta signs every webhook with this; without it, anyone who finds
171
+ # your URL can forge payloads and drive the agent.
172
+ # WHATSAPP_APP_SECRET=
173
+ # Any random string — you'll enter it in Meta's webhook config page.
174
+ # WHATSAPP_VERIFY_TOKEN=
175
+ # Optional: lock the gateway to one phone number (without '+' prefix).
176
+ # WHATSAPP_ALLOWED_PHONE=
177
+
178
+ # ── Supabase vector memory (optional): pip install -e '.[supabase]' ────────
179
+ # The launch-rag upgrade path: run sql/init_supabase.sql on a fresh project.
180
+ # Embeddings use OPENAI_API_KEY above (text-embedding-3-small).
181
+ # WAKU_SEMANTIC_STORE=supabase
182
+ # SUPABASE_URL=
183
+ # SUPABASE_SERVICE_KEY=
184
+
185
+ # ── Notion episodic memory (optional): pip install -e '.[notion]' ───────────
186
+ # Store episodes (dated memory summaries) in a Notion database instead of the
187
+ # local state.db. Create an integration at https://www.notion.so/my-integrations,
188
+ # share a database with it (properties: Name = title, Summary = rich text), then
189
+ # paste its copied Notion link below (a raw database ID also works):
190
+ # WAKU_EPISODIC_STORE=notion
191
+ # NOTION_TOKEN=ntn_...
192
+ # NOTION_EPISODES_DATABASE_ID=https://app.notion.com/p/...
@@ -0,0 +1,31 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ .env
5
+ state.db
6
+ traces/
7
+ *.ics
8
+ .DS_Store
9
+ dist/
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+ .waku/
13
+ .waku.bak-*/
14
+ .waku.prerename-bak/
15
+ # Any ALTERNATE agent home, not just the default one. DISCORD_HOME gives the
16
+ # bot its own memory (see waku/gateway/discord.py); WAKU_HOME can point anywhere.
17
+ # Without this glob only `.waku/` was covered, so a second home's SOUL.md,
18
+ # usage.jsonl and outbox/ were tracked — the exact files you least want pushed.
19
+ .waku-*/
20
+ .env.prerename-bak
21
+
22
+ # Delegated coding deliverables (dated run folders + auto-run logs)
23
+ waku_workspace/
24
+
25
+ # Google OAuth: the client file you download from Cloud Console, and any token
26
+ # it produces. Nothing here should ever be committed — belt and braces, because
27
+ # the docs used to tell people to drop credentials.json in the repo root.
28
+ credentials.json
29
+ client_secret*.json
30
+ *token*.json
31
+ .gcp/
@@ -0,0 +1,68 @@
1
+ # waku-agent — working conventions
2
+
3
+ **Waku** — a local-first personal assistant demonstrating the four pillars behind every
4
+ serious agent: Harness, Loop, Memory, and Eval/LLM-Ops. It began as a teaching repo you
5
+ could read in an afternoon, and it's now growing toward a full open-source assistant (the
6
+ next Hermes / OpenClaw). The bar for every change: **clear, honest code a newcomer can
7
+ follow** — each pillar legible on its own. The project will get bigger; it must never get
8
+ muddier. New scope is welcome when it stays self-contained, tested, and readable; complexity
9
+ for its own sake is not.
10
+
11
+ ## Architecture map (file ↔ diagram box)
12
+
13
+ - `waku/gateway/` — cli, voice (wake word), telegram. Gateways only move text.
14
+ - `waku/runtime/session.py` — working memory assembly (SOUL.md + memory + history)
15
+ - `waku/loop/agent.py` — THE loop; `loop/models.py` — pluggable providers, 2 wire formats
16
+ - `waku/tools/` — create_event / save_note / send_message (flagship task only)
17
+ - `waku/memory/` — semantic (FTS5) / episodic / procedural (SKILL.md) +
18
+ `retrieval_gate.py` (hero 1) + `consolidation.py` (every N exchanges)
19
+ - `waku/ops/` — tracing (JSONL + OTel), dashboard (localhost:7777), release_gate,
20
+ `compare_history.py` (the Compare arena's own JSONL scoreboard — never state.db)
21
+ - `evals/deterministic/` (0/1, pytest) vs `evals/judge/` (DeepEval, scored) — never mix
22
+ - Runtime state lives in `.waku/` (state.db, calendar.ics, outbox/, traces/) — gitignored
23
+
24
+ ## Rules
25
+
26
+ - **Be concise.** Sean wants short replies: lead with the answer, cut preamble and
27
+ recap. A few lines beats a wall of text. Expand only when he asks for detail.
28
+ - **Never wipe runtime data without asking first, every time.** `scripts/demo_seed.py`
29
+ and anything else that clears `.waku` (memory, calendar, chat log, traces, or the
30
+ `usage.jsonl` spend ledger) must be proposed and explicitly approved by the user
31
+ *immediately before each run*. Permission never carries over from a previous run.
32
+ The script backs up first, but restoring is a hassle — ask, wait for a clear yes,
33
+ then run. It refuses to do anything without the `--yes` flag for this reason.
34
+ - **Version control — commit AND ship every milestone, same turn.** The moment a change
35
+ works (tests pass / verified live), commit it with a detailed message (subject = what,
36
+ body = WHY + what it survived) and get it onto GitHub before moving on. Never end a
37
+ turn or session with working changes left uncommitted — the repo must always be traceable
38
+ from GitHub, and uncommitted work has been lost to branch switches before. Use the `/ship`
39
+ skill. If several milestones land in one session, commit each as its own logical commit.
40
+ - **`main` is protected — `git push origin main` is REJECTED, for everyone.** Since
41
+ 2026-07-26 a commit only lands once `skills-and-evals` is green, and `enforce_admins`
42
+ is on, so the rule binds Sean and Claude identically. Ship via
43
+ `git checkout -b <topic>` → `gh pr create --fill` → `gh pr checks --watch` (~30s) →
44
+ `gh pr merge --squash --delete-branch`. `GH006: Protected branch update failed` is the
45
+ guard working; never route around it. Merging a COMMUNITY PR still needs Sean's
46
+ explicit per-PR yes (see `.claude/skills/review-pr/SKILL.md`).
47
+ - **Gate before push**: `make gate` (deterministic must pass; judge runs with a key).
48
+ When a live bug is found, fix it AND add a regression case to `evals/deterministic/`.
49
+ - **No emojis** in any UI surface (dashboard, CLI output, README prose).
50
+ - **No new dependencies without discussion** — the core is stdlib + anthropic/openai.
51
+ Optional features go behind extras (`[voice]`, `[telegram]`, ...).
52
+ - **Footprint ladder — where new capability goes.** Every registered tool ships in
53
+ every prompt, so the core stays narrow and capability lives at the edges. In order:
54
+ extend existing code → a skill (`SKILL.md`, no Python) → a CLI + README →
55
+ a tool behind an extra → a gateway (one file, text in/out only) →
56
+ **a new core tool, last resort**. Full version, with the "declined even when
57
+ well-built" list, in `CONTRIBUTING.md`.
58
+ - **Scope**: scheduling is the flagship teaching task, but the project is growing toward a
59
+ full assistant. New capabilities (providers, tools, gateways, integrations) are welcome
60
+ when they're self-contained, tested, and keep the core legible. Reject only complexity
61
+ that muddies how the system works or bloats the default path — prefer opt-in extras.
62
+ - Providers are framed neutrally in docs (Anthropic, OpenAI, Gemini, DeepSeek, Kimi, GLM,
63
+ OpenRouter) — no ranking, no "open-source vs closed" framing.
64
+
65
+ ## Commands
66
+
67
+ `make run` · `make voice` · `make dashboard` (7777) · `make trace` (6006) ·
68
+ `make eval` · `make gate` · `make lint` · tests live under `evals/`, not `tests/`
@@ -0,0 +1,44 @@
1
+ # Code of Conduct
2
+
3
+ ## The short version
4
+
5
+ Be decent. Assume the other person is trying to help. Critique code, not people.
6
+
7
+ waku is a teaching repo — a lot of the people opening their first-ever pull
8
+ request will do it here. That's the point, and it sets the bar for how we
9
+ answer them.
10
+
11
+ ## What that means in practice
12
+
13
+ - **Explain the why.** "This won't work" is useless; "this crashes because the
14
+ SQLite connection is bound to the thread that opened it" teaches something.
15
+ - **A rejected PR is not a rejected person.** If we decline a change, we say
16
+ what would have made it land — and forking is always fair game, that's what
17
+ MIT is for.
18
+ - **No harassment, personal attacks, or demeaning comments** about anyone's
19
+ experience level, background, identity, or English. Plenty of contributors
20
+ here aren't writing in their first language.
21
+ - **Don't derail.** Issues are for the work; the [Discord](https://discord.gg/7Ntxzm3eJ)
22
+ is for everything else.
23
+ - **Credit people.** If someone's idea shaped a change, say so in the PR.
24
+
25
+ ## Scope
26
+
27
+ This applies in issues, pull requests, reviews, commit messages, the Discord,
28
+ and anywhere someone is representing the project.
29
+
30
+ ## Enforcement
31
+
32
+ Report anything that crosses the line by private message to
33
+ [@ShenSeanChen](https://github.com/ShenSeanChen), or the email on his GitHub
34
+ profile. Reports stay private.
35
+
36
+ Responses are proportionate: usually a quiet word, sometimes an edited or
37
+ removed comment, and — for repeated or serious behavior — a block from the
38
+ repo. The maintainer's call is final, and he'll explain it.
39
+
40
+ ## A note on tone
41
+
42
+ Direct, evidence-first review is welcome and encouraged; that's what makes the
43
+ code good. There's a difference between "this has a race condition, here's the
44
+ trace" and being unkind about it. Stay on the first side of that line.
@@ -0,0 +1,113 @@
1
+ # Contributing to Waku
2
+
3
+ Waku started as a teaching repo you could read in an afternoon, and it's growing toward a
4
+ full local-first assistant — the next Hermes / OpenClaw, with 1/100th the code. Contributions
5
+ are genuinely welcome. The project will get bigger; the one thing it must never do is get
6
+ *muddier*.
7
+
8
+ **The bar for every PR:** clear, self-contained, and tested. A newcomer should be able to open
9
+ the file you touched and follow what it does. New capability is great — complexity that hides
10
+ how the system works is what we push back on.
11
+
12
+ ## The easiest contribution: a skill (no Python needed)
13
+
14
+ 1. Copy [`skills/TEMPLATE.md`](skills/TEMPLATE.md) to `skills/community/<your-skill>/SKILL.md`
15
+ 2. Fill in `name` + `description` (the Agent Skills frontmatter) and the body
16
+ 3. Test locally: `python scripts/validate_skills.py`, then chat — your skill loads when it matches
17
+ 4. Open a PR. CI runs the same validator.
18
+
19
+ Anyone can then try your skill instantly:
20
+ `waku skill install <link to your SKILL.md>`
21
+
22
+ ## Code contributions
23
+
24
+ Good places to add real value:
25
+
26
+ - **Providers** (`waku/loop/models.py`): most models expose an OpenAI- or Anthropic-compatible
27
+ endpoint, so a new provider is usually one `PROVIDERS` row — no new wire code. Add a pricing
28
+ row in the dashboard and a case to `evals/deterministic/test_providers.py`.
29
+ - **Gateways** (`waku/gateway/`): receive/send for a new channel (WhatsApp, Discord, Slack,
30
+ email). Keep it to one file; the CLI gateway is the reference.
31
+ - **Memory stores** (`waku/memory/semantic/`): match the `add`/`search` interface of
32
+ `SqliteFactStore`. The Supabase adapter is the reference.
33
+ - **Tools** (`waku/tools/`): a new capability the agent can call. Follow `calendar.py` and the
34
+ `new-tool` skill — schema, safe execution, honest output, and a deterministic eval.
35
+
36
+ Two rules that keep contributions safe to merge:
37
+
38
+ - **Test what you add.** Every behavior change gets a deterministic eval in
39
+ `evals/deterministic/` (0/1, no network). If you found a bug, add the case that catches it.
40
+ - **Heavy or optional deps go behind an extra** (`[voice]`, `[telegram]`, `[voice-neural]`, …),
41
+ never in the default install. No new core dependency without discussion.
42
+
43
+ Run the gate before pushing: `make gate` (deterministic must pass; judge evals run if you have
44
+ a key). `make lint` too. CI runs the gate on every PR — it must be green to merge.
45
+
46
+ ## Where does my change go? — the footprint ladder
47
+
48
+ The core is a narrow waist; capability belongs at the edges. Every tool waku
49
+ registers is sent to the model on **every single call**, so the bar for adding
50
+ one is deliberately high. Start at the top of this ladder and only move down
51
+ when the rung above genuinely can't do it:
52
+
53
+ 1. **Extend something that already exists.** A new provider is usually one
54
+ `PROVIDERS` row. A new memory backend matches an existing interface.
55
+ 2. **A skill** — `skills/community/<name>/SKILL.md`. Markdown, no Python, no new
56
+ context cost until the model actually needs it. This is the easiest and most
57
+ underrated contribution; see above.
58
+ 3. **A CLI + a README.** waku can already run any program on your machine. A
59
+ command-line tool with docs beside it costs nothing until it's used.
60
+ 4. **A tool behind an extra** — `waku/tools/`, heavy deps gated by
61
+ `[voice]`/`[notion]`/`[gcal]`-style extras, off by default.
62
+ 5. **A gateway** — `waku/gateway/`, one file. Gateways only move text: in via
63
+ `waku.respond()`, out again. No memory, no tools, no loop logic.
64
+ 6. **A new core tool — last resort.** It has to earn its place in every prompt.
65
+
66
+ If you're unsure which rung you're on, open an issue and ask before writing
67
+ code. That conversation is cheaper than a rejected PR.
68
+
69
+ ## Scope — what we'll say no to, kindly
70
+
71
+ We welcome growth; we decline **complexity that muddies the core**: frameworks that hide the
72
+ loop, changes that bloat the default path for everyone, or features that can't be read and
73
+ tested on their own. When we say no, we'll explain why — and forking is always fair game
74
+ (that's what MIT is for).
75
+
76
+ Concretely, these get declined **even when the code is good**:
77
+
78
+ - **Speculative infrastructure** — an abstraction with no second caller yet. Add
79
+ the second use case first; the right shape is obvious then and guessed now.
80
+ - **A new core dependency.** The default install is stdlib plus the two API
81
+ clients. Heavy or optional things go behind an extra.
82
+ - **Anything that costs every user context** for a feature some users want —
83
+ that's what the ladder above is for.
84
+ - **A behavior change with no deterministic eval.** If it can break, pin it.
85
+ - **Hidden network calls, reading `.env` or secrets, or running code at install
86
+ time.** waku runs on people's own machines with their own keys.
87
+ - **A "fix" that removes the thing it secures** — e.g. sandboxing a tool by
88
+ making it not work.
89
+
90
+ None of this is about the quality of your code. It's about what everyone who
91
+ installs waku has to carry.
92
+
93
+ ## What you can expect from us
94
+
95
+ - **A first response within 48 hours** — even if it's "this needs a proper look,
96
+ give me a few days." Silence is the one thing we try never to do.
97
+ - **Comment on an issue before you start and it gets assigned to you**, so two
98
+ people never build the same thing. (This has already gone wrong once, and it
99
+ cost someone a weekend.)
100
+ - **CI runs on your PR** — if it's your first contribution, GitHub needs a
101
+ maintainer to approve the run. If it seems stuck, say so on the PR; that
102
+ delay is ours, not yours.
103
+
104
+ ## A note on safety
105
+
106
+ Because Waku runs on people's own machines with their own keys, PRs must never add hidden
107
+ network calls, read or transmit secrets/`.env`, or run code at install time. Keep it local,
108
+ keep it legible.
109
+
110
+ ## Community
111
+
112
+ Questions, show-and-tell, pair-debugging: [Discord](https://discord.gg/7Ntxzm3eJ). By
113
+ contributing you agree your work is licensed under the repo's MIT license.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sean Chen (ShenSeanChen)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,56 @@
1
+ # waku-agent — one command per pillar.
2
+ #
3
+ # Make is not a framework — it's a 45-year-old command shortcut tool that
4
+ # ships with every Mac/Linux. Each target below is just the shell command
5
+ # you'd otherwise type. `make run` = "run the python below", nothing more.
6
+ #
7
+ # PY picks the project venv automatically so you never need to remember
8
+ # `source .venv/bin/activate` — both work, this is just fewer steps.
9
+ PY := $(shell [ -x .venv/bin/python ] && echo .venv/bin/python || echo python)
10
+
11
+ .PHONY: run voice telegram discord brief dashboard trace eval eval-judge gate lint
12
+ .PHONY: run voice telegram whatsapp brief dashboard trace eval eval-judge gate lint
13
+
14
+ run: ## chat with Waku in the terminal
15
+ $(PY) -m waku
16
+
17
+ voice: ## talk to it — push-to-talk, or always-on with WAKU_WAKE_WORD
18
+ $(PY) -m waku voice
19
+
20
+ telegram: ## phone → laptop (needs TELEGRAM_BOT_TOKEN in .env)
21
+ $(PY) -m waku telegram
22
+
23
+ discord: ## Discord → laptop (needs DISCORD_BOT_TOKEN in .env)
24
+ $(PY) -m waku discord
25
+ whatsapp: ## WhatsApp → laptop (needs WHATSAPP_TOKEN in .env, public URL)
26
+ $(PY) -m waku whatsapp
27
+
28
+ brief: ## morning briefing from calendar + mail + memory
29
+ $(PY) -m waku brief
30
+
31
+ # The server holds dashboard.py in memory: static JS/CSS reload on refresh, but
32
+ # Python routes do NOT. After pulling a change that touches dashboard.py (or any
33
+ # imported module), stop this and re-run it, or the UI shows stale backend data.
34
+ dashboard: ## everything on one page — http://localhost:7777 (restart after a backend pull)
35
+ $(PY) -m waku.ops.dashboard
36
+
37
+ trace: ## deep trace waterfalls (Phoenix) at http://localhost:6006
38
+ $(PY) -m phoenix.server.main serve
39
+
40
+ eval: ## deterministic evals (0/1, no judge involved)
41
+ $(PY) -m pytest -q evals/deterministic
42
+
43
+ eval-judge: ## LLM-as-judge evals (scored %, needs an API key)
44
+ $(PY) -m pytest -q evals/judge
45
+
46
+ gate: ## the release gate: deterministic must pass, judge must clear threshold
47
+ $(PY) -m waku.ops.release_gate
48
+
49
+ shootout: ## same tasks, different brains: make shootout RUNS="kimi:kimi-k3 anthropic:claude-opus-4-8"
50
+ $(PY) scripts/shootout.py $(RUNS)
51
+
52
+ shootout-coding: ## coding round via pi, scored by tests: make shootout-coding RUNS="kimi:kimi-k3 anthropic:claude-opus-4-8"
53
+ $(PY) scripts/shootout.py $(RUNS) --coding
54
+
55
+ lint:
56
+ $(PY) -m ruff check waku evals scripts