From hamster
Executes Hamster Studio briefs: merges base branch, implements tasks in parallel waves, tests, reviews code, creates bisectable commits, optionally PRs via GitHub. Use to ship briefs.
npx claudepluginhub gethamster/cli --plugin hamsterThis skill uses the workspace's default tool permissions.
Orchestrates the full execution of a Hamster Studio brief using specialized agents. Reads briefs/tasks from `.hamster/`, plans parallel execution waves, merges base branch, dispatches independent parent tasks simultaneously, gates on tests, reviews and simplifies code, creates bisectable commits, and optionally creates a PR.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Orchestrates the full execution of a Hamster Studio brief using specialized agents. Reads briefs/tasks from .hamster/, plans parallel execution waves, merges base branch, dispatches independent parent tasks simultaneously, gates on tests, reviews and simplifies code, creates bisectable commits, and optionally creates a PR.
Argument: "$ARGUMENTS"
Run the following to verify all requirements at once:
errors=""
which hamster >/dev/null 2>&1 || errors="${errors}hamster CLI not found. Install from https://tryhamster.com\n"
[ -d ".hamster" ] || errors="${errors}.hamster/ directory not found. Run 'hamster sync' first.\n"
which gh >/dev/null 2>&1 || errors="${errors}gh CLI not found. Install from https://cli.github.com\n"
dirty=$(git status --porcelain 2>/dev/null | head -5)
[ -n "$dirty" ] && errors="${errors}Uncommitted changes:\n${dirty}\n"
if [ -n "$errors" ]; then printf "PREREQ_FAIL:\n$errors"; else echo "PREREQ_OK"; fi
PREREQ_FAIL: show the errors to the user and stop (except for uncommitted changes — ask whether to proceed or stash)PREREQ_OK: continueDiscover account slug:
account=$(ls -d .hamster/*/ 2>/dev/null | head -1 | xargs basename)
echo "$account"
Start live sync so task status updates are reflected in local .hamster/ files:
hamster sync --watch > /dev/null 2>&1 &
HAMSTER_SYNC_PID=$!
echo "Live sync started (PID: $HAMSTER_SYNC_PID)"
Parse the argument — extract a brief slug from a URL, UUID, or use as-is. URLs use a brief UUID (not slug) in the path, e.g. https://tryhamster.com/home/hamster/briefs/2de8d546-...:
arg="$ARGUMENTS"
arg="${arg%/}"
# Extract identifier from URL or use as-is
if echo "$arg" | grep -qE '^https?://'; then
identifier=$(echo "$arg" | sed -E 's|^https?://[^/]+/home/[^/]+/briefs/([^/]+)(/tasks)?$|\1|')
else
identifier="$arg"
fi
# If identifier is a UUID, resolve to slug via brief frontmatter
if echo "$identifier" | grep -qE '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'; then
slug=""
for brief_dir in .hamster/${account}/briefs/*/; do
bf="${brief_dir}brief.md"
[ -f "$bf" ] || continue
eid=$(awk -F'"' '/^---$/{n++; next} n==1 && /^entity_id:/ { print $2; exit }' "$bf")
if [ "$eid" = "$identifier" ]; then
slug=$(basename "$brief_dir")
break
fi
done
[ -z "$slug" ] && echo "No brief found with ID $identifier"
else
slug="$identifier"
fi
echo "$slug"
Verify it exists:
ls ".hamster/${account}/briefs/${slug}/brief.md"
If not found, search for partial matches:
ls -d .hamster/${account}/briefs/*${slug}*/ 2>/dev/null | head -5
List actionable briefs with task counts grouped by status:
account=$(ls -d .hamster/*/ 2>/dev/null | head -1 | xargs basename)
briefs_dir=".hamster/${account}/briefs"
last_status=""
index=0
for brief_dir in "${briefs_dir}"/*/; do
[ ! -d "$brief_dir" ] && continue
slug=$(basename "$brief_dir")
brief_file="${brief_dir}brief.md"
[ ! -f "$brief_file" ] && continue
tasks_dir="${brief_dir}tasks"
[ ! -d "$tasks_dir" ] && continue
brief_status=$(awk -F'"' '/^---$/{n++; next} n==1 && /^status:/ { print $2; exit }' "$brief_file")
case "$brief_status" in aligned|delivering|refining) ;; *) continue ;; esac
total=$(ls "$tasks_dir"/*.md 2>/dev/null | wc -l | tr -d ' ')
[ "$total" -eq 0 ] && continue
done_count=$(grep -l '^status: "done"' "$tasks_dir"/*.md 2>/dev/null | wc -l | tr -d ' ')
title=$(awk -F'"' '/^---$/{n++; next} n==1 && /^title:/ { print $2; exit }' "$brief_file")
echo "${brief_status}|${slug}|${title}|${done_count}|${total}"
done | sort -t'|' -k1,1 | while IFS='|' read -r bstatus bslug btitle bdone btotal; do
if [ "$bstatus" != "$last_status" ]; then
[ -n "$last_status" ] && echo ""
printf " %s:\n" "$(echo "$bstatus" | awk '{print toupper(substr($0,1,1)) substr($0,2)}')"
last_status="$bstatus"
fi
index=$((index + 1))
printf " %2d. %-55s (%s/%s tasks done) [%s]\n" "$index" "$btitle" "$bdone" "$btotal" "$bslug"
done
Present this output to the user and use AskUserQuestion to let them pick a brief. The [slug] at the end of each line is the value to use.
Launch the brief-planner agent with:
The planner returns an execution plan with:
Display the execution plan to the user including the Parallel Waves visualization.
Use AskUserQuestion:
Create the feature branch directly (no agent needed):
Get the lowest display ID for branch naming:
tasks_dir=".hamster/${account}/briefs/${slug}/tasks"
lowest_id=$(ls "$tasks_dir"/*.md 2>/dev/null | xargs -I{} basename {} | grep -oE 'ham-[0-9]+' | sed 's/ham-//' | sort -n | head -1)
branch="feature/ham-${lowest_id}-${slug}"
Create and switch to the branch:
git checkout -b "$branch"
echo "Created branch: $branch"
Before starting execution, merge the latest base branch to catch conflicts early:
# Detect the default branch
default_branch=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name 2>/dev/null || echo "main")
# Fetch and merge
git fetch origin "$default_branch"
git merge "origin/$default_branch" --no-edit
Process tasks in the parallel waves determined by the brief-planner.
Launch ALL task-executor agents for this wave simultaneously in a single turn (parallel Agent calls).
For each parent task in this wave, launch a task-executor agent with:
IMPORTANT: Launch ALL executors for this wave as parallel Agent calls in a single message. Do not wait for one to complete before starting the next. If the runtime serializes them, they will still execute correctly — just sequentially.
Wait for ALL task-executors in this wave to complete.
Each executor reports:
Collect ALL file lists from ALL executors in this wave.
After ALL executors complete, run project validation ONCE:
[ -f "package.json" ] && command -v pnpm >/dev/null && { pnpm typecheck 2>/dev/null; pnpm lint 2>/dev/null; }
[ -f "package.json" ] && command -v npm >/dev/null && ! command -v pnpm >/dev/null && { npm run typecheck 2>/dev/null; npm run lint 2>/dev/null; }
[ -f "package.json" ] && command -v yarn >/dev/null && ! command -v pnpm >/dev/null && { yarn typecheck 2>/dev/null; yarn lint 2>/dev/null; }
[ -f "Makefile" ] && make check 2>/dev/null
[ -f "Cargo.toml" ] && cargo check && cargo clippy 2>/dev/null
[ -f "go.mod" ] && go build ./... && go vet ./... 2>/dev/null
If validation fails: fix the errors before proceeding. This may require using Edit directly for type errors, or re-launching a task-executor with the specific fix.
After validation passes, run the project's test suite for affected areas:
# Detect tooling and run tests
if [ -f "package.json" ]; then
if command -v pnpm >/dev/null; then pnpm test 2>/dev/null
elif command -v yarn >/dev/null; then yarn test 2>/dev/null
elif command -v npm >/dev/null; then npm test 2>/dev/null
fi
elif [ -f "Cargo.toml" ]; then cargo test 2>/dev/null
elif [ -f "go.mod" ]; then go test ./... 2>/dev/null
elif [ -f "Makefile" ]; then make test 2>/dev/null
fi
Launch ALL quality-gate agents for this wave simultaneously in a single turn (parallel Agent calls).
For each parent in this wave, launch a quality-gate agent with:
IMPORTANT: Launch ALL quality-gates for this wave as parallel Agent calls in a single message.
Wait for ALL quality-gate agents to complete.
For each quality-gate result:
If NEEDS_FIXES:
If PASS: the quality-gate may have made simplification changes. Those are already in the working tree.
For each parent in this wave (sequentially — commits are serial for git safety):
When a parent task has changes across multiple concerns, split into logical commits ordered for bisectability:
Each commit should be independently buildable. Never mix concerns (e.g., migration + UI change in one commit).
If a parent task's changes are small or cohesive (single concern), a single commit is fine:
# Stage specific files only (all files changed by executor + any simplification changes)
git add {file1} {file2} {file3}
# Verify nothing unwanted is staged
git diff --cached --name-only
# Commit
git commit -m "$(cat <<'EOF'
feat(ham-{id}): {concise description of parent task}
- {bullet: key change 1}
- {bullet: key change 2}
Task: HAM-{id}
Brief: {brief-slug}
EOF
)"
For quality-gate simplification changes (if any were made):
git add {simplified-files}
git commit -m "refactor(ham-{id}): simplify post-review
- {what was simplified}
Task: HAM-{id}
Brief: {brief-slug}"
NEVER use git add . or git add -A — always stage specific files.
If any pre-commit hook fails: read the error, fix the issue, create a new commit (never --no-verify).
Non-interactive by default: Auto-include all unstaged changes for the parent task, auto-split commits for bisectability. Only stop for: merge conflicts, test failures, CRITICAL review findings, agent failures.
After each wave completes, report progress:
Wave {n} complete:
HAM-{id}: {title} — {n} subtasks, PASS, {n} commits
HAM-{id}: {title} — {n} subtasks, PASS, {n} commits
Remaining: {n} waves, {n} parent tasks
After all subtasks complete for a parent, the task-executor marks it done via hamster task status. Verify this happened by checking task statuses in the progress report.
[ -n "$HAMSTER_SYNC_PID" ] && kill "$HAMSTER_SYNC_PID" 2>/dev/null && echo "Live sync stopped"
Run whatever validation the project uses. Detect the project's tooling and run appropriate checks:
# Detect and run project validation
[ -f "package.json" ] && command -v pnpm >/dev/null && { pnpm typecheck 2>/dev/null; pnpm lint 2>/dev/null; }
[ -f "package.json" ] && command -v npm >/dev/null && ! command -v pnpm >/dev/null && { npm run typecheck 2>/dev/null; npm run lint 2>/dev/null; }
[ -f "package.json" ] && command -v yarn >/dev/null && ! command -v pnpm >/dev/null && { yarn typecheck 2>/dev/null; yarn lint 2>/dev/null; }
[ -f "Makefile" ] && make check 2>/dev/null
[ -f "Cargo.toml" ] && cargo check && cargo clippy 2>/dev/null
[ -f "go.mod" ] && go build ./... && go vet ./... 2>/dev/null
If tests are configured for the affected areas, run the project's test command.
Use AskUserQuestion to ask the user:
If yes:
default_branch=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name 2>/dev/null || echo "main")
git push -u origin HEAD$default_branchhamster brief status {slug} delivering
Brief execution complete!
Brief: {title}
Branch: feature/ham-{id}-{slug}
PR: {PR URL or "skipped"}
Tasks completed: {n}/{total}
Waves executed: {n}
Commits: {total commits}
Review rounds: {n}
All tasks implemented, reviewed, and simplified.
| Error | Recovery |
|---|---|
| Hamster CLI not found | Stop with installation instructions |
.hamster/ missing | Stop — tell user to run hamster sync |
| Brief not found | Search for partial matches, suggest closest |
| Auth expired | Run hamster auth login, continue without status updates |
| Base branch merge conflict | Stop, report conflicts to user, do NOT auto-resolve |
| Wave validation fails | Fix errors before proceeding to quality gates |
| Test gate fails | Stop, report failures, ask user to fix or skip |
| Parallel executor conflict: two executors modified the same file | Stop, report conflict to user, ask for guidance |
| Quality gate NEEDS_FIXES after 2 rounds | Report issues to user, ask whether to skip or fix manually |
| Git conflict | Report to user, pause execution |
| Pre-commit hook fails | Fix the issues, create a new commit (never --no-verify) |
| Task already done | Skip it, move to next |
| Agent fails | Report error, ask user whether to retry or skip |
/resume to continue