Agent skill

Finish NanoClaw V1 Migration

by nanocoai in nanocoai/nanoclaw

Completes a NanoClaw v1 to v2 upgrade after the migrate-v2.sh script has run, handling failed steps, owner setup, memory, container configs and custom code.

MITAuto-check: notesDevelopment

Install Finish NanoClaw V1 Migration

skills CLI
$ npx skills add nanocoai/nanoclaw --skill migrate-from-v1 -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install nanocoai/nanoclaw migrate-from-v1 --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/nanocoai/nanoclaw.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/migrate-from-v1 .claude/skills/migrate-from-v1 && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
migrate-from-v1
GitHub stars
31k
Token cost
~2.9k tokens
SKILL.md length
1,276 words
Files
1
Skills in repo
59
Repo updated
First seen
Licence
MIT

At a glance

Completes a NanoClaw v1 to v2 upgrade after the migrate-v2.sh script has run, handling failed steps, owner setup, memory, container configs and custom code.

  • Works in 5 steps: Get v2 routing real messages → Owner and access → Migrate legacy memory → …
  • migrate-v2.sh has finished and handed control back to the agent
  • SKILL.md covers Preflight: was the script run?, Phase 0: Get v2 routing real…, Phase 1: Owner and access and Phase 2: Migrate legacy memory, plus 5 more sections
  • Calls pnpm, git and bash

What it does

The script migrate-v2.sh does the mechanical work: merging .env keys, seeding the v2 database, copying group folders and session data, porting scheduled tasks, installing channel code, copying container skills and building the image. This skill covers what needs judgment, and starts by reading logs/setup-migration/handoff.json for overall status, per-step results and follow-ups.

If that file is missing, the agent stops and tells you to run the script yourself in a terminal, because it needs interactive prompts and tooling that do not fit inside an agent session. Phase 0 first proves v2 answers real messages: fix only blocking failures, stop the v1 service, start v2, watch the host log and have you send a test message. v1 is paused, not changed, so switching back is a service restart. Later phases seed the owner, migrate shared memory, reconcile configs and port fork customizations.

When your agent uses it

  • migrate-v2.sh has finished and handed control back to the agent
  • Triaging failed steps from a v1 to v2 migration
  • Porting custom v1 code to the v2 layout

Example prompts

  • “migrate-v2.sh just completed. Finish the migration and tell me which steps failed.”
  • “Help me port my v1 fork customizations after the NanoClaw v2 migration.”

Requirements

  • A NanoClaw v1 install that has already run migrate-v2.sh
  • logs/setup-migration/handoff.json present

Workflow steps

5 steps, taken from the step headings in SKILL.md.

  1. Get v2 routing real messages
  2. Owner and access
  3. Migrate legacy memory
  4. Container config
  5. Fork customizations

What it can do on your machine

Read from SKILL.md and the folder at commit 66f0823. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • pnpm
    • git
    • bash

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use pnpm and git, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Finish NanoClaw V1 Migration loads about 2.9k tokens when it runs. Until then it costs about 69 tokens; SKILL.md has 1,276 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~69
When it runs · the whole SKILL.md, loaded when a task matches
~2.9k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: notes

The automated check noted patterns worth knowing about, such as sudo or a known installer.

  • NoteMentions a .env fileSKILL.md:10
    - .env keys merged

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from nanocoai/nanoclaw at commit 66f0823, republished under its MIT licence (© nanocoai). 1,276 words, ~2,853 tokens.

