Help us improve
Share bugs, ideas, or general feedback.
From claudeclaw-plus
Modifies existing agents: change personality, workflow, add/edit/remove scheduled jobs, update Discord channels, swap model, or delete the agent.
How this skill is triggered — by the user, by Claude, or both
Slash command
/claudeclaw-plus:update-agentThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill walks the user through updating an existing agent without losing its accumulated MEMORY.md state.
Share bugs, ideas, or general feedback.
This skill walks the user through updating an existing agent without losing its accumulated MEMORY.md state.
NEVER read or write
agents/<name>/MEMORY.md. It's the agent's accumulated state — preserving it across edits is the entire point of this skill.NEVER touch
agents/<name>/session.json. Same reason.The only exception is the "Delete agent" menu option, which removes the entire
agents/<name>/directory by design.All edits go through helpers in
src/agents.ts— they're full-file rewrites with marker-aware patching. Do not hand-edit SOUL.md or CLAUDE.md with the Edit tool.
Friendly, brief, opinionated. Same vibe as create-agent. Acknowledge each answer in a sentence or less and move on.
If $ARGUMENTS already names an agent, skip to Step 3. Otherwise:
bun -e 'const { listAgents } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`); console.log((await listAgents()).join("\n"));'
Show the list and ask "Which one?".
Capture the chosen name. Validate it exists in the list above.
bun -e '
const { loadAgent, listAgentJobs } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
const ctx = await loadAgent("AGENT_NAME");
const jobs = await listAgentJobs("AGENT_NAME");
console.log("SOUL.md (head):");
console.log((await Bun.file(ctx.soulPath).text()).split("\n").slice(0,30).join("\n"));
console.log("\nJobs:");
for (const j of jobs) console.log(` - ${j.label} (${j.cron}) ${j.enabled ? "" : "[disabled]"} ${j.model ? "model="+j.model : ""}`);
'
Present this menu and loop until the user picks Done. One selection at a time.
1. Workflow — rewrite the agent's operating manual
2. Personality — rewrite the personality block
3. Add job — add a new scheduled task
4. Edit job — change cron / trigger / enabled / model on an existing job
5. Remove job — delete a scheduled task
6. Discord channels — re-set the channel list
7. Data sources — rewrite the data sources block
8. Default model — set or clear the agent's defaultModel (opus/sonnet/haiku/glm — middle fallback tier)
9. Delete agent — nuke the entire agent directory (requires re-typing the name)
10. Done — exit
For each option, ask the relevant follow-up question(s), then run the matching bun -e invocation. Use temp JSON files for any multi-line content (workflow, personality, trigger prompts) to keep escaping sane.
IMPORTANT — Jobs are LOCAL cron. The Add/Edit/Remove job options below operate on
agents/<name>/jobs/<label>.mdfiles which are scanned byloadJobs()and fired by ClaudeClaw's in-process cron loop. They are NOT the remotescheduleskill. Do NOT invoke thescheduleskill from this wizard.
Before collecting new content for Workflow / Personality / Data sources, ask:
How should this be applied?
a. Append — add to the existing <section> (keeps everything already there) [DEFAULT]
b. Replace — wipe and rewrite the entire block
c. Show current — print the current content first, then ask again
If the user picks a or just hits enter → use mode: "append" (default — non-destructive).
If b → use mode: "replace".
If c → read the current marker block from SOUL.md (Workflow/Personality) or CLAUDE.md (Data sources), print it back to the user, then re-prompt for the mode choice.
To read current content for Show current:
bun -e '
const { loadAgent } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
const ctx = await loadAgent("AGENT_NAME");
const path = "SOUL_OR_CLAUDE_PATH"; // ctx.soulPath or ctx.claudeMdPath
const text = await Bun.file(path).text();
const start = "<!-- claudeclaw:workflow:start -->"; // or :personality: / :datasources:
const end = "<!-- claudeclaw:workflow:end -->";
const i = text.indexOf(start), j = text.indexOf(end);
console.log(i === -1 ? "(no existing block)" : text.slice(i + start.length, j).trim());
'
Run the mode selection above, then re-prompt: "What's the new workflow? (multi-line)".
Write to /tmp/claudeclaw-update.json as {"value": "...", "mode": "append"|"replace"} then:
bun -e '
import { readFileSync } from "fs";
const { updateAgent } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
const { value, mode } = JSON.parse(readFileSync("/tmp/claudeclaw-update.json", "utf8"));
await updateAgent("AGENT_NAME", { workflow: { value, mode } });
console.log("workflow updated (" + mode + ")");
'
Run the mode selection above, then re-prompt for the new personality content:
bun -e '
import { readFileSync } from "fs";
const { updateAgent } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
const { value, mode } = JSON.parse(readFileSync("/tmp/claudeclaw-update.json", "utf8"));
await updateAgent("AGENT_NAME", { personality: { value, mode } });
console.log("personality updated (" + mode + ")");
'
Collect: label (validate via validateJobLabel), cron (validate via parseScheduleToCron), recurring vs one-shot (use AskUserQuestion — default Recurring (cron); pick One-shot only when the user is clear they want a single fire), trigger prompt, model (default/opus/haiku — empty for default).
The recurring step is non-optional: jobs without recurring: true are silently converted to one-shots by src/jobs.ts:clearJobSchedule() on first fire. Default to recurring: true if the user expresses any uncertainty.
bun -e '
import { readFileSync } from "fs";
const { addJob } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
const j = JSON.parse(readFileSync("/tmp/claudeclaw-update.json", "utf8"));
// Pass recurring explicitly (default true) so the wizard never produces silent one-shots.
await addJob("AGENT_NAME", j.label, j.cron, j.trigger, j.model, j.recurring ?? true);
console.log("added " + j.label);
'
List jobs first (via listAgentJobs), let the user pick a label, then ask which fields to change. Build a patch object with only the changed fields:
bun -e '
import { readFileSync } from "fs";
const { updateJob } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
const { label, patch } = JSON.parse(readFileSync("/tmp/claudeclaw-update.json", "utf8"));
await updateJob("AGENT_NAME", label, patch);
console.log("updated " + label);
'
patch may contain any subset of { cron, trigger, enabled, recurring, model }. Flipping recurring from false to true re-arms a previously-cleared schedule; the daemon picks it up on the next hot-reload tick.
List jobs, let the user pick one, confirm ("Remove <label>? y/n"), then:
bun -e '
const { removeJob } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
await removeJob("AGENT_NAME", "LABEL");
console.log("removed");
'
Re-prompt for the comma-separated list. Parse to array.
bun -e '
import { readFileSync } from "fs";
const { updateAgent } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
const { discordChannels } = JSON.parse(readFileSync("/tmp/claudeclaw-update.json", "utf8"));
await updateAgent("AGENT_NAME", { discordChannels });
console.log("channels updated");
'
Run the mode selection above (default Append). Then collect the new data-sources content.
bun -e '
import { readFileSync } from "fs";
const { updateAgent } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
const { value, mode } = JSON.parse(readFileSync("/tmp/claudeclaw-update.json", "utf8"));
await updateAgent("AGENT_NAME", { dataSources: { value, mode } });
console.log("data sources updated (" + mode + ")");
'
Ask: "New default model? (opus / sonnet / haiku / glm, or empty to clear)". This is the agent's middle fallback tier — job frontmatter model: still wins per-task. Append mode is NOT supported (single-value field).
bun -e '
const { updateAgent } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
await updateAgent("AGENT_NAME", { defaultModel: "opus" }); // or "" to clear
console.log("default model updated");
'
This is destructive. Require the user to re-type the agent name verbatim as a confirmation guard. If the typed name does not match, abort and return to the menu.
bun -e '
const { deleteAgent } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
await deleteAgent("AGENT_NAME");
console.log("deleted");
'
This call IS allowed to remove MEMORY.md and session.json because the entire agent directory is going away.
Exit the loop and print a one-line summary of what changed.
You: /claudeclaw:update-agent reg
Claude: pulling reg's current state...
[shows SOUL.md head + jobs list]
what do you want to change?
1. Workflow 2. Personality 3. Add job 4. Edit job
5. Remove job 6. Discord 7. Data sources 8. Delete 9. Done
You: 1
Claude: paste the new workflow (multi-line ok)
You: [pastes 30 lines of new operating manual]
Claude: [writes /tmp/claudeclaw-update.json, runs updateAgent]
✓ workflow updated. MEMORY.md untouched.
anything else?
You: 9
Claude: done. reg's workflow has been replaced. one change total.
You: /claudeclaw:update-agent suzy
Claude: [lists current state]
...
You: 3
Claude: label?
You: weekly-review
Claude: when?
You: every monday at 8am
Claude: [validates → 0 8 * * 1]
trigger prompt?
You: scan the week's clippings and write a synthesis to MEMORY.md
Claude: model? (default/opus/haiku)
You: opus
Claude: [runs addJob]
✓ added weekly-review (0 8 * * 1, model=opus)
anything else?
You: 9
npx claudepluginhub terryspov/claudeclaw-plus --plugin claudeclaw-plusCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.