- Isolate Claude sessions per-group (data/sessions/{group}/.claude/)
to prevent cross-group access to conversation history
- Remove Gmail MCP from built-in (now available via /add-gmail skill)
- Add SECURITY.md documenting the security model
- Move docs to docs/ folder (SPEC.md, REQUIREMENTS.md, SECURITY.md)
- Update documentation to reflect changes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update main group CLAUDE.md with Qwibit Ops folder access docs
- Add WhatsApp formatting guidelines
- Create NanoClaw Testing group folder
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Skill guides users through adding Gmail to NanoClaw with two modes:
- Tool Mode: Agent can read/send emails when triggered from WhatsApp
- Channel Mode: Emails can trigger the agent and receive replies
Includes step-by-step GCP OAuth setup, code integration instructions,
and troubleshooting guidance.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix potential memory DoS via unbounded container output
Add CONTAINER_MAX_OUTPUT_SIZE (default 10MB) to limit accumulated
stdout/stderr from container processes. Without this limit, a malicious
or buggy container could emit huge output leading to host memory
exhaustion.
Changes:
- Add configurable CONTAINER_MAX_OUTPUT_SIZE in config.ts
- Implement size-limited output buffering in runContainerAgent
- Log warnings when truncation occurs
- Include truncation status in container logs
https://claude.ai/code/session_01TjVDwwaGwbcFDdmrFF2y8B
* Update package-lock.json
https://claude.ai/code/session_01TjVDwwaGwbcFDdmrFF2y8B
---------
Co-authored-by: Claude <noreply@anthropic.com>
Previously, lastTimestamp was unconditionally advanced after each message,
even if processMessage failed. This caused transient errors to permanently
drop messages since they would never be retried.
Now the cursor only advances after successful processing, implementing
at-least-once delivery semantics. On failure, the loop breaks and the
failed message will be retried on the next poll iteration.
https://claude.ai/code/session_01SEQDWxXeZHe7t1bb5cw2CA
Co-authored-by: Claude <noreply@anthropic.com>
ASSISTANT_NAME was interpolated directly into a regex without escaping.
If the name contained regex metacharacters (e.g., @A.*), the trigger
would match unintended patterns. This adds escapeRegex() to properly
escape special characters before building the TRIGGER_PATTERN.
https://claude.ai/code/session_01Lvuxq73qa9S4rtmGpX1WsP
Co-authored-by: Claude <noreply@anthropic.com>
updateChatName() was inserting new groups with last_message_time set to
Unix epoch (1970-01-01), causing newly discovered groups to appear at
the bottom of activity-ordered listings. Changed to use current time
for new groups while preserving existing timestamps for known groups.
https://claude.ai/code/session_018rcZvALfF3ND2jfcvBaFo2
Co-authored-by: Claude <noreply@anthropic.com>
- Remove unused claude-agent-sdk from host deps (only used in container)
- Remove dead scheduler MCP config (built into IPC)
- Remove unused eslint script
- Add clear error message when Apple Container fails to start
- Auto-generate launchd plist with real paths in setup skill
- Standardize Node.js version to 20+ everywhere
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add secure mount allowlist validation
Addresses arbitrary host mount vulnerability by validating additional
mounts against an external allowlist stored at ~/.config/nanoclaw/.
This location is never mounted into containers, making it tamper-proof.
Security measures:
- Allowlist cached in memory (edits require process restart)
- Real path resolution (blocks symlink and .. traversal attacks)
- Blocked patterns for sensitive paths (.ssh, .gnupg, .aws, etc.)
- Non-main groups forced to read-only when nonMainReadOnly is true
- Container path validation prevents /workspace/extra escape
https://claude.ai/code/session_01BPqdNy4EAHHJcdtZ27TXkh
* Add mount allowlist setup to /setup skill
Interactive walkthrough that asks users:
- Whether they want agents to access external directories
- Which directories to allow (with paths)
- Read-write vs read-only for each
- Whether non-main groups should be restricted to read-only
Creates ~/.config/nanoclaw/mount-allowlist.json based on answers.
https://claude.ai/code/session_01BPqdNy4EAHHJcdtZ27TXkh
---------
Co-authored-by: Claude <noreply@anthropic.com>
- Add TIMEZONE config using system timezone for cron expressions
- Filter bot messages by content prefix instead of is_from_me
(user shares WhatsApp account with bot)
- Format messages as XML for cleaner agent parsing
- Update schedule_task tool to clarify local time usage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
52+ modules, 8 config files, 45+ deps, 15 channel providers.
Security is application-level (allowlists) vs actual container isolation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Sync group names from WhatsApp via groupFetchAllParticipating()
- Store group names in chats table (jid -> name mapping)
- Daily sync with 24h cache, on-demand refresh via IPC
- Write available_groups.json snapshot for agent (main group only)
- Agent can request refresh_groups via IPC if group not found
- Update documentation in main CLAUDE.md and debug skill
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Scheduled tasks can now run in either:
- "group" mode: uses the group's conversation session for context
- "isolated" mode: runs with a fresh session (previous behavior)
The tool description guides the agent on when to use each mode and
prompts them to ask the user if unclear. Group mode is now the default.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- PR #10: Add sentinel markers for robust JSON parsing between container
and host. Fallback to last-line parsing for backwards compatibility.
- PR #5: Look up target JID from registeredGroups instead of trusting
IPC payload, fixing cross-group scheduled tasks getting wrong chat_jid.
- PR #8: Add lightweight schedule validation in container MCP that
returns errors to agents (cron syntax, positive interval, valid ISO
timestamp). Also defensive validation on host side.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, lastAgentTimestamp was updated regardless of whether
runAgent succeeded or failed. This caused messages to be skipped
on retry after a failure since they were already marked as processed.
Now the timestamp is only advanced when the agent returns a valid
response, ensuring failed messages will be included in the next retry.
https://claude.ai/code/session_0118wNAJCKY2Asr17Lb91TE2
Previously, lastTimestamp was advanced before processing messages.
If processMessage threw an error, those messages would be skipped
on the next tick since the timestamp had already moved past them.
Now we advance lastTimestamp after each message is successfully
processed (or after catching an error), ensuring no messages are
lost on retry.
https://claude.ai/code/session_01LgHSAs9XbcvZckCe8xPipj
Replace environment-specific fallback '/Users/gavriel' with os.homedir()
and proper error handling. The new getHomeDir() helper function:
- First checks process.env.HOME
- Falls back to os.homedir() for cross-platform support
- Throws a clear error if home directory cannot be determined
https://claude.ai/code/session_011Cs2FWxXMvAdAh4w9A6AZC
Each container now gets its own IPC directory (/data/ipc/{groupFolder}/)
instead of a shared global directory. Identity is determined by which
directory a request came from, not by self-reported data in IPC files.
Authorization enforced:
- send_message: only to chatJids belonging to the source group
- schedule_task: only for the source group (main can target any)
- pause/resume/cancel_task: only for tasks owned by source group
https://claude.ai/code/session_018nmxNEbtgJH7cKDyBSQGAw
Previously, the entire .env file was copied and mounted into containers,
exposing all environment variables to the agent. Now only the specific
authentication variables needed by Claude Code (CLAUDE_CODE_OAUTH_TOKEN
and ANTHROPIC_API_KEY) are extracted and mounted.
https://claude.ai/code/session_01Y6Az5oUPkYmJhA1N9MUd67
Delete child records (task_run_logs) before parent (scheduled_tasks) to avoid foreign key constraint violation when cancelling tasks.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix Apple Container mount issue: move groups/CLAUDE.md to groups/global/
directory (Apple Container only supports directory mounts, not file mounts)
- Fix scheduled tasks for main group: properly detect isMain based on
group_folder instead of always setting false
- Add isScheduledTask flag so agent knows when running as scheduled task
- Improve schedule_task tool description with clear format examples for
cron, interval, and once schedule types
- Update global CLAUDE.md with instructions for scheduled tasks to use
mcp__nanoclaw__send_message when needed
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Keep only comments that explain non-obvious behavior or add context
not apparent from reading the code.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add authorization checks to IPC task operations (pause/resume/cancel)
to prevent cross-group task manipulation
- Only store message content for registered groups; unregistered chats
only get metadata stored for group discovery
- Container logs now only include full input/output in debug mode;
default logging omits sensitive message content
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add PreCompact hook in agent-runner that archives conversations before
compaction, using session summary from sessions-index.json for filename
- Remove /clear command (programmatic compaction not supported by SDK)
- Add /add-clear to RFS for future implementation
- Update CLAUDE.md templates with memory system instructions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Shows "typing..." in WhatsApp while the agent container is running.
Uses Baileys sendPresenceUpdate with 'composing' and 'paused' states.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove dash-as-em-dash patterns throughout
- Add FAQ about what changes are accepted (security, bugs, clear fixes)
- Clarify that enhancements should be skills, not PRs
- Fix "Leverage" → "Use" in REQUIREMENTS.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Acknowledge OpenClaw's vision and usefulness while explaining the
personal motivation: inability to understand or trust a complex
codebase. Emphasize NanoClaw's 8-minute comprehensibility with
Claude Code assistance.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add "Why This Exists" section contrasting with OpenClaw
- Document core philosophy: small, secure, AI-native, skills over features
- Add RFS (Request for Skills) for community contributions
- Rewrite README with proper structure, examples, and FAQ
- Emphasize Claude Agent SDK benefits and ToS compliance
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Setup skill now asks subscription vs API key, can auto-grab token
- Debug skill updated for both auth methods
- SPEC.md documents both authentication options
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix session mount path: ~/.claude/ now mounts to /home/node/.claude/
(container runs as 'node' user with HOME=/home/node, not root)
- Fix ~/.gmail-mcp/ mount path similarly
- Use absolute paths for GROUPS_DIR and DATA_DIR (required for container mounts)
- Auto-start Apple Container system on NanoClaw startup
- Update debug skill with session troubleshooting guide
- Update spec.md with startup sequence and troubleshooting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Container fixes:
- Run as non-root 'node' user (required for --dangerously-skip-permissions)
- Add allowDangerouslySkipPermissions: true to SDK options
- Mount .env file to work around Apple Container -i env var bug
- Use --mount for readonly, -v for read-write (Apple Container quirk)
- Bump SDK to 0.2.29, zod to v4
- Install Claude Code CLI globally in container
Logging improvements:
- Write per-run logs to groups/{folder}/logs/container-*.log
- Add debug-level logging for mounts and container args
Documentation:
- Add /debug skill with comprehensive troubleshooting guide
- Update /setup skill with API key configuration step
- Update SPEC.md with container details, mount syntax, security notes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Main gets /workspace/project with full project access
- Main can query SQLite database and edit configs
- Updated main CLAUDE.md with container paths
- Added docs for configuring additional mounts per group
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Agents run in isolated Linux VMs via Apple Container
- All groups get Bash access (safe - sandboxed in container)
- Browser automation via agent-browser + Chromium
- Per-group configurable additional directory mounts
- File-based IPC for messages and scheduled tasks
- Container image with Node.js 22, Chromium, agent-browser
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Custom nanoclaw MCP server with scheduling tools (schedule_task,
list_tasks, get_task, update_task, pause/resume/cancel_task, send_message)
- Tasks run as full agents in their group's context
- Support for cron, interval, and one-time schedules
- Task run logging with duration and results
- Main channel has Bash access for admin tasks (query DB, manage groups)
- Other groups restricted to file operations only
- Updated docs and requirements
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Format: [Jan 31 2:35 PM] instead of [14:35:00]
Date provides important context for ongoing conversations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>