@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.
- package/.claude/settings.json +1 -0
- package/.claude/skills/add-compact/SKILL.md +135 -0
- package/.claude/skills/add-discord/SKILL.md +203 -0
- package/.claude/skills/add-gmail/SKILL.md +220 -0
- package/.claude/skills/add-image-vision/SKILL.md +94 -0
- package/.claude/skills/add-ollama-tool/SKILL.md +153 -0
- package/.claude/skills/add-parallel/SKILL.md +290 -0
- package/.claude/skills/add-pdf-reader/SKILL.md +104 -0
- package/.claude/skills/add-reactions/SKILL.md +117 -0
- package/.claude/skills/add-slack/SKILL.md +207 -0
- package/.claude/skills/add-telegram/SKILL.md +222 -0
- package/.claude/skills/add-telegram-swarm/SKILL.md +384 -0
- package/.claude/skills/add-voice-transcription/SKILL.md +148 -0
- package/.claude/skills/add-whatsapp/SKILL.md +372 -0
- package/.claude/skills/convert-to-apple-container/SKILL.md +175 -0
- package/.claude/skills/customize/SKILL.md +110 -0
- package/.claude/skills/debug/SKILL.md +349 -0
- package/.claude/skills/get-qodo-rules/SKILL.md +122 -0
- package/.claude/skills/get-qodo-rules/references/output-format.md +41 -0
- package/.claude/skills/get-qodo-rules/references/pagination.md +33 -0
- package/.claude/skills/get-qodo-rules/references/repository-scope.md +26 -0
- package/.claude/skills/qodo-pr-resolver/SKILL.md +326 -0
- package/.claude/skills/qodo-pr-resolver/resources/providers.md +329 -0
- package/.claude/skills/setup/SKILL.md +218 -0
- package/.claude/skills/update-nanoclaw/SKILL.md +235 -0
- package/.claude/skills/update-skills/SKILL.md +130 -0
- package/.claude/skills/use-local-whisper/SKILL.md +152 -0
- package/.claude/skills/x-integration/SKILL.md +417 -0
- package/.claude/skills/x-integration/agent.ts +243 -0
- package/.claude/skills/x-integration/host.ts +159 -0
- package/.claude/skills/x-integration/lib/browser.ts +148 -0
- package/.claude/skills/x-integration/lib/config.ts +62 -0
- package/.claude/skills/x-integration/scripts/like.ts +56 -0
- package/.claude/skills/x-integration/scripts/post.ts +66 -0
- package/.claude/skills/x-integration/scripts/quote.ts +80 -0
- package/.claude/skills/x-integration/scripts/reply.ts +74 -0
- package/.claude/skills/x-integration/scripts/retweet.ts +62 -0
- package/.claude/skills/x-integration/scripts/setup.ts +87 -0
- package/.env.example +1 -0
- package/.github/CODEOWNERS +10 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- package/.github/workflows/bump-version.yml +32 -0
- package/.github/workflows/ci.yml +25 -0
- package/.github/workflows/merge-forward-skills.yml +160 -0
- package/.github/workflows/update-tokens.yml +42 -0
- package/.husky/pre-commit +1 -0
- package/.mcp.json +3 -0
- package/.nvmrc +1 -0
- package/.prettierrc +3 -0
- package/CHANGELOG.md +8 -0
- package/CLAUDE.md +64 -0
- package/CONTRIBUTING.md +23 -0
- package/CONTRIBUTORS.md +15 -0
- package/LICENSE +21 -0
- package/NanoClaw_with_Web-Support.md +325 -0
- package/README.md +261 -0
- package/README_zh.md +200 -0
- package/assets/nanoclaw-favicon.png +0 -0
- package/assets/nanoclaw-icon.png +0 -0
- package/assets/nanoclaw-logo-dark.png +0 -0
- package/assets/nanoclaw-logo.png +0 -0
- package/assets/nanoclaw-profile.jpeg +0 -0
- package/assets/nanoclaw-sales.png +0 -0
- package/assets/social-preview.jpg +0 -0
- package/config-examples/mount-allowlist.json +25 -0
- package/container/Dockerfile +70 -0
- package/container/agent-runner/package.json +21 -0
- package/container/agent-runner/src/index.ts +774 -0
- package/container/agent-runner/src/ipc-mcp-stdio.ts +338 -0
- package/container/agent-runner/tsconfig.json +15 -0
- package/container/build.sh +23 -0
- package/container/skills/agent-browser/SKILL.md +159 -0
- package/container/skills/capabilities/SKILL.md +100 -0
- package/container/skills/cwd/SKILL.md +32 -0
- package/container/skills/pwd/SKILL.md +19 -0
- package/container/skills/status/SKILL.md +104 -0
- package/dist/channels/index.d.ts +2 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js +10 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/registry.d.ts +13 -0
- package/dist/channels/registry.d.ts.map +1 -0
- package/dist/channels/registry.js +11 -0
- package/dist/channels/registry.js.map +1 -0
- package/dist/channels/registry.test.d.ts +2 -0
- package/dist/channels/registry.test.d.ts.map +1 -0
- package/dist/channels/registry.test.js +32 -0
- package/dist/channels/registry.test.js.map +1 -0
- package/dist/channels/web.d.ts +2 -0
- package/dist/channels/web.d.ts.map +1 -0
- package/dist/channels/web.js +1843 -0
- package/dist/channels/web.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +182 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +36 -0
- package/dist/config.js.map +1 -0
- package/dist/container-runner.d.ts +44 -0
- package/dist/container-runner.d.ts.map +1 -0
- package/dist/container-runner.js +511 -0
- package/dist/container-runner.js.map +1 -0
- package/dist/container-runner.test.d.ts +2 -0
- package/dist/container-runner.test.d.ts.map +1 -0
- package/dist/container-runner.test.js +150 -0
- package/dist/container-runner.test.js.map +1 -0
- package/dist/container-runtime.d.ts +22 -0
- package/dist/container-runtime.d.ts.map +1 -0
- package/dist/container-runtime.js +96 -0
- package/dist/container-runtime.js.map +1 -0
- package/dist/container-runtime.test.d.ts +2 -0
- package/dist/container-runtime.test.d.ts.map +1 -0
- package/dist/container-runtime.test.js +93 -0
- package/dist/container-runtime.test.js.map +1 -0
- package/dist/credential-proxy.d.ts +21 -0
- package/dist/credential-proxy.d.ts.map +1 -0
- package/dist/credential-proxy.js +95 -0
- package/dist/credential-proxy.js.map +1 -0
- package/dist/credential-proxy.test.d.ts +2 -0
- package/dist/credential-proxy.test.d.ts.map +1 -0
- package/dist/credential-proxy.test.js +134 -0
- package/dist/credential-proxy.test.js.map +1 -0
- package/dist/db.d.ts +115 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +549 -0
- package/dist/db.js.map +1 -0
- package/dist/db.test.d.ts +2 -0
- package/dist/db.test.d.ts.map +1 -0
- package/dist/db.test.js +360 -0
- package/dist/db.test.js.map +1 -0
- package/dist/env.d.ts +8 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +42 -0
- package/dist/env.js.map +1 -0
- package/dist/formatting.test.d.ts +2 -0
- package/dist/formatting.test.d.ts.map +1 -0
- package/dist/formatting.test.js +183 -0
- package/dist/formatting.test.js.map +1 -0
- package/dist/group-folder.d.ts +5 -0
- package/dist/group-folder.d.ts.map +1 -0
- package/dist/group-folder.js +44 -0
- package/dist/group-folder.js.map +1 -0
- package/dist/group-folder.test.d.ts +2 -0
- package/dist/group-folder.test.d.ts.map +1 -0
- package/dist/group-folder.test.js +29 -0
- package/dist/group-folder.test.js.map +1 -0
- package/dist/group-queue.d.ts +40 -0
- package/dist/group-queue.d.ts.map +1 -0
- package/dist/group-queue.js +276 -0
- package/dist/group-queue.js.map +1 -0
- package/dist/group-queue.test.d.ts +2 -0
- package/dist/group-queue.test.d.ts.map +1 -0
- package/dist/group-queue.test.js +341 -0
- package/dist/group-queue.test.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +592 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc-auth.test.d.ts +2 -0
- package/dist/ipc-auth.test.d.ts.map +1 -0
- package/dist/ipc-auth.test.js +434 -0
- package/dist/ipc-auth.test.js.map +1 -0
- package/dist/ipc.d.ts +32 -0
- package/dist/ipc.d.ts.map +1 -0
- package/dist/ipc.js +311 -0
- package/dist/ipc.js.map +1 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +14 -0
- package/dist/logger.js.map +1 -0
- package/dist/mount-security.d.ts +34 -0
- package/dist/mount-security.d.ts.map +1 -0
- package/dist/mount-security.js +325 -0
- package/dist/mount-security.js.map +1 -0
- package/dist/remote-control.d.ts +32 -0
- package/dist/remote-control.d.ts.map +1 -0
- package/dist/remote-control.js +185 -0
- package/dist/remote-control.js.map +1 -0
- package/dist/remote-control.test.d.ts +2 -0
- package/dist/remote-control.test.d.ts.map +1 -0
- package/dist/remote-control.test.js +321 -0
- package/dist/remote-control.test.js.map +1 -0
- package/dist/router.d.ts +8 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +37 -0
- package/dist/router.js.map +1 -0
- package/dist/routing.test.d.ts +2 -0
- package/dist/routing.test.d.ts.map +1 -0
- package/dist/routing.test.js +81 -0
- package/dist/routing.test.js.map +1 -0
- package/dist/sender-allowlist.d.ts +14 -0
- package/dist/sender-allowlist.d.ts.map +1 -0
- package/dist/sender-allowlist.js +79 -0
- package/dist/sender-allowlist.js.map +1 -0
- package/dist/sender-allowlist.test.d.ts +2 -0
- package/dist/sender-allowlist.test.d.ts.map +1 -0
- package/dist/sender-allowlist.test.js +186 -0
- package/dist/sender-allowlist.test.js.map +1 -0
- package/dist/session-commands.d.ts +47 -0
- package/dist/session-commands.d.ts.map +1 -0
- package/dist/session-commands.js +104 -0
- package/dist/session-commands.js.map +1 -0
- package/dist/session-commands.test.d.ts +2 -0
- package/dist/session-commands.test.d.ts.map +1 -0
- package/dist/session-commands.test.js +194 -0
- package/dist/session-commands.test.js.map +1 -0
- package/dist/task-scheduler.d.ts +22 -0
- package/dist/task-scheduler.d.ts.map +1 -0
- package/dist/task-scheduler.js +241 -0
- package/dist/task-scheduler.js.map +1 -0
- package/dist/task-scheduler.test.d.ts +2 -0
- package/dist/task-scheduler.test.d.ts.map +1 -0
- package/dist/task-scheduler.test.js +107 -0
- package/dist/task-scheduler.test.js.map +1 -0
- package/dist/timezone.d.ts +6 -0
- package/dist/timezone.d.ts.map +1 -0
- package/dist/timezone.js +17 -0
- package/dist/timezone.js.map +1 -0
- package/dist/timezone.test.d.ts +2 -0
- package/dist/timezone.test.d.ts.map +1 -0
- package/dist/timezone.test.js +23 -0
- package/dist/timezone.test.js.map +1 -0
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/docs/APPLE-CONTAINER-NETWORKING.md +90 -0
- package/docs/DEBUG_CHECKLIST.md +143 -0
- package/docs/REQUIREMENTS.md +196 -0
- package/docs/SDK_DEEP_DIVE.md +643 -0
- package/docs/SECURITY.md +122 -0
- package/docs/SPEC.md +785 -0
- package/docs/docker-sandboxes.md +359 -0
- package/docs/nanoclaw-architecture-final.md +1063 -0
- package/docs/nanorepo-architecture.md +168 -0
- package/docs/skills-as-branches.md +662 -0
- package/groups/global/CLAUDE.md +58 -0
- package/groups/main/CLAUDE.md +246 -0
- package/launchd/com.nanoclaw.plist +32 -0
- package/package.json +45 -0
- package/repo-tokens/README.md +113 -0
- package/repo-tokens/action.yml +186 -0
- package/repo-tokens/badge.svg +23 -0
- package/repo-tokens/examples/green.svg +14 -0
- package/repo-tokens/examples/red.svg +14 -0
- package/repo-tokens/examples/yellow-green.svg +14 -0
- package/repo-tokens/examples/yellow.svg +14 -0
- package/scripts/run-migrations.ts +105 -0
- package/setup/container.ts +144 -0
- package/setup/environment.test.ts +121 -0
- package/setup/environment.ts +94 -0
- package/setup/groups.ts +229 -0
- package/setup/index.ts +58 -0
- package/setup/mounts.ts +115 -0
- package/setup/platform.test.ts +120 -0
- package/setup/platform.ts +132 -0
- package/setup/register.test.ts +257 -0
- package/setup/register.ts +177 -0
- package/setup/service.test.ts +187 -0
- package/setup/service.ts +362 -0
- package/setup/status.ts +16 -0
- package/setup/verify.ts +192 -0
- package/setup.sh +161 -0
- package/src/channels/index.ts +15 -0
- package/src/channels/registry.test.ts +42 -0
- package/src/channels/registry.ts +32 -0
- package/src/channels/web.ts +1931 -0
- package/src/cli.ts +209 -0
- package/src/config.ts +73 -0
- package/src/container-runner.test.ts +210 -0
- package/src/container-runner.ts +768 -0
- package/src/container-runtime.test.ts +149 -0
- package/src/container-runtime.ts +127 -0
- package/src/credential-proxy.test.ts +192 -0
- package/src/credential-proxy.ts +125 -0
- package/src/db.test.ts +484 -0
- package/src/db.ts +803 -0
- package/src/env.ts +42 -0
- package/src/formatting.test.ts +256 -0
- package/src/group-folder.test.ts +43 -0
- package/src/group-folder.ts +44 -0
- package/src/group-queue.test.ts +484 -0
- package/src/group-queue.ts +379 -0
- package/src/index.ts +832 -0
- package/src/ipc-auth.test.ts +679 -0
- package/src/ipc.ts +461 -0
- package/src/logger.ts +16 -0
- package/src/mount-security.ts +419 -0
- package/src/remote-control.test.ts +397 -0
- package/src/remote-control.ts +224 -0
- package/src/router.ts +52 -0
- package/src/routing.test.ts +170 -0
- package/src/sender-allowlist.test.ts +216 -0
- package/src/sender-allowlist.ts +128 -0
- package/src/session-commands.test.ts +247 -0
- package/src/session-commands.ts +163 -0
- package/src/task-scheduler.test.ts +129 -0
- package/src/task-scheduler.ts +328 -0
- package/src/timezone.test.ts +29 -0
- package/src/timezone.ts +16 -0
- package/src/types.ts +109 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +7 -0
- 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`.
|
package/CONTRIBUTING.md
ADDED
|
@@ -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.
|
package/CONTRIBUTORS.md
ADDED
|
@@ -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).
|