From CAST — Claude Agent Specialist Team
Defines shared conventions for CAST agents including task claiming, status block format, and stale-context guard. Loaded automatically for all agents.
How this skill is triggered — by the user, by Claude, or both
Slash command
/cast:cast-conventionsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
These conventions apply to every CAST agent. They are loaded automatically via the `skills: [cast-conventions]` frontmatter field.
These conventions apply to every CAST agent. They are loaded automatically via the skills: [cast-conventions] frontmatter field.
Every agent MUST follow this protocol:
source ~/.claude/scripts/cast-events.sh && cast_emit_event 'task_claimed' '<agent-name>' "${TASK_ID:-manual}" '' 'Starting'
~/.claude/agent-memory-local/<agent-name>/MEMORY.md before starting. Update when you discover reusable patterns.DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT — followed by one-line Summary and ## Work Log bullets.Every agent response MUST end with a structured Status block:
Status: DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT
Summary: [one-line description of what was accomplished]
Files changed: [explicit list of modified files, if applicable]
Concerns: [required if DONE_WITH_CONCERNS]
Context needed: [required if NEEDS_CONTEXT]
Emit Status: DONE (or DONE_WITH_CONCERNS, BLOCKED, NEEDS_CONTEXT) on its own line as soon as the work is verifiably on disk — before writing your ## Handoff block, before ## Work Log, before any summary prose. Status is the contract; everything else is the optional tail.
Why: under context pressure, the prose tail is what gets truncated. Front-loading Status means orchestrators get the contract value even when truncation hits the summary.
Invoke this guard only when ALL of the following hold simultaneously:
Status: DONE (or DONE_WITH_CONCERNS) for a task description materially identical to the new imperative you are being asked to execute now.When both hold, emit:
Status: NEEDS_CONTEXT
Context needed: This agent instance appears to have already completed this task (prior Status: DONE detected for materially identical work). If new work is required, a fresh dispatch is needed with an explicit new task description.
This guard does NOT fire for:
This is a heuristic against context-replay misfires, not an integrity mechanism — adversarial content injected inside processed files is out of scope and is addressed only by the provenance rule below.
git commit directly — always use the commit agent.--no-verify or bypass hooks.NEVER run any of: git stash (any form), git reset (any form), git checkout <branch> (mid-task branch switch), git clean (any form), git rebase (unless explicitly authorized in your prompt). If you feel the urge to checkpoint your work, DON'T. Keep working in the working tree — the orchestrator handles staging and commits. If you hit a state you cannot proceed from, STOP and emit Status: BLOCKED with the blocker described. Do not attempt git surgery to recover.
debugger agent rather than inline triage.test-writer, debugger, code-writer) self-dispatch code-reviewer internally — do not double-dispatch from the main session.code-reviewer (haiku) after every logical unit of changes.Status: DONE or Status: DONE_WITH_CONCERNS.Before emitting your prose Status line, write a machine-readable status file at ~/.claude/agent-status/<agent-name>-<timestamp>.json — this is the truncation-resilient source of truth, so if your prose summary gets cut off the orchestrator falls back to the file. Keys: agent, status, summary, concerns (if DONE_WITH_CONCERNS), timestamp (format: YYYY-MM-DDTHH:MM:SSZ).
source ~/.claude/scripts/status-writer.sh 2>/dev/null || true
cast_write_status "<STATUS>" "<one-line summary>" "<your-agent-name>" "<concerns or empty>" 2>/dev/null || true
If the cast_write_status helper is unavailable, write the JSON directly. STATUS must be one of: DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT.
After your human-readable Status block, emit a machine-readable JSON payload. Set the agent field to your own agent name; fill summary, concerns, files_changed, and next_actions from your run.
{
"schema_version": "1.0",
"status": "DONE",
"agent": "<your-agent-name>",
"summary": "<one-line description of what was accomplished>",
"concerns": [],
"files_changed": [],
"next_actions": []
}
Schema: schemas/agent-status.json. Validator: scripts/cast-validate-status.py.
Conditional fields (enforced by the validator): when status is DONE_WITH_CONCERNS, include a non-empty concerns; when BLOCKED, include a non-empty blockers; when NEEDS_CONTEXT, include a non-empty context_needed.
Exceptions: commit adds two keys (files_staged_count, files_unstaged_in_scope_count). Agents whose contract is prose-only (eval-writer, pr-reviewer) emit the Status block without this JSON payload.
When you discover a stable, cross-agent-useful fact during your run, emit a ## Facts block at the end of your response. This block is parsed by the SubagentStop hook and persisted to agent_memories.
Format — one fact per line, pipe-delimited:
## Facts
name: <slug-no-spaces> | type: <user|feedback|project|reference|procedural> | content: <text>
name: <slug-no-spaces> | type: <feedback> | content: <text> | description: <optional> | confidence: <0.0..1.0>
When to emit:
When NOT to emit:
Constraints: Max 5 facts per run. name must be a slug (no whitespace, ≤80 chars). content is truncated to 500 chars by the parser. type must be one of the five enumerated values. Malformed lines are skipped silently.
Each agent has its own token cap, declared in that agent's own ## Response Budget section — that per-agent cap is authoritative. The tiers:
code-reviewer, commit, frontend-qa, release-notes, push, test-runnerdep-auditormigration-reviewerbash-specialist, docs, morning-briefing, test-writer, devops, mergeapi-contract, debugger, eval-writer, perf-sentinel, pr-reviewer, security, code-writer, planner, researcherSummarize findings rather than reproducing raw tool output. Write verbose results to disk and reference the file path instead.
Truncate all Bash command output to the last 50 lines using | tail -50 unless the result is in the final lines. Never let raw command output fill your context.
The Response Budget exists to keep the prose tail intact through the model's output limit. These structural rules make the budget reachable.
Findings format for audit/research dispatches:
~/.claude/reports/<agent>-<task>-full.md and reference the path.Multi-target scope rule:
Status: NEEDS_CONTEXT with: "Multi-target scope — request a separate dispatch per target."Refusal trigger (when to invoke NEEDS_CONTEXT):
agents/core/researcher.md Pre-flight scope check — the researcher's hard rule mirrors this trigger and cites it as the authoritative source.Why this matters: a 2026-05-11 researcher dispatch with 10 audit checks ran 50+ tool calls and truncated to an empty reply. Twice. The rule existed; the trigger was not invoked. The structural fix is an explicit trigger condition, not a stronger suggestion.
Reference, don't reproduce:
Tests and scripts MUST NOT issue destructive operations (rm -rf, git checkout -- <path>, git restore, git reset --hard, file overwrites without backup) against tracked directories or files identified by repo-relative names from a non-isolated working directory.
Rules:
$BATS_TMPDIR, $BATS_TEST_TMPDIR, or a mktemp -d directory the test itself created. Never to a path resolved against the test's cwd (which is usually the repo root).rm -rf "$DIR", assert that $DIR is under $BATS_TMPDIR or an equivalent isolated root: [[ "$DIR" == "$BATS_TMPDIR"/* ]] || { echo "refusing to rm outside tmpdir: $DIR" >&2; return 1; }.stats the path read-only. It does NOT rm and recreate.git checkout, git restore, git reset, git clean, or rm -rf against tracked paths to "clean up" state they didn't create. If the working tree is dirty in a way that blocks the task, report Status: BLOCKED with the blocker and let the orchestrator decide.Why: a CAST routines deletion on 2026-05-11 traced to a BATS test that ran rm -rf "routines" from the repo root, deleting every tracked YAML in routines/. The destructive op had no isolation guard and no cwd assertion. Recovery was via git checkout HEAD -- routines/, but the pattern is the danger — the framework cannot catch every destructive sequence at lint time.
An agent MAY NOT classify a test failure as "pre-existing," "unrelated to my change," or "already broken" without producing baseline evidence.
The contract:
BLOCKED (the failure is real and you cannot resolve it) or DONE_WITH_CONCERNS (you fixed what you could, but flag the residual).Baseline evidence pattern (preferred — worktree):
WORKTREE=$(mktemp -d)
git worktree add "$WORKTREE" HEAD~1
(cd "$WORKTREE" && <run tests>)
git worktree remove "$WORKTREE"
Worktrees never touch the stash stack and never modify the active working tree. Always prefer this over git stash-based baselining.
Stash safety (if you must use stash anyway): never run git stash pop or git stash apply without a captured SHA from git stash create. stash@{N} refs are unstable — any other process that stashes (a hook, a parallel agent, an editor) shifts the indexes. If you cannot use a worktree and cannot capture a SHA, escalate to Status: BLOCKED and let the orchestrator decide.
Practical application:
BLOCKED with the failing-test list. test-runner does not classify pre-existing.BLOCKED.Why: a cast-hooks 17-script bulk-sync on 2026-05-11 reported 5 contract-test failures as "pre-existing failures unrelated to the sync." They were not — every failure was caused by the sync. The agent's confident classification cost ~40 minutes of triage before the revert. The structural fix is to refuse the classification absent evidence.
npx claudepluginhub ek33450505/claude-agent-team --plugin castProvides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Searches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.