- "Never ask again" now removes diagnostics from both skills
- Added shell commands to gather version, platform, arch, node version
- Show only properties object to user, not api_key/distinct_id
- Write full PostHog payload to temp file, send with curl -d @file
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove send-diagnostics.ts entirely. Claude writes the JSON, shows
it to the user, and sends via curl. Opt-out is permanent: Claude
replaces diagnostics.md contents and removes the section from SKILL.md.
No dependencies, no state files, no .nanoclaw/ directory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show example commands with placeholder values. Claude fills in the
actual values from the session in one shot — no multi-step build process.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace shared _shared/diagnostics.md with dedicated diagnostics.md
files in setup/ and update-nanoclaw/. Each contains only the event
types relevant to that skill. References updated to local links.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove diagnostics appendage from all other skills. Only /setup and
/update-nanoclaw need telemetry — these are the two points where we
can detect regressions and track improvements across the user base.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Demote Docker Sandboxes from a prominent hero banner to inline
mentions in the features list and FAQ. New users now land on
Quick Start first.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the Python CLI script from inline markdown into scripts/claw,
aligning with the Claude Code skills standard (code in files, not md).
Remove non-standard `author` frontmatter field. SKILL.md now uses
${CLAUDE_SKILL_DIR} substitution to copy the script during install.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Users can send /remote-control from the main group in any channel to
spawn a detached `claude remote-control` process on the host. The
session URL is sent back through the channel. /remote-control-end
kills the session.
Key design decisions:
- One global session at a time, restricted to main group only
- Process is fully detached (stdout/stderr to files, not pipes) so it
survives NanoClaw restarts
- PID + URL persisted to data/remote-control.json; restored on startup
- Commands intercepted in onMessage before DB storage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Step-by-step guide for running NanoClaw in Docker Sandboxes from
scratch without the install script. Covers proxy patches, DinD
mount fixes, channel setup, networking details, and troubleshooting.
Validated on macOS (Apple Silicon) with WhatsApp — other channels
and environments may need additional proxy patches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keep heading and description centered, but left-align the install
blocks and labels so they don't clash with the code block layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the Agent Swarms / Claude Code lines at the top with a
prominent Docker Sandboxes announcement section including install
commands and a link to the blog post.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of failing on package-lock.json merge conflicts, take the
fork's version and continue. Applied to all channel skill merge
instructions and CLAUDE.md troubleshooting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
setup.sh ran npm install which modified package-lock.json, causing
git merge to refuse during channel skill installation. Switch to
npm ci (deterministic, doesn't modify lockfile) and clean up stale
peer flags in the lockfile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move skill definitions from the nanoclaw-skills marketplace plugin
into .claude/skills/ so they're available as unprefixed slash commands
(e.g. /add-whatsapp instead of /nanoclaw-skills:add-whatsapp).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the custom skills engine with standard git operations.
Feature skills are now git branches (on upstream or channel forks)
applied via `git merge`. Channels are separate fork repos.
- Remove skills-engine/ (6,300+ lines), apply/uninstall/rebase scripts
- Remove old skill format (add/, modify/, manifest.yaml) from all skills
- Remove old CI (skill-drift.yml, skill-pr.yml)
- Add merge-forward CI for upstream skill branches
- Add fork notification (repository_dispatch to channel forks)
- Add marketplace config (.claude/settings.json)
- Add /update-skills operational skill
- Update /setup and /customize for marketplace plugin install
- Add docs/skills-as-branches.md architecture doc
Channel forks created: nanoclaw-whatsapp (with 5 skill branches),
nanoclaw-telegram, nanoclaw-discord, nanoclaw-slack, nanoclaw-gmail.
Upstream retains: skill/ollama-tool, skill/apple-container, skill/compact.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
schedule_task was creating duplicate tasks when users asked to modify
a schedule, because the agent had no way to update an existing task
and didn't know the ID of the task it created. Now schedule_task
generates and returns the task ID, and a new update_task tool allows
modifying prompt, schedule_type, and schedule_value in place.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The underscore prefix convention signals an unused parameter, but it's
now actively used by the sender allowlist logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After validation, the update skill now diffs CHANGELOG.md against the
backup tag to detect [BREAKING] entries. If found, it shows each
breaking change and offers to run the referenced migration skill.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
applySkill() now creates .nanoclaw/ automatically if state.yaml is
missing, removing the need to run --init as a separate step.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: shadow .env file in container to prevent agents from reading secrets
The main agent's container mounts the project root read-only, which
inadvertently exposed the .env file containing API keys. Mount /dev/null
over /workspace/project/.env to shadow it — secrets are already passed
via stdin and never need to be read from disk inside the container.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: adapt .env shadowing and runtime for Apple Container
Apple Container (VirtioFS) only supports directory mounts, not file
mounts. The previous /dev/null host-side mount over .env crashes with
VZErrorDomain "A directory sharing device configuration is invalid".
- Dockerfile: entrypoint now shadows .env via mount --bind inside the
container, then drops privileges via setpriv to the host UID/GID
- container-runner: main containers skip --user and pass RUN_UID/RUN_GID
env vars so entrypoint starts as root for mount --bind
- container-runtime: switch to Apple Container CLI (container), fix
cleanupOrphans to use container list --format json
- Skill: add Dockerfile and container-runner.ts to
convert-to-apple-container skill (v1.1.0)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: revert src to Docker runtime, keep Apple Container in skill only
The source files should remain Docker-compatible. The Apple Container
adaptations live in the convert-to-apple-container skill and are applied
on demand.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Validate PID as positive integer and use process.kill() instead of
shell interpolation via execSync, eliminating injection vector.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The new /update-nanoclaw skill (PR #217) replaces the old update
mechanism. Delete the old skill, update module, CLI scripts, and tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The telegram.ts implementation was updated to pass channel and isGroup
to onChatMetadata but the test file still asserted the old 3-arg form.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- connect() warns and returns instead of throwing when ~/.gmail-mcp/
credentials are missing, preventing app crash
- index.ts wraps gmail.connect() in try/catch as a safety net
- Poll loop uses exponential backoff on consecutive errors (caps at 30m)
instead of hammering the Gmail API every 60s on auth failures
- Switch from setInterval to setTimeout chain for proper backoff timing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The fetchLatestWaWebVersion call added in #443 could crash the
connection flow if the HTTP fetch fails. Wrap with .catch() to log
and fall back to the default Baileys version.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add /update to skills tables in CLAUDE.md and REQUIREMENTS.md. Add
"Updating" section to README. Remove /add-telegram and /add-discord
from RFS (already exist). Add CI workflow to bump patch version on
source/container changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Interactive skill that guides Claude through fetching upstream NanoClaw,
previewing changes, merging with customizations, running migrations, and
verifying the result. Includes:
- SKILL.md with 9-step update flow
- fetch-upstream.sh: detects remote, fetches, extracts tracked paths
- run-migrations.ts: discovers and runs version-ordered migrations
- post-update.ts: clears backup after conflict resolution
- update-core.ts: adds --json and --preview-only flags
- BASE_INCLUDES moved to constants.ts as single source of truth
- 16 new tests covering fetch, migrations, and CLI flags
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Containers had no TZ set, so any time-aware code inside ran in UTC while
the host interpreted bare timestamps as local time. Now TIMEZONE from
config.ts is passed via -e TZ= to the container args.
Also rejects Z-suffixed or offset-suffixed timestamps in the container's
schedule_task validation, since bare timestamps are expected to be local
time and silently accepting UTC suffixes would cause an offset mismatch.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The main group's project root was mounted read-write, allowing the
container agent to modify host application code (e.g. dist/container-runner.js)
to inject arbitrary mounts on next restart — a full sandbox escape.
Fix: mount the project root read-only. Writable paths the agent needs
(group folder, IPC, .claude/) are already mounted separately. The
agent-runner source is now copied into a per-group writable location
so agents can still customize container-side behavior without affecting
host code or other groups.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Setup scripts are standalone CLI tools run via tsx with no runtime
imports from the main app. Moving them out of src/ excludes them from
the tsc build output and reduces the compiled bundle size.
- git mv src/setup/ setup/
- Fix imports to use ../src/logger.js and ../src/config.js
- Update package.json, vitest.config.ts, SKILL.md references
- Fix platform tests to be cross-platform (macOS + Linux)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Several async calls in the message loop and group queue are
fire-and-forget without .catch() handlers. When WhatsApp disconnects
or containers fail unexpectedly, these produce unhandled rejections
that can crash the process.
Add explicit .catch() at each call site so errors are logged with
full context (groupJid, taskId) instead of crashing:
- channel.setTyping() in message loop (adapted for channel abstraction)
- startMessageLoop() in main()
- runForGroup() and runTask() in group-queue (5 call sites)
Closes#221
Co-authored-by: Naveen Jain <1779929+naveenspark@users.noreply.github.com>
Co-authored-by: Skip Potter <skip.potter.va@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The test expected voice notes (audioMessage with no caption) to be
delivered with empty content, but 6f177ad added a guard that skips
messages with no text content. Update assertion accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The original notifyIdle condition (!result.result) never fired in
streaming input mode because every result has non-null text content.
This caused due tasks to wait up to 30 minutes for the idle timer.
- Call notifyIdle for ALL successful results (not just null ones)
- Add isTaskContainer flag so user messages queue instead of being
forwarded to task containers (which blocked notifyIdle from the
message container's onOutput path)
- Reset idleWaiting in sendMessage so containers aren't preempted
while actively working on a new incoming message
- Replace 30-min IDLE_TIMEOUT with 10s close timer for task containers
since they are single-turn and should exit promptly after their result
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Containers that finish work but stay alive in waitForIpcMessage() block
queued scheduled tasks. Previous approaches killed active containers
mid-work. This fix tracks idle state via the session-update marker
(status: success, result: null) and only preempts when the container
is idle-waiting, not actively working.
Closes#293
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix 你→您 inconsistency in README_zh.md
- Add missing nanoclaw.dev link to README_zh.md header
- Remove Skills System CLI section from both README.md and README_zh.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cleanupMergeState() without a filePath runs bare `git reset`, which
resets the entire index and can stage deletions of unrelated files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Docker is now the default runtime. The /convert-to-apple-container skill
uses the new skills engine format (manifest.yaml, modify/, intent files,
tests/) to switch to Apple Container on macOS.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add voice transcription skill package at
.claude/skills/add-voice-transcription/ so it can be applied via the
skills engine. Skill adds src/transcription.ts (OpenAI Whisper), modifies
whatsapp.ts to detect/transcribe voice notes, and includes intent files,
3 test cases, and 8 skill validation tests.
Also fixes skills engine runNpmInstall() to use --legacy-peer-deps,
needed for any skill adding deps with Zod v3 peer requirements.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
All skills now reference Docker CLI instead of Apple Container CLI.
Setup skill defaults to Docker with optional /convert-to-apple-container.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>