Each group's on-disk state (CLAUDE.md, .claude-shared/, agent-runner-src/)
is now initialized exactly once at group creation and owned by the group
forever after. Spawn does only mounts — no copies, no settings.json
overwrites, no skill clobbers, no source resyncs.
Global memory composition switches from "host reads /workspace/global/CLAUDE.md
at bootstrap and stuffs it into systemPrompt.append" to "group CLAUDE.md
imports it via @/workspace/global/CLAUDE.md at the top." Edits to global
propagate instantly through the existing read-only mount; no copy, no
restart.
- src/group-init.ts: new initGroupFilesystem(group, opts?) — idempotent,
populates groups/<folder>/, .claude-shared/, agent-runner-src/ only when
paths don't already exist.
- src/container-runner.ts: buildMounts() calls init defensively at the
top (catches existing groups on first spawn after this change), drops
the inline settings.json write, skills cpSync loop, and agent-runner-src
rm-then-copy. Just mounts now.
- src/delivery.ts: create_agent flow uses initGroupFilesystem with
optional instructions, replacing the inline mkdirSync + writeFileSync.
- container/agent-runner/src/index.ts: drops GLOBAL_CLAUDE_MD reading.
systemContext.instructions is now only the runtime-generated
destinations addendum.
- scripts/migrate-group-claude-md.ts: one-shot migration that prepends
the @-import to existing groups' CLAUDE.md. Skips if global doesn't
exist or if the @-import is already present (regex match on the @ form
to avoid false positives from prose mentions of the path).
- groups/main/CLAUDE.md: prepended by the migration.
Existing groups need a one-time wipe of their agent-runner-src/ dir so
init re-populates from current host source — done locally before this
commit. Future host-side updates to container/skills/ or
container/agent-runner/src/ won't auto-propagate; that's the trade-off
for unconditional persistence and will be covered by host-mediated
refresh tools in a follow-up.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- session-manager.ts: shrink the cross-mount invariant header from 31
lines to 12, keeping each invariant's cause and consequence inline.
- agent-runner/db/connection.ts: parallel cross-mount comment for the
container-side reader (inbound.db must be journal_mode=DELETE).
- agent-runner/db/messages-out.ts: document that even/odd seq parity
is load-bearing — seq is the agent-facing message ID returned by
send_message and consumed by edit_message / add_reaction, looked
up across both tables.
- v2-checklist.md: record the cross-mount invariants and seq parity
under Core Architecture so future "simplifications" don't regress
them.
- scripts/sanity-live-poll.ts: empirical validation harness for the
three cross-mount invariants — flips each one and observes silent
message loss / corruption.
- delivery.ts: inline routeAgentMessage at its single callsite (-17
net lines). The wrapper added more boilerplate than it factored.
- docs/v2-architecture-diagram.{md,html}: rendered Mermaid diagrams
of the v2 system, message flow, named destinations, entity model,
and the two-DB split.
- channels/adapter.ts, chat-sdk-bridge.ts, credentials.ts,
db/sessions.ts, db/db-v2.test.ts: prettier format pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Eliminates SQLite write contention across the host-container mount
boundary by splitting the single session.db into two files, each with
exactly one writer:
inbound.db — host writes (messages_in, delivered tracking)
outbound.db — container writes (messages_out, processing_ack)
Key changes:
- Host uses even seq numbers, container uses odd (collision-free)
- Container heartbeat via file touch instead of DB UPDATE
- Scheduling MCP tools now emit system actions via messages_out
(host applies them to inbound.db during delivery)
- Host sweep reads processing_ack + heartbeat file for stale detection
- OneCLI ensureAgent() call added (was missing from v2, caused
applyContainerConfig to reject unknown agent identifiers)
Verified: tsc clean, 327 tests pass, real e2e through Docker works.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Override entrypoint to compile and run index-v2.js (no stdin)
- Add better-sqlite3 + @types to agent-runner dependencies
- Exclude test files from agent-runner tsconfig (Docker build)
- Add real e2e test script (host → container → Claude → session DB)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Host orchestrator connecting channel events to session DBs and
delivering responses back through channel adapters.
- session-manager.ts: session folder/DB lifecycle, message writing
- container-runner-v2.ts: Docker spawn with session + agent group
mounts, OneCLI, idle timeout, agent-runner recompilation
- router-v2.ts: inbound routing (channel → messaging group → agent
group → session → messages_in → wake container)
- delivery.ts: two-tier polling (1s active, 60s sweep) for
messages_out, channel adapter delivery
- host-sweep.ts: stale detection with backoff, recurrence, wake
containers for due messages
- index-v2.ts: thin entry point wiring everything together
- scripts/test-v2-agent.ts: real Claude provider integration test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace macOS-only `stat -f%z` with portable `wc -c` for Linux compat
- Replace `find | while` pipes with process substitution so TOTAL_FREED
counter survives the loop (pipe runs in subshell, losing mutations)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Session files (JSONLs, debug logs, todos, telemetry, group logs) accumulate
unboundedly — especially from daily cron tasks. This adds a cleanup script
that prunes old artifacts while protecting active sessions (read from DB),
and wires it into the main process on a 24h interval.
Co-Authored-By: Claude Opus 4.6 (1M context) <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>
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>
* fix(db): remove unique constraint on folder to support multi-channel agents
* ci: implement automated skill drift detection and self-healing PRs
* fix: align registration logic with Gavriel's feedback and fix build/test issues from Daniel Mi
* style: conform to prettier standards for CI validation
* test: fix branch naming inconsistency in CI (master vs main)
* fix(ci): robust module resolution by removing file extensions in scripts
* refactor(ci): simplify skill validation by removing redundant combination tests
* style: conform skills-engine to prettier, unify logging in index.ts and cleanup unused imports
* refactor: extract multi-channel DB changes to separate branch
Move channel column, folder suffix logic, and related migrations
to feat/multi-channel-db-v2 for independent review. This PR now
contains only CI/CD optimizations, Prettier formatting, and
logging improvements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
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>
* refactor: multi-channel infrastructure with explicit channel/is_group tracking
- Add channels[] array and findChannel() routing in index.ts, replacing
hardcoded whatsapp.* calls with channel-agnostic callbacks
- Add channel TEXT and is_group INTEGER columns to chats table with
COALESCE upsert to protect existing values from null overwrites
- is_group defaults to 0 (safe: unknown chats excluded from groups)
- WhatsApp passes explicit channel='whatsapp' and isGroup to onChatMetadata
- getAvailableGroups filters on is_group instead of JID pattern matching
- findChannel logs warnings instead of silently dropping unroutable JIDs
- Migration backfills channel/is_group from JID patterns for existing DBs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: skills engine v0.1 — deterministic skill packages with rerere resolution
Three-way merge engine for applying skill packages on top of a core
codebase. Skills declare which files they add/modify, and the engine
uses git merge-file for conflict detection with git rerere for
automatic resolution of previously-seen conflicts.
Key components:
- apply: three-way merge with backup/rollback safety net
- replay: clean-slate replay for uninstall and rebase
- update: core version updates with deletion detection
- rebase: bake applied skills into base (one-way)
- manifest: validation with path traversal protection
- resolution-cache: pre-computed rerere resolutions
- structured: npm deps, env vars, docker-compose merging
- CI: per-skill test matrix with conflict detection
151 unit tests covering merge, rerere, backup, replay, uninstall,
update, rebase, structured ops, and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Discord and Telegram skill packages
Skill packages for adding Discord and Telegram channels to NanoClaw.
Each package includes:
- Channel implementation (add/src/channels/)
- Three-way merge targets for index.ts, config.ts, routing.test.ts
- Intent docs explaining merge invariants
- Standalone integration tests
- manifest.yaml with dependency/conflict declarations
Applied via: npx tsx scripts/apply-skill.ts .claude/skills/add-discord
These are inert until applied — no runtime impact.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* remove unused docs (skills-system-status, implementation-guide)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>