From claudeclaw-plus
Walks the user through scaffolding a new ClaudeClaw agent teammate with identity, soul, memory, and scheduled jobs. Ask one question at a time, warm and conversational.
How this skill is triggered — by the user, by Claude, or both
Slash command
/claudeclaw-plus:create-agentThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Wizard for scaffolding a new ClaudeClaw agent — a focused Claude persona with its own identity, soul, memory, session, and any number of scheduled jobs.
Wizard for scaffolding a new ClaudeClaw agent — a focused Claude persona with its own identity, soul, memory, session, and any number of scheduled jobs.
You are guiding the user through creating a teammate. Be conversational, warm, and direct. Ask one question at a time. Wait for the answer before moving on. DO NOT dump all questions at once. This is a wizard, not a form.
At the start of EVERY question after Q1, repeat the previously captured value back to the user so they know it landed. Format: Got it — <field>: "<value>". Next: <next question>. For multi-line values (workflow, personality), echo a 1-line summary like Got it — workflow captured (NN words). Next: ....
After EACH answer is captured, write the full in-progress wizard state to /tmp/claudeclaw-agent-wizard.json via a bun -e snippet. Do NOT wait until scaffold time. If the network glitches or context resets, the next session can resume by reading this file. The snippet:
const fs = await import("fs/promises");
await fs.writeFile("/tmp/claudeclaw-agent-wizard.json", JSON.stringify(state, null, 2));
Match the vibe of skills/create-skill/SKILL.md: friendly, brief, opinionated. You're texting a friend who happens to be brilliant. No filler, no walls of text. Acknowledge each answer in a sentence or less, then move to the next question.
Ask these in order, one at a time.
Ask: "What should we call them? (kebab-case — lowercase, hyphens only, like daily-digest or suzy-v2)"
Validate immediately. Run this in a Bash tool call:
bun -e 'const {validateAgentName} = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`); console.log(JSON.stringify(validateAgentName("USER_INPUT")));'
If valid: false, tell the user the error in one line and re-ask. Common rejects: capitals (Suzy), spaces, starting with a digit, or the agent already existing.
Ask: "What does this agent do? One line — what's their job?"
Free text. Goes into IDENTITY.md.
Ask: "Who are they? Give me 2–4 sentences on their personality and vibe."
Free text. Becomes the Personality section of SOUL.md.
Ask: "How does this agent operate? What are their guidelines, tone, do's and don'ts? This can be as long as you want — write it like a mini operating manual."
This is a dedicated multi-line field, separate from any schedule. It becomes the ## Workflow block in SOUL.md. If the answer is gnarly or long, write it to a temp file (e.g. /tmp/claudeclaw-agent-workflow.txt) so escaping doesn't bite you later.
Ask: "Any Discord channels they should know about? Comma-separated (#content,#research) or none."
Parse comma-separated into an array. none → empty array.
Ask: "What information sources do they pull from? (RSS feeds, APIs, files, websites — free text, or none)"
Free text.
Ask: "What model should this agent use by default? Options: default (daemon setting), opus, sonnet, haiku, glm. Individual jobs can still override this per-task."
If the user picks anything other than default (or presses enter), capture it as defaultModel. This becomes the agent's middle-tier fallback: job frontmatter model: wins, then this agent default, then the daemon setting.
IMPORTANT — Jobs are LOCAL cron. Scheduled tasks here are managed by ClaudeClaw's in-process cron loop (
src/jobs.ts→src/commands/start.ts setInterval). They are NOT the remotescheduleskill (which uses cloud triggers like Vercel cron). Do NOT invoke thescheduleskill from this wizard. All job files live atagents/<name>/jobs/<label>.mdwithschedule:frontmatter and are loaded byloadJobs()on the running daemon.
Ask: "Want to add a scheduled task? (y/n)"
If n, skip to scaffold. If y, run this loop until the user is done:
Single-job workflow reuse: If the user provided a non-empty Workflow (Q4) AND this is the first scheduled task AND the user does not add a second task, do NOT ask for a trigger prompt for this job. Default the trigger prompt to the literal string Run the workflow defined in SOUL.md. Then ask: Want to override the trigger prompt for this job? (y/n, default n). Only prompt for a custom trigger if the user answers y.
Multi-job agents (2+ scheduled tasks) still need per-job trigger prompts as before — different jobs do different things.
For each task:
digest-scan, morning-brief)". Validate via:
bun -e 'const {validateJobLabel} = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`); console.log(JSON.stringify(validateJobLabel("USER_INPUT")));'
every weekday at 9am, daily at 6pm, every 4 hours) or raw cron." Validate via:
bun -e 'const {parseScheduleToCron} = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`); console.log(parseScheduleToCron("USER_INPUT"));'
If null, re-ask with examples.Recurring (cron) (default) and One-shot (fire once, then clear schedule).recurring: true for Recurring, recurring: false for One-shot.src/jobs.ts:clearJobSchedule() strips the schedule: line on the first fire of any job without recurring: true, converting it to a one-shot. A wizard job that the user expects to recur (the common case) MUST be written with recurring: true or it silently becomes a one-shot after the first run. Setting this explicitly is the fix for the silent-strip footgun.default / opus / haiku — press enter for default)"Then: "Add another task? (y/n)" — loop or break out.
Print a complete review of every captured answer (name, role, personality summary, workflow word count, discord channels, data sources, and each scheduled task with its label/cron/trigger). Then ask: Scaffold this agent? (y/n, or 'edit <field>' to amend). If the user types edit <field>, jump back to that question; if y, proceed; if n, abort and unlink the temp state file.
Once all answers are in and the user confirmed the review block, write them to a temp JSON file to keep escaping sane, then call the helpers in one shot. Mirror Phase 16's temp-file pattern.
# 1. Write the collected wizard state (use the Write tool for the temp file).
# /tmp/claudeclaw-agent-wizard.json shape:
# {
# "name": "...",
# "role": "...",
# "personality": "...",
# "workflow": "...",
# "discordChannels": ["#a","#b"],
# "dataSources": "...",
# "defaultModel": "opus", // optional — omit for daemon default
# "jobs": [
# { "label": "digest-scan", "cron": "0 9 * * *", "recurring": true, "trigger": "...", "model": "opus" },
# ...
# ]
# }
# 2. Scaffold + add jobs in one bun -e:
bun -e '
import { readFileSync } from "fs";
const { createAgent, addJob } = await import(`${process.env.CLAUDECLAW_ROOT || "."}/src/agents.ts`);
const cfg = JSON.parse(readFileSync("/tmp/claudeclaw-agent-wizard.json", "utf8"));
const ctx = await createAgent({
name: cfg.name,
role: cfg.role,
personality: cfg.personality,
workflow: cfg.workflow,
discordChannels: cfg.discordChannels,
dataSources: cfg.dataSources,
defaultModel: cfg.defaultModel,
});
for (const job of cfg.jobs) {
// Pass recurring through so the wizard does not silently produce one-shot jobs.
// addJob defaults to recurring=true if omitted, but the wizard must capture the
// user choice explicitly per the Q3 step above.
await addJob(ctx.name, job.label, job.cron, job.trigger, job.model, job.recurring ?? true);
}
console.log(JSON.stringify({ agent: ctx.name, jobs: cfg.jobs.map(j => j.label) }, null, 2));
'
Notes:
createAgent() handles IDENTITY.md, SOUL.md (Personality + Workflow markers), CLAUDE.md, MEMORY.md, session.json, .gitignore.addJob() writes each scheduled task to agents/<name>/jobs/<label>.md with frontmatter (label, cron, recurring, enabled, model). When recurring: true (the wizard default), the daemon preserves the schedule across fires. When recurring: false, the daemon clears the schedule on first fire (one-shot).Print a short summary:
✓ Agent <name> created.
Files:
agents/<name>/IDENTITY.md
agents/<name>/SOUL.md ← personality + workflow
agents/<name>/CLAUDE.md
agents/<name>/MEMORY.md
agents/<name>/jobs/<label>.md ← one per scheduled task
Try it:
claudeclaw send --agent <name> "say hello"
If any jobs were scheduled, list them with their cron + model. Mention the daemon hot-reloads jobs on the next tick.
Then ask if they want to tweak IDENTITY.md or SOUL.md before they take it for a spin.
If createAgent() or addJob() throws (duplicate name, bad schedule, fs error), surface the error verbatim, suggest a fix, and offer to retry from the failing step. Don't restart the whole wizard — the temp JSON still has the state.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub terryspov/claudeclaw-plus --plugin claudeclaw-plus