@rozek/nanoclaw 0.0.1

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 (306) hide show
  1. package/.claude/settings.json +1 -0
  2. package/.claude/skills/add-compact/SKILL.md +135 -0
  3. package/.claude/skills/add-discord/SKILL.md +203 -0
  4. package/.claude/skills/add-gmail/SKILL.md +220 -0
  5. package/.claude/skills/add-image-vision/SKILL.md +94 -0
  6. package/.claude/skills/add-ollama-tool/SKILL.md +153 -0
  7. package/.claude/skills/add-parallel/SKILL.md +290 -0
  8. package/.claude/skills/add-pdf-reader/SKILL.md +104 -0
  9. package/.claude/skills/add-reactions/SKILL.md +117 -0
  10. package/.claude/skills/add-slack/SKILL.md +207 -0
  11. package/.claude/skills/add-telegram/SKILL.md +222 -0
  12. package/.claude/skills/add-telegram-swarm/SKILL.md +384 -0
  13. package/.claude/skills/add-voice-transcription/SKILL.md +148 -0
  14. package/.claude/skills/add-whatsapp/SKILL.md +372 -0
  15. package/.claude/skills/convert-to-apple-container/SKILL.md +175 -0
  16. package/.claude/skills/customize/SKILL.md +110 -0
  17. package/.claude/skills/debug/SKILL.md +349 -0
  18. package/.claude/skills/get-qodo-rules/SKILL.md +122 -0
  19. package/.claude/skills/get-qodo-rules/references/output-format.md +41 -0
  20. package/.claude/skills/get-qodo-rules/references/pagination.md +33 -0
  21. package/.claude/skills/get-qodo-rules/references/repository-scope.md +26 -0
  22. package/.claude/skills/qodo-pr-resolver/SKILL.md +326 -0
  23. package/.claude/skills/qodo-pr-resolver/resources/providers.md +329 -0
  24. package/.claude/skills/setup/SKILL.md +218 -0
  25. package/.claude/skills/update-nanoclaw/SKILL.md +235 -0
  26. package/.claude/skills/update-skills/SKILL.md +130 -0
  27. package/.claude/skills/use-local-whisper/SKILL.md +152 -0
  28. package/.claude/skills/x-integration/SKILL.md +417 -0
  29. package/.claude/skills/x-integration/agent.ts +243 -0
  30. package/.claude/skills/x-integration/host.ts +159 -0
  31. package/.claude/skills/x-integration/lib/browser.ts +148 -0
  32. package/.claude/skills/x-integration/lib/config.ts +62 -0
  33. package/.claude/skills/x-integration/scripts/like.ts +56 -0
  34. package/.claude/skills/x-integration/scripts/post.ts +66 -0
  35. package/.claude/skills/x-integration/scripts/quote.ts +80 -0
  36. package/.claude/skills/x-integration/scripts/reply.ts +74 -0
  37. package/.claude/skills/x-integration/scripts/retweet.ts +62 -0
  38. package/.claude/skills/x-integration/scripts/setup.ts +87 -0
  39. package/.env.example +1 -0
  40. package/.github/CODEOWNERS +10 -0
  41. package/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  42. package/.github/workflows/bump-version.yml +32 -0
  43. package/.github/workflows/ci.yml +25 -0
  44. package/.github/workflows/merge-forward-skills.yml +160 -0
  45. package/.github/workflows/update-tokens.yml +42 -0
  46. package/.husky/pre-commit +1 -0
  47. package/.mcp.json +3 -0
  48. package/.nvmrc +1 -0
  49. package/.prettierrc +3 -0
  50. package/CHANGELOG.md +8 -0
  51. package/CLAUDE.md +64 -0
  52. package/CONTRIBUTING.md +23 -0
  53. package/CONTRIBUTORS.md +15 -0
  54. package/LICENSE +21 -0
  55. package/NanoClaw_with_Web-Support.md +325 -0
  56. package/README.md +261 -0
  57. package/README_zh.md +200 -0
  58. package/assets/nanoclaw-favicon.png +0 -0
  59. package/assets/nanoclaw-icon.png +0 -0
  60. package/assets/nanoclaw-logo-dark.png +0 -0
  61. package/assets/nanoclaw-logo.png +0 -0
  62. package/assets/nanoclaw-profile.jpeg +0 -0
  63. package/assets/nanoclaw-sales.png +0 -0
  64. package/assets/social-preview.jpg +0 -0
  65. package/config-examples/mount-allowlist.json +25 -0
  66. package/container/Dockerfile +70 -0
  67. package/container/agent-runner/package.json +21 -0
  68. package/container/agent-runner/src/index.ts +774 -0
  69. package/container/agent-runner/src/ipc-mcp-stdio.ts +338 -0
  70. package/container/agent-runner/tsconfig.json +15 -0
  71. package/container/build.sh +23 -0
  72. package/container/skills/agent-browser/SKILL.md +159 -0
  73. package/container/skills/capabilities/SKILL.md +100 -0
  74. package/container/skills/cwd/SKILL.md +32 -0
  75. package/container/skills/pwd/SKILL.md +19 -0
  76. package/container/skills/status/SKILL.md +104 -0
  77. package/dist/channels/index.d.ts +2 -0
  78. package/dist/channels/index.d.ts.map +1 -0
  79. package/dist/channels/index.js +10 -0
  80. package/dist/channels/index.js.map +1 -0
  81. package/dist/channels/registry.d.ts +13 -0
  82. package/dist/channels/registry.d.ts.map +1 -0
  83. package/dist/channels/registry.js +11 -0
  84. package/dist/channels/registry.js.map +1 -0
  85. package/dist/channels/registry.test.d.ts +2 -0
  86. package/dist/channels/registry.test.d.ts.map +1 -0
  87. package/dist/channels/registry.test.js +32 -0
  88. package/dist/channels/registry.test.js.map +1 -0
  89. package/dist/channels/web.d.ts +2 -0
  90. package/dist/channels/web.d.ts.map +1 -0
  91. package/dist/channels/web.js +1843 -0
  92. package/dist/channels/web.js.map +1 -0
  93. package/dist/cli.d.ts +11 -0
  94. package/dist/cli.d.ts.map +1 -0
  95. package/dist/cli.js +182 -0
  96. package/dist/cli.js.map +1 -0
  97. package/dist/config.d.ts +19 -0
  98. package/dist/config.d.ts.map +1 -0
  99. package/dist/config.js +36 -0
  100. package/dist/config.js.map +1 -0
  101. package/dist/container-runner.d.ts +44 -0
  102. package/dist/container-runner.d.ts.map +1 -0
  103. package/dist/container-runner.js +511 -0
  104. package/dist/container-runner.js.map +1 -0
  105. package/dist/container-runner.test.d.ts +2 -0
  106. package/dist/container-runner.test.d.ts.map +1 -0
  107. package/dist/container-runner.test.js +150 -0
  108. package/dist/container-runner.test.js.map +1 -0
  109. package/dist/container-runtime.d.ts +22 -0
  110. package/dist/container-runtime.d.ts.map +1 -0
  111. package/dist/container-runtime.js +96 -0
  112. package/dist/container-runtime.js.map +1 -0
  113. package/dist/container-runtime.test.d.ts +2 -0
  114. package/dist/container-runtime.test.d.ts.map +1 -0
  115. package/dist/container-runtime.test.js +93 -0
  116. package/dist/container-runtime.test.js.map +1 -0
  117. package/dist/credential-proxy.d.ts +21 -0
  118. package/dist/credential-proxy.d.ts.map +1 -0
  119. package/dist/credential-proxy.js +95 -0
  120. package/dist/credential-proxy.js.map +1 -0
  121. package/dist/credential-proxy.test.d.ts +2 -0
  122. package/dist/credential-proxy.test.d.ts.map +1 -0
  123. package/dist/credential-proxy.test.js +134 -0
  124. package/dist/credential-proxy.test.js.map +1 -0
  125. package/dist/db.d.ts +115 -0
  126. package/dist/db.d.ts.map +1 -0
  127. package/dist/db.js +549 -0
  128. package/dist/db.js.map +1 -0
  129. package/dist/db.test.d.ts +2 -0
  130. package/dist/db.test.d.ts.map +1 -0
  131. package/dist/db.test.js +360 -0
  132. package/dist/db.test.js.map +1 -0
  133. package/dist/env.d.ts +8 -0
  134. package/dist/env.d.ts.map +1 -0
  135. package/dist/env.js +42 -0
  136. package/dist/env.js.map +1 -0
  137. package/dist/formatting.test.d.ts +2 -0
  138. package/dist/formatting.test.d.ts.map +1 -0
  139. package/dist/formatting.test.js +183 -0
  140. package/dist/formatting.test.js.map +1 -0
  141. package/dist/group-folder.d.ts +5 -0
  142. package/dist/group-folder.d.ts.map +1 -0
  143. package/dist/group-folder.js +44 -0
  144. package/dist/group-folder.js.map +1 -0
  145. package/dist/group-folder.test.d.ts +2 -0
  146. package/dist/group-folder.test.d.ts.map +1 -0
  147. package/dist/group-folder.test.js +29 -0
  148. package/dist/group-folder.test.js.map +1 -0
  149. package/dist/group-queue.d.ts +40 -0
  150. package/dist/group-queue.d.ts.map +1 -0
  151. package/dist/group-queue.js +276 -0
  152. package/dist/group-queue.js.map +1 -0
  153. package/dist/group-queue.test.d.ts +2 -0
  154. package/dist/group-queue.test.d.ts.map +1 -0
  155. package/dist/group-queue.test.js +341 -0
  156. package/dist/group-queue.test.js.map +1 -0
  157. package/dist/index.d.ts +13 -0
  158. package/dist/index.d.ts.map +1 -0
  159. package/dist/index.js +592 -0
  160. package/dist/index.js.map +1 -0
  161. package/dist/ipc-auth.test.d.ts +2 -0
  162. package/dist/ipc-auth.test.d.ts.map +1 -0
  163. package/dist/ipc-auth.test.js +434 -0
  164. package/dist/ipc-auth.test.js.map +1 -0
  165. package/dist/ipc.d.ts +32 -0
  166. package/dist/ipc.d.ts.map +1 -0
  167. package/dist/ipc.js +311 -0
  168. package/dist/ipc.js.map +1 -0
  169. package/dist/logger.d.ts +3 -0
  170. package/dist/logger.d.ts.map +1 -0
  171. package/dist/logger.js +14 -0
  172. package/dist/logger.js.map +1 -0
  173. package/dist/mount-security.d.ts +34 -0
  174. package/dist/mount-security.d.ts.map +1 -0
  175. package/dist/mount-security.js +325 -0
  176. package/dist/mount-security.js.map +1 -0
  177. package/dist/remote-control.d.ts +32 -0
  178. package/dist/remote-control.d.ts.map +1 -0
  179. package/dist/remote-control.js +185 -0
  180. package/dist/remote-control.js.map +1 -0
  181. package/dist/remote-control.test.d.ts +2 -0
  182. package/dist/remote-control.test.d.ts.map +1 -0
  183. package/dist/remote-control.test.js +321 -0
  184. package/dist/remote-control.test.js.map +1 -0
  185. package/dist/router.d.ts +8 -0
  186. package/dist/router.d.ts.map +1 -0
  187. package/dist/router.js +37 -0
  188. package/dist/router.js.map +1 -0
  189. package/dist/routing.test.d.ts +2 -0
  190. package/dist/routing.test.d.ts.map +1 -0
  191. package/dist/routing.test.js +81 -0
  192. package/dist/routing.test.js.map +1 -0
  193. package/dist/sender-allowlist.d.ts +14 -0
  194. package/dist/sender-allowlist.d.ts.map +1 -0
  195. package/dist/sender-allowlist.js +79 -0
  196. package/dist/sender-allowlist.js.map +1 -0
  197. package/dist/sender-allowlist.test.d.ts +2 -0
  198. package/dist/sender-allowlist.test.d.ts.map +1 -0
  199. package/dist/sender-allowlist.test.js +186 -0
  200. package/dist/sender-allowlist.test.js.map +1 -0
  201. package/dist/session-commands.d.ts +47 -0
  202. package/dist/session-commands.d.ts.map +1 -0
  203. package/dist/session-commands.js +104 -0
  204. package/dist/session-commands.js.map +1 -0
  205. package/dist/session-commands.test.d.ts +2 -0
  206. package/dist/session-commands.test.d.ts.map +1 -0
  207. package/dist/session-commands.test.js +194 -0
  208. package/dist/session-commands.test.js.map +1 -0
  209. package/dist/task-scheduler.d.ts +22 -0
  210. package/dist/task-scheduler.d.ts.map +1 -0
  211. package/dist/task-scheduler.js +241 -0
  212. package/dist/task-scheduler.js.map +1 -0
  213. package/dist/task-scheduler.test.d.ts +2 -0
  214. package/dist/task-scheduler.test.d.ts.map +1 -0
  215. package/dist/task-scheduler.test.js +107 -0
  216. package/dist/task-scheduler.test.js.map +1 -0
  217. package/dist/timezone.d.ts +6 -0
  218. package/dist/timezone.d.ts.map +1 -0
  219. package/dist/timezone.js +17 -0
  220. package/dist/timezone.js.map +1 -0
  221. package/dist/timezone.test.d.ts +2 -0
  222. package/dist/timezone.test.d.ts.map +1 -0
  223. package/dist/timezone.test.js +23 -0
  224. package/dist/timezone.test.js.map +1 -0
  225. package/dist/types.d.ts +79 -0
  226. package/dist/types.d.ts.map +1 -0
  227. package/dist/types.js +2 -0
  228. package/dist/types.js.map +1 -0
  229. package/docs/APPLE-CONTAINER-NETWORKING.md +90 -0
  230. package/docs/DEBUG_CHECKLIST.md +143 -0
  231. package/docs/REQUIREMENTS.md +196 -0
  232. package/docs/SDK_DEEP_DIVE.md +643 -0
  233. package/docs/SECURITY.md +122 -0
  234. package/docs/SPEC.md +785 -0
  235. package/docs/docker-sandboxes.md +359 -0
  236. package/docs/nanoclaw-architecture-final.md +1063 -0
  237. package/docs/nanorepo-architecture.md +168 -0
  238. package/docs/skills-as-branches.md +662 -0
  239. package/groups/global/CLAUDE.md +58 -0
  240. package/groups/main/CLAUDE.md +246 -0
  241. package/launchd/com.nanoclaw.plist +32 -0
  242. package/package.json +45 -0
  243. package/repo-tokens/README.md +113 -0
  244. package/repo-tokens/action.yml +186 -0
  245. package/repo-tokens/badge.svg +23 -0
  246. package/repo-tokens/examples/green.svg +14 -0
  247. package/repo-tokens/examples/red.svg +14 -0
  248. package/repo-tokens/examples/yellow-green.svg +14 -0
  249. package/repo-tokens/examples/yellow.svg +14 -0
  250. package/scripts/run-migrations.ts +105 -0
  251. package/setup/container.ts +144 -0
  252. package/setup/environment.test.ts +121 -0
  253. package/setup/environment.ts +94 -0
  254. package/setup/groups.ts +229 -0
  255. package/setup/index.ts +58 -0
  256. package/setup/mounts.ts +115 -0
  257. package/setup/platform.test.ts +120 -0
  258. package/setup/platform.ts +132 -0
  259. package/setup/register.test.ts +257 -0
  260. package/setup/register.ts +177 -0
  261. package/setup/service.test.ts +187 -0
  262. package/setup/service.ts +362 -0
  263. package/setup/status.ts +16 -0
  264. package/setup/verify.ts +192 -0
  265. package/setup.sh +161 -0
  266. package/src/channels/index.ts +15 -0
  267. package/src/channels/registry.test.ts +42 -0
  268. package/src/channels/registry.ts +32 -0
  269. package/src/channels/web.ts +1931 -0
  270. package/src/cli.ts +209 -0
  271. package/src/config.ts +73 -0
  272. package/src/container-runner.test.ts +210 -0
  273. package/src/container-runner.ts +768 -0
  274. package/src/container-runtime.test.ts +149 -0
  275. package/src/container-runtime.ts +127 -0
  276. package/src/credential-proxy.test.ts +192 -0
  277. package/src/credential-proxy.ts +125 -0
  278. package/src/db.test.ts +484 -0
  279. package/src/db.ts +803 -0
  280. package/src/env.ts +42 -0
  281. package/src/formatting.test.ts +256 -0
  282. package/src/group-folder.test.ts +43 -0
  283. package/src/group-folder.ts +44 -0
  284. package/src/group-queue.test.ts +484 -0
  285. package/src/group-queue.ts +379 -0
  286. package/src/index.ts +832 -0
  287. package/src/ipc-auth.test.ts +679 -0
  288. package/src/ipc.ts +461 -0
  289. package/src/logger.ts +16 -0
  290. package/src/mount-security.ts +419 -0
  291. package/src/remote-control.test.ts +397 -0
  292. package/src/remote-control.ts +224 -0
  293. package/src/router.ts +52 -0
  294. package/src/routing.test.ts +170 -0
  295. package/src/sender-allowlist.test.ts +216 -0
  296. package/src/sender-allowlist.ts +128 -0
  297. package/src/session-commands.test.ts +247 -0
  298. package/src/session-commands.ts +163 -0
  299. package/src/task-scheduler.test.ts +129 -0
  300. package/src/task-scheduler.ts +328 -0
  301. package/src/timezone.test.ts +29 -0
  302. package/src/timezone.ts +16 -0
  303. package/src/types.ts +109 -0
  304. package/tsconfig.json +20 -0
  305. package/vitest.config.ts +7 -0
  306. package/vitest.skills.config.ts +7 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ All notable changes to NanoClaw will be documented in this file.
