migrate-from-openclaw
The migrate-from-openclaw skill guides users through converting an OpenClaw installation to NanoClaw v2 by reading existing configuration, explaining what will move where in the new entity model, and applying changes only after user confirmation. Use this when an OpenClaw user wants to preserve their agents, messaging groups, credentials, and scheduled tasks in the v2 architecture, which isolates agents into containers and stores configuration in a central database rather than distributed files.
git clone --depth 1 https://github.com/nanocoai/nanoclaw /tmp/migrate-from-openclaw && cp -r /tmp/migrate-from-openclaw/.claude/skills/migrate-from-openclaw ~/.claude/skills/migrate-from-openclawSKILL.md
# Migrate from OpenClaw
Guide the user through migrating their OpenClaw installation into NanoClaw v2.
This is a conversation, not a batch job. Read OpenClaw state, discuss it with
the user, decide together what to bring over and where it belongs in v2's
entity model, and show proposed changes before applying.
**Principle:** Never silently copy data. Read it, explain it, place it, then
apply. Credentials are masked when displayed (first 4 + `...` + last 4). Make
judgment calls about what's core vs. reference material.
**UX:** Use `AskUserQuestion` for multiple-choice only. Use plain text for
free-form input. Don't dump raw data — summarize and explain conversationally.
## What this skill changes (conformance)
This skill drives existing NanoClaw entry points (`setup/index.ts --step
register`, `scripts/init-first-agent.ts`, the `onecli` CLI) and copies a few
files in (workspace markdown, OpenClaw skills, and its own transform module +
test). It makes no code-level reach-in into core. Its integration assumptions
about v2 are guarded by `scripts/transform.test.ts`, which is copied into the
project's `scripts/` test tree on apply (Phase 8) so vitest runs it against the
composed install. `REMOVE.md` reverses every file the skill copies.
## v2 architecture the migration targets
OpenClaw and NanoClaw v2 differ structurally. Keep these in mind throughout:
- **Entity model.** v2's central DB (`data/v2.db`) holds `users`,
`user_roles`, `agent_groups`, `messaging_groups`, and the
`messaging_group_agents` wiring between them. There is no `store/messages.db`
and no `scheduled_tasks` table.
- **Container isolation.** Each agent group runs in its own Linux container.
An OpenClaw "agent" maps to a v2 *agent group* (workspace + memory +
CLAUDE.md); an OpenClaw chat/group maps to a v2 *messaging group*; the wiring
row connects them.
- **Shared vs per-group context.** v2 has no `groups/global/`. Shared
instructions live in `container/CLAUDE.md` (mounted read-only into every
container). Per-group memory is `groups/<folder>/CLAUDE.local.md`; the
`CLAUDE.md` in each group is **composed at spawn — do not edit it.**
- **Credentials.** Container-facing API credentials (Anthropic, OpenAI, …) are
held in the OneCLI Agent Vault and injected per request — never in container
env vars. Host-side channel tokens (Telegram/Discord/Slack bot tokens) stay
in `.env`; the NanoClaw host process reads them to connect to the platform.
- **Access control.** Per messaging group `unknown_sender_policy` plus
`user_roles` (owner/admin) and `agent_group_members` — not a JSON allowlist
file.
- **Scheduled tasks.** A task is a `messages_in` row (`kind='task'`) in a
session's `inbound.db`, carrying a cron `recurrence` and a `process_after`
timestamp. The agent creates them via its `schedule_task` MCP tool.
## Migration State File
Create `migration-state.md` in the project root at the start of Phase 0. Update
it after each phase. It's the single source of truth — if context is lost,
re-read it to recover decisions and progress. Re-read it before starting any
phase.
Sections to maintain:
- **Progress** — checkbox list of phases (Phase 0–8)
- **Discovery** — STATE_DIR, IDENTITY_NAME, channels, groups (with v2
platform_id mappings), workspace files, cron count, MCP servers
- **Decisions** — assistant_name, shared-vs-separate, primary owner agent
- **Owner & Primary Agent** — user id, role, agent group folder
- **Registered Groups** — table: folder, platform_id, channel, session_mode
- **Credentials** — table: credential, destination (vault / .env), status
- **Settings Migrated** — timezone, container timeout
- **Identity & Memory** — paths of files created, which CLAUDE.local.md edited
- **Scheduled Tasks** — table: original_id, name, mapped schedule, status
- **Deferred / Not Applicable** — unsupported channels, OpenClaw-only features
Keep it factual and terse. Delete it at the end of Phase 8 (or offer to keep it
as a record).
## Phase 0: Discovery
Run the discovery script to find and summarize the OpenClaw installation:
```bash
pnpm exec tsx ${CLAUDE_SKILL_DIR}/scripts/discover-openclaw.ts
```
If the user specifies a custom path, pass `--state-dir <path>`.
Parse the status block. Key fields: STATUS, STATE_DIR, CHANNELS,
WORKSPACE_FILES, DAILY_MEMORY_FILES, SKILL_COUNT, SKILLS, CRON_JOBS,
MCP_SERVERS, IDENTITY_NAME, AGENT_COUNT, AGENT_IDS, GROUPS (each formatted
`channel:id(name)=>v2_platform_id` — the right-hand value is what to pass as
`--platform-id` to register).
**Sanity-check the output.** The script detects known structures but can miss
data if OpenClaw's format changed. Check `CONFIG_TOP_KEYS` and
`CONFIG_CHANNEL_KEYS` — if you see keys it didn't report on, read that section
of the config with the Read tool. Check `STATE_DIR_CONTENTS` for directories it
doesn't scan.
**If STATUS=not_found:** Tell the user no OpenClaw install was detected at the
standard locations (`~/.openclaw`, `~/.clawdbot`). Ask for a custom path; if
none, exit.
**If STATUS=found:** Present a human-readable summary (identity name, workspace
files, channels and which v2 supports, daily memory count, skills, cron count,
MCP servers, agent count). Then paraphrase the key architectural differences
from the section above — don't dump it as a table.
AskUserQuestion: "Ready to start migrating? I'll go through each area one at a
time."
1. **Yes, let's go** — proceed to Phase 1
2. **Tell me more** — explain any area they ask about
3. **Skip migration** — exit
## Phase 1: Agents, Groups, and Shared vs Separate
**Decide this before identity/memory** — it determines where files go.
**OpenClaw model:** all groups routed to one agent share a workspace
(SOUL/MEMORY/IDENTITY) and personality; only the session is per-group.
**v2 model:** each agent group is a separate container with its own filesystem,
memory, and CLAUDE.local.md. Shared instructions are placed in
`container/CLAUDE.md` (read-only in every container). ThAdd Atomic Chat MCP server so the container agent can call local models served by the Atomic Chat desktop app via its OpenAI-compatible API.
Use Codex (CLI + AppServer) as the full agent provider — planning, tool orchestration, native compaction, MCP tools, session resume — in place of the Claude Agent SDK. ChatGPT subscription or OPENAI_API_KEY. Per-group via agent_provider. Distinct from using OpenAI as an MCP tool (where Claude remains the planner).
Add a monitoring dashboard to NanoClaw. Installs @nanoco/nanoclaw-dashboard and a pusher that sends periodic JSON snapshots.
Add DeltaChat channel integration via @deltachat/stdio-rpc-server. Native adapter — no Chat SDK bridge. Email-based messaging with end-to-end encryption.
Add Discord bot channel integration via Chat SDK.
Add Emacs as a channel. Opens an interactive chat buffer and org-mode integration so you can talk to NanoClaw from within Emacs (Doom, Spacemacs, or vanilla). Local HTTP bridge — no bot token or external service needed.
Add Google Calendar as an MCP tool (list calendars, list/search/create events, free/busy queries) using OneCLI-managed OAuth. Multi-calendar and multi-account supported. Mirrors /add-gmail-tool's stub pattern — no raw credentials ever reach the container; OneCLI injects real tokens at request time.
Add Google Chat channel integration via Chat SDK.