Merge upstream/main: resolve conflicts preserving local customizations
Some checks failed
Bump version / bump-version (push) Has been cancelled
Update token count / update-tokens (push) Has been cancelled

Merge 207 upstream commits (up to v1.2.41) while keeping Apple Container
runtime support and MiniMax model forwarding. Remove deleted telegram.ts
and credential-proxy.ts imports, widen CONTAINER_RUNTIME_BIN type for
Apple Container detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
woozu-shin
2026-03-28 14:44:28 +09:00
65 changed files with 2948 additions and 3092 deletions

View File

@@ -11,6 +11,34 @@ Both timers fire at the same time, so containers always exit via hard SIGKILL (c
### 3. Cursor advanced before agent succeeds
`processGroupMessages` advances `lastAgentTimestamp` before the agent runs. If the container times out, retries find no messages (cursor already past them). Messages are permanently lost on timeout.
### 4. Kubernetes image garbage collection deletes nanoclaw-agent image
**Symptoms**: `Container exited with code 125: pull access denied for nanoclaw-agent` — the container image disappears overnight or after a few hours, even though you just built it.
**Cause**: If your container runtime has Kubernetes enabled (Rancher Desktop enables it by default), the kubelet runs image garbage collection when disk usage exceeds 85%. NanoClaw containers are ephemeral (run and exit), so `nanoclaw-agent:latest` is never protected by a running container. The kubelet sees it as unused and deletes it — often overnight when no messages are being processed. Other images (docker-compose services) survive because they have long-running containers referencing them.
**Fix**: Disable Kubernetes if you don't need it:
```bash
# Rancher Desktop
rdctl set --kubernetes-enabled=false
# Then rebuild the container image
./container/build.sh
```
**Diagnosis**: Check the k3s log for image GC activity:
```bash
grep -i "nanoclaw" ~/Library/Logs/rancher-desktop/k3s.log
# Look for: "Removing image to free bytes" with the nanoclaw-agent image ID
```
Check NanoClaw logs for image status:
```bash
grep -E "image found|image NOT found|image missing" logs/nanoclaw.log
```
If you need Kubernetes enabled, set `CONTAINER_IMAGE` to an image stored in a registry that the kubelet won't GC, or raise the GC thresholds.
## Quick Status Check
```bash
@@ -19,16 +47,16 @@ launchctl list | grep nanoclaw
# Expected: PID 0 com.nanoclaw (PID = running, "-" = not running, non-zero exit = crashed)
# 2. Any running containers?
container ls --format '{{.Names}} {{.Status}}' 2>/dev/null | grep nanoclaw
docker ps --format '{{.Names}} {{.Status}}' 2>/dev/null | grep nanoclaw
# 3. Any stopped/orphaned containers?
container ls -a --format '{{.Names}} {{.Status}}' 2>/dev/null | grep nanoclaw
docker ps -a --format '{{.Names}} {{.Status}}' 2>/dev/null | grep nanoclaw
# 4. Recent errors in service log?
grep -E 'ERROR|WARN' logs/nanoclaw.log | tail -20
# 5. Is WhatsApp connected? (look for last connection event)
grep -E 'Connected to WhatsApp|Connection closed|connection.*close' logs/nanoclaw.log | tail -5
# 5. Are channels connected? (look for last connection event)
grep -E 'Connected|Connection closed|connection.*close|channel.*ready' logs/nanoclaw.log | tail -5
# 6. Are groups loaded?
grep 'groupCount' logs/nanoclaw.log | tail -3
@@ -77,7 +105,7 @@ grep -E 'Scheduling retry|retry|Max retries' logs/nanoclaw.log | tail -10
## Agent Not Responding
```bash
# Check if messages are being received from WhatsApp
# Check if messages are being received from channels
grep 'New messages' logs/nanoclaw.log | tail -10
# Check if messages are being processed (container spawned)
@@ -107,10 +135,10 @@ sqlite3 store/messages.db "SELECT name, container_config FROM registered_groups;
# Test-run a container to check mounts (dry run)
# Replace <group-folder> with the group's folder name
container run -i --rm --entrypoint ls nanoclaw-agent:latest /workspace/extra/
docker run -i --rm --entrypoint ls nanoclaw-agent:latest /workspace/extra/
```
## WhatsApp Auth Issues
## Channel Auth Issues
```bash
# Check if QR code was requested (means auth expired)

15
docs/README.md Normal file
View File

@@ -0,0 +1,15 @@
# NanoClaw Documentation
The official documentation is at **[docs.nanoclaw.dev](https://docs.nanoclaw.dev)**.
The files in this directory are original design documents and developer references. For the most current and accurate information, use the documentation site.
| This directory | Documentation site |
|---|---|
| [SPEC.md](SPEC.md) | [Architecture](https://docs.nanoclaw.dev/concepts/architecture) |
| [SECURITY.md](SECURITY.md) | [Security model](https://docs.nanoclaw.dev/concepts/security) |
| [REQUIREMENTS.md](REQUIREMENTS.md) | [Introduction](https://docs.nanoclaw.dev/introduction) |
| [skills-as-branches.md](skills-as-branches.md) | [Skills system](https://docs.nanoclaw.dev/integrations/skills-system) |
| [DEBUG_CHECKLIST.md](DEBUG_CHECKLIST.md) | [Troubleshooting](https://docs.nanoclaw.dev/advanced/troubleshooting) |
| [docker-sandboxes.md](docker-sandboxes.md) | [Docker Sandboxes](https://docs.nanoclaw.dev/advanced/docker-sandboxes) |
| [APPLE-CONTAINER-NETWORKING.md](APPLE-CONTAINER-NETWORKING.md) | [Container runtime](https://docs.nanoclaw.dev/advanced/container-runtime) |

View File

@@ -22,9 +22,9 @@ The entire codebase should be something you can read and understand. One Node.js
Instead of application-level permission systems trying to prevent agents from accessing things, agents run in actual Linux containers. The isolation is at the OS level. Agents can only see what's explicitly mounted. Bash access is safe because commands run inside the container, not on your Mac.
### Built for One User
### Built for the Individual User
This isn't a framework or a platform. It's working software for my specific needs. I use WhatsApp and Email, so it supports WhatsApp and Email. I don't use Telegram, so it doesn't support Telegram. I add the integrations I actually want, not every possible integration.
This isn't a framework or a platform. It's software that fits each user's exact needs. You fork the repo, add the channels you want (WhatsApp, Telegram, Discord, Slack, Gmail), and end up with clean code that does exactly what you need.
### Customization = Code Changes
@@ -44,41 +44,31 @@ When people contribute, they shouldn't add "Telegram support alongside WhatsApp.
## RFS (Request for Skills)
Skills we'd love contributors to build:
Skills we'd like to see contributed:
### Communication Channels
Skills to add or switch to different messaging platforms:
- `/add-telegram` - Add Telegram as an input channel
- `/add-slack` - Add Slack as an input channel
- `/add-discord` - Add Discord as an input channel
- `/add-sms` - Add SMS via Twilio or similar
- `/convert-to-telegram` - Replace WhatsApp with Telegram entirely
- `/add-signal` - Add Signal as a channel
- `/add-matrix` - Add Matrix integration
### Container Runtime
The project uses Docker by default (cross-platform). For macOS users who prefer Apple Container:
- `/convert-to-apple-container` - Switch from Docker to Apple Container (macOS-only)
### Platform Support
- `/setup-linux` - Make the full setup work on Linux (depends on Docker conversion)
- `/setup-windows` - Windows support via WSL2 + Docker
> **Note:** Telegram, Slack, Discord, Gmail, and Apple Container skills already exist. See the [skills documentation](https://docs.nanoclaw.dev/integrations/skills-system) for the full list.
---
## Vision
A personal Claude assistant accessible via WhatsApp, with minimal custom code.
A personal Claude assistant accessible via messaging, with minimal custom code.
**Core components:**
- **Claude Agent SDK** as the core agent
- **Containers** for isolated agent execution (Linux VMs)
- **WhatsApp** as the primary I/O channel
- **Multi-channel messaging** (WhatsApp, Telegram, Discord, Slack, Gmail) — add exactly the channels you need
- **Persistent memory** per conversation and globally
- **Scheduled tasks** that run Claude and can message back
- **Web access** for search and browsing
- **Browser automation** via agent-browser
**Implementation approach:**
- Use existing tools (WhatsApp connector, Claude Agent SDK, MCP servers)
- Use existing tools (channel libraries, Claude Agent SDK, MCP servers)
- Minimal glue code
- File-based systems where possible (CLAUDE.md for memory, folders for groups)
@@ -87,7 +77,7 @@ A personal Claude assistant accessible via WhatsApp, with minimal custom code.
## Architecture Decisions
### Message Routing
- A router listens to WhatsApp and routes messages based on configuration
- A router listens to connected channels and routes messages based on configuration
- Only messages from registered groups are processed
- Trigger: `@Andy` prefix (case insensitive), configurable via `ASSISTANT_NAME` env var
- Unregistered groups are ignored completely
@@ -136,10 +126,11 @@ A personal Claude assistant accessible via WhatsApp, with minimal custom code.
## Integration Points
### WhatsApp
- Using baileys library for WhatsApp Web connection
### Channels
- WhatsApp (baileys), Telegram (grammy), Discord (discord.js), Slack (@slack/bolt), Gmail (googleapis)
- Each channel lives in a separate fork repo and is added via skills (e.g., `/add-whatsapp`, `/add-telegram`)
- Messages stored in SQLite, polled by router
- QR code authentication during setup
- Channels self-register at startup — unconfigured channels are skipped with a warning
### Scheduler
- Built-in scheduler runs on the host, spawns containers for task execution
@@ -170,12 +161,12 @@ A personal Claude assistant accessible via WhatsApp, with minimal custom code.
- Each user gets a custom setup matching their exact needs
### Skills
- `/setup` - Install dependencies, authenticate WhatsApp, configure scheduler, start services
- `/customize` - General-purpose skill for adding capabilities (new channels like Telegram, new integrations, behavior changes)
- `/update` - Pull upstream changes, merge with customizations, run migrations
- `/setup` - Install dependencies, configure channels, start services
- `/customize` - General-purpose skill for adding capabilities
- `/update-nanoclaw` - Pull upstream changes, merge with customizations
### Deployment
- Runs on local Mac via launchd
- Runs on macOS (launchd), Linux (systemd), or Windows (WSL2)
- Single Node.js process handles everything
---

View File

@@ -7,7 +7,7 @@
| Main group | Trusted | Private self-chat, admin control |
| Non-main groups | Untrusted | Other users may be malicious |
| Container agents | Sandboxed | Isolated execution environment |
| WhatsApp messages | User input | Potential prompt injection |
| Incoming messages | User input | Potential prompt injection |
## Security Boundaries
@@ -64,20 +64,22 @@ Messages and task operations are verified against group identity:
| View all tasks | ✓ | Own only |
| Manage other groups | ✓ | ✗ |
### 5. Credential Isolation (Credential Proxy)
### 5. Credential Isolation (OneCLI Agent Vault)
Real API credentials **never enter containers**. Instead, the host runs an HTTP credential proxy that injects authentication headers transparently.
Real API credentials **never enter containers**. NanoClaw uses [OneCLI's Agent Vault](https://github.com/onecli/onecli) to proxy outbound requests and inject credentials at the gateway level.
**How it works:**
1. Host starts a credential proxy on `CREDENTIAL_PROXY_PORT` (default: 3001)
2. Containers receive `ANTHROPIC_BASE_URL=http://host.docker.internal:<port>` and `ANTHROPIC_API_KEY=placeholder`
3. The SDK sends API requests to the proxy with the placeholder key
4. The proxy strips placeholder auth, injects real credentials (`x-api-key` or `Authorization: Bearer`), and forwards to `api.anthropic.com`
5. Agents cannot discover real credentials — not in environment, stdin, files, or `/proc`
1. Credentials are registered once with `onecli secrets create`, stored and managed by OneCLI
2. When NanoClaw spawns a container, it calls `applyContainerConfig()` to route outbound HTTPS through the OneCLI gateway
3. The gateway matches requests by host and path, injects the real credential, and forwards
4. Agents cannot discover real credentials — not in environment, stdin, files, or `/proc`
**Per-agent policies:**
Each NanoClaw group gets its own OneCLI agent identity. This allows different credential policies per group (e.g. your sales agent vs. support agent). OneCLI supports rate limits, and time-bound access and approval flows are on the roadmap.
**NOT Mounted:**
- WhatsApp session (`store/auth/`) - host only
- Mount allowlist - external, never mounted
- Channel auth sessions (`store/auth/`) host only
- Mount allowlist external, never mounted
- Any credentials matching blocked patterns
- `.env` is shadowed with `/dev/null` in the project root mount
@@ -97,7 +99,7 @@ Real API credentials **never enter containers**. Instead, the host runs an HTTP
```
┌──────────────────────────────────────────────────────────────────┐
│ UNTRUSTED ZONE │
WhatsApp Messages (potentially malicious) │
Incoming Messages (potentially malicious)
└────────────────────────────────┬─────────────────────────────────┘
▼ Trigger check, input escaping
@@ -107,7 +109,7 @@ Real API credentials **never enter containers**. Instead, the host runs an HTTP
│ • IPC authorization │
│ • Mount validation (external allowlist) │
│ • Container lifecycle │
│ • Credential proxy (injects auth headers)
│ • OneCLI Agent Vault (injects credentials, enforces policies)
└────────────────────────────────┬─────────────────────────────────┘
▼ Explicit mounts only, no secrets
@@ -116,7 +118,7 @@ Real API credentials **never enter containers**. Instead, the host runs an HTTP
│ • Agent execution │
│ • Bash commands (sandboxed) │
│ • File operations (limited to mounts) │
│ • API calls routed through credential proxy
│ • API calls routed through OneCLI Agent Vault
│ • No real credentials in environment or filesystem │
└──────────────────────────────────────────────────────────────────┘
```