Download SKILL.mdSave it as .claude/skills/migrate-from-v1/SKILL.md (or your agent's skills folder).
name
migrate-from-v1
description
Finish migrating a NanoClaw v1 install into v2. Run after `bash migrate-v2.sh` completes. Seeds the owner, migrates legacy memory, reconciles container configs, and helps port custom v1 code. Triggers on "migrate from v1", "finish migration", "v1 migration".

Finish v1 → v2 migration

bash migrate-v2.sh already ran the deterministic migration. It handled:

  • .env keys merged
  • v2 DB seeded (agent_groups, messaging_groups, wiring)
  • Group folders copied (v1 CLAUDE.md → v2 CLAUDE.local.md)
  • Session data copied with conversation continuity (incl. Claude Code memory + JSONL transcripts)
  • Scheduled tasks ported
  • Channel code installed and auth state copied (incl. WhatsApp Baileys keystore)
  • WhatsApp LIDs resolved from store/auth and aliased into messaging_groups
  • Container skills copied
  • Container image built

Your job is the parts that need human judgment: triage failed steps, seed the owner, run the shared-memory migration, reconcile configs, and port fork customizations.

Read logs/setup-migration/handoff.json first — it has overall_status, per-step results in steps, and a followups list.

Preflight: was the script run?

Before anything else, check that logs/setup-migration/handoff.json exists. If it doesn't, the user is invoking this skill before migrate-v2.sh ran. Stop and tell them, verbatim:

This skill finishes a migration that migrate-v2.sh started. Run that first, in your terminal — not from inside Claude:

bash
bash migrate-v2.sh

It needs interactive prompts (channel selection, service switchover) and runs Node/pnpm bootstrap, Docker, OneCLI setup, and a container build that don't fit inside a Claude session. When it finishes, it'll hand control back to Claude automatically — at which point this skill picks up.

Do not attempt to run the script yourself, simulate its effects, or pick up the migration mid-stream. The deterministic side has dependencies on a real interactive shell.

Once handoff.json exists, proceed to Phase 0.

Phase 0: Get v2 routing real messages

Before any deeper migration work, prove v2 actually answers messages on the user's real channels. v1 is paused, not touched — flipping back is a service restart.

0a — Fix blockers only

Walk handoff.steps. Fix only the failures that would stop the bot from routing one message; defer the rest to its later phase.

0b — Smoke test, then continue

Tell the user the switch is non-destructive (v1 is paused, not modified; reverting is one command). Help them stop v1's service unit and start v2's, tail the host log for a clean boot, and have them send a real test message. Use AskUserQuestion to confirm the bot responded.

If yes, continue to Phase 1. If no, diagnose from logs/nanoclaw.log and re-test — don't proceed to deeper work on a broken router.

Deferred failures

Re-visit anything you skipped in 0a before declaring the migration done. Most surface naturally in later phases (1c-groups ↔ Phase 2, 1e-tasks ↔ task verification).

Phase 1: Owner and access

v2 auto-creates a users row for every sender it sees (via extractAndUpsertUser in src/modules/permissions/index.ts). By the time this skill runs, the owner's row likely already exists — it just needs the owner role granted.

User ID format: always <channel_type>:<platform_handle>. Each channel populates this differently:

  • Telegram: telegram:<numeric_user_id> (e.g. telegram:6037840640)
  • Discord: discord:<snowflake_user_id> (e.g. discord:123456789012345678)
  • WhatsApp: whatsapp:<phone>@s.whatsapp.net (e.g. whatsapp:14155551234@s.whatsapp.net)
  • Slack: slack:<user_id> (e.g. slack:U04ABCDEF)
  • Others: <channel_type>:<platform_id>

Steps:

  1. Query users table: SELECT id, kind, display_name FROM users.
  2. If exactly one user exists, confirm: AskUserQuestion: "Is <display_name> (<id>) you?" — Yes / No, let me type it.
  3. If multiple users exist, present them as options in AskUserQuestion.
  4. If no users exist yet (service hasn't received a message), ask the user to send a test message first, then re-query.
  5. Once confirmed, check user_roles via getUserRoles(userId). If an owner row already exists, skip. Otherwise grant it with grantRole. grantRole inserts a new row per call, so the getUserRoles check keeps this re-runnable.

Use the DB helpers in src/modules/permissions/db/user-roles.ts (getUserRoles, grantRole). Init the DB first, then call the helpers:

ts
import { closeDb, initDb } from '../src/db/connection.js';
import { runMigrations } from '../src/db/migrations/index.js';
import { CENTRAL_DB_PATH } from '../src/config.js';
import { getUserRoles, grantRole } from '../src/modules/permissions/db/user-roles.js';

const db = await initDb(CENTRAL_DB_PATH);
try {
  await runMigrations(db); // idempotent

  const userId = '<user_id>';
  if (!(await getUserRoles(userId)).some((r) => r.role === 'owner')) {
    await grantRole({
      user_id: userId,
      role: 'owner',
      agent_group_id: null, // owner role must be global
      granted_by: null,
      granted_at: new Date().toISOString(),
    });
  }
} finally {
  await closeDb();
}
Access policy

After seeding the owner, discuss the access policy. v2's messaging_groups.unknown_sender_policy controls who can interact with the bot. migrate-v2.sh set it to public so the bot would respond during the switchover test, but the user may want to tighten it.

Present the options via AskUserQuestion:

  1. Public (public, current) — anyone can message the bot. Good for personal DM bots.
  2. Known users only (strict) — only users the access gate accepts (owner, admin, or agent_group_members) can trigger the bot. Others are silently dropped.
  3. Approval required (request_approval) — unknown senders trigger an approval request to the owner. Good for group chats where you want to vet new members.

The unknown_sender_policy column accepts exactly these three values; use the parenthesized value for <chosen_policy> below.

If the user picks option 2 or 3, seed the known users from v1's message history. The v1 database is at <handoff.v1_path>/store/messages.db. It has a messages table with sender and sender_name columns. For each group:

sql
-- v1: unique senders per chat (excluding bot messages)
SELECT DISTINCT sender, sender_name
FROM messages
WHERE chat_jid = '<v1_jid>' AND is_from_me = 0 AND sender IS NOT NULL

The sender value is a platform handle (e.g. 6037840640 for Telegram). Build the v2 user ID by inferring the channel type from the chat JID prefix (use parseJid from setup/migrate-v2/shared.ts) and combining: <channel_type>:<sender>.

For each sender:

  1. Upsert into users(id, kind, display_name) if not already present.
  2. Insert into agent_group_members(user_id, agent_group_id) for each agent group wired to that messaging group.

Show the user the list of senders being imported and let them deselect any they don't want.

Then update the messaging groups:

sql
UPDATE messaging_groups SET unknown_sender_policy = '<chosen_policy>'
WHERE id IN (SELECT id FROM messaging_groups WHERE channel_type IN (<migrated_channels>))
Show full SKILL.md (494 more words)Show less

Phase 2: Migrate legacy memory

Run /migrate-memory for the imported groups. It quiesces each group, moves the v1 CLAUDE.local.md into the shared memory/ tree without reading it during staging, then has the invoking coding harness distill standing identity into instructions.prepend.md and durable facts into Core Memory or focused linked files before the NanoClaw group runs again.

Do not duplicate that migration logic here. Record each group's result in the handoff before continuing.

Phase 3: Container config

migrate-v2.sh writes container.json directly from v1's container_config (the additionalMounts shape is identical). If the v1 config was unparseable, it falls back to a .v1-container-config.json sidecar.

For each group, check:

  1. If container.json exists, read it and verify the additionalMounts host paths are still valid on this machine. Flag any that don't exist.
  2. If .v1-container-config.json exists (parse failure fallback), read it, discuss with the user, and write a proper container.json. Then delete the sidecar.
  3. Check for env or packages fields — env may overlap with OneCLI vault, packages (apt/npm) are portable.

Phase 4: Fork customizations

Check whether the user's v1 install was a customized fork.

bash
cd <v1_path>
git remote -v
git log --oneline <upstream>/main..HEAD 2>/dev/null

If no commits ahead of upstream: stock v1, skip this phase.

If there are commits:

  1. Show the commit list to the user.
  2. AskUserQuestion: "How do you want to handle your v1 customizations?"
    • Copy portable items (recommended) — copy container/skills/*, .claude/skills/*, docs/*. Grep each copied file for v1-only references that won't resolve in v2 and flag them to the user: workspace paths (/workspace/group/, /workspace/project/, /workspace/ipc/, /workspace/extra/), the v1 IPC mechanism, registered_groups / is_main, the v1 sender allowlist, and store/messages.db.
    • Full walkthrough — go commit by commit, decide together.
    • Reference only — stash to docs/v1-fork-reference/ for later.
  3. Source code (src/*, container/agent-runner/src/*) is NOT portable — v2's architecture is fundamentally different. Stash to docs/v1-fork-reference/ with a README explaining what each file did. Don't translate.

Principles

  • v1 checkout is read-only. Never modify files under handoff.v1_path.
  • Show before writing. Show diffs or proposed content before modifying standing instructions, memory, or container.json.
  • Mask credentials when displaying (first 4 + ... + last 4 characters).
  • handoff.json is the recovery point. If context gets compacted, re-read it and git status to recover state.

Setup steps you can run

The setup flow at setup/index.ts has individual steps you can invoke if something is missing or failed:

bash
pnpm exec tsx setup/index.ts --step <name>
StepWhen to use
onecliOneCLI not installed or not healthy
authNo Anthropic credential in vault
containerContainer image needs rebuild
serviceService not installed or not running
mountsMount allowlist missing
verifyEnd-to-end health check (run after everything else)
environmentSystem check (Node, dirs)

When done

  1. Run the verify step to confirm everything works:
    bash
    pnpm exec tsx setup/index.ts --step verify
  2. Delete logs/setup-migration/handoff.json — offer to save as docs/migration-<date>.md first.
  3. Restart the service if running so changes take effect. The v2 service label is install-specific (nanoclaw-v2-<slug> / com.nanoclaw-v2-<slug>), so derive it from src/install-slug.ts rather than guessing:
    bash
    # Linux
    UNIT=$(pnpm exec tsx -e "import{getSystemdUnit}from'./src/install-slug.js';console.log(getSystemdUnit())")
    systemctl --user restart "$UNIT"
    # macOS
    LABEL=$(pnpm exec tsx -e "import{getLaunchdLabel}from'./src/install-slug.js';console.log(getLaunchdLabel())")
    launchctl kickstart -k "gui/$(id -u)/$LABEL"

© nanocoai, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/migrate-from-v1 of nanocoai/nanoclaw.

Open the folder on GitHubat commit 66f0823

Compare with similar skills

Finish NanoClaw V1 Migration next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Finish NanoClaw V1 Migration compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Finish NanoClaw V1 Migration this skillnanocoai/nanoclaw31k—~2.9kAutomated safety check: NotesMIT
Migrate Core Code to Submodulestinyhumansai/openhuman42k—~2.6kAutomated safety check: PassGPL-3.0
Swarm Migrateyonatangross/orchestkit290—~3.7kAutomated safety check: NotesMIT
Migrate Internal Package into GhostTryGhost/Ghost56k—~3.8kAutomated safety check: PassMIT
ast-grep Structural Searchcode-yeongyu/oh-my-openagent70k—~3.3kAutomated safety check: PassMIT
Next Cache Components Adoptionvercel/next.js143k6 repos~8.3kAutomated safety check: PassMIT

Similar skills

  • Migrate Core Code to Submodules

    tinyhumansai/openhuman

    Plans and carries out moving non-host-specific code and its tests from the OpenHuman core into vendored tiny submodule libraries, then releases the submodule and re-pins the host.

    42k GitHub stars~2.6k tokensUpdated today
    DevelopmentAuto-check passed
  • Swarm Migrate

    yonatangross/orchestkit

    Cross-repo migration swarm — one coordinator + N parallel subagents (one per target repo) that apply the same transformation, open PRs, wait for CI, and report back to a shared JSON ledger.

    290 GitHub stars~3.7k tokensUpdated today
    DevelopmentAuto-check: notes
  • Moves a package from another TryGhost repository into Ghost as an internal workspace package while keeping its Git history, with checkpoints for the steps that need an administrator.

    56k GitHub stars~3.8k tokensUpdated today
    DevelopmentAuto-check passed
  • ast-grep Structural Search

    code-yeongyu/oh-my-openagent

    Searches and rewrites code by syntax-tree shape across 25 languages with ast-grep, for codemods, structural queries and YAML lint rules, using a Python wrapper script.

    70k GitHub stars~3.3k tokensUpdated today
    DevelopmentAuto-check passed
  • Official

    Turn on Cache Components in a Next.js app and resolve the blocking routes it surfaces.

    143k GitHub starsUsed in 6 repos~8.3k tokens
    DevelopmentAuto-check passed
  • Walks through deprecating an R function or argument in a package: lifecycle warning, silenced tests, a new snapshot test, documentation badge and NEWS entry.

    5.1k GitHub starsUsed in 1 repo~1.2k tokens
    DevelopmentAuto-check passed

More from nanocoai/nanoclaw

All 59 skills in this repo
  • Installs or refreshes Iron Proxy and its Iron Control web console for NanoClaw, with a local Docker setup, database, credentials and a human approval bridge.

    31k GitHub stars~4.6k tokensUpdated 3 days ago
    Auto-check: notes
  • Installs or refreshes OneCLI as the gateway provider for NanoClaw, copying the adapter files, registering the provider and running the setup script.

    31k GitHub stars~1.1k tokensUpdated 3 days ago
    Auto-check: notes
  • Agent Browser

    nanocoai/nanoclaw

    Drives a web browser from the shell with the agent-browser CLI: open pages, read an element snapshot, click and fill by reference, grab text and screenshots.

    31k GitHub starsUsed in 2 repos~1.6k tokens
    Auto-check passed
  • Guides a conversational migration from an OpenClaw install to NanoClaw v2, carrying over identity, channel credentials, scheduled tasks and workspace files.

    31k GitHub stars~6k tokensUpdated 3 days ago
    Auto-check: notes
  • Wires up an additional phone number onto an already-installed Dial channel, so one NanoClaw install answers SMS and AI voice calls on more than one line.

    31k GitHub stars~1.5k tokensUpdated 3 days ago
    Auto-check passed
  • Add Dial Tool

    nanocoai/nanoclaw

    Installs the `dial` CLI and a credential in NanoClaw agent containers so chosen agents can send SMS, place AI voice calls and receive verification codes.

    31k GitHub stars~4.4k tokensUpdated 3 days ago
    Auto-check passed

Questions about Finish NanoClaw V1 Migration

What does Finish NanoClaw V1 Migration do?

Completes a NanoClaw v1 to v2 upgrade after the migrate-v2.sh script has run, handling failed steps, owner setup, memory, container configs and custom code. env keys, seeding the v2 database, copying group folders and session data, porting scheduled tasks, installing channel code, copying container skills and building the image.json for overall status, per-step results and follow-ups.

When should I use Finish NanoClaw V1 Migration?

Finish NanoClaw V1 Migration fits situations like: migrate-v2.sh has finished and handed control back to the agent; triaging failed steps from a v1 to v2 migration; porting custom v1 code to the v2 layout.

How do I install Finish NanoClaw V1 Migration in Claude Code?

Run `npx skills add nanocoai/nanoclaw --skill migrate-from-v1 -a claude-code`. Or copy the skill folder (.claude/skills/migrate-from-v1 in nanocoai/nanoclaw) into .claude/skills/migrate-from-v1 in your project. Claude Code loads it when a task matches its description.

How do I install Finish NanoClaw V1 Migration in Codex?

Run `npx skills add nanocoai/nanoclaw --skill migrate-from-v1 -a codex`. Or copy the skill folder (.claude/skills/migrate-from-v1 in nanocoai/nanoclaw) into .agents/skills/migrate-from-v1 in your project. Codex loads it when a task matches its description.

Can I use Finish NanoClaw V1 Migration in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add nanocoai/nanoclaw --skill migrate-from-v1 -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/migrate-from-v1, .gemini/skills/migrate-from-v1, .github/skills/migrate-from-v1 and .opencode/skills/migrate-from-v1 in your project.

What does Finish NanoClaw V1 Migration need to run?

Going by SKILL.md and its folder, Finish NanoClaw V1 Migration needs the command-line tools its instructions call (pnpm, git and bash). Our summary lists: A NanoClaw v1 install that has already run migrate-v2.sh; logs/setup-migration/handoff.json present.

Does Finish NanoClaw V1 Migration access the network?

SKILL.md contains no URLs. Its commands use git, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Finish NanoClaw V1 Migration safe to install?

Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.

What licence does Finish NanoClaw V1 Migration use?

Finish NanoClaw V1 Migration is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Finish NanoClaw V1 Migration use?

About 2.9k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Finish NanoClaw V1 Migration?

Skills that share tags, products or a category with Finish NanoClaw V1 Migration: Migrate Core Code to Submodules (tinyhumansai/openhuman, 42k stars), Swarm Migrate (yonatangross/orchestkit, 290 stars), Migrate Internal Package into Ghost (TryGhost/Ghost, 56k stars) and ast-grep Structural Search (code-yeongyu/oh-my-openagent, 70k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Finish NanoClaw V1 Migration?

nanocoai (a GitHub organization) maintains it in nanocoai/nanoclaw, which has 30,902 GitHub stars. The repository holds 59 skills in this directory. The repository was last updated on October 6, 2026.

Source: nanocoai/nanoclaw on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.