Agent
Spawn and manage autonomous background agents with persistent state across sessionsFrom its SKILL.md
npx -y skills add devhimanshulohani/claude-agent-manager --skill agentAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
20.6 KB, as published. Nobody here has run it
Agent Manager v4
Parse $ARGUMENTS and execute the matching command below. Persistent state lives in .claude/agents/registry.json (source of truth). Task system is for live monitoring only.
Pre-flight: Before executing any command, verify the current directory is inside a git repository (git rev-parse --is-inside-work-tree). If not, reject: "Agent manager requires a git repository. Run git init first."
Registry: Read .claude/agents/registry.json — if missing/corrupt, default to { "version": 2, "defaultBranch": null, "agents": [] }. If version is 1 or missing, migrate: add model: null, effort: null, color: null, maxTurns: null to each agent entry, add defaultBranch: null at top level, set version to 2, write immediately. Always mkdir -p .claude/agents before writing.
Atomic writes: Always write registry to .claude/agents/registry.json.tmp first, then rename to .claude/agents/registry.json. This prevents corruption from interrupted writes.
Default branch: Read from registry.defaultBranch. If null (first time using the plugin in this repo), ask the user using AskUserQuestion: "What is your default/base branch? (e.g., main, master, develop)". Store the answer in registry.defaultBranch and write registry. Once set, never ask again. Use {defaultBranch} everywhere in this document instead of a hardcoded branch name.
Agent ID: Generate via echo "$(date +%s)$$.$RANDOM" | shasum | head -c 6 (6-char hex). $$ (PID) + $RANDOM ensures uniqueness even when called multiple times in the same second (e.g., batch).
Age format: <N>m ago / <N>h ago / <N>d ago relative to createdAt.
Prefix match: All ID-based commands support prefix matching. If the prefix is ambiguous (matches multiple agents), reject and show the matching IDs. If no match, show all available IDs.
Templates dir: .claude/agents/templates/ — JSON files with required fields { name, description } and optional { verifyCommand, commitFormat }. verifyCommand overrides Phase 4 auto-detection; commitFormat overrides the default conventional commit format.
User defaults: If env var CLAUDE_PLUGIN_OPTION_DEFAULT_MODEL is set, use it as default model when --model is not specified. If CLAUDE_PLUGIN_OPTION_DEFAULT_EFFORT is set, use it as default effort level. These are configured when the user enables the plugin.
Auto-registry: A SubagentStop hook automatically updates the registry when a worker agent completes. The list command still verifies status as a fallback.
Flag validation: --model must be one of haiku, sonnet, opus. --color must be one of red, blue, green, yellow, purple, orange, pink, cyan. --effort must be one of low, medium, high, max. --max-turns must be a positive integer. Reject invalid values with a clear error message listing valid options.
list
- Read registry. If empty, say "No agents found. Spawn one with:
/agent "your task"" - For each agent with status
running:- If
taskIdis null → mark asunknown, continue - First, check if
.claude/agents/<id>-result.txtexists (Read it). If it exists → parse it, update entry tocompletedwith branch/commit/files/completedAt. Continue to next agent. - If no result file, try
TaskOutputwithblock: false, timeout: 3000using storedtaskId - If task found & completed → check result file again, update to
completed - If task found & still running → leave status as
running, continue - If task found & errored → mark as
failed - If task NOT found (new session) → if
branchis null →unknown. Otherwise checkgit branch --list <branch>— branch exists →unknown, no branch →failed
- If
- Write updated registry. Display table: ID | Status | Description | Branch | Age
switch <id>
- Look up agent by ID in registry (prefix match). If not found, show available IDs.
- If
runningandtaskIdis not null → first check result file.claude/agents/<id>-result.txt. If exists, update tocompletedand show summary. Otherwise tryTaskOutputwithblock: false, timeout: 5000and display the latest output to the user. Ifrunningwith nulltaskId→ say "Agent is running but has no task handle (spawn may have partially failed). Try/agent listto refresh or/agent stop <id>." - Otherwise → read
.claude/agents/<id>-result.txtfor summary. If file missing, say "No result file yet. Agent may still be in progress or failed without output." - Show: status, description, branch, model (if set), color (if set). Suggest next actions based on status:
running→/agent watch <id>or/agent stop <id>completed→/agent merge <id>,/agent diff <id>unknown/stopped→/agent merge <id>,/agent diff <id>,/agent resume <id>failed→/agent retry <id>or/agent resume <id>merged→/agent clean- If branch exists (any status), also suggest
git diff {defaultBranch}...<branch>
stop <id>
- Look up agent in registry (prefix match). If not found, say so. If status is not
running, reject: "Agent<id>is<status>, not running." - If
taskIdis not null, tryTaskStopwithtask_id(ignore errors if gone). IftaskIdis null, skip — just update status. - Update registry: status →
stopped, setcompletedAt. Write registry. Confirm.
history
- Read registry. If empty, say "No agent history found"
- Display ALL agents sorted by
createdAtdesc. Table: ID | Status | Description | Branch | Commit Message | Model | Date. Show "—" for null/empty fields. Show notes count if agent has notes (e.g., "2 notes").
clean
- Read registry. Filter agents with status
completed/stopped/merged/failed/unknown - For each: delete
.claude/agents/<id>-result.txtand.claude/agents/<id>.patch(if exists), delete branch ifmergedandbranchis not null (git branch -d <branch>). Ignore errors. (Worktrees fromisolation: "worktree"are auto-managed by Claude Code.) - Remove entries from registry, write it. Report: "Cleaned up N agent(s). M still running."
merge <id>
- Look up agent (prefix match). If not found or status not
completed/unknown/stopped, reject with reason. - If
branchis null, reject: "No branch recorded for this agent." Otherwise, verify branch exists (git branch --list <branch>). If not, say so. - Check working tree is clean (
git status --porcelain). If dirty, reject: "Working tree has uncommitted changes. Commit or stash first." - Run
git checkout {defaultBranch} && git merge <branch>. On success → update status tomerged, write registry, suggest/agent clean. On conflict → tell user, suggestgit merge --abort.
resume <id>
- Look up agent in registry (prefix match). Must have status
stopped/failed/unknown/completed. Reject ifrunning/merged. - If
branchis null, say "No branch to resume from. Use/agent retry <id>to start fresh." Otherwise, verify branch exists (git branch --list <branch>). If not, say "Branch no longer exists. Use/agent retry <id>to start fresh." - Read
.claude/agents/<id>-result.txt— this contains the completion context (branch, files changed, summary of what was done). If missing, fall back togit log {defaultBranch}..<branch> --oneline(1 command only). - Update registry: status →
running, clearcompletedAt. Write registry. TaskCreatewith subject:Resume: <original description>(60 chars max), activeForm (present continuous).- Spawn
Agentwithsubagent_type: "agent-manager:worker", prompt:
You are RESUMING previous work. **Task:** {description} | **Agent ID:** {id}
**Previous work summary:**
{result file contents}
**Resume instructions:**
- Fetch and checkout the existing branch: `git fetch origin {branch} 2>/dev/null; git checkout {branch} 2>/dev/null || git checkout -b {branch} origin/{branch} 2>/dev/null || echo "Warning: branch {branch} not found"`
- Read the changed files and understand what was already completed
- Identify what remains to be done vs what is already done
- Do NOT redo completed work — only pick up where it left off
- Then proceed through the standard phases (Plan, Implement, Verify, Commit)
{if verifyCommand}
**Verify command:** `{verifyCommand}`
{end}
{if commitFormat}
**Commit format:** `{commitFormat}`
{end}
**CRITICAL — after committing, write the result file to the ORIGINAL repo (not worktree):**
BRANCH=$(git rev-parse --abbrev-ref HEAD)
COMMIT=$(git rev-parse --short HEAD)
COMMIT_MSG=$(git log -1 --pretty=%s)
FILES=$(git diff {defaultBranch}..HEAD --name-only 2>/dev/null | tr '\n' ', ' | sed 's/,$//')
DIFF_STAT=$(git diff {defaultBranch}..HEAD --stat 2>/dev/null | tail -5)
COMMIT_LOG=$(git log {defaultBranch}..HEAD --oneline 2>/dev/null)
mkdir -p {repo_absolute_path}/.claude/agents
cat > {repo_absolute_path}/.claude/agents/{id}-result.txt << RESULT_EOF
branch: $BRANCH
commit: $COMMIT
commitMessage: $COMMIT_MSG
filesChanged: $FILES
summary: Resumed and completed task — {short description}
commitLog: $COMMIT_LOG
diffStat: $DIFF_STAT
RESULT_EOF
Template handling (same as Spawn): Read verifyCommand and commitFormat from the registry entry. Include {if ...} blocks only when the value is set. Remove {if}/{end} markers from the final prompt. Also pass model from registry entry if set (via Agent tool's model parameter).
- Update registry entry's
taskIdfrom the background Agent task. Write registry. - Tell user: agent
<id>resumed on branch<branch>.
retry <id>
- Look up agent in registry (prefix match). Must have status
stopped/failed/unknown. Reject otherwise. - Save the original
description,verifyCommand,commitFormat,model,effort,color, andmaxTurnsfrom the entry. - Generate a NEW agent ID.
- Add new entry to registry (using standard schema from Spawn step 4) with original description and all saved fields, status
running. Write registry. - Run
TaskCreate(subject, description, activeForm) then spawnAgent(same params as Spawn step 5, passing through all saved fields). Update the entry'staskIdfrom the Agent task. Write registry. - Tell user: "Retrying as new agent
<new_id>(original:<old_id>). Original agent preserved in history."
diff <id>
- Look up agent in registry (prefix match). If not found, show available IDs.
- Get the branch name. If no branch, reject: "No branch found for this agent."
- Run
git diff {defaultBranch}...<branch> --statto show file-level summary. - Run
git diff {defaultBranch}...<branch>to show full diff. - Display the stat summary first, then the full diff (truncate if extremely long — show first 200 lines and note if truncated).
logs <id>
- Look up agent in registry (prefix match).
- Read
.claude/agents/<id>-result.txt— display if exists. - If
taskIdis not null, find the agent's subagent transcript: search for files matching~/.claude/projects/*/subagents/agent-*.jsonlusing Glob. Look for the transcript that corresponds to the agent'staskId. IftaskIdis null, skip to step 5. - If transcript found, read it and extract a summary:
- List tools used (Read, Write, Edit, Bash, etc.) with counts
- Show files read/modified
- Show bash commands executed
- Show any errors encountered
- If no transcript found and branch is not null, check git log on the branch:
git log {defaultBranch}..<branch> --oneline --stat. If branch is null, say "No branch or transcript available." - Display: Agent ID | Status | Description | Activity Summary | Files Touched | Errors (if any)
batch "task1" "task2" ...
- Parse arguments — use shell-style quote parsing. Each quoted string is a separate task description. Unquoted words are joined as a single task. If no tasks parsed, reject: "Usage:
/agent batch \"task one\" \"task two\" ..." - For each task: generate a unique ID, add entry to registry (using standard schema from Spawn step 4) with status
running. Write registry once with all new entries. - For each task: run
TaskCreate(subject, description, activeForm) then spawnAgent(same params as Spawn step 5). Update the entry'staskIdfrom the Agent task. Write registry after each spawn to persisttaskId. - Display table of all spawned agents: ID | Description | Status
- Tell user: "Spawned {N} agents. Use
/agent listto monitor."
Batch flags: batch also supports --model, --effort, and --max-turns flags. If provided, they apply to ALL agents in the batch. Place flags before the task strings: /agent batch --model sonnet "task one" "task two".
note <id> "text"
- Look up agent in registry (prefix match).
- Parse the note text from arguments (everything after the ID). If no text provided, reject: "Usage:
/agent note <id> \"your note text\"" - Add/append to a
notesarray in the registry entry:{ text, timestamp: <ISO now> }. - Write registry. Confirm: "Note added to agent
<id>." - When displaying agent details (in
switch,history), show notes if present.
watch <id>
- Look up agent in registry (prefix match). Must have status
running. Reject otherwise. - If
taskIdis null, reject: "Agent has no task handle. Try/agent listto refresh status." - Tell user: "Watching agent
<id>... (up to 5 minutes, Ctrl+C to stop)" - Try
TaskOutputwithblock: true, timeout: 300000(single blocking call, 5 minutes max). IfTaskOutputfails or is unavailable (deprecated), fall back to polling: check.claude/agents/<id>-result.txtevery 10 seconds usingBash(sleep 10)+ Read, for up to 30 iterations (5 minutes). If the result file appears during polling, treat as completed. - Handle the result:
- If completed → parse result file (if missing, update registry to
completedwith no file details and note "Result file not found — agent may have failed to write it")- If branch is not null, run
git diff {defaultBranch}...<branch> --statto preview changes. If branch is null, say "Agent completed but no branch was recorded." - Show the diff summary to the user
- Ask user explicitly: "Agent completed. Merge branch
<branch>into current branch?" — wait for confirmation. Do NOT auto-merge. (Skip merge prompt if branch is null.) - If user confirms → check working tree is clean (
git status --porcelain), then rungit merge <branch>. On success → update status tomerged, write registry, suggest/agent clean. On conflict → tell user, suggestgit merge --abort - If user declines → tell user: "Skipped merge. Use
/agent merge <id>later or/agent diff <id>to review."
- If branch is not null, run
- If errored → update registry to
failed, write registry. Tell user: "Agent failed. Use/agent logs <id>to investigate or/agent retry <id>to try again." - If still running (timeout reached) → say: "Agent still running after 5 minutes. Use
/agent watch <id>again or/agent listto check."
- If completed → parse result file (if missing, update registry to
rebase <id>
- Look up agent in registry (prefix match). Must have status
completed/unknown/stopped. Reject ifrunning/merged/failedwith reason. - If
branchis null, reject: "No branch recorded for this agent." Otherwise, verify branch exists (git branch --list <branch>). If not, say so. - Check working tree is clean (
git status --porcelain). If dirty, reject: "Working tree has uncommitted changes. Commit or stash first." - Run
git fetch origin {defaultBranch}(ignore errors if no remote). - Run
git checkout <branch> && git rebase {defaultBranch}. - On success → run
git checkout -to return to original branch. Tell user: "Branch<branch>rebased onto{defaultBranch}. Ready to merge with/agent merge <id>." - On conflict → tell user the conflicting files, suggest
git rebase --abortor manual resolution.
export <id>
- Look up agent in registry (prefix match).
- Get branch name. If no branch, reject.
- Run
mkdir -p .claude/agents && git format-patch {defaultBranch}..<branch> --stdout > .claude/agents/<id>.patch - Tell user: "Patch exported to
.claude/agents/<id>.patch. Apply withgit am < .claude/agents/<id>.patch."
stats
- Read registry.
- Calculate:
- Total spawned: count of all agents
- By status: count per status (running/completed/stopped/failed/merged/unknown)
- Success rate: completed+merged / total (exclude running). If no non-running agents, show "N/A"
- Most active day: group by date of
createdAt, find max - Avg files changed: average length of
filesChangedarrays (for completed/merged). If none, show "N/A" - Models used: count per model value (for agents with
modelset)
- Display as a formatted summary panel.
Spawn (default — no command match)
Handles: plain task descriptions, --template <name>, --model <model>, --effort <level>, --color <color>, and --max-turns <N> flags.
- Parse flags from arguments:
--template <name>: read.claude/agents/templates/<name>.json. If not found, list available templates and abort. Use template's description prefix + remaining args as description. StoreverifyCommandandcommitFormatfrom the template.--model <model>: one ofhaiku,sonnet,opus. Store for Agent tool'smodelparameter and registry. Falls back toCLAUDE_PLUGIN_OPTION_DEFAULT_MODELenv var if not specified.--effort <level>: one oflow,medium,high,max. Registry metadata only — the worker always runs ateffort: high(set in its definition). This flag is stored for tracking/display purposes. Falls back toCLAUDE_PLUGIN_OPTION_DEFAULT_EFFORTenv var if not specified.--color <color>: one ofred,blue,green,yellow,purple,orange,pink,cyan. Store in registry.--max-turns <N>: positive integer. Registry metadata only — the worker always usesmaxTurns: 200(set in its definition). This flag is stored for tracking/display purposes.- Everything else (after removing flags) is the task description. If no flags matched, use full
$ARGUMENTSas description. Set unspecified flags tonull.
- Generate ID, read registry.
TaskCreatewith subject (60 chars max), description, activeForm (present continuous).- Add entry to registry:
{ id, taskId: null, description, status: "running", branch: null, commit: null, commitMessage: null, createdAt: <ISO now>, completedAt: null, filesChanged: [], notes: [], verifyCommand, commitFormat, model, effort, color, maxTurns }. Write registry. - Spawn
Agentwithsubagent_type: "agent-manager:worker", and ifmodelis set pass it via the Agent tool'smodelparameter. The prompt:
**Task:** {description} | **Agent ID:** {id}
{if verifyCommand}
**Verify command:** `{verifyCommand}`
{end}
{if commitFormat}
**Commit format:** `{commitFormat}`
{end}
**CRITICAL — after committing, write the result file to the ORIGINAL repo (not worktree):**
BRANCH=$(git rev-parse --abbrev-ref HEAD)
COMMIT=$(git rev-parse --short HEAD)
COMMIT_MSG=$(git log -1 --pretty=%s)
FILES=$(git diff {defaultBranch}..HEAD --name-only 2>/dev/null | tr '\n' ', ' | sed 's/,$//')
DIFF_STAT=$(git diff {defaultBranch}..HEAD --stat 2>/dev/null | tail -5)
COMMIT_LOG=$(git log {defaultBranch}..HEAD --oneline 2>/dev/null)
mkdir -p {repo_absolute_path}/.claude/agents
cat > {repo_absolute_path}/.claude/agents/{id}-result.txt << RESULT_EOF
branch: $BRANCH
commit: $COMMIT
commitMessage: $COMMIT_MSG
filesChanged: $FILES
summary: Completed task — {short description}
commitLog: $COMMIT_LOG
diffStat: $DIFF_STAT
RESULT_EOF
Template handling: Include {if ...} blocks only when the value is set. Remove {if}/{end} markers from the final prompt.
Note: The agent-manager:worker subagent already has background: true, isolation: worktree, and effort: high in its definition. The 5-phase execution process (Analyze, Plan, Implement, Verify, Commit) is in the worker's system prompt — do NOT duplicate it in the task prompt.
- Update registry entry's
taskIdfrom the background Agent task (NOT TaskCreate). Write registry. - Tell user: agent
<id>spawned. Show model/color if set. Available commands:list,switch,stop,merge,resume,retry,diff,logs,batch,note,watch,rebase,export,stats,history,clean.