From agent
Imports an OpenClaw agent workspace (SOUL.md, IDENTITY.md, MEMORY.md, etc.) into the current project. Useful when migrating or referencing an agent's identity and memory.
How this skill is triggered — by the user, by Claude, or both
Slash command
/agent:importThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Import an existing agent from an OpenClaw installation into this directory, then offer the same setup steps a new agent gets (QMD, messaging, crons).
Import an existing agent from an OpenClaw installation into this directory, then offer the same setup steps a new agent gets (QMD, messaging, crons).
Discover OpenClaw workspaces across plausible source locations. Users
commonly run OpenClaw as root and then run ClawCode as a non-root user
(e.g. inside an LXC where the service user is claude), so checking only
~/.openclaw misses those setups. Look in every readable root below and
union the results:
for root in \
"${CLAWCODE_OPENCLAW_ROOT:-}" \
"$HOME/.openclaw" \
"/root/.openclaw"; do
[[ -z "$root" ]] && continue
[[ -r "$root" ]] || continue
ls -d "$root"/workspace* 2>/dev/null
done | sort -u
Override the search roots with the CLAWCODE_OPENCLAW_ROOT env var when
OpenClaw data lives in a non-standard location (e.g. a mounted volume).
If the loop returns nothing, ask the user for an absolute path to the source workspace instead of silently falling back.
For each workspace found, read IDENTITY.md to show the agent's name.
Typical layouts:
<root>/workspace/ — default agent (main)<root>/workspace-eva/ — agent "eva"<root>/workspace-jack/ — agent "jack"Let the user choose which agent to import (or use argument if provided).
Determine the source path: use the absolute path from the chosen
workspace (e.g. /root/.openclaw/workspace-eva/ or
/home/claude/.openclaw/workspace/). Do NOT re-expand ~ from an
agent-id alone — the discovered path already carries the correct root.
Copy bootstrap files to the current project root: Files to copy from the source workspace:
SOUL.md, IDENTITY.md, USER.md, AGENTS.md, TOOLS.md, HEARTBEAT.mdAlso copy CLAUDE.md from the plugin templates (NOT from OpenClaw):
cp ${CLAUDE_PLUGIN_ROOT}/templates/CLAUDE.md ./
Import memory (ask user first):
MEMORY.md to ./memory/MEMORY.mdmemory/ (last 30 days by default, or all if user wants full history)./memory/.dreams/ directory with empty short-term-recall.jsoncredential, password, secret, .env in their name5a. Channel-content guard (privacy / scope provenance) — mandatory. OpenClaw
daily logs often summarize WhatsApp/Telegram chats. Copied verbatim into top-level
memory/*.md they are classified local provenance and bypass channel-scope
filtering until manually moved or curated — a log imported as local is never
promoted to the .scoped lane by dreaming, so once scope is later armed in
enforce that channel content stays visible to operators who should not see it.
After copying the dated daily logs, scan their contents for channel markers and
flag, never auto-classify:
CHANNEL_MARKERS='whats[[:space:]-]?app|\bwsp\b|\bwacli\b|baileys|@g\.us|@s\.whatsapp\.net|\btelegram\b|t\.me/|(nota|mensaje|audio) de voz|voice (note|message)'
# Dated daily logs only — `find` avoids the zsh no-match glob error.
find ./memory -maxdepth 1 -type f \( -name '????-??-??.md' -o -name '????-??-??-*.md' \) -print0 |
while IFS= read -r -d '' f; do
if LC_ALL=C grep -qiE "$CHANNEL_MARKERS" "$f"; then
markers=$(LC_ALL=C grep -Eio "$CHANNEL_MARKERS" "$f" | sort -fu | paste -sd ', ' -)
printf '%s\t%s\n' "$f" "$markers"
fi
done
If any dated file is flagged, use AskUserQuestion (counts + sample file names and
matched markers only — never the content):
AskUserQuestion(
question: "<N> imported memory files contain channel-derived content (e.g. WhatsApp). Kept as plain memory they bypass scope filtering if you later arm enforce. What should I do with them?",
options: [
{ label: "Quarantine (recommended)", description: "Move to ./import-quarantine/ (gitignored, NOT indexed). Preserved for manual curation; no scope leak." },
{ label: "Skip them", description: "Delete the copies; don't import these files." },
{ label: "Import as local anyway", description: "Keep as memory/*.md. I accept they bypass scope filtering under enforce." }
]
)
Apply the choice to the flagged files only:
mkdir -p ./import-quarantine && mv <flagged> ./import-quarantine/,
then ensure import-quarantine/ is gitignored in the target project (append it to
.gitignore, creating the file if absent). Files outside memory/ are never
indexed by builtin or QMD, so memory_search won't surface them.rm <flagged>.Also scan ./memory/MEMORY.md warn-only with the same CHANNEL_MARKERS.
MEMORY.md is the curated index and IS indexed — but never auto-quarantine it
(gutting it breaks the agent). If it matches, record it in the backlog for manual
curation instead of moving it.
Record every flagged file in IMPORT_BACKLOG.md under
## Memory — Channel-content flagged (file name + marker matched + chosen action;
never the content), noting that mixed personal+channel logs need manual
split/curation to be both searchable-as-personal and scope-filtered.
Adapt AGENTS.md for Claude Code: After copying, remove or comment out sections referencing OpenClaw-specific tools:
sessions_spawn, message tool, browser toolgateway, cron tool (native OpenClaw cron), OpenClaw CLI commandsHEARTBEAT_OK, NO_REPLY, ANNOUNCE_SKIP, SILENT_REPLY_TOKENKeep: safety rules, behavioral rules, memory protocols, learning rules, personal conventions.
After the files are copied, the imported agent is functional but not fully configured. Offer the same setup steps a new agent gets, so imported agents end up with full parity.
Check if QMD is installed: qmd --version 2>/dev/null
Use AskUserQuestion to present the choice (do NOT dump this with other questions):
AskUserQuestion(
question: "Memory backend for this agent?",
options: [
{ label: "QMD (semantic search)", description: "Local embeddings, reranking. Best quality. Requires qmd installed." },
{ label: "Builtin (SQLite + FTS5)", description: "Full-text search with BM25. Works out of the box." }
]
)
If QMD is not installed, skip the question and auto-select builtin — just inform the user: "Using builtin memory (QMD not detected). Install later with bun install -g qmd."
Write agent-config.json via Bash heredoc (NOT the Write tool — agent-config.json is on the always-on protected-paths list; direct Write is refused with exec-gate: write to protected path refused (workspace-agent-config)).
Step 1: Read current agent-config.json with the Read tool (or treat as {} if it doesn't exist). Step 2: in your reasoning, build the merged object: take the existing object, set memory to the QMD or builtin block depending on the user's pick, preserve every other top-level key. Step 3: write via heredoc with validate + atomic mv, substituting <FULL_MERGED_JSON>:
Bash('cat > agent-config.json.tmp << "JSON_EOF" &&
<FULL_MERGED_JSON>
JSON_EOF
node -e \'JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))\' agent-config.json.tmp \
&& mv agent-config.json.tmp agent-config.json \
&& echo "wrote agent-config.json" \
|| { rm -f agent-config.json.tmp; echo "ABORTED: invalid JSON or filesystem error"; exit 1; }')
Reference blocks for the memory key:
QMD: { "backend": "qmd", "citations": "auto", "qmd": { "searchMode": "vsearch", "includeDefaultMemory": true, "limits": { "maxResults": 6, "timeoutMs": 15000 } } }
Builtin: { "backend": "builtin", "citations": "auto", "builtin": { "temporalDecay": true, "halfLifeDays": 30, "mmr": true, "mmrLambda": 0.7 } }
Single Bash permission prompt. The "JSON_EOF" (double-quoted delimiter) form makes the body verbatim — no shell expansion of $, backticks, etc. cat > ... << "JSON_EOF" && puts the heredoc write itself in the && chain so a cat failure short-circuits the rest. The JSON.parse step aborts on malformed JSON before any rename, so a broken write can never clobber existing config.
Wait for the user's answer before proceeding to Step B.
The SessionStart reconcile flow handles default crons automatically via the registry at memory/crons.json. During onboarding, just call writeback.sh seed-defaults to bootstrap it:
bash "$CLAUDE_PLUGIN_ROOT/skills/crons/writeback.sh" seed-defaults
This creates registry entries for heartbeat-default (*/30 * * * *) and dreaming-default (0 3 * * *) if missing; idempotent if already present. The next SessionStart (or a manual /agent:crons reconcile) will call CronCreate to realize them in the harness.
Do NOT create touch .crons-created — that marker is obsolete, cleaned up by reconcile.
Do NOT call CronCreate directly for defaults during import — the reconcile flow handles it and avoids PostToolUse duplicate-capture races.
The OpenClaw agent likely has skills it relied on (Wally has 44, Eva has 20+, etc.). Offer to import them, letting the user pick all, some, or none.
C.1 — Discover. List everything under the source workspace's skills/ directory. For each subdirectory, read the first ~20 lines of SKILL.md to get the frontmatter name and description.
SRC_SKILLS="$SOURCE_WORKSPACE/skills"
test -d "$SRC_SKILLS" || { echo "No skills dir — skipping step C"; }
ALL_SKILLS=$(ls "$SRC_SKILLS" 2>/dev/null)
TOTAL=$(echo "$ALL_SKILLS" | wc -l | tr -d ' ')
C.2 — Classify (silent pre-pass). Run each skill's SKILL.md through the classifier:
HARD_RED='sessions_spawn|gateway config\.patch|http://192\.168\.|canvas\(|remindctl|wacli|openclaw gateway|HEARTBEAT_OK|NO_REPLY|peekaboo'
SOFT_YELLOW='sessions_send|message\(|~/\.openclaw/|\.openclaw/credentials'
classify_skill() {
local file="$1"
local hard soft
hard=$(grep -cE "$HARD_RED" "$file" 2>/dev/null || true)
[ -z "$hard" ] && hard=0
soft=$(grep -cE "$SOFT_YELLOW" "$file" 2>/dev/null || true)
[ -z "$soft" ] && soft=0
if [ "$hard" -gt 0 ]; then echo "RED"
elif [ "$soft" -gt 0 ]; then echo "YELLOW"
else echo "GREEN"
fi
}
# NOTE: don't use `|| echo 0` here — `grep -c` already prints 0 when empty,
# and `|| echo 0` would produce "0\n0" causing `[: integer expected` on bash 3.2.
For each skill, record: name, tier, matched tokens (for reason text), description (first line).
C.3 — Present results and ask via AskUserQuestion.
First, show a brief summary: "Found skills: green, yellow, red."
Then use AskUserQuestion (one question at a time — do NOT combine with other steps):
AskUserQuestion(
question: "Found <TOTAL> skills in <agent>'s workspace: <G> portable, <Y> need adaptation, <R> incompatible. What to do?",
options: [
{ label: "Import all portable (<G+Y>)", description: "GREEN as-is, YELLOW with adaptation headers. RED skipped." },
{ label: "Let me pick specific ones", description: "I'll show the full list with tiers so you can choose." },
{ label: "Skip skills", description: "Don't import any skills for now." }
]
)
Wait for the user's answer before proceeding.
C.4 — Handle the choice:
AskUserQuestion or let the user type the numbers/names. If the user picks a RED skill, import it with a 🛑 header (see C.5)."Skills: skipped" to the report.C.5 — Import each selected skill. For each chosen skill:
If GREEN: Copy the entire directory verbatim — NO comments, NO headers, NO annotations:
mkdir -p "./skills/<name>"
cp -r "$SRC_SKILLS/<name>/." "./skills/<name>/"
The file should look identical to the source. Clean.
If YELLOW: Copy the directory verbatim — same as GREEN, NO headers in the file. Instead, record the adaptation notes in IMPORT_BACKLOG.md (Step C.8) so the file stays clean but the user knows what to review later.
If RED (only if user explicitly selected): Copy verbatim. Record the incompatibility details in IMPORT_BACKLOG.md.
IMPORTANT: Never add comments, headers, or annotations inside imported files. They fill context unnecessarily and reference external systems. All adaptation notes go to IMPORT_BACKLOG.md — one centralized place, not scattered across files.
C.6 — Append to AGENTS.md. For every successfully imported skill (GREEN + YELLOW + any forced RED), append a row to a ## Local imported skills section in ./AGENTS.md. Create the section if it doesn't exist yet.
Trigger phrases come from parsing the skill's description frontmatter — extract the comma-separated clauses that look like trigger phrases (often after "Triggers on" or similar):
## Local imported skills
When the user's message matches a trigger phrase below, read the corresponding
SKILL.md file in `./skills/` and follow its instructions:
- **first-principles** (`./skills/first-principles/SKILL.md`) — "think from first principles", "break down from scratch"
- **deep-profile** (`./skills/deep-profile/SKILL.md`) — "profile this person", "deep research on"
- **shopping** (`./skills/shopping/SKILL.md`) — "buy", "compare prices", "shopping list"
All entries look the same — no tier markers in AGENTS.md. Adaptation details live in IMPORT_BACKLOG.md.
C.7 — Per-item summary. Print to the user:
Skills imported (<G+Y>):
✅ first-principles (green)
✅ deep-profile (green)
⚠️ shopping (yellow — uses `~/.openclaw/` at lines 15, 89)
⚠️ wally-instagram (yellow — uses `message()` at line 42)
...
Skipped (<R>):
❌ fix-api-keys — depends on `gateway config.patch` (OpenClaw gateway)
❌ control-center — depends on `http://192.168.3.102:3123` HTTP API
❌ reminders — depends on `remindctl` and `canvas()`
...
Every skipped item has a concrete why, not just a tier label.
C.8 — Record skipped skills in the backlog. For every RED skill that was NOT imported (and every YELLOW one the user didn't select during [s]), append an entry to ./IMPORT_BACKLOG.md. Create the file if it doesn't exist yet. Entry format:
### fix-api-keys
- **Original path**: `~/.openclaw/workspace/skills/fix-api-keys/`
- **Reason**: Depends on `gateway config.patch` (OpenClaw gateway) — no Claude Code equivalent
- **Original description**: <first line of description frontmatter>
- **Recovery notes**: The gateway is OpenClaw's runtime config system. To port: rewrite the skill to use environment variables or a config file managed via `/agent:settings`.
Group the entries under ## Skills — Skipped and create the file header if it's the first entry (see format at the bottom of this skill).
OpenClaw agents often have dozens of scheduled crons. Offer to import them with the same interactive flow as skills.
D.1 — Discover. Read ~/.openclaw/cron/jobs.json. The file has the shape {"version": 1, "jobs": [...]} — you must access data["jobs"], not iterate data directly. Filter by the imported agent's agentId (for the default workspace it's usually "main"; for workspace-eva/ it's "eva"; etc.). Skip jobs where enabled: false.
python3 -c "
import json
with open('$HOME/.openclaw/cron/jobs.json') as f: data = json.load(f)
jobs = [j for j in data['jobs'] if j.get('agentId') == '$AGENT_ID' and j.get('enabled')]
print(len(jobs))
for j in jobs:
print(j['id'], '|', j.get('name'), '|', j['schedule'].get('kind'), '|', j['schedule'].get('expr'))
"
D.2 — Classify:
enabled: true, kind: cron, payload.kind: agentTurn, payload message does NOT match HARD_RED regex, AND (no delivery.channel OR the channel's plugin is already installed — check ls ~/.claude/plugins/cache/ 2>/dev/null | grep -i <channel>)kind: at with future timestamp, OR kind: every (convertible to */N), OR delivery.channel references a plugin not yet installed, OR payload message matches SOFT_YELLOW regexkind: at with expired timestamp (expr==null and no future triggering), OR kind: systemEvent, OR payload message matches HARD_RED regexFor each classified cron, also record the specific reason (matched token name, schedule kind problem, channel problem).
D.3 — Present results and ask via AskUserQuestion.
Show brief summary, then use AskUserQuestion:
AskUserQuestion(
question: "<agent> has <N> enabled crons: <G> portable, <Y> need adaptation, <R> incompatible. What to do?",
options: [
{ label: "Import all portable (<G+Y>)", description: "GREEN as-is, YELLOW with adapted prompts. RED skipped." },
{ label: "Let me pick specific ones", description: "I'll show the full list with schedules and tiers." },
{ label: "Skip crons", description: "Don't import user crons. Default heartbeat + dreaming already set up." }
]
)
Wait for the user's answer before proceeding.
D.4 — Handle the choice. If "Let me pick", show numbered list:
# Tier Name Schedule Reason
1 🟢 Ideas Check-in 0 14 * * 3,6 OK
2 🔴 eva-sync-systemEvent every 5min kind:systemEvent — no equivalent
3 🟡 meditation 0 2 * * * channel=whatsapp (fallback to memory)
D.5 — Import each selected cron. Before the batch, suppress PostToolUse capture so entries get the correct openclaw-<uuid> key and source: openclaw-import:
touch "$CLAUDE_PROJECT_DIR/memory/.reconciling"
trap 'rm -f "$CLAUDE_PROJECT_DIR/memory/.reconciling"' EXIT
For each chosen cron, build an adapted prompt:
"You are running as agent <AgentName>. Read SOUL.md, IDENTITY.md, USER.md for context. "sessions_spawn(...) → "Use the Agent tool (one-shot delegation)"sessions_send(...) → "Use the Agent tool"message(...) → "Use the messaging plugin's reply tool (or append to memory/$(date +%Y-%m-%d).md if no plugin is loaded)"delivery.channel is set, append: "Send the result via <channel> reply tool; if the plugin isn't loaded, append to memory/$(date +%Y-%m-%d).md instead."kind: cron → keep expr, drop tz (CronCreate uses local time)kind: every with everyMs → */N * * * * where N is max(1, round(everyMs / 60000)). If N > 59, warn and fall back to 0 */N * * * if possible, otherwise skip with a red warning.kind: at → one-shot with recurring: false. If expr is a specific date, convert to a minute-precision cron that fires once around that time; if expr is null, skip.Then load the CronCreate schema (first time per session), create the cron, and immediately register it in the registry with the stable OpenClaw key:
ToolSearch(query="select:CronCreate") # deferred tool, load schema once
CronCreate(
cron: "<converted expr>", # parameter is `cron`, NOT `schedule`
prompt: "<adapted message>",
durable: true,
recurring: <true for cron/every, false for at>
)
# Capture the returned 8-hex task_id from the response.
bash "$CLAUDE_PLUGIN_ROOT/skills/crons/writeback.sh" upsert \
--key "openclaw-<original-uuid>" \
--source openclaw-import \
--harness-task-id "<new task_id>" \
--cron "<converted expr>" \
--prompt "<adapted message>" \
--recurring <true|false>
For schedule.kind: "at" jobs ALSO pass --target-epoch <epoch-seconds> (convert the job's ISO timestamp: macOS date -j -u -f "%Y-%m-%dT%H:%M:%SZ" "<iso>" +%s, Linux date -u -d "<iso>" +%s). Without it the imported reminder has no explicit expiry, so after it fires it is only suspect-reported instead of auto-retired by prune-expired.
The --source openclaw-import also auto-marks migration.openclawAnsweredAt = "auto-imported" if it was null, preventing future SessionStart migration offers.
For RED crons the user forced via s, include a warning in the prompt: "[WARNING: this cron depends on <specific reason> which has no Claude Code equivalent — it may fail at runtime]".
After the batch, remove the suppression marker:
rm -f "$CLAUDE_PROJECT_DIR/memory/.reconciling"
trap - EXIT
D.6 — Per-item summary:
Crons imported (<G+Y>):
✅ Ideas Check-in (0 14 * * 3,6)
✅ reddit-ideas-scan (0 3 * * *)
⚠️ meditation (0 2 * * *) — whatsapp channel fallback to memory file
⚠️ wacli-keepalive (every 4h → 0 */4 * * *)
...
Skipped (<R>):
❌ eva-sync-systemEvent — kind:systemEvent has no Claude Code equivalent
❌ old-reminder-at — kind:at with expired timestamp
❌ cc-task-monitor — payload references `http://192.168.3.102:3123` Control Center HTTP
...
D.7 — Record skipped crons in the backlog. Append entries to ./IMPORT_BACKLOG.md under ## Crons — Skipped. Format:
### eva-sync-systemEvent (ID: `1234-abcd-...`)
- **Original schedule**: `kind: systemEvent` (every 5min)
- **Original agentId**: `main`
- **Reason**: `kind: systemEvent` is an OpenClaw internal tick — no Claude Code equivalent
- **Original payload** (first 200 chars): `<truncated message>`
- **Recovery notes**: SystemEvent crons triggered internal ticks. To port, convert to an `agentTurn` with an equivalent prompt and register via `/agent:crons`.
After Steps C and D, consolidate the backlog and register the import event in the agent's memory so the agent can retrieve the context later.
E.1 — Finalize ./IMPORT_BACKLOG.md. If the file was created during C.8 or D.7, make sure it has the header at the top:
# Import Backlog — Items Not Imported Automatically
This file records OpenClaw skills and crons from the import flow that couldn't be translated directly to Claude Code. Review each entry and decide case-by-case: port manually, set up the missing infrastructure, or drop the item.
Generated: <YYYY-MM-DD HH:MM>
Source workspace: <path>
Agent: <Name>
---
## Skills — Skipped
<entries from C.8>
## Crons — Skipped
<entries from D.7>
If both lists are empty, don't create the file — print "Backlog: empty (everything was importable)" to the user.
E.2 — Record the import event in memory. Append to memory/$(date +%Y-%m-%d).md:
## Import event ($(date +%H:%M))
Imported agent <Name> from `<path>`.
- Skills imported: <G+Y> (<G> portable, <Y> need adaptation — details in IMPORT_BACKLOG.md)
- Skills skipped: <R> — see `IMPORT_BACKLOG.md` for the full list and recovery notes
- Crons imported: <G+Y> (<G> as-is, <Y> adapted)
- Crons skipped: <R> — see `IMPORT_BACKLOG.md`
**If the user asks** *"what about X cron/skill?"*, *"let's revisit the ones we skipped"*, or *"how do we recover Y?"*, read `IMPORT_BACKLOG.md` for the specific reason and recovery notes, then help them port it.
**Skipped skills were**: fix-api-keys, control-center, reminders, ... (list names)
**Skipped crons were**: eva-sync-systemEvent, cc-task-monitor, ... (list names)
This is important: the memory entry is how the agent "remembers" the backlog exists across sessions. Without it, when the user later says "retomemos los crons" the agent won't know which crons were skipped.
E.3 — Offer a reminder cron (optional). Ask the user with AskUserQuestion:
question: "¿Configuro un recordatorio semanal para que revises los items que no se importaron automáticamente (IMPORT_BACKLOG.md)?",
header: "Recordatorio semanal",
options:
- label: "Sí, lunes 10:00"
- label: "No, gracias"
If yes, suppress PostToolUse, create + register explicitly:
touch "$CLAUDE_PROJECT_DIR/memory/.reconciling"
CronCreate(
cron: "0 10 * * 1",
prompt: "Read ./IMPORT_BACKLOG.md and remind the user about any skipped skills/crons that still need porting. If the file is empty or doesn't exist, do nothing.",
durable: true,
recurring: true
)
# Capture returned 8-hex task_id.
bash "$CLAUDE_PLUGIN_ROOT/skills/crons/writeback.sh" upsert \
--key "backlog-reminder" \
--source backlog-reminder \
--harness-task-id "<new task_id>" \
--cron "0 10 * * 1" \
--prompt "Read ./IMPORT_BACKLOG.md and remind the user about any skipped skills/crons that still need porting. If the file is empty or doesn't exist, do nothing." \
--recurring true \
--note "Weekly backlog review reminder"
rm -f "$CLAUDE_PROJECT_DIR/memory/.reconciling"
If no, continue without the cron — the memory entry and the file itself are enough for later retrieval.
Use AskUserQuestion:
AskUserQuestion(
question: "Set up a messaging channel so you can reach this agent from your phone?",
options: [
{ label: "WhatsApp (recommended)", description: "Via crisandrews/claude-whatsapp. QR scan pairing." },
{ label: "Telegram", description: "Official Bot API via claude-plugins-official." },
{ label: "Other", description: "Discord, iMessage, Slack — I'll guide you." },
{ label: "Later", description: "Skip for now. Run /agent:messaging anytime." }
]
)
Wait for the answer. If the user picks a platform, run the /agent:messaging skill flow for that platform. If "Later", skip.
If the user already has a messaging plugin installed (from a previous agent), offer to add its log directory to memory.extraPaths so past conversations become searchable. This is the correct lane for channel history when the extraPath's logical path contains a known channel marker (for WhatsApp, e.g. claude-whatsapp or whatsapp, per deriveChannelHint): those paths get channel provenance and ARE honored by scope filtering — unlike chat summaries copied into memory/*.md, which the Step 5a guard flags because they would be mislabeled local.
After everything is copied and written, scan Claude Code's config files for
absolute paths that point at a different user's home directory. This is the
other half of the cross-user import problem: Claude Code writes absolute paths
into its own settings when plugins are installed, and switching the runtime
user (e.g. from root to claude) leaves those paths pointing at a home dir
the new user can't read. Skills silently fail with "unknown skill" errors.
ClawCode does NOT own these files, so don't auto-patch them — just detect and warn:
# Any absolute path in Claude Code's config that doesn't live under $HOME is
# suspect. /root paths are the usual culprit after a user switch.
for f in \
"$HOME/.claude/settings.json" \
"$HOME/.claude/installed_plugins.json" \
"./agent-config.json"; do
[[ -f "$f" ]] || continue
# Match quoted absolute paths; reject anything under $HOME.
grep -oE '"/[^"]+"' "$f" \
| tr -d '"' \
| grep -v "^$HOME/" \
| grep -v "^/usr/\|^/bin/\|^/etc/\|^/tmp/\|^/opt/" \
| while read -r p; do echo "$f → $p"; done
done
For every hit, print a specific, fix-ready warning — e.g.:
⚠️ ~/.claude/installed_plugins.json references /root/.claude/plugins/...
but this agent runs as $(whoami) ($HOME). Skills from those plugins will
fail with "unknown skill". Fix with:
sed -i "s|/root/.claude|$HOME/.claude|g" ~/.claude/installed_plugins.json
If nothing is flagged, print one line: "Paths OK — no stale home-dir references."
Tell the user to reload the MCP server so all the new config takes effect:
/mcp
Select clawcode and reconnect.
Summarize what was imported and what was set up:
✅ Import complete
Agent: <Name> <emoji>
Files copied: <N> bootstrap + <M> memory files
Memory backend: <builtin | qmd>
Skills: <G> as-is, <Y> adapted, <R> skipped (or "skipped" if user chose [n])
Crons: <G> as-is, <Y> adapted, <R> skipped + 2 default (heartbeat, dreaming)
Backlog: IMPORT_BACKLOG.md written (<Sr + Cr> items pending review) [or: "empty"]
Memory: Import event logged to memory/<YYYY-MM-DD>.md
Memory guard: <Q> quarantined, <S> skipped, <K> kept-as-local, <W> MEMORY.md warn-only (or "none flagged")
Messaging: <not yet | <platform> | skipped>
Per-item details scrolled above. For any ⚠️ or ❌, read the reason and decide
if you want to port it manually. Later, ask me "let's revisit the backlog" and
I'll read IMPORT_BACKLOG.md to help you work through the pending items.
Next: /mcp to reload and start using the agent.
When Step C.8 or D.7 first writes to ./IMPORT_BACKLOG.md, create the file with this skeleton:
# Import Backlog — Items Not Imported Automatically
This file records skills and crons from the import that couldn't be
translated directly. Review each entry and decide case-by-case:
port manually, set up the missing infrastructure, or drop the
item.
Generated: <YYYY-MM-DD HH:MM>
Source workspace: <path>
Agent: <Name>
---
## Skills — Skipped
<entries from Step C.8 appended here, one H3 per skill>
## Crons — Skipped
<entries from Step D.7 appended here, one H3 per cron>
## Memory — Channel-content flagged
<entries from Step 5a appended here, one H3 per flagged file: file name, marker
matched, chosen action (quarantined / skipped / kept-as-local / manual-curation).
Never the content. Mixed personal+channel logs need manual split/curation.>
.env).gateway config.patch (OpenClaw gateway, no Claude Code equivalent)" is useful.IMPORT_BACKLOG.md AND in the memory entry at memory/<date>.md. That's how the user can later ask "retomemos los crons que no se importaron" and the agent can find the context.memory/*.md; otherwise they're classified local and bypass scope filtering until manually moved or curated. Flag, ask, quarantine/skip/keep per the user's choice, and record in the backlog./agent:crons, /agent:messaging later — but Step E (backlog + memory) should still run if Steps C or D ran at all.npx claudepluginhub crisandrews/clawcode --plugin agentGuides creation and configuration of autonomous agents for Claude Code plugins, covering frontmatter, triggering descriptions, system prompts, tools, teams, permissions, and best practices.
Knowledge base on Claude Code formats, patterns, and configurations for commands, agents, skills, hooks, memory, plugins, settings. Use for creating, improving, auditing components.
Builds persistent multi-agent operating systems on Claude Code with kernel architecture, specialist agents, slash commands, file-based memory, and scheduled automation.