4-phase systematic debugging — investigate, analyze, hypothesize, implement. Auto-freezes scope to the module boundary to prevent scope creep.
Install
npx skillscat add jthorare/agentic-workflow/rootcause Install via the SkillsCat registry.
Root Cause Analysis
4-phase systematic debugging with automatic scope freeze at the module boundary.
Before anything else: read $HOME/.agentic-workflow/toolkit/skills/_preamble.md and follow it (skill index, provider capability map, bootstrap check, session context). Run its Session Close section when this skill finishes.
Phase 0: Parse Input
Extract the starting point for the investigation from the argument:
--depth N— dispatch-chain depth guard (default 0). If N ≥ 2, this run must NOT dispatch any sub-skill (Sub-skill Dispatch is disabled) — report findings only. When dispatching, always pass--depth N+1.--investigate-only— diagnose without fixing (used by/bugFixOrchestrator, whose implementers write the fix). Run Phases 0–3.5, skip Phase 4, write the Phase 5 report + handoff — statusdiagnosedwhen a hypothesis is confirmed,unfixedwhen all were ruled out — and never dispatch a sub-skill. The working tree must end exactly as it started.- Error message or issue description — the normal entry.
- Production-incident entry — if the argument is a JSON object of the shape
{merge_sha, release_id, symptom, logs_excerpt}(as passed by/canaryon an UNHEALTHY verdict), treat this as a production incident:logs_excerptis the primary evidence;symptomis the failure description.- Scope the first suspect set to
git diff <merge_sha>^..<merge_sha>(the released change). - There is usually no local failing command — plan for the verify-app journey branch in Phases 1 and 4.
Phase 1: Investigate
Reproduce the error and collect evidence.
- Run the failing command or test. If the argument contains a runnable command (e.g.,
npm test, a file path with a stack trace hint), execute it to reproduce the failure. Capture the full output including stack traces. - If no runnable command (production/UI symptom), search files for the error message in the codebase, and write down concrete repro steps (navigate/click/fill sequence) from the symptom — these become the verify-app journey used for verification in Phase 4.
- Collect artifacts: full error output / stack trace / logs excerpt; affected files (from the trace, logs, diff, or search); related test files or the repro-steps journey.
Phase 2: Analyze
Read the relevant source and map the call chain.
- Read every file identified in Phase 1. Follow imports and function calls from the error site back to the root cause.
- Map the call chain — document the sequence of function calls from the entry point to the error site.
- Identify the module boundary — the nearest common ancestor directory of (a) the error site and (b) the hypothesized cause site. The repo root and generic top-level source dirs (
src/,lib/,app/) are rejected as boundaries: if the ancestor resolves to one of those, narrow to the most specific package/directory that still contains both sites, or declare the cause-side directory as the boundary and treat the error site as read-only context. Declare it explicitly:
SCOPE FREEZE: Module boundary is
<path-or-package>(nearest common ancestor of<error-site>and<cause-site>). All fixes in Phase 4 must stay within this boundary.
Phase 3: Hypothesize
Generate 2-3 hypotheses ranked by likelihood. Document each as: Hypothesis (one-sentence suspected cause) · Confirms if (evidence that would confirm it) · Rules out if (evidence that would eliminate it) · Likelihood (High / Medium / Low).
Phase 3.5: Confirm Before Editing
Run the "Confirms if" check for hypothesis #1 BEFORE editing any code — add the log line, run the narrowed test, inspect the state, whatever the check specifies.
- Confirmed → proceed to Phase 4 with hypothesis #1.
- Ruled out → record the result in the hypotheses table, promote hypothesis #2, and run its check.
- Never implement a fix whose hypothesis has not been confirmed by its own check. "Confirms if / Rules out if" is an executable contract, not documentation.
With --investigate-only: run the confirm check for each hypothesis in order until one is confirmed or all are ruled out, recording every result. Revert any temporary instrumentation (log lines, narrowed test edits) — git status --porcelain must show nothing you added. Then skip Phase 4 and go to Phase 5 with status diagnosed if a hypothesis was confirmed, or unfixed if every one was ruled out (the caller must not fix an unconfirmed cause). In the report, write n/a — investigate-only under Fix Applied and Verification.
Phase 4: Implement
Fix the confirmed cause.
- Implement the fix for the confirmed hypothesis. All changes MUST stay within the declared module boundary.
- Verify:
- If a local failing command exists, re-run it.
- If the symptom is production/UI-only (no local failing command), run the app-path check instead: Invoke skill
verify-appwith args--yes --journey <repro steps from Phase 1>. The fix is verified only on a PASS verdict in the resulting evidence pack.
- If verification still fails, revert the change, return to Phase 3.5 for the next hypothesis. Repeat up to hypothesis #3.
- If a fix requires changes outside the module boundary, do NOT make the change. Instead, flag it:
SCOPE BREACH: Fixing this requires changes in
<outside-path>. Asking the user for permission before proceeding.
Then Ask the user whether to expand the scope or stop.
Phase 5: Write Investigation Report + Handoff
Write the report to $HOME/.agentic-workflow/$REPO_SLUG/investigations/{timestamp}-{slug}.md where:
{timestamp}isYYYYMMDD-HHmmssformat{slug}is a short kebab-case summary of the error (max 40 chars)
(Re-derive the paths in bash via the shared helper — shell state does not persist between blocks:)
SHARED_DIR="$HOME/.agentic-workflow/toolkit/skills/_shared"
source "$SHARED_DIR/repo-slug.sh"
mkdir -p "$AW_DIR/investigations/<slug>"Report format:
# Investigation: {short description}
**Date:** {ISO timestamp}
**Status:** {fixed | unfixed | scope-breach | diagnosed}
## Error Description
{Original error message and context}
## Module Boundary
`{declared boundary path}`
## Call Chain
{entry-point} -> {fn1} -> {fn2} -> {error-site}
## Hypotheses
| # | Hypothesis | Likelihood | Result |
|---|-----------|------------|--------|
| 1 | {description} | High | {confirmed/ruled-out/untested} |
| 2 | {description} | Medium | {confirmed/ruled-out/untested} |
| 3 | {description} | Low | {confirmed/ruled-out/untested} |
## Root Cause
{Confirmed root cause explanation}
## Fix Applied
{Description of the fix}
- `{file}:{line}` — {what changed}
## Verification
{Command run and its output — pass/fail; or the verify-app journey + evidence pack path and verdict}Also write the handoff file to $HOME/.agentic-workflow/$REPO_SLUG/investigations/<slug>/handoff.md — this is the structured input /bugHunt --from-investigation <path> consumes, so the full investigation is never discarded:
# Handoff: {slug}
status: {fixed | unfixed | scope-breach | diagnosed}
report: {absolute path to the investigation report}
boundary: {declared module boundary path}
repro: {failing command, or the verify-app journey steps}
## Root Cause
{confirmed or best-supported root cause, one paragraph}
## Hypotheses
| # | Hypothesis | Cause-site files | Likelihood | Result |
|---|-----------|------------------|------------|--------|
| 1 | {description} | `{file}`, `{file}` | High | {confirmed/ruled-out/untested} |
| 2 | {description} | `{file}` | Medium | {confirmed/ruled-out/untested} |
## Ruled Out
- {hypothesis} — {evidence that ruled it out}
## Suggested Fix
{concrete fix direction, file paths, constraints}Phase 6: Report to User
Root cause analysis complete.
Status: {fixed | unfixed | scope-breach | diagnosed}
Module boundary: {path}
Root cause: {one-line summary}
Report: ~/.agentic-workflow/<repo-slug>/investigations/{filename}
Handoff: ~/.agentic-workflow/<repo-slug>/investigations/{slug}/handoff.mdEnd the response with exactly one fenced JSON block (machine-readable tail — /review and other callers parse this):
{ "status": "fixed | unfixed | scope-breach | diagnosed", "report_path": "<absolute report path>", "handoff_path": "<absolute handoff.md path>", "boundary": "<boundary path>" }Sub-skill Dispatch
Never with --investigate-only (status diagnosed is the intended end — the caller fixes). Otherwise, if Phase 4 ends with status unfixed or scope-breach, and the depth guard allows (--depth < 2):
Invoke skill
bugHuntwith args--from-investigation <handoff.md path> --depth <N+1>
Do not invoke bugHunt if the fix was verified — rootCause's own report is sufficient on success. At depth ≥ 2, stop the chain and report only.
Next steps
/bugHunt --from-investigation <handoff path>— auto-fix the bug using the full diagnosis/review— re-review the codebase after applying fixes