arc — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited arc (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.
Chains 19 phases into a single automated pipeline (v3.0.0-alpha.6 — was 30 pre-alpha.2; goldmask + bot-review + PR-comment resolution moved out of the default order; Day 5 alpha.6 absorbed plan_refine, drift_review, inspect_fix, verify_inspect, verify_mend, pre_ship_validation into their parents and removed deploy_verify). Each phase runs as its own Claude Code turn with fresh context — the arc-phase-stop-hook.sh drives phase iteration via the Stop hook pattern. Artifact-based handoff connects phases. Checkpoint state enables resume after failure.
Context budget advisory: Full arc run: 19 phases x ~3.7min avg = ~70 minutes (lower bound). Context compaction is almost guaranteed in a single session. For constrained sessions, use --no-forge to skip Phase 1 enrichment, or split into multiple /rune:arc --resume sessions. For context optimization, use --step-groups to pause at group boundaries — each group gets a fresh context window on resume. The PreCompact hook saves checkpoint state automatically.
Load skills: roundtable-circle, context-weaving, rune-orchestration, elicitation, team-sdk, testing
When the user invokes /rune:arc without --quick-mode, execute the full arc pipeline immediately. Do NOT:
The user chose /rune:arc deliberately. Respect that choice. If the plan is small, arc still works — it just finishes faster. If the user wanted the lightweight 4-phase path, they would have invoked /rune:arc --quick-mode.
Exception: The --confirm flag explicitly opts into a pause on all-CONCERN escalation. That is the ONLY confirmation point in the pipeline.
EVERY phase that summons agents MUST follow this exact pattern. No exceptions.
1. TeamCreate({ team_name: "{phase-prefix}-{id}" }) ← CREATE TEAM FIRST
2. TaskCreate({ subject: ..., description: ... }) ← CREATE TASKS
3. Agent({ team_name: "...", name: "...", ← SPAWN WITH team_name
subagent_type: "general-purpose", ← ALWAYS general-purpose
prompt: "You are {agent-name}...", ... }) ← IDENTITY VIA PROMPT
4. Monitor → Shutdown → TeamDelete with fallback ← CLEANUPNEVER DO:
Agent({ ... }) without team_name — bare Agent calls bypass Agent Teams entirely.subagent_type values — always use subagent_type: "general-purpose" and inject agent identity via the prompt.ENFORCEMENT: The enforce-teams.sh PreToolUse hook blocks bare Agent calls when a Rune workflow is active.
The pipeline uses named phases (not numeric IDs) in PHASE_ORDER. The numeric labels below are for human reference only — execution order is always determined by position in PHASE_ORDER.
| # | Exec Order | Phase Key | Type | Timeout | Delegated To |
|---|---|---|---|---|---|
| 1 | 1 | forge | Team | 15 min | /rune:forge |
| 1.1 | 2 | forge_qa | Team | 5 min | QA gate (1 agent) |
| 2 | 3 | plan_review | Team | 15 min | /rune:appraise (inspect mode); absorbs the former plan_refine sub-step (v3.0.0-alpha.6 C4a) |
| 2.7 | 4 | verification | Inline | 30 sec | — |
| 5 | 5 | work | Team | 35 min | /rune:strive; absorbs the former drift_review sub-step (v3.0.0-alpha.6 C4b) |
| 5.01 | 6 | work_qa | Team | 5 min | QA gate (1 agent) |
| 5.9 | 7 | inspect | Team | 45 min | /rune:inspect (4 Inspector Ashes) — unified plan-vs-implementation engine. Sub-steps: STEP A deterministic pre-checks (absorbed gap_analysis STEP A v3.0.0-alpha.7 Day 6), STEP 1-4 audit, STEP 4.5 halt-gate with Task Completion Gate + plan writeback (absorbed gap_analysis STEP D), STEP 5 gap-fixer dispatch (absorbed inspect_fix C4c + gap_remediation Day 6), STEP 6 convergence (absorbed verify_inspect C4c). |
| 6 | 8 | code_review | Team | 15 min | /rune:appraise --deep |
| 6.1 | 9 | code_review_qa | Team | 5 min | QA gate (1 agent) |
| 6.6 | 10 | verify | Team | 10 min | Finding verification gate |
| 7 | 11 | mend | Team | 23 min | /rune:mend |
| 7.01 | 12 | mend_qa | Team | 9 min | QA gate (1 agent) + runMendQAConvergence post-step (absorbed verify_mend v3.0.0-alpha.6 C4d) |
| 7.7 | 13 | test | Team | 25-50 min | Testing agents |
| 7.71 | 14 | test_qa | Team | 5 min | QA gate (1 agent) |
| 9 | 15 | ship | Inline | 11 min | preShipValidator pre-step (absorbed pre_ship_validation v3.0.0-alpha.6 C4e) + PR creation; deploy_verify removed |
| 9.5 | 16 | merge | Inline | 10 min | — |
Execution order: The "Exec Order" column shows the actual sequence (1–16). Phase numbers (#) are for human reference only — always use PHASE_ORDER array position. Total: 16 default phases (v3.0.0-alpha.7 Day 6 absorbed gap_analysis + gap_analysis_qa + gap_remediation into inspect; v3.0.0-alpha.6 Day 5 absorbed plan_refine→plan_review, drift_review→work, inspect_fix+verify_inspect→inspect, verify_mend→mend_qa post-step, pre_ship_validation→ship; deploy_verify removed entirely. Prior history: v3.0.0-alpha.2 cut goldmask_verification, goldmask_correlation, bot_review_wait, pr_comment_resolution; alpha.1 cut design_, semantic_verification, task_decomposition, test_coverage_critique, release_quality_check, browser_test, storybook_verification, ux_verification)./rune:arc <plan_file.md> # Full pipeline
/rune:arc <plan_file.md> --no-forge # Skip research enrichment
/rune:arc <plan_file.md> --approve # Require human approval for work tasks
/rune:arc --resume # Resume from last checkpoint
/rune:arc <plan_file.md> --skip-freshness # Skip freshness validation
/rune:arc <plan_file.md> --confirm # Pause on all-CONCERN escalation
/rune:arc <plan_file.md> --no-pr # Skip PR creation (Phase 9)
/rune:arc <plan_file.md> --no-merge # Skip auto-merge (Phase 9.5)
/rune:arc <plan_file.md> --draft # Create PR as draft
/rune:arc <plan_file.md> --no-accept-external # Prompt when unrelated changes detected (default: accept)
/rune:arc <plan_file.md> --step-groups # Pause at each phase group boundary
/rune:arc --quick-mode "<prompt|plan-path>" [--force] # Lightweight 4-phase pipeline| Flag | Description | Default |
|---|---|---|
--no-forge | Skip Phase 1 (research enrichment), use plan as-is | Off |
--approve | Require human approval for each work task (Phase 5 only) | Off |
--resume | Resume from last checkpoint. Plan path auto-detected from checkpoint | Off |
--skip-freshness | Skip plan freshness check (bypass stale-plan detection) | Off |
--confirm | Pause for user input when all plan reviewers raise CONCERN verdicts | Off |
--no-pr | Skip Phase 9 (PR creation) | Off |
--no-merge | Skip Phase 9.5 (auto merge) | Off |
--no-test | Skip Phase 7.7 (testing) | Off |
--draft | Create PR as draft | Off |
--accept-external | Accept external changes (bug fixes, audit commits) on branch without prompting | On |
--no-accept-external | Prompt user when unrelated changes are detected on branch | Off |
--step-groups | Pause at each phase group boundary for context optimization | Off |
--status | Show current arc phase, progress, and elapsed time (delegates to rune-status.sh) | Off |
--quick-mode | Lightweight 4-phase pipeline (plan → work+evaluate → review → mend). Skips checkpoint init and PHASE_ORDER dispatch — runs as a single-turn delegation chain. See arc-quick-mode.md | Off |
--force | (--quick-mode only) Skip the complexity gate warning on plans with 8+ tasks | Off |
Note: Worktree mode for/rune:strive(Phase 5) is activated viawork.worktree.enabled: truein talisman.yml, not via a--worktreeflag on arc.
accept_external_changes)When --accept-external is passed (or arc.defaults.accept_external_changes: true in talisman), the pipeline tolerates commits on the working branch that are NOT part of the plan. This is common when:
/rune:arc-batch where prior arcs leave commits on the branch/rune:audit or manual bug fixes in a parallel session that commit to the same branchBehavior when enabled:
Default: true (accept external changes silently). Use --no-accept-external or arc.defaults.accept_external_changes: false to restore the prompting behavior.
const lockConflicts = Bash(`cd "${CWD}" && source plugins/rune/scripts/lib/workflow-lock.sh && rune_check_conflicts "writer"`)
if (lockConflicts.includes("CONFLICT")) {
AskUserQuestion({ question: `Active workflow conflict:\n${lockConflicts}\nProceed anyway?` })
}
Bash(`cd "${CWD}" && source plugins/rune/scripts/lib/workflow-lock.sh && rune_acquire_lock "arc" "writer"`)See arc-preflight.md for the full pre-flight sequence.
Read and execute the arc-preflight.md algorithm at dispatcher init.
See freshness-gate.md for the full algorithm.
Read and execute the algorithm. Store freshnessResult for checkpoint initialization below.
const bridgePattern = `/tmp/rune-ctx-*.json`
const bridgeFiles = Bash(`ls ${bridgePattern} 2>/dev/null | head -1`).trim()
if (!bridgeFiles) {
warn(`Context monitoring bridge not detected.`)
}
const ctxBridgeFile = bridgeFiles || nullRead arc-phase-constants.md for PHASE_ORDER, PHASE_TIMEOUTS, CYCLE_BUDGET, calculateDynamicTimeout(), FORBIDDEN_PHASE_KEYS, and updateCascadeTracker().
See arc-checkpoint-init.md for the full initialization.
Read and execute the arc-checkpoint-init.md algorithm.
See arc-preflight.md for prePhaseCleanup().
Read(references/arc-preflight.md)
Read(references/arc-phase-cleanup.md)See arc-preflight.md for the stale team scan algorithm.
--status)Early return — display current arc phase, progress, and elapsed time without entering the pipeline.
if (args.includes("--status")) {
const output = Bash(`"${RUNE_PLUGIN_ROOT}/scripts/rune-status.sh"`)
// Display current phase, elapsed time, completed/total phases
return output
}--quick-mode)Early return — runs the lightweight 4-phase pipeline (plan → work+evaluate → review → mend) as a single-turn delegation chain. Skips checkpoint init and PHASE_ORDER dispatch entirely. Mirrors the --status early-return pattern above so quick-mode never touches the full-pipeline state machine.
if (args.includes("--quick-mode")) {
// Read and execute the arc-quick-mode.md algorithm.
// The branch is fully self-contained — devise/strive/appraise/mend each manage
// their own teams; arc neither creates a checkpoint nor invokes the stop hook.
Read(references/arc-quick-mode.md)
return // Do not fall through to checkpoint init or PHASE_ORDER dispatch
}--resume)See arc-resume.md for the full resume algorithm.
if (args.includes("--resume")) {
Read(references/arc-preflight.md)
Read(references/arc-phase-cleanup.md)
Read and execute the arc-resume.md algorithm.
}Enforces ONE arc at a time — checks for existing state files from previous or concurrent sessions. Handles 6 cases (F1-F6) including hard blocks, resume prompts, and stale cleanup.
See arc-state-conflict.md for the full conflict detection algorithm and case table.
Co-located with checkpoint init (v2.6.0): The phase loop state file is now written as part of arc-checkpoint-init.md, immediately after the checkpoint Write() call. This eliminates the "missing state file" bug where the LLM wrote the checkpoint but skipped this step under context pressure.
If you are here during execution, the state file (.rune/arc-phase-loop.local.md) should already exist. If it does not, the safety guard in "First Phase Invocation" below will catch and recover.
See arc-phase-loop-state.md for the state file schema reference.
Integrates at 3 points: Phase 5 (work loop with AC criteria), Phase 8.5 (SCR/proof metrics), Post-Arc (echo persist). Config: discipline.enabled (default: true), discipline.block_on_fail (default: false). See strive/references/discipline-work-loop.md and discipline/references/metrics-schema.md.
When blind_verification.enabled: true in talisman, strive Phase 4.6 runs a blind AC verification gate within the work phase. A blind-validation-agent receives ONLY the plan's acceptance criteria and the committed code — no worker context, no task files, no implementation notes. This is NOT a separate arc phase; it runs inside /rune:strive as a quality gate before Phase 5 (echo persist). Config: blind_verification.model (default: "sonnet"), blind_verification.fail_on_partial (default: false), blind_verification.max_remediation (default: 1), blind_verification.timeout_ms (default: 120000).
Independent QA gates enforce quality obligations at every gated phase. The Tarnished (orchestrator) and all phase agents MUST adhere to these 6 obligations:
tmp/arc/{id}/qa/{phase}-verdict.json before the stop hook advances. Missing verdict files default to FAIL with timed_out: true.MAX_QA_RETRIES (2), which MUST remain strictly less than MAX_PHASE_DISPATCHES - 1 (currently 3). Exceeding this invariant triggers GUARD 9 destruction of the state file. Do NOT increase MAX_QA_RETRIES without first raising MAX_PHASE_DISPATCHES in the stop hook.tmp/arc/{id}/qa/dashboard.md). No phase may suppress or alter QA scores after they are written.AskUserQuestion — never silently skip or auto-pass a failed gate.generateQADashboard(arcId) MUST be called to produce the consolidated pipeline quality summary. The dashboard is injected into the PR body (Phase 9) for reviewer visibility.See arc-phase-qa-gate.md for the full QA gate architecture, scoring system, and per-phase checklists.
Execute the first pending phase from the checkpoint. The Stop hook (arc-phase-stop-hook.sh) handles all subsequent phases automatically.
CRITICAL — Single-Phase-Per-Turn Rule: You MUST execute exactly ONE phase per turn, then STOP responding. Do NOT batch-process multiple phases in a single turn. Do NOT skip conditional phases (semantic_verification, task_decomposition) based on assumptions — each phase has its own gate logic in its reference file that MUST be executed. The Stop hook advances to the next phase automatically. Violating this rule causes phases to be skipped without proper gate evaluation.
// ── SAFETY GUARD: Verify phase loop state file exists before first phase ──
// FIX (v2.6.0): Catches the case where checkpoint init completed but state file
// write was skipped (context pressure, LLM shortcutting, or error between steps).
// Without this file, the Stop hook silently exits 0 and the arc stalls after Phase 1.
const stateFilePath = '.rune/arc-phase-loop.local.md'
const stateFileExists = Bash(`test -f "${stateFilePath}" && echo "ok" || echo "missing"`).trim()
if (stateFileExists !== 'ok') {
warn('RECOVERY: Phase loop state file missing — recreating from checkpoint.')
// Reconstruct from checkpoint data (checkpoint was written successfully)
const cp = JSON.parse(Read(checkpointPath))
const recoverySessionId = "${CLAUDE_SESSION_ID}" || Bash('echo "${RUNE_SESSION_ID:-}"').trim() || 'unknown'
const recoveryBranch = Bash("git branch --show-current 2>/dev/null").trim() || 'main'
const recoveryOwnerPid = Bash('echo $PPID').trim()
// ── INTEG-RECOVERY validation (v2.29.8): Validate checkpoint fields before propagating ──
// BUG FIX: If checkpoint has corrupt config_dir (e.g., tmp/arc/...), the recovery path
// would propagate the corruption to the new state file, bypassing all 3 layers of validation.
// Resolve config_dir from CLAUDE_CONFIG_DIR directly — do NOT trust checkpoint's config_dir.
const recoveryConfigDir = Bash('cd "${CLAUDE_CONFIG_DIR:-$HOME/.claude}" 2>/dev/null && pwd -P').trim()
if (!recoveryConfigDir || recoveryConfigDir.startsWith('tmp/') || recoveryConfigDir.includes('/tmp/arc/')) {
throw new Error(`FATAL (INTEG-RECOVERY-001): Resolved config_dir "${recoveryConfigDir}" is invalid. Cannot recover state file.`)
}
if (!recoveryOwnerPid || !/^\d+$/.test(recoveryOwnerPid)) {
throw new Error(`FATAL (INTEG-RECOVERY-002): owner_pid "${recoveryOwnerPid}" is invalid.`)
}
if (recoverySessionId === 'unknown') {
throw new Error(`FATAL (INTEG-RECOVERY-003): session_id is unknown — cannot recover state file without session identity.`)
}
if (!cp.plan_file || cp.plan_file === 'null') {
throw new Error(`FATAL (INTEG-RECOVERY-004): checkpoint.plan_file is empty/null — cannot recover.`)
}
// Warn if checkpoint config_dir was corrupt (the bug we're fixing)
if (cp.config_dir && (cp.config_dir.startsWith('tmp/') || cp.config_dir.includes('/tmp/arc/'))) {
warn(`INTEG-RECOVERY: Checkpoint had corrupt config_dir="${cp.config_dir}" — using fresh resolution "${recoveryConfigDir}" instead.`)
}
const recoveryContent = `---
active: true
iteration: 0
max_iterations: 66
checkpoint_path: ${checkpointPath}
plan_file: ${cp.plan_file}
branch: ${recoveryBranch}
arc_flags: ${(cp.flags?.no_forge ? '--no-forge ' : '') + (cp.flags?.approve ? '--approve ' : '') + (cp.flags?.no_test ? '--no-test ' : '')}
config_dir: ${recoveryConfigDir}
owner_pid: ${recoveryOwnerPid}
session_id: ${recoverySessionId}
compact_pending: false
user_cancelled: false
cancel_reason: null
cancelled_at: null
stop_reason: null
---
`
Write(stateFilePath, recoveryContent)
// Post-write verification (same pattern as arc-checkpoint-init.md)
const recoveryVerifyConfigDir = Bash('grep "^config_dir:" .rune/arc-phase-loop.local.md | sed "s/^config_dir: //"').trim()
if (recoveryVerifyConfigDir !== recoveryConfigDir) {
throw new Error(`FATAL (INTEG-RECOVERY-POST): Written config_dir "${recoveryVerifyConfigDir}" ≠ expected "${recoveryConfigDir}".`)
}
log('Phase loop state file recovered successfully.')
}
// Check for context-critical shutdown signal before starting next phase (Layer 1)
const shutdownSignalCheck = (() => {
try {
const sid = "${CLAUDE_SESSION_ID}" || Bash(`echo "\${RUNE_SESSION_ID:-}"`).trim()
const signalPath = `tmp/.rune-shutdown-signal-${sid}.json`
const signal = JSON.parse(Read(signalPath))
return signal?.signal === "context_warning"
} catch { return false }
})()
if (shutdownSignalCheck) {
warn("CTX-WARNING: Context pressure detected between phases. Skipping remaining phases.")
// Mark remaining phases as skipped in checkpoint
for (const p of PHASE_ORDER) {
if (checkpoint.phases[p]?.status === 'pending') {
checkpoint.phases[p].status = 'skipped'
checkpoint.phases[p].skip_reason = 'context_pressure'
}
}
Write(checkpointPath, checkpoint)
return
}
// Find first pending phase
const firstPending = PHASE_ORDER.find(p => checkpoint.phases[p]?.status === 'pending')
if (!firstPending) {
log("All phases already complete. Nothing to execute.")
return
}
// Schema v19: stamp phase start time before executing
checkpoint.phases[firstPending].started_at = new Date().toISOString()
Write(checkpointPath, checkpoint)
// Read and execute the phase reference file
const refFile = getPhaseReferenceFile(firstPending)
Read(refFile)
// Execute the phase algorithm as described in the reference file.
// When done, update checkpoint.phases[firstPending].status to "completed".
// Schema v19: stamp phase completion time and compute duration
const completionTs = Date.now()
checkpoint.phases[firstPending].completed_at = new Date(completionTs).toISOString()
const phaseStartMs = new Date(checkpoint.phases[firstPending].started_at).getTime()
checkpoint.totals = checkpoint.totals ?? { phase_times: {}, total_duration_ms: null, cost_at_completion: null }
const phaseDuration = completionTs - phaseStartMs
checkpoint.totals.phase_times[firstPending] = Number.isFinite(phaseDuration) && phaseDuration >= 0
? phaseDuration : null
// Then STOP responding — the Stop hook will advance to the next phase.Phase-to-reference mapping: See arc-phase-stop-hook.sh _phase_ref() function for the canonical phase → reference file mapping.
Timing instrumentation: Each phase MUST stamp started_at before execution and completed_at + totals.phase_times[phaseName] (duration in ms) after. The Stop hook re-injects this same pattern for all subsequent phases via the phase prompt template. The totals.phase_times map accumulates durations across the full pipeline.
The plan_file path written to the phase loop state file and checkpoint is propagated to downstream phases that need the original plan specification as their source-of-truth. Each phase reference file reads plan_file from the checkpoint before spawning agents.
| Phase | Checkpoint Key | Purpose |
|---|---|---|
plan_review (Phase 2) | plan_file_path → review agents | Reviewers read plan to evaluate scope and detect drift |
inspect (Phase 5.9, STEP A + STEP D) | plan_file_path → STEP A deterministic checks + STEP D halt-gate | v3.0.0-alpha.7 Day 6: absorbed gap_analysis flow. STEP A extracts acceptance criteria + cross-references committed files; STEP D applies Task Completion Gate (PR #310 floor) and writes Implementation Status appendix back to the plan |
test (Phase 7.7) | plan_file_path → test agents | Test agents derive coverage targets from plan requirements |
ship (Phase 9, STEP -0.5) | plan_file_path → preShipValidator | Pre-ship gate (absorbed pre_ship_validation v3.0.0-alpha.6 C4e) reads plan to verify all stated criteria are met before PR |
Rule: Phases that consume plan_file_path MUST read it from checkpoint.plan_file (not from the state file or flags). Workers receive it as planFilePath in their context prompt so they can cross-reference the original spec, even when the pipeline spans multiple sessions via --resume.
MANDATORY: These steps run after Phase 9.5 MERGE (the last phase). The Stop hook injects a completion prompt when all phases are done. You MUST read and execute arc-phase-completion-stamp.md and post-arc.md — do NOT skip them or just present a summary. The plan file update is the primary deliverable of this phase.
Before calling the Plan Completion Stamp, record arc-level timing metrics:
// Schema v19: record arc completion time and total duration
const completedAtTs = new Date().toISOString()
checkpoint.completed_at = completedAtTs
checkpoint.totals = checkpoint.totals ?? { phase_times: {}, total_duration_ms: null, cost_at_completion: null }
const totalDuration = Date.now() - new Date(checkpoint.started_at).getTime()
if (!Number.isFinite(totalDuration) || totalDuration < 0) {
warn(`Arc timing anomaly: computed duration ${totalDuration}ms — setting to null`)
checkpoint.totals.total_duration_ms = null
} else {
checkpoint.totals.total_duration_ms = totalDuration
}
// Read cost from statusline bridge file (non-blocking — skip if unavailable)
if (ctxBridgeFile) {
try {
const bridge = JSON.parse(Bash(`cat "${ctxBridgeFile}" 2>/dev/null`))
checkpoint.totals.cost_at_completion = bridge.cost ?? null
} catch (e) { /* bridge unavailable — leave null */ }
}
Write(checkpointPath, checkpoint)See arc-phase-completion-stamp.md. Runs FIRST after merge — writes persistent record before context-heavy steps.
Written automatically by arc-result-signal-writer.sh PostToolUse hook. No manual call needed. See arc-result-signal.md.
See post-arc.md for the completion report template.
Echo persist removed: v3.0.0-alpha.1 removed the persistent memory layer (no rune-echoes skill, no.rune/echoes/runtime consumer). Post-arc no longer writes echoes — agent output is now ephemeral (tmp/).
Persists the proof manifest (SCR per criterion) as a PR comment after ship/merge. Uses --body-file for injection-safe PR comments.
See arc-proof-manifest.md for the full manifest schema and persistence logic.
Bash(`cd "${CWD}" && source plugins/rune/scripts/lib/workflow-lock.sh && rune_release_all_locks`)See post-arc.md. 30-second budget. After sweep, finish your response immediately — IGNORE zombie teammate messages (Stop hook handles cleanup).
--quick-mode 4-phase pipeline (plan → work+eval → review → mend)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.