When /add-vercel is applied, agents that need to build websites spin up
a dedicated Frontend Engineer agent instead of building inline. The
frontend agent enforces build-test-verify discipline with visual browser
verification before deploying to Vercel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Self-contained skill: SKILL.md has instructions, resources/ holds
the dashboard-pusher.ts that gets copied to src/ at install time.
No src/ changes until the skill is applied.
npm package: @nanoco/nanoclaw-dashboard
Repo: https://github.com/qwibitai/nanoclaw-dashboard
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the "print the pairing code as plain text" directive from three
skill docs into the CLI output itself. Every caller of pair-telegram
(init-first-agent, manage-channels, add-telegram-v2, future callers)
now sees the reminder directly in the PAIR_TELEGRAM_ISSUED and
PAIR_TELEGRAM_NEW_CODE blocks. Skill docs shortened to point at it.
Also add a short pre-tool-call sentence in init-first-agent step 3b
instructing the assistant to extract the code and ask the user to send
it in Telegram.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reword pair-code instruction across add-telegram-v2, manage-channels,
and init-first-agent so the very last user-visible message after
generating the code MUST be a plain-text print of it.
- Replace init-first-agent's tail -f based verify step with a plain-text
prompt asking the user to confirm receipt of the welcome DM, falling
back to DB-based diagnostics only on non-arrival. Avoids harness
blocks on long leading sleeps and fragile log-string greps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude Code's UI collapses bash tool output, so the user never sees the
pairing code emitted by pair-telegram. Reframe the skill instructions
to require the last user-visible message at this step to be a plain-text
print of the code.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude Code's UI folds bash tool results by default, hiding the 4-digit
pairing code from the user. Instruct the skill to echo the CODE as plain
text in the reply so it's always visible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the agent-group-centric "main group" concept with user-level
privileges and adds the cold-DM infrastructure needed for proactive
outbound messaging (pairing, approvals, welcome flows).
Privilege model
- New tables: users, user_roles (owner global-only; admin global or
scoped to an agent_group), agent_group_members (explicit non-
privileged access; admin/owner imply membership), user_dms (cold-DM
resolution cache).
- Removed agent_groups.is_admin, messaging_groups.admin_user_id. Replaced
with messaging_groups.unknown_sender_policy (strict | request_approval
| public) for per-chat unknown-sender gating.
- src/access.ts: canAccessAgentGroup, pickApprover, pickApprovalDelivery.
- src/router.ts: access gate on every inbound, honoring
unknown_sender_policy for unknown senders.
- src/channels/telegram.ts: pairing interceptor upserts the paired user
and promotes them to owner if hasAnyOwner() is false (first-pair-wins).
Cold DM infrastructure
- ChannelAdapter.openDM?(handle) — optional method. Chat-SDK-bridge wires
it to chat.openDM() for resolution-required channels (Discord, Slack,
Teams, Webex, gChat); direct-addressable channels (Telegram, WhatsApp,
iMessage, Matrix, Resend) fall through to the handle directly.
- src/user-dm.ts: ensureUserDm(userId) — resolves + caches via user_dms.
Approval routing
- onecli-approvals + delivery use pickApprover + pickApprovalDelivery:
scoped admins → global admins → owners (dedup), first reachable via
ensureUserDm, same-channel-kind tie-break. Approvals land in the
approver's DM, not the origin chat.
Delivery fixes
- delivery.ts ACL rejection now throws instead of returning undefined —
the outer loop previously marked rejected messages as delivered.
- Implicit-origin allow: session.messaging_group_id === target skips the
destination check.
- createMessagingGroupAgent auto-creates the companion agent_destinations
row (normalized local_name from the messaging group's name, collision-
broken within the agent's namespace).
Container
- container-runner.ts: /workspace/global always read-only; drops
NANOCLAW_IS_ADMIN; adds NANOCLAW_ADMIN_USER_IDS (owners + global admins
+ scoped admins for this agent group). Agent-runner poll-loop gates
slash commands against that set.
New skill: /init-first-agent
- Walks the operator through standing up the first agent for a channel:
channel pick → identity lookup (reads each channel SKILL.md's
## Channel Info > how-to-find-id) → DM platform_id resolution (direct-
addressable, cold-DM via "user DMs bot first + sqlite lookup", or
Telegram pair-code fallback) → run scripts/init-first-agent.ts →
verify via tail of nanoclaw.log.
- scripts/init-first-agent.ts: parameterized helper that upserts the
user + grants owner (if none), creates dm-with-<display-name> agent
group + initGroupFilesystem, reuses/creates the DM messaging_group,
wires it (auto-creates destination), resolves the session, and writes
a kind:'chat' / sender:'system' welcome message into inbound.db. Host
sweep wakes the container and the agent DMs the operator via the
normal delivery path.
/manage-channels rewrite
- Drops --is-main / --jid / main-vs-non-main isolation references.
- First-channel flow delegates to /init-first-agent.
- Explains createMessagingGroupAgent auto-creates destinations.
- Adds a privileged-users show section.
setup/
- register.ts: drop --is-main, --jid, --local-name, --trigger
requiresTrigger defaults; call initGroupFilesystem; normalize to
v2 schema (no is_admin, no admin_user_id, sets unknown_sender_policy
'strict'); let createMessagingGroupAgent handle the destination row.
- pair-telegram.ts: emit PAIRED_USER_ID (namespaced "telegram:<id>")
instead of ADMIN_USER_ID; update header comment.
- register.test.ts deleted — was v1-only, tested a registered_groups
table that no longer exists.
Docs
- v2-architecture-diagram.{md,html}: ER diagram updated to drop
is_admin/admin_user_id, add unknown_sender_policy, and include
users/user_roles/agent_group_members/user_dms.
- v2-architecture-draft.md: approval-routing paragraph rewritten for
pickApprover/pickApprovalDelivery/ensureUserDm; SQL schema block
updated; admin-verification paragraph references
NANOCLAW_ADMIN_USER_IDS.
- v2-setup-wiring.md: entity-model sketch rewritten.
- v2-checklist.md: marked privilege refactor / container filtering /
approval routing / unknown-sender gating done; removed obsolete
admin_user_id and main-vs-non-main items.
Scripts
- scripts/init-first-agent.ts (new) replaces scripts/welcome-owner-dm.ts
(removed; welcome-owner was a Discord-specific one-off).
- test-v2-host.ts, test-v2-channel-e2e.ts, seed-discord.ts: drop
is_admin + admin_user_id, use unknown_sender_policy.
Tests
- src/access.test.ts (new): 14 tests for canAccessAgentGroup, role
helpers, pickApprover, ensureUserDm, pickApprovalDelivery.
- src/db/db-v2.test.ts: adds 3 tests for the auto-created
agent_destinations row (normalized name, no duplicates, collision
break within an agent group).
- host-core.test.ts, channel-registry.test.ts: updated fixtures to
use unknown_sender_policy: 'public' where the test exercises routing
rather than the access gate.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Setup skill that installs Vercel CLI in agent containers and configures
OneCLI credential injection for api.vercel.com. Container skill bundled
in .claude/skills/add-vercel/container-skills/ and copied to
container/skills/ during setup. Also adds dashboard & web apps prompt
to /setup flow (step 5b).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Separate from the v1 /add-whatsapp skill — v1 remains untouched.
Follows the v2 skill pattern (flat sections, defers to /manage-channels
for wiring). Covers Baileys auth, pairing code, QR code, and
documents the native adapter's features and limitations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- createPairing now replaces any existing pending pairing for the same intent
(replace-by-default; no "two pending codes for one intent" state)
- tryConsume records each attempt on pending records (capped at 10); a
wrong code invalidates the pairing immediately (one attempt per code)
- waitForPairing gains onAttempt callback for misses and rejects with a
distinct "invalidated by wrong code" message so callers can distinguish
TTL expiry from user-error
- pair-telegram emits PAIR_TELEGRAM_ATTEMPT on misses and auto-regenerates
the pairing up to 5 times, emitting PAIR_TELEGRAM_NEW_CODE for each
- Skill docs updated so the host Claude knows to show new codes and
offer another batch on max-regenerations-exceeded
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Require the message to be exactly the 4 digits (optionally prefixed by
@botname). Loose matches like "my pin is 0349" are rejected to avoid false
positives from chat traffic that happens to contain a 4-digit number.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BotFather issues bot tokens with no user binding, so anyone who guesses the
bot's username can DM it and get registered as a channel. Pairing closes that
gap: setup issues a one-time 4-digit code, the operator echoes it back from
the chat they want to register, and the inbound interceptor binds
admin_user_id before the message reaches the router.
- src/channels/telegram-pairing.ts: JSON-backed store with createPairing,
tryConsume, getStatus, waitForPairing (fs.watch + poll fallback)
- src/channels/telegram.ts: wraps bridge.setup with an onInbound interceptor
that consumes pairing codes and upserts messaging_groups
- setup/pair-telegram.ts: CLI step issues a code and waits up to 5 min for
the operator to echo it back, emitting PLATFORM_ID/IS_GROUP/ADMIN_USER_ID
- Skill docs: /setup reorders mounts -> service -> wire (pairing needs a
live polling adapter); /manage-channels and /add-telegram-v2 use pairing
instead of asking the user to discover chat IDs
All other channels still bind admin via install-time identity (OAuth/QR/token);
pairing is Telegram-only. The bridge, router, and other adapters are untouched.
Rewrites the add-teams-v2 skill with step-by-step instructions
covering App Registration, client secret, Azure Bot creation (portal
and CLI), messaging endpoint, Teams channel, manifest template,
sideloading, and RSC permissions for receiving all messages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Aligns with upstream feat/chat-sdk-integration pattern: regex-based
routing (/webhook/{adapterName}), response streaming, cleanup function.
Updates Slack and Teams skill docs to match /webhook/{name} convention
used by all other v2 channel skills.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Route webhook requests through chat.webhooks[name]() instead of calling
adapter.handleWebhook() directly, getting proper auto-initialization and
signature verification. Extract Node↔Web Request/Response conversion
into reusable helpers, parse URL pathname properly for query string
safety, and support all HTTP methods (not just POST).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Teams adapter now reads TEAMS_APP_TYPE and TEAMS_APP_TENANT_ID from
env, supporting both MultiTenant (default) and SingleTenant configs.
Updated add-teams-v2 skill docs with full Azure Bot setup flow,
webhook endpoint format, and app package sideloading instructions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Corrects webhook URL to /api/webhooks/slack, adds Enable DMs step
(App Home > Messages Tab), documents reinstall requirement after
adding event subscriptions, and adds webhook server section.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Discord adapter fails to start without all three env vars. Also
fix platform ID format docs to show discord:{guildId}:{channelId}.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add three-level isolation model (shared session, same agent, separate agent)
with agent-shared session mode for cross-channel shared sessions
- Create /manage-channels skill for wiring channels to agent groups
- Refactor all 12 v2 channel skills: lean SKILL.md + VERIFY.md + REMOVE.md
with structured Channel Info section for platform-specific metadata
- Create /add-discord-v2 skill (was missing)
- Add step 5a to setup SKILL.md invoking /manage-channels after channel install
- Update setup/verify.ts to check all 12 channel token types
- Add docs/v2-isolation-model.md explaining the isolation model
- Update v2-checklist.md and v2-setup-wiring.md to reflect completed work
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move all v1 files (index, router, container-runner, db, ipc, types,
logger, channels/registry, and all utilities) to src/v1/ as a
fully self-contained archive with no shared dependencies
- Rename v2 files to remove -v2 suffix (index-v2.ts → index.ts, etc.)
- Update all imports across v2 source, tests, and setup files
- Migrate shared utilities (config, env, container-runtime, mount-security,
timezone, group-folder) from pino logger to v2 log module
- Migrate setup/ files from logger to log with argument order swap
- Container agent-runner: move v1 entry to v1/, rename v2 to index.ts
- Update setup skill to offer all 13 v2 channels
- Install all Chat SDK adapter packages
- dist/index.js now runs v2; dist/v1/index.js runs v1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Lint schedule now uses NanoClaw scheduled_tasks table instead of
Claude Code cron — runs in the group's agent container
2. CLAUDE.md must enforce one-at-a-time file ingestion — never batch
3. Expanded CLAUDE.md guidance: explain system, index files, point to
container skill, enforce ingest discipline
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove hardcoded file path checks. Step 4 now discusses source types
with the user and helps install needed skills dynamically. Fix "use use"
typo and change curl example to file download.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove pre-written container skill. Instead, include llm-wiki.md
(Karpathy's gist) as the reference material and have the setup skill
guide the user through collaboratively building their own wiki schema,
container skill, and directory structure based on the pattern.
Add NanoClaw-specific notes: image vision, PDF reader, voice
transcription, curl for full document fetch, file attachment handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Container skill teaches the agent to maintain a structured, interlinked
wiki from ingested sources. Feature skill bootstraps the setup — directory
structure, group CLAUDE.md, optional scheduled lint.
Based on Karpathy's LLM Wiki pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Matches the pattern used by /setup and /update-nanoclaw. Captures
migration-specific properties (tier, phase, customization count,
skill interactions). Opt-out permanently disables across all skills.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Based on analysis of a live migration (v1.2.42 -> v1.2.47):
1. Absolute worktree paths: Bash tool resets cwd between calls,
so relative cd .upgrade-worktree fails. Store PROJECT_ROOT and
WORKTREE as absolute paths, use them throughout.
2. Smarter tier assessment: discount files from skill merges when
counting — a fork with 3 skills and no other changes is Tier 2,
not Tier 3 just because 24 files changed.
3. Inter-skill conflict analysis: new "Skill Interactions" section
in the migration guide captures conflicts between applied skills
(duplicate declarations, conflicting env var handling).
4. Cleaner swap recipe: use git reset --hard to the upgrade commit
instead of git checkout -B intermediate branch. Backup tag
preserves rollback. Copy guide to /tmp before worktree removal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces merge-based upgrades with a two-phase approach:
1. Extract: analyzes user's fork, captures customizations as a
migration guide (intent + implementation details in markdown)
2. Upgrade: checks out clean upstream in a worktree, reapplies
customizations from the guide, validates, and swaps in
Key features:
- Tiered complexity (lightweight/standard/complex)
- Sub-agent exploration with haiku for efficient analysis
- Incremental guide updates instead of full re-extraction
- Live e2e testing via worktree symlinks before swapping
- New-changes guard prevents losing unrecorded work
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously required `[BREAKING]` at the start of the line, missing
entries formatted as `- [BREAKING] ...` in changelogs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The apple-container branch already includes the credential proxy code.
Applying /use-native-credential-proxy on top would conflict. Setup now
inlines the credential collection steps instead of delegating.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OneCLI is incompatible with Apple Container. Setup now picks the
credential system after the container runtime: Docker → OneCLI,
Apple Container → native credential proxy. Also marks Apple Container
as experimental, pauses after claude setup-token, limits AskUserQuestion
to multiple-choice, and removes telegram swarm upsell.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update SKILL.md to ask users during setup whether they want model
management tools (pull, delete, show, list-running) and set
OLLAMA_ADMIN_TOOLS=true in .env accordingly. Core inference tools
remain always available.
Incorporates #1456 by @bitcryptic-gw. Closes#1331.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clarify that only long-lived OAuth tokens (claude setup-token) or API keys
should be used — short-lived tokens from the keychain expire within hours
and cause recurring 401s. Also update native credential proxy skill to
swap the OneCLI reference when applied.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>