4
+
5
+ ## [1.2.0](https://github.com/qwibitai/nanoclaw/compare/v1.1.6...v1.2.0)
6
+
7
+ [BREAKING] WhatsApp removed from core, now a skill. Run `/add-whatsapp` to re-add (existing auth/groups preserved).
8
+ - **fix:** Prevent scheduled tasks from executing twice when container runtime exceeds poll interval (#138, #669)
package/CLAUDE.md ADDED
@@ -0,0 +1,64 @@
1
+ # NanoClaw
2
+
3
+ Personal Claude assistant. See [README.md](README.md) for philosophy and setup. See [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md) for architecture decisions.
4
+
5
+ ## Quick Context
6
+
7
+ Single Node.js process with skill-based channel system. Channels (WhatsApp, Telegram, Slack, Discord, Gmail) are skills that self-register at startup. Messages route to Claude Agent SDK running in containers (Linux VMs). Each group has isolated filesystem and memory.
8
+
9
+ ## Key Files
10
+
11
+ | File | Purpose |
12
+ |------|---------|
13
+ | `src/index.ts` | Orchestrator: state, message loop, agent invocation |
14
+ | `src/channels/registry.ts` | Channel registry (self-registration at startup) |
15
+ | `src/ipc.ts` | IPC watcher and task processing |
16
+ | `src/router.ts` | Message formatting and outbound routing |
17
+ | `src/config.ts` | Trigger pattern, paths, intervals |
18
+ | `src/container-runner.ts` | Spawns agent containers with mounts |
19
+ | `src/task-scheduler.ts` | Runs scheduled tasks |
20
+ | `src/db.ts` | SQLite operations |
21
+ | `groups/{name}/CLAUDE.md` | Per-group memory (isolated) |
22
+ | `container/skills/agent-browser.md` | Browser automation tool (available to all agents via Bash) |
23
+
24
+ ## Skills
25
+
26
+ | Skill | When to Use |
27
+ |-------|-------------|
28
+ | `/setup` | First-time installation, authentication, service configuration |
29
+ | `/customize` | Adding channels, integrations, changing behavior |
30
+ | `/debug` | Container issues, logs, troubleshooting |
31
+ | `/update-nanoclaw` | Bring upstream NanoClaw updates into a customized install |
32
+ | `/qodo-pr-resolver` | Fetch and fix Qodo PR review issues interactively or in batch |
33
+ | `/get-qodo-rules` | Load org- and repo-level coding rules from Qodo before code tasks |
34
+
35
+ ## Development
36
+
37
+ Run commands directly—don't tell the user to run them.
38
+
39
+ ```bash
40
+ npm run dev # Run with hot reload
41
+ npm run build # Compile TypeScript
42
+ ./container/build.sh # Rebuild agent container
43
+ ```
44
+
45
+ Service management:
46
+ ```bash
47
+ # macOS (launchd)
48
+ launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
49
+ launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist
50
+ launchctl kickstart -k gui/$(id -u)/com.nanoclaw # restart
51
+
52
+ # Linux (systemd)
53
+ systemctl --user start nanoclaw
54
+ systemctl --user stop nanoclaw
55
+ systemctl --user restart nanoclaw
56
+ ```
57
+
58
+ ## Troubleshooting
59
+
60
+ **WhatsApp not connecting after upgrade:** WhatsApp is now a separate channel fork, not bundled in core. Run `/add-whatsapp` (or `git remote add whatsapp https://github.com/qwibitai/nanoclaw-whatsapp.git && git fetch whatsapp main && (git merge whatsapp/main || { git checkout --theirs package-lock.json && git add package-lock.json && git merge --continue; }) && npm run build`) to install it. Existing auth credentials and groups are preserved.
61
+
62
+ ## Container Build Cache
63
+
64
+ The container buildkit caches the build context aggressively. `--no-cache` alone does NOT invalidate COPY steps — the builder's volume retains stale files. To force a truly clean rebuild, prune the builder then re-run `./container/build.sh`.
@@ -0,0 +1,23 @@
1
+ # Contributing
2
+
3
+ ## Source Code Changes
4
+
5
+ **Accepted:** Bug fixes, security fixes, simplifications, reducing code.
6
+
7
+ **Not accepted:** Features, capabilities, compatibility, enhancements. These should be skills.
8
+
9
+ ## Skills
10
+
11
+ A [skill](https://code.claude.com/docs/en/skills) is a markdown file in `.claude/skills/` that teaches Claude Code how to transform a NanoClaw installation.
12
+
13
+ A PR that contributes a skill should not modify any source files.
14
+
15
+ Your skill should contain the **instructions** Claude follows to add the feature—not pre-built code. See `/add-telegram` for a good example.
16
+
17
+ ### Why?
18
+
19
+ Every user should have clean and minimal code that does exactly what they need. Skills let users selectively add features to their fork without inheriting code for features they don't want.
20
+
21
+ ### Testing
22
+
23
+ Test your skill by running it on a fresh clone before submitting.
@@ -0,0 +1,15 @@
1
+ # Contributors
2
+
3
+ Thanks to everyone who has contributed to NanoClaw!
4
+
5
+ - [Alakazam03](https://github.com/Alakazam03) — Vaibhav Aggarwal
6
+ - [tydev-new](https://github.com/tydev-new)
7
+ - [pottertech](https://github.com/pottertech) — Skip Potter
8
+ - [rgarcia](https://github.com/rgarcia) — Rafael
9
+ - [AmaxGuan](https://github.com/AmaxGuan) — Lingfeng Guan
10
+ - [happydog-intj](https://github.com/happydog-intj) — happy dog
11
+ - [bindoon](https://github.com/bindoon) — 潕量
12
+ - [taslim](https://github.com/taslim) — Taslim
13
+ - [baijunjie](https://github.com/baijunjie) — BaiJunjie
14
+ - [Michaelliv](https://github.com/Michaelliv) — Michael
15
+ - [kk17](https://github.com/kk17) — Kyle Zhike Chen
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gavriel
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,325 @@
1
+ # NanoClaw with Web Support
2
+
3
+ This document describes the changes added in the [rozek/nanoclaw](https://github.com/rozek/nanoclaw) fork of [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw). It serves as installation guide, feature reference, and API documentation.
4
+
5
+ ---
6
+
7
+ ## Quick Start (npx)
8
+
9
+ No cloning, no `npm install` — just run:
10
+
11
+ ```bash
12
+ npx @rozek/nanoclaw
13
+ ```
14
+
15
+ Then open **http://localhost:3099** in your browser.
16
+
17
+ ### Prerequisites
18
+
19
+ | Requirement | How to check | Notes |
20
+ |-------------|-------------|-------|
21
+ | **Node.js ≥ 20** | `node --version` | |
22
+ | **Claude Code** | `claude --version` | `npm install -g @anthropic-ai/claude-code` |
23
+ | **Container runtime** | `docker info` *or* `container --version` | Docker Desktop **or** macOS Sequoia 15+ Apple Container Runtime |
24
+
25
+ > **No API key required** if you have a Claude Pro or Max subscription — NanoClaw uses Claude Code, which is included in those plans.
26
+
27
+ ---
28
+
29
+ ## Web Channel Features
30
+
31
+ ### UI & Design
32
+
33
+ - **Light and dark themes** — with your system theme as default
34
+ - **Full-viewport layout** — always fills the screen
35
+ - **Responsive** — desktop: fixed sidebar; mobile: sidebar as overlay with backdrop
36
+
37
+ ### Rich Content Rendering
38
+
39
+ Bot responses are rendered with full Markdown support:
40
+
41
+ | Library | Purpose |
42
+ |---------|---------|
43
+ | [marked.js](https://marked.js.org) | GitHub Flavored Markdown |
44
+ | [KaTeX](https://katex.org) | Inline (`$...$`) and block (`$$...$$`) math formulas |
45
+ | [highlight.js](https://highlightjs.org) | Syntax highlighting (TypeScript, Java, and many more) |
46
+ | [Mermaid](https://mermaid.js.org) | Flowcharts, sequence diagrams, etc. |
47
+
48
+ ### Multi-Session Chat
49
+
50
+ - Unlimited parallel chat sessions per browser
51
+ - Sessions are listed in the sidebar, freely sortable by dragging
52
+ - Each session has an editable name (pencil icon ✏; default: date+time)
53
+ - Sessions persist in `localStorage` and SQLite — survive browser reloads and server restarts
54
+ - Sessions from other devices appear automatically in the sidebar (polled every 5 s)
55
+ - Unread message indicators (blue dot) per session, persisted in `localStorage`
56
+ - Sessions can be deleted (removes all messages from DB and `localStorage`)
57
+
58
+ ### Session Name Sync
59
+
60
+ Conflict-free name synchronisation across devices:
61
+
62
+ - Every rename carries a `nameUpdatedAt` UNIX timestamp
63
+ - Server-side guard: `UPDATE … WHERE excluded.name_updated_at >= chats.name_updated_at`
64
+ - On SSE connect, the client pushes its local name; if it is newer than the server's name, the server adopts it
65
+
66
+ ### Message History
67
+
68
+ - Local `localStorage` cache (`hist:{sid}`) for instant display on load
69
+ - Full conversation history served from SQLite via `GET /history?sid=…`
70
+ - Both user messages and bot replies are persisted and synced across devices
71
+ - Individual messages can be deleted (trash icon; removes from DOM, cache, and DB)
72
+
73
+ ### Real-Time Updates (Server-Sent Events)
74
+
75
+ All live updates arrive over a single SSE connection (`GET /events?sid=…`):
76
+
77
+ | Event | Payload | Purpose |
78
+ |-------|---------|---------|
79
+ | `message` | `{"text":"…","id":"…"}` | Append bot reply |
80
+ | `typing` | `"true"` / `"false"` | Show/hide typing indicator |
81
+ | `status` | `{"tool":"…","input":"…"}` or `null` | Display active tool (e.g. "searching…") |
82
+ | `cwd` | path string | Update working-directory display in header |
83
+
84
+ On connect, the server immediately sends the current `typing`, `status`, and `cwd` state so reconnects are seamless. Additionally, the client fetches `GET /pwd?sid=…` in the SSE `open` handler to reliably sync the CWD even if the `cwd` event arrives before the session is fully initialized.
85
+
86
+ ### Working Folder (CWD)
87
+
88
+ - Current working folder shown in the header: `NanoClaw — IP:Port — <relative-path>`
89
+ - Set by the agent or user via `switching to folder: <relative-path>` (in any message or response)
90
+ - User shorthand commands available in the chat input:
91
+ - `/cwd <path>` — change the working folder instantly (no agent invocation)
92
+ - `/pwd` — display the current working folder
93
+ - Persisted in `chats.cwd` (SQLite) — survives server restarts
94
+ - Also cached in `localStorage` per session
95
+ - NanoClaw ships with built-in skills (`container/skills/cwd/` and `container/skills/pwd/`) that instruct the AI how to use these commands
96
+ - All CWD values (from agent output, `/cwd` command, or `POST /cwd`) are passed through `sanitizeCwd()` which resolves paths relative to the workspace root and rejects any attempt to escape it (absolute paths outside the workspace are silently clamped to `''`)
97
+
98
+ ### File Upload
99
+
100
+ - Drag files into the browser window
101
+ - Files are written to the session's current working directory (or group root if no CWD)
102
+ - Maximum file size: 10 MB
103
+
104
+ ### Cancel In-Progress Requests
105
+
106
+ - A **Cancel** button appears while the agent is processing
107
+ - Clicking it immediately kills the container process (SIGTERM) via `POST /cancel?sid=…`
108
+ - The button is disabled while the cancel request is in flight to prevent double-clicks
109
+
110
+ ### Cron Jobs Tab
111
+
112
+ - A dedicated **Cron Jobs** tab (`local@web-cron`) shows output from all scheduled tasks
113
+ - The text input is disabled in this tab — it is reserved for task output only
114
+
115
+ ### Access Control
116
+
117
+ Token-based authentication is optional but recommended when NanoClaw is reachable from the LAN:
118
+
119
+ ```bash
120
+ npx @rozek/nanoclaw --token mySecretToken
121
+ ```
122
+
123
+ Clients authenticate via:
124
+ 1. `Authorization: Bearer mySecretToken` header
125
+ 2. `?token=mySecretToken` URL query parameter (sets an HttpOnly session cookie)
126
+ 3. The HttpOnly session cookie set after step 2
127
+
128
+ ---
129
+
130
+ ## Installation & Usage
131
+
132
+ ### Simplest start
133
+
134
+ ```bash
135
+ npx @rozek/nanoclaw
136
+ ```
137
+
138
+ Auto-detects the container runtime (Docker first, then Apple Container). Binds to `127.0.0.1:3099` by default (localhost only).
139
+
140
+ ### Common options
141
+
142
+ ```bash
143
+ # Custom port
144
+ npx @rozek/nanoclaw --port 8080
145
+
146
+ # Custom workspace (directory NanoClaw works in)
147
+ npx @rozek/nanoclaw --workspace ~/my-workspace
148
+
149
+ # Token protection — recommended when accessible from the LAN
150
+ npx @rozek/nanoclaw --token mySecretToken
151
+
152
+ # Make accessible from the LAN (bind to all interfaces) — use with a token!
153
+ npx nanoclaw --host 0.0.0.0 --token mySecretToken
154
+
155
+ # Explicit container runtime
156
+ npx @rozek/nanoclaw --sandbox docker
157
+ npx @rozek/nanoclaw --sandbox apple
158
+
159
+ # With an Anthropic API key (for users without Pro/Max)
160
+ npx @rozek/nanoclaw --key sk-ant-...
161
+
162
+ # Combine options
163
+ npx @rozek/nanoclaw --port 8080 --workspace ~/my-workspace --token mySecretToken --sandbox docker
164
+ ```
165
+
166
+ ### All CLI options
167
+
168
+ ```
169
+ Options:
170
+ --host <address> Bind address for the web channel (default: 127.0.0.1)
171
+ --port <number> Port for the web channel (default: 3099)
172
+ --workspace <path> Workspace directory (default: current directory)
173
+ --key <api-key> Anthropic API key
174
+ Not required with Claude Pro/Max — NanoClaw uses
175
+ Claude Code, which is included in those plans.
176
+ --token <token> Access token for the web interface (default: no protection)
177
+ Clients supply it via:
178
+ Authorization: Bearer <token>
179
+ ?token=<value> query parameter
180
+ or a session cookie
181
+ --sandbox <type> Container runtime: "docker" or "apple"
182
+ Defaults to auto-detect (docker → apple).
183
+ -h, --help Show this help and exit
184
+ ```
185
+
186
+ ### Environment variables
187
+
188
+ CLI flags take precedence. Alternatively, set environment variables:
189
+
190
+ ```bash
191
+ NANOCLAW_HOST=127.0.0.1
192
+ NANOCLAW_PORT=3099
193
+ NANOCLAW_TOKEN=mySecretToken
194
+ NANOCLAW_KEY=sk-ant-...
195
+ NANOCLAW_WORKSPACE=/path/to/workspace
196
+ NANOCLAW_SANDBOX=docker # or: apple
197
+ ```
198
+
199
+ ---
200
+
201
+ ## HTTP API Reference
202
+
203
+ | Method | Path | Description |
204
+ |--------|------|-------------|
205
+ | `GET` | `/` | Serves the web UI (HTML) |
206
+ | `GET` | `/events?sid=…` | SSE stream for real-time updates |
207
+ | `GET` | `/sessions` | All web sessions with custom display order (JSON) |
208
+ | `GET` | `/history?sid=…` | Conversation history (JSON) |
209
+ | `GET` | `/favicon.ico` | Favicon (ICO) |
210
+ | `GET` | `/favicon.png` | Favicon (PNG) |
211
+ | `GET` | `/apple-touch-icon.png` | iOS home-screen icon |
212
+ | `POST` | `/message` | Send a chat message |
213
+ | `POST` | `/session-name` | Rename a session |
214
+ | `POST` | `/session-order` | Persist the user-defined session display order (drag-and-drop) |
215
+ | `POST` | `/delete-session` | Delete a session and all its messages |
216
+ | `POST` | `/delete-message` | Delete a single message `{sid, id}` |
217
+ | `GET` | `/pwd?sid=…` | Get the current working folder for a session (JSON: `{cwd}`) |
218
+ | `POST` | `/cwd` | Set the working folder for a session (`{cwd, sessionId}`) |
219
+ | `POST` | `/upload` | Upload a file (Base64-encoded body) |
220
+ | `POST` | `/cancel?sid=…` | Cancel the active request for a session |
221
+
222
+ ---
223
+
224
+ ## Architecture
225
+
226
+ ```
227
+ Browser Server (web.ts) DB (SQLite)
228
+ ─────── ─────────────── ───────────
229
+ GET / ←───────────── Embedded HTML/CSS/JS
230
+ GET /events ←── SSE ────── sseClients Map
231
+ POST /message ────────────→ onMessage() → agent run
232
+ agent replies → broadcastToSession()
233
+ GET /sessions ←── poll 5s ─ getAllChats() + sessionCwds chats table
234
+ POST /session-name ────────→ updateChatName() (with guard) chats.name
235
+ POST /session-order ────────→ setWebSessionOrder() router_state
236
+ GET /history ←───────────── getConversation() messages table
237
+ POST /delete-session ──────→ deleteChat() chats + messages
238
+ POST /delete-message ──────→ deleteMessage(id) messages table
239
+ GET /pwd ←───────────── sessionCwds.get(sid)
240
+ POST /cwd ────────────→ updateChatCwd() → broadcast chats.cwd
241
+ POST /upload ────────────→ fs.writeFile() into CWD dir
242
+ POST /cancel ────────────→ onCancelRequest()
243
+ ```
244
+
245
+ ### In-Memory Server State
246
+
247
+ | Variable | Type | Content |
248
+ |----------|------|---------|
249
+ | `sseClients` | `Map<sid, Set<Response>>` | Open SSE connections per session |
250
+ | `sessionCwds` | `Map<sid, string>` | Current CWD per session |
251
+ | `sessionTyping` | `Map<sid, boolean>` | Whether the agent is processing |
252
+ | `sessionStatus` | `Map<sid, string\|null>` | Last tool-status payload |
253
+ | `registeredSessions` | `Set<sid>` | Sessions already registered with NanoClaw |
254
+
255
+ ### Database Schema (relevant columns in `chats`)
256
+
257
+ | Column | Type | Purpose |
258
+ |--------|------|---------|
259
+ | `jid` | TEXT PK | `local@web-{sessionId}` |
260
+ | `name` | TEXT | Session display name |
261
+ | `name_updated_at` | INTEGER | UNIX epoch of the last rename |
262
+ | `cwd` | TEXT | Current working directory |
263
+ | `last_message_time` | TEXT | ISO timestamp updated on every message |
264
+
265
+ ---
266
+
267
+ ## Development Workflow
268
+
269
+ If you are running NanoClaw from source (not via `npx`):
270
+
271
+ ```bash
272
+ # 1. Install dependencies
273
+ npm install
274
+
275
+ # 2. Build
276
+ npm run build
277
+
278
+ # 3. Run
279
+ node dist/cli.js [options]
280
+ ```
281
+
282
+ To apply changes and rebuild in one step:
283
+
284
+ ```bash
285
+ npm run build && node dist/cli.js
286
+ ```
287
+
288
+ ---
289
+
290
+ ## What's New
291
+
292
+ The following files were added or changed relative to [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw) `main`:
293
+
294
+ ### New files
295
+
296
+ | File | Purpose |
297
+ |------|---------|
298
+ | `src/cli.ts` | CLI entry point — parses arguments, validates them, starts NanoClaw; enables `npx @rozek/nanoclaw` |
299
+ | `src/channels/web.ts` | Complete HTTP server with embedded browser chat UI (HTML/CSS/JS inline) |
300
+ | `src/mount-security.ts` | Validates additional container mounts against an allowlist stored outside the project root (prevents agents from tampering with security config) |
301
+ | `src/session-commands.ts` | Session management commands (e.g. `/compact` for context compaction) — merged from upstream `skill/compact` branch |
302
+ | `src/session-commands.test.ts` | Unit tests for session commands |
303
+ | `container/skills/cwd/SKILL.md` | Built-in skill: instructs the AI to output `switching to folder: <path>` to update the working folder display |
304
+ | `container/skills/pwd/SKILL.md` | Built-in skill: instructs the AI how to determine and report the current working folder |
305
+
306
+ ### Modified files
307
+
308
+ | File | What changed |
309
+ |------|-------------|
310
+ | `package.json` | Added `"bin": {"nanoclaw": "dist/cli.js"}` so the package works as an `npx` command |
311
+ | `src/channels/index.ts` | Exports the new web channel |
312
+ | `src/channels/registry.ts` | Adds `registerGroup` and `onCancelRequest` to `ChannelOpts` so channels can register groups and handle cancel requests |
313
+ | `src/index.ts` | Integrates the web channel and session commands into the orchestrator's main loop; exports `main()` for use by `cli.ts`; adds `formatApiError()` to display Anthropic API errors (401/429/529/500) as user-facing chat messages; uses per-session chat IDs as Claude session keys; adds `statusCallback` to forward live tool-use events to the channel |
314
+ | `src/group-queue.ts` | Adds `cancelContainer()` — writes the close sentinel and sends SIGTERM to the container process for immediate cancellation |
315
+ | `src/db.ts` | Adds `name_updated_at` and `cwd` columns to the `chats` table; updates `updateChatName()` with timestamp guard and optional `nameUpdatedAt` argument; extends `getAllChats()` to return the new columns; adds `getWebSessionOrder()`, `setWebSessionOrder()`, `updateChatCwd()`, `getConversation()`, `deleteChat()`, `clearChatMessages()`, `deleteMessage()` |
316
+ | `src/types.ts` | Adds optional `setStatus?(jid, tool, inputSnippet)` to the channel interface so channels can show live tool-use status |
317
+ | `src/container-runner.ts` | Adds status-marker protocol (`---NANOCLAW_STATUS_START---` / `---NANOCLAW_STATUS_END---`) so the agent runner can emit tool-use status events; always syncs agent-runner source from master on container start |
318
+ | `src/task-scheduler.ts` | Routes scheduled task output for web sessions to a dedicated `local@web-cron` session (with task header); each task runs in its own queue slot (`task:<id>`) for parallel execution; uses per-session session IDs; falls back to the first `isMain` group when the task's `group_folder` is not found |
319
+ | `container/agent-runner/src/index.ts` | Updated agent runner: emits status markers for tool use; supports external MCP servers from `MCP-Servers/`; supports context compaction (`/compact`) |
320
+
321
+ ---
322
+
323
+ ## License
324
+
325
+ MIT — same as the upstream [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw).