com um clique
crank
Run crank.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Menu
Run crank.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Baseado na classificação ocupacional SOC
Dispatch fresh-context refuters (model-agnostic; multi-model opt-in) to attack a completion claim at the shared-trunk pawl before landing. Triggers: pre-land validation, refute.
Dispatch fresh-context refuters (model-agnostic; multi-model opt-in) to attack a completion claim at the shared-trunk pawl before landing. Triggers: pre-land validation, refute.
Run pre mortem.
Stress-test plans before work. Use when: a plan is drafted but not yet executed and you want to surface failure modes, risks, and what would prove it wrong before committing.
Repair skill hygiene. Triggers: "heal-skill", "heal skill", "repair skill hygiene.".
Repair skill hygiene. Triggers: "heal-skill", "heal skill", "repair skill hygiene.".
| name | crank |
| description | Run crank. |
Quick Ref: Execute every open issue in an epic via wave-based workers using
spawn_agent,wait_agent,send_input, andclose_agent. Output: closed issues + final validation.
You must execute this workflow. Do not just describe it.
Crank (lead agent)
|
+-> br ready (current wave)
|
+-> Build a wave task packet
|
+-> spawn_agent per issue (worker or explorer role)
|
+-> wait_agent for all worker ids
|
+-> Validate results + br update
|
+-> Loop until epic DONE
spawn_agent is available.agent_type=worker for implementation agents and agent_type=explorer for discovery agents when the runtime exposes roles.send_input only for short steering or retry prompts.close_agent for stalled or unnecessary agents.spawn_agent, wait_agent, send_input, and close_agent instead.When this skill runs in Codex hookless mode (CODEX_THREAD_ID is set or
CODEX_INTERNAL_ORIGINATOR_OVERRIDE is Codex Desktop), ensure startup context
before the first wave:
ao codex ensure-start 2>/dev/null || true
ao codex ensure-start is the single startup guard for Codex skills. It records
startup once per thread and skips duplicate startup automatically. Leave
ao codex ensure-stop to closeout skills after the implementation wave ends.
| Flag | Default | Description |
|---|---|---|
--test-first | off | SPEC -> TEST -> IMPL wave sequence. Workers classify tests by pyramid level (L0-L3) per the test pyramid standard (test-pyramid.md in the standards skill). When $plan includes test_levels metadata, carry it into metadata.validation.test_levels. |
MAX_EPIC_WAVES = 50 (hard limit). Typical epics use 5-10 waves.
After each wave, output one of:
<promise>DONE</promise> - epic complete, all issues closed<promise>BLOCKED</promise> - cannot proceed, with reason<promise>PARTIAL</promise> - incomplete, with remaining itemsNever claim completion without the marker.
Feed the orchestrator's re-plan loop — don't swallow findings into a silent retry. When run under $rpi, surface what a wave proved or broke UP to the orchestrator. A failed or surprising wave (a PARTIAL/BLOCKED marker) is re-plan input, not just a retry target: per the $rpi Agile Re-Plan Loop, the remaining waves may be refactored, inserted, dropped, or reordered before the next runs. Re-cranking the same objective forever instead of letting the remaining plan change is the waterfall anti-pattern.
When a task fails during wave execution, classify as RETRY (transient — re-add with adjustment, max 2), DECOMPOSE (too complex — split into sub-issues, terminal), or PRUNE (blocked — escalate immediately). Budget: 2 per task.
Mutation logging on failure: DECOMPOSE logs task_removed + task_added per sub-task. PRUNE logs task_removed. RETRY logs nothing (task identity unchanged).
Given $crank [epic-id | .agents/rpi/execution-packet.json | plan-file.md | "description"]:
if command -v ao &>/dev/null; then
ao lookup --query "<epic-title>" --limit 5 2>/dev/null || true
ao ratchet status 2>/dev/null || true
fi
Apply retrieved knowledge: If learnings are returned, check each for applicability to this epic. For applicable learnings, treat as implementation constraints and cite by filename. Record citations with the correct type: ao metrics cite "<path>" --type applied when the learning influenced a decision, or --type retrieved when loaded but not referenced.
Section evidence: When lookup results include section_heading, matched_snippet, or match_confidence fields, prefer the matched section over the whole file — it pinpoints the relevant portion. Higher match_confidence (>0.7) means the section is a strong match; lower values (<0.4) are weaker signals. Use the matched_snippet as the primary context rather than reading the full file.
if br ready --json >/dev/null 2>&1 && br list --type epic --status open --json >/dev/null 2>&1; then
TRACKING_MODE="beads"
else
TRACKING_MODE="tasklist"
fi
Create the shared notes file for cross-wave context persistence. See references/shared-task-notes.md for the full pattern.
mkdir -p .agents/crank
cat > .agents/crank/SHARED_TASK_NOTES.md <<EOF
# Shared Task Notes — Epic ${EPIC_ID:-unknown}
> Cross-wave context for workers. Read before starting. Report discoveries in task output.
> Maintained by the crank orchestrator — workers do NOT write to this file directly.
EOF
Create the JSONL file that tracks every plan mutation during execution. See references/plan-mutations.md for the full schema and mutation budget.
mkdir -p .agents/rpi
: > .agents/rpi/plan-mutations.jsonl
# Budget counters
MUTATION_TASK_ADDED=0
MUTATION_TASK_ADDED_LIMIT=5
MUTATION_TASK_REORDERED=0
MUTATION_TASK_REORDERED_LIMIT=3
Helper function:
log_plan_mutation() {
local mutation_type="$1" task_id="$2" before="$3" after="$4"
local ts
ts=$(date -Iseconds)
if [[ "$mutation_type" == "task_added" ]]; then
MUTATION_TASK_ADDED=$((MUTATION_TASK_ADDED + 1))
if [[ $MUTATION_TASK_ADDED -gt $MUTATION_TASK_ADDED_LIMIT ]]; then
echo "WARN: task_added budget exceeded ($MUTATION_TASK_ADDED/$MUTATION_TASK_ADDED_LIMIT). Consider re-running $plan."
fi
elif [[ "$mutation_type" == "task_reordered" ]]; then
MUTATION_TASK_REORDERED=$((MUTATION_TASK_REORDERED + 1))
if [[ $MUTATION_TASK_REORDERED -gt $MUTATION_TASK_REORDERED_LIMIT ]]; then
echo "WARN: task_reordered budget exceeded ($MUTATION_TASK_REORDERED/$MUTATION_TASK_REORDERED_LIMIT)."
fi
fi
echo "{\"timestamp\":\"$ts\",\"wave\":$wave,\"task_id\":\"$task_id\",\"mutation_type\":\"$mutation_type\",\"before\":$before,\"after\":$after}" \
>> .agents/rpi/plan-mutations.jsonl
}
Mutation types: task_added, task_removed, task_reordered, scope_changed, dependency_changed.
Beads mode:
br list --type epic --status open 2>/dev/null | head -5Execution-packet/file mode:
.agents/rpi/execution-packet.json, read objective, epic_id, tracker_mode, done_criteria, and validation_commandsepic_id exists inside the execution packet, keep that epic as the execution spineepic_id is absent, keep the packet objective as the execution spine and continue in file-backed mode instead of inventing an epic IDBefore wave-1 commit, refuse to crank on main/master. Cut crank/<epic-id> to prevent parallel-session reset clobbers. See references/branch-isolation.md for the gate script and override flag.
Beads mode:
br show <epic-id> 2>/dev/null
Execution-packet/file mode:
br readyBeads mode:
br ready 2>/dev/null
br ready returns all unblocked issues - these can run in parallel.
Execution-packet/file mode:
.agents/rpi/execution-packet.json or the plan file.agents/council/ for pre-mortem evidence.beads and the legacy-named scripts/bd-audit.sh exists, run the backlog audit before spawning workers.--skip-audit only when you intentionally want to bypass that gate.Detect project language (go.mod -> Go, pyproject.toml -> Python, etc.) and read applicable standards from $standards. Include a Testing section in worker prompts.
Crank follows the FIRE loop for each wave:
Read cross-wave context to include in worker prompts:
SHARED_NOTES=""
if [ -f .agents/crank/SHARED_TASK_NOTES.md ]; then
SHARED_NOTES=$(cat .agents/crank/SHARED_TASK_NOTES.md)
fi
If SHARED_NOTES exceeds ~50 lines, summarize older waves (keep last 3 in full detail, preserve [CRITICAL] entries).
Create one packet per ready issue. Do not use CSV fan-out.
mkdir -p .agents/crank
cat > ".agents/crank/wave-${wave}-tasks.json" << EOF
{
"wave": $wave,
"epic_id": "$EPIC_ID",
"tasks": [
{
"issue_id": "bd-123",
"subject": "Short issue summary",
"description": "Issue details and acceptance criteria",
"files": ["path/to/file.go"],
"validation_cmd": "go test ./...",
"metadata": {
"issue_type": "feature"
}
}
]
}
EOF
Each task packet must include metadata.issue_type.
wave_tasks = [tasks from packet]
all_files = {}
for task in wave_tasks:
for f in task.files:
if f in all_files:
CONFLICT -> serialize into sub-waves
all_files[f] = task.id
Display an ownership table before spawning workers. If conflicts exist, split into sub-waves and keep file ownership disjoint.
For waves with 2+ workers, three tiers prevent sibling-worker clobber without re-introducing worktree sprawl. Read references/parallel-wave-isolation.md for the full tier definitions, the worker prompt template, the preflight-swarm.sh escalation criterion, and the check-worktree-disposition.sh cleanup gate.
Tier 1 (always): inject the branch-isolation prompt rule (worker's first git op = git checkout -b feat/<epic>-<slug> origin/main; never git switch, stash pop, reset --hard).
Tier 2 (escalate on preflight-swarm.sh non-zero): ephemeral per-worker worktree.
Tier 3 (wave-end): scripts/check-worktree-disposition.sh flags stragglers.
Spawn one agent per issue. Prefer worker roles for implementation and explorer roles for file discovery when the runtime exposes agent_type.
spawn_agent(
agent_type="worker",
message="You are worker-<issue-id>.
Assignment: <subject>
<description>
---
Context from prior waves (read before starting):
<SHARED_NOTES content, or 'First wave — no prior context.' if empty>
---
FILE MANIFEST (files you are permitted to modify):
<list of files>
Rules:
1. Stay within your assigned files
2. Run validation: <validation_cmd>
3. Keep your response short
4. Write any durable notes to .agents/crank/results/<issue-id>.md or .agents/crank/results/<issue-id>.json
5. DISCOVERY REPORTING: If you discover codebase quirks, failed approaches,
convention requirements, or dependency constraints, include a section in your
output titled '## Discoveries' with one bullet per finding.
Use the repo's current Codex primitives only."
)
If a task is missing its file manifest, spawn a short-lived explorer agent first:
spawn_agent(
agent_type="explorer",
message="You are explorer-<issue-id>.
Task: identify the files that must be created or modified for this issue.
Return a JSON array of paths only."
)
wait_agent(targets=["agent-id-1", "agent-id-2"])
If a worker needs a short correction, use send_input(target=..., message=...).
If a worker stalls or is no longer needed, use close_agent(target=...).
External Gate Enforcement: After each worker completes, the orchestrator (not the worker) runs the gate command. Workers must not declare their own completion. See references/external-gate-protocol.md.
For each completed worker:
Update beads with evidence:
COMMIT_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
CHANGED_FILES=$(git diff --name-only HEAD~1 2>/dev/null | head -10 | tr '\n' ' ' | sed 's/ $//')
br close "$issue_id" --reason "commit:${COMMIT_SHA} files:[${CHANGED_FILES}]" 2>/dev/null
br update "$issue_id" --status blocked 2>/dev/null
br comments add "$issue_id" "Wave $wave FAIL: $reason" 2>/dev/null
After all workers complete:
git diff for the wave..github/workflows/*.yml, run bash scripts/validate-ci-policy-parity.sh; on non-zero exit treat the wave verdict as FAIL and surface the drift report. Trigger pattern (narrow — workflow YAML only):
if git diff --name-only "$WAVE_START_SHA" HEAD -- | grep -qE '^\.github/workflows/.*\.ya?ml$'; then
bash scripts/validate-ci-policy-parity.sh || exit 1
fi
See references/wave-patterns.md "CI-Policy Parity Gate" for the worked example and the soc-lmww1 / commit c587b361 motivation.FILES_CHANGED_JSON="${FILES_CHANGED_JSON:-$(git diff --name-only "${WAVE_START_SHA:-HEAD~1}..HEAD" | jq -R -s -c 'split("\n")[:-1]')}"
GIT_SHA="$(git rev-parse HEAD)"
cat > ".agents/crank/wave-${wave}-checkpoint.json" << EOF
{
"schema_version": 1,
"wave": $wave,
"epic_id": "$EPIC_ID",
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"tasks_completed": ${TASKS_COMPLETED_JSON:-[]},
"tasks_failed": ${TASKS_FAILED_JSON:-[]},
"files_changed": $FILES_CHANGED_JSON,
"git_sha": "$GIT_SHA",
"acceptance_verdict": "${ACCEPTANCE_VERDICT:-WARN}",
"commit_strategy": "${COMMIT_STRATEGY:-wave-batch}",
"mutations_this_wave": $(grep -c "\"wave\":${wave}" .agents/rpi/plan-mutations.jsonl 2>/dev/null || echo 0),
"total_mutations": $(wc -l < .agents/rpi/plan-mutations.jsonl 2>/dev/null | tr -d ' '),
"mutation_budget": {
"task_added": {"used": ${MUTATION_TASK_ADDED:-0}, "limit": 5},
"task_reordered": {"used": ${MUTATION_TASK_REORDERED:-0}, "limit": 3}
}
}
EOF
bash skills-codex/crank/scripts/validate-wave-checkpoint.sh ".agents/crank/wave-${wave}-checkpoint.json"
Do not copy or consume the checkpoint downstream until validation passes. The validator fails closed when git_sha does not resolve in the current repo, timestamp is invalid or more than 5 minutes in the future, or required checkpoint fields are missing/malformed.
Harvest discoveries from completed workers and append to the shared notes file:
WAVE_DISCOVERIES=""
for result_file in .agents/crank/results/*; do
if [ -f "$result_file" ]; then
DISCOVERIES=$(sed -n '/^## Discoveries/,/^## /{ /^## Discoveries/d; /^## /d; p; }' "$result_file" 2>/dev/null)
if [ -n "$DISCOVERIES" ]; then
WAVE_DISCOVERIES="${WAVE_DISCOVERIES}${DISCOVERIES}\n"
fi
fi
done
if [ -n "$WAVE_DISCOVERIES" ]; then
cat >> .agents/crank/SHARED_TASK_NOTES.md <<EOF
## Wave ${wave} ($(date -Iseconds))
$(echo -e "$WAVE_DISCOVERIES")
EOF
fi
Capture: Failed approaches, codebase quirks, convention discoveries, dependency notes. Skip: Full error logs, implementation details, task status.
After processing wave results, log mutations for any plan changes. Call log_plan_mutation for each:
task_removed for original, task_added for each sub-tasktask_removed with block reasonscope_changed when file manifest updated after explorationdependency_changed when blocked-by list modifiedtask_reordered when task moves between waves# Example: task decomposed into sub-tasks
log_plan_mutation "task_removed" "$decomposed_id" \
"{\"subject\":\"$ORIGINAL_SUBJECT\",\"status\":\"decomposed\"}" "null"
log_plan_mutation "task_added" "$sub_id" "null" \
"{\"subject\":\"$SUB_SUBJECT\",\"reason\":\"Split from $decomposed_id\"}"
# Example: scope change after exploration
log_plan_mutation "scope_changed" "$task_id" \
"{\"files\":$ORIGINAL_FILES}" \
"{\"files\":$UPDATED_FILES,\"reason\":\"$REASON\"}"
Mutations are append-only to .agents/rpi/plan-mutations.jsonl. Read by $post-mortem for drift analysis.
Lead-only commit - workers write files, lead validates and commits once per wave:
for f in $WORKER_FILES_CHANGED; do
git add -- "$f"
done
git commit -m "feat(<scope>): wave $wave - $COMPLETED_COUNT issues completed"
wave=$((wave + 1))
if [[ $wave -ge 50 ]]; then
echo "<promise>BLOCKED</promise>"
echo "Global wave limit (50) reached."
exit 1
fi
REMAINING=$(br ready 2>/dev/null | wc -l)
if [[ $REMAINING -eq 0 ]]; then
OPEN_TOTAL=$(br list --status open 2>/dev/null | wc -l || echo 0)
IN_PROGRESS_TOTAL=$(br list --status in_progress 2>/dev/null | wc -l || echo 0)
if [[ $((OPEN_TOTAL + IN_PROGRESS_TOTAL)) -eq 0 ]]; then
echo "<promise>DONE</promise>"
else
echo "<promise>BLOCKED</promise>"
echo "No ready issues but $((OPEN_TOTAL + IN_PROGRESS_TOTAL)) issues remain open or in progress."
fi
else
# Continue to next wave - return to Step 3
fi
When the epic is DONE:
$validate validate the completed epic
Move the shared notes to an archive after epic completion:
if [ -f .agents/crank/SHARED_TASK_NOTES.md ]; then
mkdir -p .agents/crank/archives
mv .agents/crank/SHARED_TASK_NOTES.md \
".agents/crank/archives/SHARED_TASK_NOTES-${EPIC_ID:-unknown}-$(date +%Y%m%d-%H%M%S).md"
fi
br comments add "$issue_id" "retry $N: $reason"| Scenario | Action |
|---|---|
| Worker timeout | Mark BLOCKED, log reason, continue wave |
| Test failure | Identify breaking change, retry once |
| All workers fail | <promise>BLOCKED</promise> with diagnostics |
| File conflict detected | Split into sub-waves, re-run |