From agentflow
Plugin-aware stateless orchestrator sweep for the AgentFlow pipeline. Detects plugin vs standalone mode, manages worker teams via TeamCreate, dispatches tasks via SendMessage handoffs, reads Kanban state, handles transitions, tracks costs, detects issues. Run via crontab every 15 min.
npx claudepluginhub urrhb/agentflowThis skill uses the workspace's default tool permissions.
Perform one stateless orchestration sweep of all AgentFlow projects.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
Perform one stateless orchestration sweep of all AgentFlow projects.
This is a ONE-SHOT command. It reads state, makes decisions, updates the Kanban board, and exits. It does NOT run continuously. Durability comes from invoking this via real crontab:
# Default (every 15 min, ~$48/day):
*/15 * * * * ~/.claude/sdlc/agentflow-cron.sh >> /tmp/agentflow-orchestrate.log 2>&1
# Sprint mode (every 5 min, use during active dev only):
# */5 * * * * ~/.claude/sdlc/agentflow-cron.sh >> /tmp/agentflow-orchestrate.log 2>&1
Detect whether running in plugin mode or standalone mode at startup:
SendMessage and TeamCreate tools are available in the current environmentplugin.json) is loaded| Condition | Mode | Behavior |
|---|---|---|
SendMessage + TeamCreate available | Plugin | Use team management and message dispatch |
| Tools not available | Standalone | Fall back to slot-based terminal instructions (original behavior) |
Set MODE = "plugin" or MODE = "standalone" and log it at sweep start.
When MODE = "plugin", the orchestrator manages worker agents directly instead of relying on terminal slots.
Use TeamCreate to spin up worker agents as needed:
TeamCreate:
name: "sdlc-worker-T<N>"
skill: "sdlc-worker"
args: "--slot T<N>"
Rules:
{ slot: "T2", agentId: "<id>", taskCode: "PROJ-003" }| Event | Action |
|---|---|
| Task ready for dispatch | TeamCreate a new worker for the assigned slot |
| Worker completes stage | Worker self-terminates; slot becomes available |
| Worker unresponsive (>10 min) | Log warning, mark slot available, task eligible for re-dispatch |
| All tasks done | No workers running — zero cost when idle |
When MODE = "plugin", replace terminal-based dispatch with SendMessage handoffs.
Instead of updating a slot tag and waiting for a terminal worker to poll:
SendMessage:
to: "sdlc-worker-T<N>"
body: |
Execute stage <STAGE> for task <TASK_CODE>.
Project: <PROJECT_NAME>
Task ID: <TASK_ID>
Retry: <N>
Predicted files: <FILE_LIST>
Acceptance criteria: <CRITERIA>
Workers send completion messages back via SendMessage:
SendMessage:
to: "sdlc-orchestrate"
body: |
[<STAGE>:<RESULT>] Task <TASK_CODE> complete.
PR: <PR_URL>
Cost: ~$<COST>
Duration: <MINUTES>m
The orchestrator processes these messages at the start of each sweep (before Step 1), updating task state accordingly. This is equivalent to reading comment tags in standalone mode.
If SendMessage delivery fails:
conventions.mdCheck the Status task for a recent [SWEEP:RUNNING <timestamp>] comment.
If a sweep started less than 10 minutes ago, EXIT immediately:
"Another sweep is still running (started <timestamp>). Skipping this invocation."
If no recent sweep or last sweep is >10 min old:
Post: [SWEEP:RUNNING <current_timestamp>]
Continue with Step 1.
At the END of the sweep (after Step 9), post: [SWEEP:COMPLETE <current_timestamp>]
Find all projects with names starting with "[SDLC]"
For each project:
Build the complete pipeline state: a map of all tasks, their stages, slots, retry counts, and costs.
Quick check: If ALL tasks across all projects are in Backlog (waiting on dispatch) or Done, and no tasks are in active stages (Research/Build/Review/Test/Integrate), post a minimal status update and EXIT early. This "idle sweep" costs ~$0.02 instead of ~$0.50.
For each project, read the pinned Status task (in "0 - Needs Human" section).
Parse [SPEC_HASH:<hash>] from its description.
For each project's source SPEC.md:
[SPEC:CHANGED] comment on Status task[NEEDS:REVALIDATION] to description[SPEC:CONTINUE] or [SPEC:REDECOMPOSE]For each task in Build/Review/Test stages with an assigned slot:
[HEARTBEAT] or [BUILD:STARTED][REASSIGNED] Previous worker (<old_slot>) unresponsive after 10 min. Reassigning.[SLOT:<old>] → [SLOT:--] in task descriptionFor each task, read the LAST 10 comments per task (not all comments). The latest comment tag determines state. If the task has >20 comments, only parse the most recent 20 for transition logic. This prevents context window overflow on long-running tasks.
Check the latest comment tag and update accordingly:
| Latest Tag | Current Section | Action |
|---|---|---|
[RESEARCH:COMPLETE] or [RESEARCH:SKIP] | 2 - Research | Move to "3 - Build" |
[BUILD:COMPLETE] + [LINT:PASS] | 3 - Build | Move to "4 - Review" |
[LINT:FAIL] | 3 - Build | Keep in Build, clear slot for retry |
[REVIEW:PASS] + [COV:PASS] | 4 - Review | Move to "5 - Test" |
[REVIEW:REJECT] | 4 - Review | Move to "3 - Build", trigger feedback loop |
[COV:FAIL] | 4 - Review | Move to "3 - Build", trigger feedback loop |
[TEST:PASS] | 5 - Test | Move to "6 - Integrate" |
[TEST:REJECT] | 5 - Test | Move to "3 - Build", trigger feedback loop |
[INTEGRATE:PASS] | 6 - Integrate | Move to "7 - Done", mark complete |
[INTEGRATE:FAIL] | 6 - Integrate | Move to "3 - Build", trigger feedback loop |
[BUILD:BLOCKED] | 3 - Build | Move to "0 - Needs Human" |
[HOLD] | Any | Move to "0 - Needs Human" |
Merge lock check: Before processing any [TEST:PASS] transition that would lead to merge, check the Status task for an active [MERGE_LOCK]. If locked by another task, do NOT transition -- leave the task in Test until the lock clears.
Batch move tasks between sections where possible.
For each task that was rejected/failed:
[RETRY:N] → [RETRY:N+1][COST:~$X][COST:WARNING][COST:CRITICAL], move to "0 - Needs Human", STOP processing this task[RETRY:<N+1>]
## Retry Context (Attempt <N+1>)
### What was tried
<Extract from the most recent [BUILD:COMPLETE] comment>
### What failed
<Extract from the rejection comment — [REVIEW:REJECT], [TEST:REJECT], etc.>
### What to do differently
<Synthesize from the rejection details — be specific>
### Accumulated learnings
<Compile ALL previous retry contexts into a summary>
[SLOT:T4] → [SLOT:--]For each task in Backlog ("1 - Backlog") section:
Check dependencies:
## Dependencies from task descriptionCheck file conflicts:
## Predicted Files from this taskCalculate priority:
Find available slot:
[SLOT:T<N>] in its descriptionAssign:
[SLOT:--] → [SLOT:T<N>] and [STAGE:Backlog] → [STAGE:Research] or [STAGE:Build]Respect role preferences:
Count completed tasks across ALL projects since last retrospective.
If >= 10 new completed tasks since last retrospective:
[REVIEW:REJECT], [TEST:REJECT], [LINT:FAIL], [INTEGRATE:FAIL] comments from those tasksLEARNINGS.md in project root:## Pattern: <pattern name>
**Frequency:** <N>/<total> tasks
**Fix:** <What builders should do differently>
**Added:** <today's date>
[RETROSPECTIVE] Analyzed <N> completed tasks. Added <M> patterns to LEARNINGS.md.Update the pinned Status task description:
[STATUS] [SPEC_HASH:<current_hash>]
---
## System Status — <timestamp>
Active: <N> tasks (<slot>: <stage> <task_code>, ...)
Completed: <N>/<total> tasks
Total retries: <N> (details: <task_code>: <retry_count>, ...)
Est. cost: ~$<total across all tasks>
Blocked: <N> (<task_code>: waiting on <dep_code>, ...)
Needs Human: <N> (<task_code>: <reason>, ...)
ETA: ~<hours> at current pace (<tasks_remaining> tasks / <tasks_per_hour> velocity)
### Recent Activity
- <timestamp>: <task_code> moved to <stage>
- <timestamp>: <task_code> <event>
Also update the Status task description with [LAST_SWEEP:<timestamp>]. External monitoring (setup.sh configures this) checks this timestamp. If >30 min stale, an alert fires.
Also post a status update to the project:
Check if Status task has [SYSTEM:PAUSING] in latest comment:
Report sweep summary:
SDLC Sweep Complete — <timestamp>
Projects scanned: <N>
Tasks transitioned: <N>
Tasks dispatched: <N>
Tasks in feedback loop: <N>
Spec drift detected: <yes/no>
Dead workers reassigned: <N>
Exit. Wait for next crontab invocation.