@rozek/nanoclaw 1.2.17
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 +290 -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-lock.json +1524 -0
- package/container/agent-runner/package.json +21 -0
- package/container/agent-runner/src/index.ts +558 -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/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 +9 -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 +1738 -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 +467 -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 +34 -0
- package/dist/group-queue.d.ts.map +1 -0
- package/dist/group-queue.js +263 -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 +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +518 -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 +102 -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 +190 -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 +210 -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 +78 -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 +12 -0
- package/src/channels/registry.test.ts +42 -0
- package/src/channels/registry.ts +32 -0
- package/src/channels/web.ts +1856 -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 +707 -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 +365 -0
- package/src/index.ts +731 -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 +295 -0
- package/src/timezone.test.ts +29 -0
- package/src/timezone.ts +16 -0
- package/src/types.ts +107 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +7 -0
- package/vitest.skills.config.ts +7 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# Running NanoClaw in Docker Sandboxes (Manual Setup)
|
|
2
|
+
|
|
3
|
+
This guide walks through setting up NanoClaw inside a [Docker Sandbox](https://docs.docker.com/ai/sandboxes/) from scratch — no install script, no pre-built fork. You'll clone the upstream repo, apply the necessary patches, and have agents running in full hypervisor-level isolation.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Host (macOS / Windows WSL)
|
|
9
|
+
└── Docker Sandbox (micro VM with isolated kernel)
|
|
10
|
+
├── NanoClaw process (Node.js)
|
|
11
|
+
│ ├── Channel adapters (WhatsApp, Telegram, etc.)
|
|
12
|
+
│ └── Container spawner → nested Docker daemon
|
|
13
|
+
└── Docker-in-Docker
|
|
14
|
+
└── nanoclaw-agent containers
|
|
15
|
+
└── Claude Agent SDK
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Each agent runs in its own container, inside a micro VM that is fully isolated from your host. Two layers of isolation: per-agent containers + the VM boundary.
|
|
19
|
+
|
|
20
|
+
The sandbox provides a MITM proxy at `host.docker.internal:3128` that handles network access and injects your Anthropic API key automatically.
|
|
21
|
+
|
|
22
|
+
> **Note:** This guide is based on a validated setup running on macOS (Apple Silicon) with WhatsApp. Other channels (Telegram, Slack, etc.) and environments (Windows WSL) may require additional proxy patches for their specific HTTP/WebSocket clients. The core patches (container runner, credential proxy, Dockerfile) apply universally — channel-specific proxy configuration varies.
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
- **Docker Desktop v4.40+** with Sandbox support
|
|
27
|
+
- **Anthropic API key** (the sandbox proxy manages injection)
|
|
28
|
+
- For **Telegram**: a bot token from [@BotFather](https://t.me/BotFather) and your chat ID
|
|
29
|
+
- For **WhatsApp**: a phone with WhatsApp installed
|
|
30
|
+
|
|
31
|
+
Verify sandbox support:
|
|
32
|
+
```bash
|
|
33
|
+
docker sandbox version
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Step 1: Create the Sandbox
|
|
37
|
+
|
|
38
|
+
On your host machine:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Create a workspace directory
|
|
42
|
+
mkdir -p ~/nanoclaw-workspace
|
|
43
|
+
|
|
44
|
+
# Create a shell sandbox with the workspace mounted
|
|
45
|
+
docker sandbox create shell ~/nanoclaw-workspace
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If you're using WhatsApp, configure proxy bypass so WhatsApp's Noise protocol isn't MITM-inspected:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
docker sandbox network proxy shell-nanoclaw-workspace \
|
|
52
|
+
--bypass-host web.whatsapp.com \
|
|
53
|
+
--bypass-host "*.whatsapp.com" \
|
|
54
|
+
--bypass-host "*.whatsapp.net"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Telegram does not need proxy bypass.
|
|
58
|
+
|
|
59
|
+
Enter the sandbox:
|
|
60
|
+
```bash
|
|
61
|
+
docker sandbox run shell-nanoclaw-workspace
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Step 2: Install Prerequisites
|
|
65
|
+
|
|
66
|
+
Inside the sandbox:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
sudo apt-get update && sudo apt-get install -y build-essential python3
|
|
70
|
+
npm config set strict-ssl false
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Step 3: Clone and Install NanoClaw
|
|
74
|
+
|
|
75
|
+
NanoClaw must live inside the workspace directory — Docker-in-Docker can only bind-mount from the shared workspace path.
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Clone to home first (virtiofs can corrupt git pack files during clone)
|
|
79
|
+
cd ~
|
|
80
|
+
git clone https://github.com/qwibitai/nanoclaw.git
|
|
81
|
+
|
|
82
|
+
# Replace with YOUR workspace path (the host path you passed to `docker sandbox create`)
|
|
83
|
+
WORKSPACE=/Users/you/nanoclaw-workspace
|
|
84
|
+
|
|
85
|
+
# Move into workspace so DinD mounts work
|
|
86
|
+
mv nanoclaw "$WORKSPACE/nanoclaw"
|
|
87
|
+
cd "$WORKSPACE/nanoclaw"
|
|
88
|
+
|
|
89
|
+
# Install dependencies
|
|
90
|
+
npm install
|
|
91
|
+
npm install https-proxy-agent
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Step 4: Apply Proxy and Sandbox Patches
|
|
95
|
+
|
|
96
|
+
NanoClaw needs several patches to work inside a Docker Sandbox. These handle proxy routing, CA certificates, and Docker-in-Docker mount restrictions.
|
|
97
|
+
|
|
98
|
+
### 4a. Dockerfile — proxy args for container image build
|
|
99
|
+
|
|
100
|
+
`npm install` inside `docker build` fails with `SELF_SIGNED_CERT_IN_CHAIN` because the sandbox's MITM proxy presents its own certificate. Add proxy build args to `container/Dockerfile`:
|
|
101
|
+
|
|
102
|
+
Add these lines after the `FROM` line:
|
|
103
|
+
|
|
104
|
+
```dockerfile
|
|
105
|
+
# Accept proxy build args
|
|
106
|
+
ARG http_proxy
|
|
107
|
+
ARG https_proxy
|
|
108
|
+
ARG no_proxy
|
|
109
|
+
ARG NODE_EXTRA_CA_CERTS
|
|
110
|
+
ARG npm_config_strict_ssl=true
|
|
111
|
+
RUN npm config set strict-ssl ${npm_config_strict_ssl}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
And after the `RUN npm install` line:
|
|
115
|
+
|
|
116
|
+
```dockerfile
|
|
117
|
+
RUN npm config set strict-ssl true
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 4b. Build script — forward proxy args
|
|
121
|
+
|
|
122
|
+
Patch `container/build.sh` to pass proxy env vars to `docker build`:
|
|
123
|
+
|
|
124
|
+
Add these `--build-arg` flags to the `docker build` command:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
--build-arg http_proxy="${http_proxy:-$HTTP_PROXY}" \
|
|
128
|
+
--build-arg https_proxy="${https_proxy:-$HTTPS_PROXY}" \
|
|
129
|
+
--build-arg no_proxy="${no_proxy:-$NO_PROXY}" \
|
|
130
|
+
--build-arg npm_config_strict_ssl=false \
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 4c. Container runner — proxy forwarding, CA cert mount, /dev/null fix
|
|
134
|
+
|
|
135
|
+
Three changes to `src/container-runner.ts`:
|
|
136
|
+
|
|
137
|
+
**Replace `/dev/null` shadow mount.** The sandbox rejects `/dev/null` bind mounts. Find where `.env` is shadow-mounted to `/dev/null` and replace it with an empty file:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// Create an empty file to shadow .env (Docker Sandbox rejects /dev/null mounts)
|
|
141
|
+
const emptyEnvPath = path.join(DATA_DIR, 'empty-env');
|
|
142
|
+
if (!fs.existsSync(emptyEnvPath)) fs.writeFileSync(emptyEnvPath, '');
|
|
143
|
+
// Use emptyEnvPath instead of '/dev/null' in the mount
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Forward proxy env vars** to spawned agent containers. Add `-e` flags for `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` and their lowercase variants.
|
|
147
|
+
|
|
148
|
+
**Mount CA certificate.** If `NODE_EXTRA_CA_CERTS` or `SSL_CERT_FILE` is set, copy the cert into the project directory and mount it into agent containers:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const caCertSrc = process.env.NODE_EXTRA_CA_CERTS || process.env.SSL_CERT_FILE;
|
|
152
|
+
if (caCertSrc) {
|
|
153
|
+
const certDir = path.join(DATA_DIR, 'ca-cert');
|
|
154
|
+
fs.mkdirSync(certDir, { recursive: true });
|
|
155
|
+
fs.copyFileSync(caCertSrc, path.join(certDir, 'proxy-ca.crt'));
|
|
156
|
+
// Mount: certDir -> /workspace/ca-cert (read-only)
|
|
157
|
+
// Set NODE_EXTRA_CA_CERTS=/workspace/ca-cert/proxy-ca.crt in the container
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 4d. Container runtime — prevent self-termination
|
|
162
|
+
|
|
163
|
+
In `src/container-runtime.ts`, the `cleanupOrphans()` function matches containers by the `nanoclaw-` prefix. Inside a sandbox, the sandbox container itself may match (e.g., `nanoclaw-docker-sandbox`). Filter out the current hostname:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// In cleanupOrphans(), filter out os.hostname() from the list of containers to stop
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 4e. Credential proxy — route through MITM proxy
|
|
170
|
+
|
|
171
|
+
In `src/credential-proxy.ts`, upstream API requests need to go through the sandbox proxy. Add `HttpsProxyAgent` to outbound requests:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
175
|
+
|
|
176
|
+
const proxyUrl = process.env.HTTPS_PROXY || process.env.https_proxy;
|
|
177
|
+
const upstreamAgent = proxyUrl ? new HttpsProxyAgent(proxyUrl) : undefined;
|
|
178
|
+
// Pass upstreamAgent to https.request() options
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 4f. Setup script — proxy build args
|
|
182
|
+
|
|
183
|
+
Patch `setup/container.ts` to pass the same proxy `--build-arg` flags as `build.sh` (Step 4b).
|
|
184
|
+
|
|
185
|
+
## Step 5: Build
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npm run build
|
|
189
|
+
bash container/build.sh
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Step 6: Add a Channel
|
|
193
|
+
|
|
194
|
+
### Telegram
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Apply the Telegram skill
|
|
198
|
+
npx tsx scripts/apply-skill.ts .claude/skills/add-telegram
|
|
199
|
+
|
|
200
|
+
# Rebuild after applying the skill
|
|
201
|
+
npm run build
|
|
202
|
+
|
|
203
|
+
# Configure .env
|
|
204
|
+
cat > .env << EOF
|
|
205
|
+
TELEGRAM_BOT_TOKEN=<your-token-from-botfather>
|
|
206
|
+
ASSISTANT_NAME=nanoclaw
|
|
207
|
+
ANTHROPIC_API_KEY=proxy-managed
|
|
208
|
+
EOF
|
|
209
|
+
mkdir -p data/env && cp .env data/env/env
|
|
210
|
+
|
|
211
|
+
# Register your chat
|
|
212
|
+
npx tsx setup/index.ts --step register \
|
|
213
|
+
--jid "tg:<your-chat-id>" \
|
|
214
|
+
--name "My Chat" \
|
|
215
|
+
--trigger "@nanoclaw" \
|
|
216
|
+
--folder "telegram_main" \
|
|
217
|
+
--channel telegram \
|
|
218
|
+
--assistant-name "nanoclaw" \
|
|
219
|
+
--is-main \
|
|
220
|
+
--no-trigger-required
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**To find your chat ID:** Send any message to your bot, then:
|
|
224
|
+
```bash
|
|
225
|
+
curl -s --proxy $HTTPS_PROXY "https://api.telegram.org/bot<TOKEN>/getUpdates" | python3 -m json.tool
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Telegram in groups:** Disable Group Privacy in @BotFather (`/mybots` > Bot Settings > Group Privacy > Turn off), then remove and re-add the bot.
|
|
229
|
+
|
|
230
|
+
**Important:** If the Telegram skill creates `src/channels/telegram.ts`, you'll need to patch it for proxy support. Add an `HttpsProxyAgent` and pass it to grammy's `Bot` constructor via `baseFetchConfig.agent`. Then rebuild.
|
|
231
|
+
|
|
232
|
+
### WhatsApp
|
|
233
|
+
|
|
234
|
+
Make sure you configured proxy bypass in [Step 1](#step-1-create-the-sandbox) first.
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# Apply the WhatsApp skill
|
|
238
|
+
npx tsx scripts/apply-skill.ts .claude/skills/add-whatsapp
|
|
239
|
+
|
|
240
|
+
# Rebuild
|
|
241
|
+
npm run build
|
|
242
|
+
|
|
243
|
+
# Configure .env
|
|
244
|
+
cat > .env << EOF
|
|
245
|
+
ASSISTANT_NAME=nanoclaw
|
|
246
|
+
ANTHROPIC_API_KEY=proxy-managed
|
|
247
|
+
EOF
|
|
248
|
+
mkdir -p data/env && cp .env data/env/env
|
|
249
|
+
|
|
250
|
+
# Authenticate (choose one):
|
|
251
|
+
|
|
252
|
+
# QR code — scan with WhatsApp camera:
|
|
253
|
+
npx tsx src/whatsapp-auth.ts
|
|
254
|
+
|
|
255
|
+
# OR pairing code — enter code in WhatsApp > Linked Devices > Link with phone number:
|
|
256
|
+
npx tsx src/whatsapp-auth.ts --pairing-code --phone <phone-number-no-plus>
|
|
257
|
+
|
|
258
|
+
# Register your chat (JID = your phone number + @s.whatsapp.net)
|
|
259
|
+
npx tsx setup/index.ts --step register \
|
|
260
|
+
--jid "<phone>@s.whatsapp.net" \
|
|
261
|
+
--name "My Chat" \
|
|
262
|
+
--trigger "@nanoclaw" \
|
|
263
|
+
--folder "whatsapp_main" \
|
|
264
|
+
--channel whatsapp \
|
|
265
|
+
--assistant-name "nanoclaw" \
|
|
266
|
+
--is-main \
|
|
267
|
+
--no-trigger-required
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Important:** The WhatsApp skill files (`src/channels/whatsapp.ts` and `src/whatsapp-auth.ts`) also need proxy patches — add `HttpsProxyAgent` for WebSocket connections and a proxy-aware version fetch. Then rebuild.
|
|
271
|
+
|
|
272
|
+
### Both Channels
|
|
273
|
+
|
|
274
|
+
Apply both skills, patch both for proxy support, combine the `.env` variables, and register each chat separately.
|
|
275
|
+
|
|
276
|
+
## Step 7: Run
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npm start
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
You don't need to set `ANTHROPIC_API_KEY` manually. The sandbox proxy intercepts requests and replaces `proxy-managed` with your real key automatically.
|
|
283
|
+
|
|
284
|
+
## Networking Details
|
|
285
|
+
|
|
286
|
+
### How the proxy works
|
|
287
|
+
|
|
288
|
+
All traffic from the sandbox routes through the host proxy at `host.docker.internal:3128`:
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
Agent container → DinD bridge → Sandbox VM → host.docker.internal:3128 → Host proxy → api.anthropic.com
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**"Bypass" does not mean traffic skips the proxy.** It means the proxy passes traffic through without MITM inspection. Node.js doesn't automatically use `HTTP_PROXY` env vars — you need explicit `HttpsProxyAgent` configuration in every HTTP/WebSocket client.
|
|
295
|
+
|
|
296
|
+
### Shared paths for DinD mounts
|
|
297
|
+
|
|
298
|
+
Only the workspace directory is available for Docker-in-Docker bind mounts. Paths outside the workspace fail with "path not shared":
|
|
299
|
+
- `/dev/null` → replace with an empty file in the project dir
|
|
300
|
+
- `/usr/local/share/ca-certificates/` → copy cert to project dir
|
|
301
|
+
- `/home/agent/` → clone to workspace instead
|
|
302
|
+
|
|
303
|
+
### Git clone and virtiofs
|
|
304
|
+
|
|
305
|
+
The workspace is mounted via virtiofs. Git's pack file handling can corrupt over virtiofs during clone. Workaround: clone to `/home/agent` first, then `mv` into the workspace.
|
|
306
|
+
|
|
307
|
+
## Troubleshooting
|
|
308
|
+
|
|
309
|
+
### npm install fails with SELF_SIGNED_CERT_IN_CHAIN
|
|
310
|
+
```bash
|
|
311
|
+
npm config set strict-ssl false
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Container build fails with proxy errors
|
|
315
|
+
```bash
|
|
316
|
+
docker build \
|
|
317
|
+
--build-arg http_proxy=$http_proxy \
|
|
318
|
+
--build-arg https_proxy=$https_proxy \
|
|
319
|
+
-t nanoclaw-agent:latest container/
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Agent containers fail with "path not shared"
|
|
323
|
+
All bind-mounted paths must be under the workspace directory. Check:
|
|
324
|
+
- Is NanoClaw cloned into the workspace? (not `/home/agent/`)
|
|
325
|
+
- Is the CA cert copied to the project root?
|
|
326
|
+
- Has the empty `.env` shadow file been created?
|
|
327
|
+
|
|
328
|
+
### Agent containers can't reach Anthropic API
|
|
329
|
+
Verify proxy env vars are forwarded to agent containers. Check container logs for `HTTP_PROXY=http://host.docker.internal:3128`.
|
|
330
|
+
|
|
331
|
+
### WhatsApp error 405
|
|
332
|
+
The version fetch is returning a stale version. Make sure the proxy-aware `fetchWaVersionViaProxy` patch is applied — it fetches `sw.js` through `HttpsProxyAgent` and parses `client_revision`.
|
|
333
|
+
|
|
334
|
+
### WhatsApp "Connection failed" immediately
|
|
335
|
+
Proxy bypass not configured. From the **host**, run:
|
|
336
|
+
```bash
|
|
337
|
+
docker sandbox network proxy <sandbox-name> \
|
|
338
|
+
--bypass-host web.whatsapp.com \
|
|
339
|
+
--bypass-host "*.whatsapp.com" \
|
|
340
|
+
--bypass-host "*.whatsapp.net"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Telegram bot doesn't receive messages
|
|
344
|
+
1. Check the grammy proxy patch is applied (look for `HttpsProxyAgent` in `src/channels/telegram.ts`)
|
|
345
|
+
2. Check Group Privacy is disabled in @BotFather if using in groups
|
|
346
|
+
|
|
347
|
+
### Git clone fails with "inflate: data stream error"
|
|
348
|
+
Clone to a non-workspace path first, then move:
|
|
349
|
+
```bash
|
|
350
|
+
cd ~ && git clone https://github.com/qwibitai/nanoclaw.git && mv nanoclaw /path/to/workspace/nanoclaw
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### WhatsApp QR code doesn't display
|
|
354
|
+
Run the auth command interactively inside the sandbox (not piped through `docker sandbox exec`):
|
|
355
|
+
```bash
|
|
356
|
+
docker sandbox run shell-nanoclaw-workspace
|
|
357
|
+
# Then inside:
|
|
358
|
+
npx tsx src/whatsapp-auth.ts
|
|
359
|
+
```
|