Source profileQuality 91/100Review permissions

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

migrate-from-v1

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".

Source repository stars
30,618
Declared platforms
0
Static risk flags
1
Last source update
2026-08-26
Source checked
2026-08-26

Decision brief

What it does: where it fits

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

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/nanocoai/nanoclaw --skill ".claude/skills/migrate-from-v1"
    Safe inspection promptEditorial

    Inspect the Agent Skill "migrate-from-v1" from https://github.com/nanocoai/nanoclaw/blob/f7376aa94d0b54aac6c2216c4533ddaaea18b7dd/.claude/skills/migrate-from-v1/SKILL.md at commit f7376aa94d0b54aac6c2216c4533ddaaea18b7dd. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      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.

      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.Walk handoff.steps. Fix only the failures that would stop the bot from routing one message; defer the rest to its later phase.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 mes…
    2. 02

      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.

      Telegram: telegram: (e.g. telegram:6037840640)Discord: discord: (e.g. discord:123456789012345678)WhatsApp: whatsapp:@s.whatsapp.net (e.g. whatsapp:[email protected])
    3. 03

      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 Co…

      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 ide…Do not duplicate that migration logic here. Record each group's result in the handoff before continuing.
    4. 04

      Phase 3: Container config

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

      If container.json exists, read it and verify the additionalMounts host paths are still valid on this machine. Flag any that don't exist.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.Check for env or packages fields — env may overlap with OneCLI vault, packages (apt/npm) are portable.
    5. 05

      Phase 4: Fork customizations

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

      Show the commit list to the user.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/, /w…

    Permission review

    Static risk signals and limitations

    Runs scripts

    medium · line 24

    The documentation asks the agent to run terminal commands or scripts.

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

    Runs scripts

    medium · line 32

    The documentation asks the agent to run terminal commands or scripts.

    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.

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score91/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars30,618SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    nanocoai/nanoclaw
    Skill path
    .claude/skills/migrate-from-v1/SKILL.md
    Commit
    f7376aa94d0b54aac6c2216c4533ddaaea18b7dd
    License
    MIT
    Collected
    2026-08-26
    Default branch
    main
    View the original SKILL.md

    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 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:[email protected])
    • 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:

    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:

    -- 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:

    UPDATE messaging_groups SET unknown_sender_policy = '<chosen_policy>'
    WHERE id IN (SELECT id FROM messaging_groups WHERE channel_type IN (<migrated_channels>))
    

    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.

    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:

    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:
      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:
      # 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"
      

    Frequently asked questions

    What to verify before installation and use

    What does the migrate-from-v1 source document cover?

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

    How do I install migrate-from-v1?

    The source record exposes this install command: npx skills add https://github.com/nanocoai/nanoclaw --skill ".claude/skills/migrate-from-v1". Inspect the command and pinned source before running it.

    Which permission-related actions were detected?

    Static rules flagged exec-script in the source; the page lists the matching lines and excerpts.

    Alternatives

    Compare before choosing

    Computed 10045,643

    coreyhaines31/marketingskills

    ab-testing

    When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

    Computed 10029,095

    garrytan/gbrain

    bulk-ingestion

    End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.

    Computed 10024,975

    alirezarezvani/claude-skills

    app-store-optimization

    App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

    Computed 1005,248

    dotnet/skills

    migrate-vstest-to-mtp

    Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing