vibe-parallel — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited vibe-parallel (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Identifies independent tasks, builds dependency waves, and dispatches each wave as parallel subagents via Claude Code.
What's new in v2:
Independent tasks have no reason to run one after another. If task B does not depend on task A — they run at the same time. Subagents execute in parallel within the same Claude Code session. The main session orchestrates: spawns waves, waits for completion, unlocks the next wave, runs automatically until done.
grep "VIBE_MODE" CLAUDE.md 2>/dev/null | cut -d= -f2 | tr -d ' 'VIBE_MODE=autonomous: Parallel detection runs automatically after every planning skill. No prompt — if independent tasks exist, subagents spawn immediately.
VIBE_MODE=manual (default): Shows the parallel plan. Asks once: "Run in parallel? (y/n)" If n — sequential execution, user drives with next. If y — subagents spawn.
On-demand (`parallel:` command): Always shows the plan and asks — regardless of VIBE_MODE. The user explicitly invoked it, so confirm before launching.
Triggered by: parallel: prefix Read vibe/TASKS.md for all pending tasks. Always show plan + ask (y/n), regardless of VIBE_MODE.
Source: vibe/features/[date-slug]/FEATURE_TASKS.md VIBE_MODE=autonomous → skip prompt, launch directly. VIBE_MODE=manual → show plan, ask (y/n).
Source: vibe/bugs/[date-slug]/BUG_TASKS.md Same mode logic as Entry B.
Source: vibe/TASKS.md Phase 1 tasks only. Same mode logic as Entry B.
grep "VIBE_MODE" CLAUDE.md 2>/dev/null | cut -d= -f2 | tr -d ' '
mkdir -p vibe/parallelRead references/WAVE_BUILDER.md — dependency graph and conflict detection logic. Read references/SUBAGENT_CONTEXT.md — context slicing and prompt construction. Read references/REPORTING.md — structured completion report format.
Read vibe/ARCHITECTURE.md — conventions every subagent must follow.
Check for vibe-graph:
ls vibe/graph/DEPENDENCY_GRAPH.json 2>/dev/null && echo "GRAPH_AVAILABLE" || echo "NO_GRAPH"
ls vibe/graph/.graph-meta.json 2>/dev/null && echo "META_AVAILABLE" || echo "NO_META"Store result — used in Step 3 for context slicing.
Read the source task file in full.
Extract for each pending [ ] task:
tasks = []
for each task block:
task = {
"id": "[TASK-ID]",
"title": "[Task title]",
"size": "S" | "M" | "L",
"dependencies": [], # list of TASK-IDs or []
"touches": [], # files this task WRITES
"reads": [], # files this task READS (infer if not explicit)
"description": "[What to do]",
"criteria": [], # acceptance criteria list
"spec_ref": "[section]",
"codebase_update": bool,
"arch_ref": "[which patterns apply]"
}
tasks.append(task)Inferring `reads` when not explicitly listed: A task Reads a file when any of these are true:
If reads cannot be inferred confidently — leave empty and treat conservatively.
Read references/WAVE_BUILDER.md for the full algorithm.
Summary:
Pass 1 — Standard dependency resolution:
Wave 1: tasks where dependencies = [] (or all deps already [x])
Wave 2: tasks whose deps are all in Wave 1
Wave N: tasks whose deps are all in Wave N-1Pass 2 — File conflict check (write-write): If two tasks in the same wave both WRITE the same file: → Move the alphabetically-later task ID to the next wave. Exception: vibe/CODEBASE.md and vibe/DECISIONS.md — append-only, safe.
Pass 3 — Read-write conflict check: If Task A WRITES a file and Task B READS that same file, and both are in the same wave: → Task B must move to the next wave — it needs Task A's output. This catches inheritance, base class, and schema dependencies missed by Touches alone.
Pass 4 — Size-aware wave splitting: Read references/WAVE_BUILDER.md for the full algorithm.
Short version: if Wave N contains an L task alongside S/M tasks, and some Wave N+1 tasks depend only on the S/M tasks (not the L task) — those Wave N+1 tasks can be promoted to run alongside the L task in Wave N as a "fast lane." The L task and the promoted tasks run in parallel; the remaining Wave N+1 tasks unlock after both the L task and fast lane complete.
Minimum threshold: If Wave 1 has only 1 task → no parallelism available. Autonomous mode: proceed sequentially, no mention of parallel. Manual mode: proceed sequentially, no prompt shown.
Read references/SUBAGENT_CONTEXT.md for the full algorithm.
Summary:
For each task, build a context slice — the minimum context a subagent needs to execute that task correctly.
If vibe-graph is available:
def build_context_slice(task, graph, meta):
slice = {
"task_files": task["touches"],
"imports": [], # EXTRACTED deps of task files
"concept": None, # concept node from CONCEPT_GRAPH
"rationale": [], # WHY/DECISION nodes for task files
"god_nodes": [], # god nodes in blast radius (extra care)
"architecture": [], # relevant ARCHITECTURE.md patterns
}
for file in task["touches"]:
node = graph.get(file, {})
# Add EXTRACTED imports only
for edge in node.get("imports", []):
if isinstance(edge, dict) and edge.get("source") == "EXTRACTED":
slice["imports"].append(edge["file"])
elif isinstance(edge, str):
slice["imports"].append(edge)
# Add rationale
slice["rationale"].extend(node.get("rationale", []))
# Check concept
if not slice["concept"]:
slice["concept"] = node.get("concept")
# Flag god nodes in the slice
god_node_files = {gn["file"] for gn in meta.get("god_nodes", [])}
for f in slice["imports"] + slice["task_files"]:
if f in god_node_files:
gn = next(gn for gn in meta["god_nodes"] if gn["file"] == f)
slice["god_nodes"].append(gn)
return sliceContext slice replaces CODEBASE.md in the subagent prompt. CODEBASE.md is NOT loaded by subagents when vibe-graph is available.
If no vibe-graph: Fall back to providing: CODEBASE.md + ARCHITECTURE.md (standard).
Context size estimate:
# With graph slice: ~2,000–4,000 tokens per subagent
# Without graph: ~25,000–40,000 tokens per subagent
# Saving per subagent: ~60-70%
# On a 6-subagent wave: saves ~120,000–216,000 tokens totalIn autonomous mode — skip this step entirely.
⚡ PARALLEL EXECUTION PLAN
Wave 1 — [N] tasks run simultaneously:
· [TASK-ID] (S) — [description]
· [TASK-ID] (M) — [description]
· [TASK-ID] (L) — [description] ← long task
Fast lane (runs with Wave 1 L task, unblocked early):
· [TASK-ID] (S) — [description] ← depends only on Wave 1 S/M tasks
Wave 2 — [N] tasks unlock when Wave 1 completes:
· [TASK-ID] (M) — [description]
[Wave N...]
Conflict resolution:
[TASK-ID] moved to Wave 2 — write conflict on src/models/brand_dna.py
[TASK-ID] moved to Wave 2 — read-write conflict (reads base_agent.py written by [TASK-ID])
Context mode: [graph-aware slicing (vibe-graph) | full CODEBASE.md]
Est. time: sequential ~[N]h → parallel ~[N]h (saving ~[N]h)
Est. cost: [graph: ~$X per wave | no graph: ~$Y per wave]
Run in parallel? (y/n)Wait for response. If n → exit, return to sequential flow.
Before dispatching any subagent, write the initial status file:
mkdir -p vibe/parallel
cat > vibe/parallel/wave-[N]-status.md << 'EOF'
# Wave [N] — [feature/bug/phase name]
Started: [ISO timestamp]
## Tasks
| ID | Size | Status | Started | Completed | Duration |
|----|------|--------|---------|-----------|----------|
| [TASK-ID] | S | 🔄 running | [time] | — | — |
| [TASK-ID] | M | 🔄 running | [time] | — | — |
| [TASK-ID] | L | 🔄 running | [time] | — | — |
## Summary
Total tasks: [N]
Complete: 0
Failed: 0
Partial: 0
## Next wave
Wave [N+1] — waiting (unlocks when all Wave [N] tasks complete)
EOFUpdate this file as each subagent reports completion.
Read references/SUBAGENT_CONTEXT.md for the full subagent prompt format.
Build the subagent prompt for each task:
You are executing [TASK-ID] as part of a parallel build.
═══ PROJECT CONTEXT ═══
[IF graph available:]
Architecture patterns: [relevant sections from ARCHITECTURE.md]
Your concept: [concept name] — [concept description from CONCEPT_GRAPH]
Your files:
[for each file in task touches:]
[file_path] ([type])
Imports: [EXTRACTED imports]
[if rationale exists:]
Rationale:
[WHY/DECISION/HACK entries]
[if god nodes in slice:]
⚠️ GOD NODE WARNING:
[file] — [N] connections. Changes here affect [N] other files.
Be especially careful with any modifications to this file.
[IF no graph:]
Read vibe/CODEBASE.md and vibe/ARCHITECTURE.md for project context.
═══ YOUR TASK ═══
[Full task block verbatim from FEATURE_TASKS.md / BUG_TASKS.md / TASKS.md]
═══ SCOPE BOUNDARIES ═══
Files you MAY write:
[Touches field contents]
Files you must NOT write (assigned to other parallel tasks):
[all Touches fields from other Wave N tasks]
Files you MAY read (your imports):
[slice imports list]
═══ COMPLETION REPORT ═══
When your task is complete, output this report EXACTLY:
TASK_COMPLETE: [TASK-ID]
STATUS: [DONE|PARTIAL|FAILED]
FILES_MODIFIED: [comma-separated list]
FILES_CREATED: [comma-separated list]
TESTS_PASSED: [N]/[total]
CRITERIA:
[x] [criterion 1]
[x] [criterion 2]
[ ] [criterion 3 — NOT MET: reason]
CODEBASE_UPDATE: [YES: what changed | NO]
BLOCKERS: [none | description of anything downstream tasks should know]
RATIONALE_ADDED: [YES: what WHY/DECISION comments were added | NO]Dispatch all tasks in the wave simultaneously as subagents.
Parse completion reports:
Read references/REPORTING.md for the full parsing logic.
For each subagent completion report:
def parse_completion(report):
status = extract("STATUS", report)
criteria = parse_criteria(report)
unmet = [c for c in criteria if not c["met"]]
if status == "DONE" and not unmet:
return "COMPLETE" # mark [x]
elif status == "PARTIAL" or unmet:
return "PARTIAL" # mark [~]
elif status == "FAILED":
return "FAILED" # mark [!], trigger diagnostic retryTask states:
[x] — fully complete, all criteria met, tests passed[~] — partially complete, some criteria unmet — downstream tasks are WARNED[!] — failed — trigger diagnostic retryA task is partial when:
Action: Log the unmet criteria in the wave progress file. Warn downstream tasks in their subagent prompts:
⚠️ UPSTREAM WARNING from [TASK-ID]:
[criterion] was not fully met: [reason]
Your task may need to account for this — verify before marking done.Do NOT block downstream tasks. Propagate the warning.
A task fails when: STATUS=FAILED, or tests fail, or the subagent errors out.
Diagnostic retry (not blind retry):
Read references/REPORTING.md for the diagnostic extraction logic.
def build_diagnostic_retry(task, failure_report):
# Extract the specific error
error = extract_error(failure_report)
# Infer most likely cause
cause = diagnose(error, task)
# Build targeted retry
return f"""
RETRY — [TASK-ID]
Your previous attempt failed:
Error: {error}
Most likely cause: {cause}
Targeted approach for this retry:
{targeted_fix(cause, task)}
[Original task prompt]
[Same scope boundaries]
[Same completion report format]
"""On retry → if COMPLETE: mark [x], continue. On retry → if still FAILED: mark [!], stop wave, surface to human.
Stop condition: Any task that fails twice stops the entire wave. Do not proceed to the next wave. Report clearly:
🔴 WAVE [N] PAUSED
[TASK-ID] failed after retry.
Error: [specific error from second attempt]
Completed tasks this wave: [list — marked [x] in task file]
Partial tasks: [list — marked [~]]
Failed task: [TASK-ID]
Fix the failure, then say "resume" to continue with Wave [N+1].
The completed tasks do not need to be re-run.After all subagents in the wave complete (or fail):
Update FEATURE_TASKS.md / BUG_TASKS.md / TASKS.md:
[x] TASK-001 · [description] ← complete
[~] TASK-002 · [description] ← partial — [unmet criterion]
[!] TASK-003 · [description] ← failed — [error summary]Update CODEBASE.md (batched — main session only): Collect all FILES_MODIFIED and FILES_CREATED from completion reports. The main session updates vibe/CODEBASE.md once — not during parallel execution. Each subagent reports what it changed; the main session writes the update.
Update wave progress log:
# Wave [N] — complete
Started: [time] · Completed: [time] · Duration: [Xm Ys]
## Tasks
| ID | Size | Status | Started | Completed | Duration |
|----|------|--------|---------|-----------|----------|
| TASK-001 | S | ✅ complete | 14:23:00 | 14:23:42 | 42s |
| TASK-002 | M | 🟡 partial | 14:23:00 | 14:24:15 | 75s |
| TASK-003 | L | ❌ failed | 14:23:00 | 14:26:00 | 3m |
## Summary
Total tasks: 3 · Complete: 1 · Partial: 1 · Failed: 1
## Unmet criteria
TASK-002: [criterion] — [reason]
## Files modified this wave
[complete list from all completion reports]
## Cost
Subagent tokens: ~[N] (estimated)
Context mode: graph-aware slicing
Approx cost: ~$[X]
vs sequential: ~$[Y] (parallel [cheaper/more expensive] by $[delta])
Time saved vs sequential: ~[N] minutesUpdate vibe/TASKS.md "What just happened":
✅ Wave [N] complete — [N] tasks done · [N] partial · [N] failed
[task IDs]
Cost: ~$[X] · Time saved: ~[N]minAfter each wave completes, run one graph update:
vibe-graph: updateThe git diff captures all subagent writes in a single pass. More reliable than each subagent updating the graph independently — subagents can't safely write the same JSON file concurrently.
If vibe-graph not installed — skip this step silently.
For each subsequent wave:
Check if wave is unlocked: All tasks in this wave have their dependencies marked [x]. Tasks depending on a [~] partial task — include the upstream warning in their prompt. If any dependency is [!] — that wave cannot proceed. Stop.
Apply size-aware splitting to subsequent waves too.
Repeat Steps 5–9 for each wave.
Wave with 1 task → run as single subagent (no parallelism, but still automatic). Wave with 2+ tasks → parallel subagents.
Emit cost summary:
⚡ Parallel execution complete
Waves:
Wave 1: [N] tasks ✅ · [N]m [N]s · ~$[X]
Wave 2: [N] tasks ✅ · [N]m [N]s · ~$[X]
Totals:
Tasks complete: [N]/[N]
Tasks partial: [N] (see vibe/parallel/ for unmet criteria)
Time taken: [Xm]
Est. sequential: ~[N]h
Time saved: ~[N]h ([N]% faster)
Total cost: ~$[X]
Context mode: [graph-aware | full CODEBASE.md]
Progress log: vibe/parallel/In autonomous mode: Signal completion to the calling skill. Do not stop — let vibe-add-feature / vibe-fix-bug / vibe-new-app invoke the review gate automatically.
In manual mode:
Run review: to gate this phase.Never give two subagents the same file to write. Write-write conflicts caught in Step 2 Pass 2 before any subagent launches.
Read-write conflicts are real conflicts. Task B reading a file Task A writes — Task B must wait. Caught in Step 2 Pass 3. Never skipped.
Each subagent is completely isolated. No subagent reads another subagent's in-progress work. They read the codebase as it existed before Wave 1 started. Results merged by main session after wave completes.
[~] partial tasks never block — they warn. A partial task passes its unmet criteria as warnings to downstream tasks. Downstream tasks decide how to handle. They are not blocked.
[!] failed tasks always stop the wave. On second failure — stop, report clearly, wait for human. Never mark a task [x] if tests did not pass.
CODEBASE.md updates are batched by the main session. Each subagent reports changes. Main session writes CODEBASE.md once. This prevents concurrent JSON write conflicts.
Graph updates happen once per wave — not per subagent. vibe-graph: update runs after wave completion. Git diff captures all subagent writes accurately.
Autonomous mode never skips the review gate. When all waves complete, signal for review. It runs automatically, but it always runs.
Cost annotation is always included. Every wave completion includes token estimate and cost. Even if vibe-cost is not installed — the annotation is written to the progress log so vibe-cost can read it later.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.