bugfix
Skill173 starsChanged 12 days agoMITView on GitHub
End-to-end bug fix workflow — report, analyze, fix, verify, ship (PR + merge + deploy + knowledge capture)
- Deletes or force-pushes
- Commits and pushes
34 other projects use a version of this.
Adopted by
Most recently taken up by
- isanchez-aguilar/relayrace-aitheir own version, first seen Nov 8, 2026
- icarloscornejo/doertheir own version, first seen Nov 7, 2026
- ClaireAll/skillstheir own version, first seen Nov 5, 2026
- bhoon716/skill-forgetheir own version, first seen Nov 2, 2026
- Snowflake-Labs/coco-skillstheir own version, first seen Nov 1, 2026
- irahardianto/awesome-agvtheir own version, first seen Nov 1, 2026
Used with
Projects with it also use feature, refactor and 7 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
bradtraversySkillfeature
Manage current feature workflow - start, review, explain or complete
Also in 7 projects that use this
GitHubSkillrefactor
Surgical code refactoring to improve maintainability without changing behavior. Covers extracting functions, renaming variables, breaking down god functions, improving type safety, eliminating code smells, and applying design patterns. Less drastic than repo-rebuilder; use for gradual improvements.
Also in 6 projects that use this
SentrySkillcommit
Create commit messages following Sentry conventions. Use when committing code changes, writing commit messages, or formatting git history. Follows conventional commits with Sentry-specific issue references.
Also in 8 projects that use this
BlockSkillplan
Draft a TDD, PRD, or lightweight plan in the conversation without committing it.
Also in 4 projects that use this
Microsoft AzureSkilldocs
Also in 3 projects that use this
MicrosoftSkillpr-review
Verify the technical accuracy of a vscode-docs pull request against the VS Code source code in microsoft/vscode. Use when reviewing a docs PR for factual correctness: setting names, command IDs, default values, API shapes, keybindings, versioned availability, and described behavior.
Also in 3 projects that use this
Other versions34 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 34
- alibaba/MNN★ 16ksame name
- SparkDevNetwork/Rock★ 701same name
- oasm-platform/open-asm★ 272same name
- team-attention/hoyeon★ 173same name
- irahardianto/awesome-agv★ 157same name
- Snowflake-Labs/coco-skills★ 49same name
- mrveiss/AutoBot-AI★ 39same name
- dan-the-dev/xp-developer-skills★ 31same name
- ecodelearn/template-claude-code-open★ 25same name
- ConfabulousDev/confab-web★ 15same name
24 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
Show its rules and text
We split this skill into the rules it gives an agent
35 rules. 0 are common, 13 are distinctive, and 22 are very specific to this project.
0
Common
Most of the 31 edited versions we read keep these.
13
Distinctive
This author's own choices. Worth a look.
22
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 17
Run this block first, with your shell tool, and read its output before you continue.
- Very specific: line 37
Before proceeding, verify that .adlc/bugs/ exists.
- Distinctive: line 44
If given a bug description (not a BUG ID), create a bug report:
- Very specific: line 68
Create .adlc/bugs/BUG-xxx-slug.md (always in the current repo — this becomes the "primary" for the bug) using the template from …
- Very specific: line 72
If given a BUG ID, read the existing bug report — note any repo: or touched_repos: field for routing.
- Distinctive: line 85
If this harness can run subagents, launch Explore agents to trace the bug.
- Distinctive: line 86
Search for relevant code paths based on the bug description
- Distinctive: line 89
Read the identified files to understand the context
- Very specific: line 90
Document the root cause in the bug report's "Root Cause" section, below the Prior lessons consulted: list.
- Distinctive: line 93
Check for secondary issues or edge cases related to the bug
- Distinctive: line 95
Update the bug report with the validated findings
- Very specific: line 131
Never write an id the partial did not return: it has already enforced the strict ^REQ-[0-9]{3,6}$ pattern and confirmed the spec directory …
- Distinctive: line 143
Ensure the fix addresses the root cause, not just symptoms
- Distinctive: line 144
Update related test files if the fix changes behavior
- Very specific: line 148
Run the test suite: npm test (or appropriate test command)
- Distinctive: line 149
If tests fail, fix and re-run
- Very specific: line 150
Update the bug report (do NOT mark resolved yet — that happens in Phase 6 after the fix is merged and deployed):
- Very specific: line 151
Leave status as open (or set to in-review if your project uses that value)
- Very specific: line 154
Update the updated date
- Very specific: line 155
Read the Record section of bugfix/references/regression-test.md and follow it before you continue.
- Very specific: line 171
Read the PR body section of bugfix/references/regression-test.md and follow it before you continue.
- Very specific: line 202
After all sibling PRs exist, edit each one (adlc_forge_pr_edit <prUrl> --body ...) to fill in the Related PRs section.
- Very specific: line 203
Wait for CI to pass on every PR: gh pr checks <prUrl>.
- Distinctive: line 239
If staging deployed but production has NOT yet been promoted, wait — the pipeline runs them sequentially.
- Very specific: line 242
Read ios.deploy_targets, ios.derived_data_clean, and ios.deploy_command from .adlc/config.yml.
- Very specific: line 243
If ios.derived_data_clean is true: rm -rf ~/Library/Developer/Xcode/DerivedData/*
- Very specific: line 246
If stack.frontends doesn't include ios, skip this section entirely.
- Distinctive: line 252
Add a Deployment section noting the staging + production revisions
- Distinctive: line 267
Ask of this bug:
- Very specific: line 311
If nothing transferable survived, the summary's ### Lessons captured carries exactly one line NO_ENTRY: <reason> — never a silent skip.
- Very specific: line 315
If the fix was done in a separate worktree, remove it: git -C <main-worktree> worktree remove <fix-worktree-path>
- Very specific: line 316
If the fix branch still exists locally after squash-merge, delete it: git branch -D fix/bug-xxx-slug
- Very specific: line 350
Use fix/bug-xxx-slug for the branch name.
- Very specific: line 358
When a bug's fix spans repos (via touched_repos: in the bug frontmatter):
- Very specific: line 363
If this gets complicated (more than 2 touched repos, or ordering matters), consider promoting the bug into a full REQ and using /proceed …
“Common” is measured: kept by at least 6 in 10 of the 31 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
/bugfix — Bug Fix Workflow
You are fixing a bug using a streamlined workflow that skips the full spec ceremony but follows the same deployment strategy as a feature: changes land via PR, ride the project's CI/CD pipeline (staging-first if the project has one), and aren't marked resolved until every declared deploy target is confirmed.
Ethos
!test -s .adlc/ETHOS.md && cat .adlc/ETHOS.md || echo No ethos found — run /init, or /adlc:init on the plugin install, to vendor .adlc/ETHOS.md
Context
Run this block first, with your shell tool, and read its output before you continue. Each read prints a notice instead of failing when its file is absent.
# adlc-context
echo '--- Project config'
test -s .adlc/config.yml && echo 'present — read .adlc/config.yml before Phase 1' || echo 'none — single-repo legacy mode'
echo '--- Bug template'
cat .adlc/templates/bug-template.md 2>/dev/null || echo 'No bug template found — run /init (/adlc:init on the plugin install) to vendor .adlc/templates'
echo '--- Conventions'
cat .adlc/context/conventions.md 2>/dev/null || echo 'No conventions found'
echo '--- Existing bugs'
ls .adlc/bugs/ 2>/dev/null || echo 'No bugs directory found'Input
The bug report is the argument: whatever follows /bugfix in the invocation (on Claude Code it can also arrive as an ARGUMENTS: line appended to this text). With none, ask the user to describe the bug.
Prerequisites
Before proceeding, verify that .adlc/bugs/ exists. If it doesn't, stop and tell the user: "The .adlc/ structure hasn't been initialized. Run /init (/adlc:init on the plugin install) first."
Read bugfix/references/regression-test.md and follow it before you continue. It holds the regression-test protocol (REQ-691): its Mode section reads bugfix.regression_test now, before Phase 1, and Phases 3 to 6 each send you back to one of its other sections. off skips them all; a setting it cannot read stops /bugfix here. Nothing in this file replaces it.
Instructions
Phase 1: Report
- If given a bug description (not a BUG ID), create a bug report:
- Determine the next BUG ID using the global atomic counter file
${ADLC_HOME:-$HOME/.claude}/.global-next-bug(shared across all repos for unique IDs, mirroring the REQ counter — see LESSON-004). The counter is now a cache, not the authority — the remote is the source of truth (REQ-518): allocation derives the remote high-water, takesmax(remote, local) + 1, and fast-forwards the local counter, all inside the existingmkdirlock. Allocate via the sharedpartials/id-alloc.shhelper (BR-5 — the lock block + its REQ-416/LESSON-014 rationale live in the partial). Source it and calladlc_alloc_idin the same fenced block (the cross-fence-fn rule — see conventions.md "Bash in skills"):ADLC_TOOLKIT_ROOT="${CLAUDE_PLUGIN_ROOT}"; [ -n "$ADLC_TOOLKIT_ROOT" ] || [ ! -d "$HOME/.claude/skills/partials" ] || ADLC_TOOLKIT_ROOT="$HOME/.claude/skills"; [ -n "$ADLC_TOOLKIT_ROOT" ] || ADLC_TOOLKIT_ROOT=$(cat "$HOME/.claude/adlc/plugin-root" 2>/dev/null); export ADLC_TOOLKIT_ROOT="${ADLC_TOOLKIT_ROOT:-$HOME/.claude/skills}" if [ -f .adlc/partials/id-alloc.sh ]; then . .adlc/partials/id-alloc.sh; else . "$ADLC_TOOLKIT_ROOT/partials/id-alloc.sh"; fi BUG_NUM=$(adlc_alloc_id bug) # `exit 1` inside adlc_alloc_id's subshell terminates only the subshell — BUG_NUM # would be silently empty. Guard the parent context (REQ-416 verify D-pass). [ -n "$BUG_NUM" ] || { echo "ERROR: failed to allocate BUG number — aborting before writing malformed bug report" >&2; exit 1; } # If ADLC_ALLOC_DEGRADED=1 (remote unreachable), the helper warned on stderr — note # "id allocated without remote verification — verify before PR" (BR-3). Never block.adlc_alloc_id bughandles the absent-counter bootstrap scan internally (highestBUG-xxxunder$ADLC_REPOS_ROOT; bug reports are.mdfiles so the scan uses-type f), themkdirlock that serializes concurrent sessions, and the remote high-water max. Single-machine behavior is unchanged when the remote has no higher allocation (BR-7). Note: the legacy per-repo.adlc/.next-bugcounter is deprecated and no longer consulted — existing files can be left in place but should not be read or written. - Pre-push recheck (BR-4, BR-8). Before the bug file is committed on a branch for push, re-verify
BUG-<id>against the remote — a colleague on another machine may have pushed the same id since allocation. Sourcepartials/id-recheck.shand calladlc_recheck_idin the same fenced block; a collision halts with the renumber instruction rather than pushing a duplicate:ADLC_TOOLKIT_ROOT="${CLAUDE_PLUGIN_ROOT}"; [ -n "$ADLC_TOOLKIT_ROOT" ] || [ ! -d "$HOME/.claude/skills/partials" ] || ADLC_TOOLKIT_ROOT="$HOME/.claude/skills"; [ -n "$ADLC_TOOLKIT_ROOT" ] || ADLC_TOOLKIT_ROOT=$(cat "$HOME/.claude/adlc/plugin-root" 2>/dev/null); export ADLC_TOOLKIT_ROOT="${ADLC_TOOLKIT_ROOT:-$HOME/.claude/skills}" if [ -f .adlc/partials/id-recheck.sh ]; then . .adlc/partials/id-recheck.sh; else . "$ADLC_TOOLKIT_ROOT/partials/id-recheck.sh"; fi BUG_ID=$(printf 'BUG-%03d' "$BUG_NUM") if ! adlc_recheck_id bug "$BUG_ID"; then echo "Halting: $BUG_ID collides on the remote — renumber before pushing (see message above)." >&2 exit 1 fi - Create
.adlc/bugs/BUG-xxx-slug.md(always in the current repo — this becomes the "primary" for the bug) using the template from.adlc/templates/bug-template.md - Fill in: description, reproduction steps (if known), expected vs actual behavior, environment
- Set status to
open, severity based on impact - Cross-repo: if
.adlc/config.ymldeclares siblings AND the bug's fix likely lives in a sibling (e.g., a frontend symptom whose root cause is in a backend repo), add arepo: <sibling-id>field to the bug frontmatter. If the fix spans multiple repos, add atouched_repos: [<id>, <id>]field. Therepo:field determines where Phase 3's commit and Phase 4's PR land.
- Determine the next BUG ID using the global atomic counter file
- If given a BUG ID, read the existing bug report — note any
repo:ortouched_repos:field for routing.
Phase 2: Analyze
Consult prior lessons first (REQ-647 BR-5). Before diagnosing, retrieve the lessons the toolkit already holds for this surface, so a known pitfall is recognized rather than rediscovered. Infer the components of the reproduction's file paths (the files the bug report names, or the ones the failing command touches) the way
/reviewStep 1 item 7a does, passing the most specific component of each path; the engine joins them with the bug's owncomponent, adds their ancestors, scores with the/specStep 1.6 rule over.adlc/knowledge/lessons/with the bug's frontmatter tags as the rest of the query, and keeps the top 5, each loaded as at most 40 lines (frontmatter,## Lesson,## Applies When):ADLC_TOOLKIT_ROOT="${CLAUDE_PLUGIN_ROOT}"; [ -n "$ADLC_TOOLKIT_ROOT" ] || [ ! -d "$HOME/.claude/skills/partials" ] || ADLC_TOOLKIT_ROOT="$HOME/.claude/skills"; [ -n "$ADLC_TOOLKIT_ROOT" ] || ADLC_TOOLKIT_ROOT=$(cat "$HOME/.claude/adlc/plugin-root" 2>/dev/null); export ADLC_TOOLKIT_ROOT="${ADLC_TOOLKIT_ROOT:-$HOME/.claude/skills}" if [ -f .adlc/partials/lessons.sh ]; then . .adlc/partials/lessons.sh; else . "$ADLC_TOOLKIT_ROOT/partials/lessons.sh"; fi # <bug> = this bug's .adlc/bugs/BUG-xxx-*.md; one --component per reproduction path's component. adlc_lessons select --set bugfix --root . --bug "<bug>" --component "<component>"The output opens with a
Prior lessons consulted:list (oneLESSON-xxx — title (score N)line per lesson, ornone), followed by each lesson's loaded text. Emit the list, read the lessons, and copy the list — ids and titles, not the loaded text — to the top of the bug report's "Root Cause" section before writing the analysis, so the report shows what was consulted. A return of 2 prints onelessons: unavailable — <reason>line: recordPrior lessons consulted: unavailable — <reason>instead and continue — retrieval never halts the phase.- If this harness can run subagents, launch Explore agents to trace the bug; if it cannot, or you are a subagent, trace the bug yourself with your harness's search and read tools:
- Search for relevant code paths based on the bug description
- Trace the execution flow that triggers the bug
- Identify the root cause (not just symptoms)
- Read the identified files to understand the context
- Document the root cause in the bug report's "Root Cause" section, below the
Prior lessons consulted:list. When a consulted lesson describes this failure, say so and cite its id — the fix should apply its remedy, not rediscover it - Validate the analysis:
- Re-read the affected code paths to confirm the root cause is correct
- Check for secondary issues or edge cases related to the bug
- Adjust the root cause and fix approach if validation reveals inaccuracies
- Update the bug report with the validated findings
Attribute the incident to the REQ that shipped its cause (REQ-593). Root-cause analysis has just produced a file/line set; that set is exactly what
git blameneeds to name the change that introduced the behavior. Derive the candidates, then record or refuse — never guess.Derivation is per-repo (BR-8), keyed off the bug's
repo:/touched_repos:frontmatter: blame each repo against its own history, but validate every id against the primary repo, because in cross-repo mode spec directories exist only there (BR-5). Source the partial and call it in the same fenced block (the cross-fence-fn rule — see conventions.md "Bash in skills"):ADLC_TOOLKIT_ROOT="${CLAUDE_PLUGIN_ROOT}"; [ -n "$ADLC_TOOLKIT_ROOT" ] || [ ! -d "$HOME/.claude/skills/partials" ] || ADLC_TOOLKIT_ROOT="$HOME/.claude/skills"; [ -n "$ADLC_TOOLKIT_ROOT" ] || ADLC_TOOLKIT_ROOT=$(cat "$HOME/.claude/adlc/plugin-root" 2>/dev/null); export ADLC_TOOLKIT_ROOT="${ADLC_TOOLKIT_ROOT:-$HOME/.claude/skills}" if [ -f .adlc/partials/attribution.sh ]; then . .adlc/partials/attribution.sh; else . "$ADLC_TOOLKIT_ROOT/partials/attribution.sh"; fi # <repo> = the repo whose history to blame (this repo, or a sibling's path from # .adlc/config.yml). <primary> = the repo holding .adlc/specs — always the current repo. # <file> <start> <end> = one root-cause range from step 5. Repeat per range, per repo. adlc_attr_blame_reqs "<repo>" "<primary>" "<file>" "<start>" "<end>"Union the output across every range and repo, then act on the distinct id count:
- 0 candidates — write
attribution: noneand leaveintroduced_by: []. Emit exactly one stderr line naming the reason (no trailer in the blamed commits / the lines pre-date the trailer convention / the file is untracked), then continue to Phase 3. A bug with no derivable REQ is a normal outcome, not a failure: never halt, and never fabricate an id (BR-7). - 1 candidate — write
introduced_by: [REQ-xxx]andattribution: derived. - 2+ candidates — present all of them and write nothing. Ask the operator to
select one or more; selecting several is legitimate when a defect genuinely emerges
from the interaction of multiple merged REQs, and is what makes
introduced_byan array. Record the selection withattribution: derived. Do not auto-union and do not pick the lowest id or the most recent commit — a detected-but-unresolvable attribution refuses rather than guessing (BR-3, LESSON-483).
Never write an id the partial did not return: it has already enforced the strict
^REQ-[0-9]{3,6}$pattern and confirmed the spec directory exists (BR-5). A trailer citing a REQ with no spec directory is dropped on purpose.The reverse edge is not written anywhere. REQ → its incidents is derived at read time by scanning
.adlc/bugs/frontmatter (/statusdoes this); storing it in the REQ spec would rot the moment an artifact is moved or renumbered (BR-4, LESSON-019).- 0 candidates — write
Phase 3: Fix
- Determine target repo: if the bug's frontmatter has
repo:and it names a sibling (not this repo), cd into that sibling's path from.adlc/config.ymland do all fix work there. Fortouched_repos: [...], cd into each in turn — one commit per repo, on a shared branch name. Otherwise fix in the current repo. - Proceed directly with the validated fix approach — do not pause for user confirmation. Read the
Write and contrastsection ofbugfix/references/regression-test.mdand follow it before you continue. It writes and runs the regression test before items 3 to 5 write the fix; skip it when the mode isoff. - Implement the fix following project conventions
- Ensure the fix addresses the root cause, not just symptoms
- Update related test files if the fix changes behavior
- Track progress with TodoWrite
Phase 4: Verify
- Run the test suite:
npm test(or appropriate test command) - If tests fail, fix and re-run
- Update the bug report (do NOT mark
resolvedyet — that happens in Phase 6 after the fix is merged and deployed):- Leave status as
open(or set toin-reviewif your project uses that value) - Fill in "Resolution" section with what was changed and why
- Fill in "Files Changed" section with specific file paths
- Update the
updateddate - Read the
Recordsection ofbugfix/references/regression-test.mdand follow it before you continue. It writesregression_testsorregression_waiverand the## Regression Testsection; skip it when the mode isoff.
- Leave status as
- Present an interim summary:
- Root cause
- What was fixed
- Files changed
- Test results
- Regression test: the tests and their contrast, the waiver, or off for this project
- Then continue to Phase 5
Phase 5: Ship — Create Pull Request(s)
For each touched repo (just the current repo in single-repo mode; each entry in touched_repos: in cross-repo mode):
- Push the fix branch:
git -C <worktree> push -u origin fix/bug-xxx-slug - Create the PR with
adlc_forge_pr_create(sourcepartials/forge.shwith the guarded spelling from conventions.md "Bash in skills" in the same fence; run from inside the worktree, or pass-R <owner/repo>). All PR ops route through the forge adapter, never directgh(REQ-520 BR-1). In cross-repo mode, create the primary repo's PR last so its body can link every sibling.- Title:
fix(BUG-xxx): short description— when cross-repo, scope to the repo (e.g.,fix(api): null deref in user serializer [BUG-042]). - Read the
PR bodysection ofbugfix/references/regression-test.mdand follow it before you continue. It fills the body's## Regression Testblock, in every mode. - Body:
## Summary [1-2 lines describing what broke and what was fixed in THIS repo] ## Bug BUG-xxx: [bug title] Severity: [critical | high | medium | low] Primary repo: <primary-repo-id> ## Root Cause [Pulled from the bug report's Root Cause section] ## Files Changed (this repo) - `path/to/file.ts` — what changed and why ## Related PRs (cross-repo) [Omit in single-repo mode. Otherwise list each sibling PR URL — back-fill sibling bodies via `adlc_forge_pr_edit` once every URL is known.] ## Regression Test [The tests and their contrast, the waiver and its reason, or "Regression tests: off for this project." — per the PR body section] ## Test Plan - [ ] Unit/integration tests pass locally - [ ] CI green on this PR - [ ] Staging deploy succeeded (verified in Phase 6) - [ ] Production deploy succeeded (verified in Phase 6)
- Title:
- After all sibling PRs exist, edit each one (
adlc_forge_pr_edit <prUrl> --body ...) to fill in the Related PRs section. - Wait for CI to pass on every PR:
gh pr checks <prUrl>. If CI fails, diagnose and re-push — never bypass with--no-verifyor admin-merge. - Report all PR URLs to the user, grouped by repo.
Phase 6: Wrapup — Merge, Deploy, Knowledge Capture
This is the equivalent of /proceed's Phase 8 / /wrapup steps, condensed for bugs.
Step 0 — Regression gate (before anything merges). Read the Gate section of bugfix/references/regression-test.md and follow it before you continue. It runs the regression check on this bug in the fix worktree; anything but a pass, or off, stops /bugfix here, with nothing merged and the bug unresolved (BR-13).
Step 1 — Merge each PR.
- Verify the PR is mergeable:
adlc_forge_pr_view <prUrl> --json mergeable,mergeStateStatusshould reportMERGEABLE(on GitHub; ADO normalizes viapr_view). If the integration branch has advanced, rebase the fix branch ontoorigin/<integration-branch>— the PR's base, resolved by/proceedstep 4's rule (branches.integrationfrom.adlc/config.ymlwhen declared, elsestagingin two-branch repos, elsemain), never a hardcodedmain(LESSON-036) — force-push with lease, wait for CI to re-pass, and run Step 0 again: the Gate certifies one head. - Merge with squash + branch delete:
adlc_forge_pr_merge <prUrl> --squash --delete-branch. When Step 0 printedregression_gate_head=<oid>, add--match-head-commit <oid>, so only the head the Gate checked can merge; where the forge cannot pin (Azure DevOps refuses the flag), re-read the PR'sheadRefOidjust before merging and stop if it is not<oid>. In cross-repo mode, walktouched_repos:order (ormerge_order:from.adlc/config.ymlif not specified on the bug). - Check
branch_deletedin the output (BUG-195).gh's post-merge cleanup routinely aborts when the default branch is checked out in another worktree — the normal state for an agent session. The adapter completes the remote deletion itself and reportsbranch_deleted=1(orskipped-fork). If it reportsbranch_deleted=0, the remote branch survived: run the exactgit push origin --delete <branch>thewarn=line names before continuing. Branch on this field, never on thewarn=prose.
Step 2 — Confirm deploys (this is the staging-first gate when the project has one — same model as features).
Skip this step entirely if the project doesn't deploy via Cloud Run (i.e., stack.backends in .adlc/config.yml doesn't include cloud-run and there's no gcp: block).
Otherwise, for each touched service that has a services: entry in .adlc/config.yml, look up gcp.staging_project and gcp.production_project from the config and confirm both:
# Staging
gcloud run services describe <service> \
--project=<gcp.staging_project from config> \
--region=<services[<id>].region or gcp.default_region> \
--format="value(status.latestReadyRevisionName,status.traffic[0].revisionName)"
# Production
gcloud run services describe <service> \
--project=<gcp.production_project from config> \
--region=<services[<id>].region or gcp.default_region> \
--format="value(status.latestReadyRevisionName,status.traffic[0].revisionName)"Confirm the merge SHA's revision is serving 100% traffic in each. If gcp.production_project is omitted (no separate prod project), only confirm staging.
If staging deployed but production has NOT yet been promoted, wait — the pipeline runs them sequentially. If either fails, surface to the user with the failed deploy log link before claiming the bug resolved.
iOS deploy (only when stack.frontends in .adlc/config.yml includes ios AND the fix touched the iOS repo):
- Read
ios.deploy_targets,ios.derived_data_clean, andios.deploy_commandfrom.adlc/config.yml. - If
ios.derived_data_cleanis true:rm -rf ~/Library/Developer/Xcode/DerivedData/* - From the iOS repo's worktree, run
<ios.deploy_command>and deploy to every device inios.deploy_targets— never skip one. Don't leave this as a follow-up for the user.
If stack.frontends doesn't include ios, skip this section entirely.
Step 3 — Update the bug report.
- Set status to
resolved(Step 0's gate passed, or reportedoff) - Update the
updateddate - Confirm Resolution and Files Changed sections are filled in (from Phase 4)
- Add a Deployment section noting the staging + production revisions
Step 4 — Capture knowledge (NEVER skip — per memory feedback_wrapup_knowledge_capture.md).
Evaluate honestly: did this bug reveal something a future implementer should know?
<!-- lesson-capture-rules -->Lesson capture rules (REQ-646): 0. Declare kind: process if the lesson is about how a skill, agent, partial or pipeline phase behaves; domain if it is about the codebase or stack the implementer works in.
- Cite the moment: a lesson you cannot trace to a specific commit, finding, bug, test or transcript line is speculation; put that moment in evidence (a commit sha, a BUG-/REQ-/LESSON-/TASK- id, a path:line, or a test name). Never a home-directory path: write ~/ for the home prefix rather than dropping the citation.
- Declare the contrast: confidence is decided by whether the evidence contains a contrast - a bug reproduced then fixed, a test failing then passing, a Phase-5 finding confirmed by its fix and re-verify, or two approaches or runs compared. high = a contrast was observed and the evidence names the mechanism (a specific line, command or finding); medium = a contrast was observed but the mechanism is inferred; low = a single observation with no contrast. An invented attribution poisons retrieval for every later REQ.
- NO_ENTRY is a valid answer: if nothing transferable survived, write NO_ENTRY:
<reason>in the summary slot; never pad. Granularity: too generic never changes behaviour (be thorough); too specific never fires again (the fee rose on Jan 1) - aim between.
<!-- /lesson-capture-rules -->Ask of this bug:
- A surprising failure mode (race condition, schema mismatch, mocked-vs-real divergence, etc.)?
- A pattern or anti-pattern worth recording?
- A check that would have caught this earlier?
- An assumption from a prior REQ that turned out false?
A reproduce-then-fix sequence is a contrast (rule 2); name it in evidence.
With regression tests on, the pre-fix-fail / post-fix-pass run recorded in the bug report's ## Regression Test section is that contrast: cite it as the lesson's evidence (the test path, the command and the first failing assertion line).
If yes, write a lesson to .adlc/knowledge/lessons/LESSON-xxx-slug.md using the global atomic counter ${ADLC_HOME:-$HOME/.claude}/.global-next-lesson (shared across all repos for unique IDs, mirroring the REQ/BUG counters — see LESSON-004). The counter is now a cache, not the authority — the remote is the source of truth (REQ-518): allocation derives the remote high-water, takes max(remote, local) + 1, and fast-forwards the local counter, all inside the shared mkdir-lock (${ADLC_HOME:-$HOME/.claude}/.global-next-lesson.lock.d, shared with /wrapup so concurrent /bugfix and /wrapup runs mutually exclude). Allocate via the shared partials/id-alloc.sh helper (BR-5 — the lock block + its LESSON-014 symlink pre-check live in the partial). Source it and call adlc_alloc_id in the same fenced block (the cross-fence-fn rule — see conventions.md "Bash in skills"):
ADLC_TOOLKIT_ROOT="${CLAUDE_PLUGIN_ROOT}"; [ -n "$ADLC_TOOLKIT_ROOT" ] || [ ! -d "$HOME/.claude/skills/partials" ] || ADLC_TOOLKIT_ROOT="$HOME/.claude/skills"; [ -n "$ADLC_TOOLKIT_ROOT" ] || ADLC_TOOLKIT_ROOT=$(cat "$HOME/.claude/adlc/plugin-root" 2>/dev/null); export ADLC_TOOLKIT_ROOT="${ADLC_TOOLKIT_ROOT:-$HOME/.claude/skills}"
if [ -f .adlc/partials/id-alloc.sh ]; then . .adlc/partials/id-alloc.sh; else . "$ADLC_TOOLKIT_ROOT/partials/id-alloc.sh"; fi
LESSON_NUM=$(adlc_alloc_id lesson)
# `exit 1` inside adlc_alloc_id's subshell terminates only the subshell — LESSON_NUM
# would be silently empty. Guard the parent context (REQ-416 verify D-pass).
[ -n "$LESSON_NUM" ] || { echo "ERROR: failed to allocate LESSON number — aborting before writing malformed lesson" >&2; exit 1; }adlc_alloc_id lesson handles the absent-counter bootstrap scan internally (highest LESSON-xxx under $ADLC_REPOS_ROOT; lessons are .md files so the scan uses -type f), the shared mkdir lock, and the remote high-water max. Single-machine behavior is unchanged when the remote has no higher allocation (BR-7). Note: the legacy per-repo .adlc/.next-lesson counter is deprecated and no longer consulted — existing files can be left in place but should not be read or written.
<!-- lesson-write-point -->Write the lesson now — before the schema check below, which reads the file, and the pre-push recheck, which checks its id against the remote. Use the lesson template (.adlc/templates/lesson-template.md, fall back to $ADLC_TOOLKIT_ROOT/templates/lesson-template.md). Filename format is LESSON-xxx-slug.md only — no date prefixes, no bare-numeric prefixes — so the file is .adlc/knowledge/lessons/LESSON-<id>-<slug>.md, <id> being the number just allocated, zero-padded to three digits. Include domain, component, and tags so future runs of /spec, /architect, /reflect, and /review can filter by relevance, and kind, evidence, and confidence per the capture rules above (rules 0–2); ## Lesson and ## Applies When must both be non-empty. Write a new file only — never edit an existing lesson: a refinement of LESSON-A is a new lesson carrying generalizes: [LESSON-A] or supersedes: [LESSON-A] (BR-2). enforcement stays none unless a lint, test, script or hook actually enforces the lesson. Every generalizes / supersedes id must match ^LESSON-[0-9]{3,6}$ and exist — find .adlc/knowledge/lessons -maxdepth 1 -type f -name '<id>-*' | head -1 must print a path (a find, not a bare glob — zsh aborts on an unmatched glob, LESSON-335); drop any id that fails (a list left empty is written []).
Schema check (REQ-646 BR-3). Validate the file you just wrote. Source partials/lesson-check.sh and call it in the same fenced block; the return codes and the rule table live in partials/lesson-check.md:
ADLC_TOOLKIT_ROOT="${CLAUDE_PLUGIN_ROOT}"; [ -n "$ADLC_TOOLKIT_ROOT" ] || [ ! -d "$HOME/.claude/skills/partials" ] || ADLC_TOOLKIT_ROOT="$HOME/.claude/skills"; [ -n "$ADLC_TOOLKIT_ROOT" ] || ADLC_TOOLKIT_ROOT=$(cat "$HOME/.claude/adlc/plugin-root" 2>/dev/null); export ADLC_TOOLKIT_ROOT="${ADLC_TOOLKIT_ROOT:-$HOME/.claude/skills}"
if [ -f .adlc/partials/lesson-check.sh ]; then . .adlc/partials/lesson-check.sh; else . "$ADLC_TOOLKIT_ROOT/partials/lesson-check.sh"; fi
# <path> is the LITERAL path of the file you just wrote — thread it in; fenced
# blocks share no shell state and LESSON_ID is not a sanctioned cross-fence var.
adlc_lesson_check .adlc/knowledge/lessons/LESSON-<id>-<slug>.mdRepair loop. rc 0 → go on to the pre-push recheck. rc 1 → stderr carries one <field>: <reason> line per violation; repair only what is named — the named frontmatter field(s), or, when the <field> is ## Lesson or ## Applies When, add that one missing or empty section — never regenerate any other section, and run the fence again. A key written without a blank after its colon (supersedes:[…], kind:process) is a frontmatter violation on that key, repaired like any other named field. Repair at most 2 times: after the third failure, delete the draft file and write NO_ENTRY: schema check failed — <field> in the ### Lessons captured summary slot (Step 6); with no file left, skip the pre-push recheck. The id allocated for the draft stays spent — a gap in the counter, never a reuse. You keep the count; the fence does not. This is not a halt — Steps 5 and 6 run regardless. rc 2 is a usage error (wrong path, unreadable file, no frontmatter block, a symlink, or a basename that is not LESSON-<digits>-<slug>.md): fix the path and re-run; never treat it as a pass.
Pre-push recheck (BR-4, BR-8). Before the lesson file is committed on a branch for push, re-verify LESSON-<id> against the remote — a colleague on another machine may have pushed the same id since allocation. Source partials/id-recheck.sh and call adlc_recheck_id in the same fenced block; a collision halts with the renumber instruction rather than pushing a duplicate:
ADLC_TOOLKIT_ROOT="${CLAUDE_PLUGIN_ROOT}"; [ -n "$ADLC_TOOLKIT_ROOT" ] || [ ! -d "$HOME/.claude/skills/partials" ] || ADLC_TOOLKIT_ROOT="$HOME/.claude/skills"; [ -n "$ADLC_TOOLKIT_ROOT" ] || ADLC_TOOLKIT_ROOT=$(cat "$HOME/.claude/adlc/plugin-root" 2>/dev/null); export ADLC_TOOLKIT_ROOT="${ADLC_TOOLKIT_ROOT:-$HOME/.claude/skills}"
if [ -f .adlc/partials/id-recheck.sh ]; then . .adlc/partials/id-recheck.sh; else . "$ADLC_TOOLKIT_ROOT/partials/id-recheck.sh"; fi
LESSON_ID=$(printf 'LESSON-%03d' "$LESSON_NUM")
if ! adlc_recheck_id lesson "$LESSON_ID"; then
echo "Halting: $LESSON_ID collides on the remote — renumber before pushing (see message above)." >&2
exit 1
fiIf nothing transferable survived, the summary's ### Lessons captured carries exactly one line NO_ENTRY: <reason> — never a silent skip.
Step 5 — Clean up.
- Switch the local checkout to main and pull:
git -C <main-worktree> checkout main && git -C <main-worktree> pull - If the fix was done in a separate worktree, remove it:
git -C <main-worktree> worktree remove <fix-worktree-path> - If the fix branch still exists locally after squash-merge, delete it:
git branch -D fix/bug-xxx-slug - Prune remote-tracking refs:
git fetch --prune
Step 6 — Final ship summary.
## BUG-xxx: Bug Title — Resolved
**Severity**: <severity>
**PR(s)**: #nn (and siblings if cross-repo)
**Merged**: YYYY-MM-DD
### Root cause
- 1-2 lines
### Fix
- 1-2 lines
### Regression test
- `path/to/test` — fails without the fix (first failing assertion), passes with it
(or: Waived: <reason>; or: off for this project, and, when the key is not set,
"set bugfix.regression_test: required in .adlc/config.yml to turn them on")
### Deployment
- Staging: <service> revision <hash> @ 100% traffic
- Production: <service> revision <hash> @ 100% traffic
- iOS: deployed to <list of ios.deploy_targets from config> (or "n/a — backend-only fix")
### Lessons captured
- `.adlc/knowledge/lessons/LESSON-xxx-slug.md` — one-line hook
(or exactly one line: NO_ENTRY: <reason>)Branch Naming
Use fix/bug-xxx-slug for the branch name. In cross-repo bugs, use the same branch name in every touched repo so PRs can be linked visually.
Commit Message Format
fix(BUG-xxx): short description of the fixCross-Repo Bugs (brief)
When a bug's fix spans repos (via touched_repos: in the bug frontmatter):
- The bug report itself always lives in the repo
/bugfixwas invoked from (the "primary" for this bug). - Phase 3 makes one commit per touched repo, each on a branch with the same name (
fix/bug-xxx-slug). - Phase 5 opens one PR per touched repo and cross-links them (primary PR's body is created last so it can reference every sibling URL).
- Phase 6 merges in the order the repos are listed in
touched_repos:. If the bug report doesn't specify an order, use themerge_orderfrom.adlc/config.yml. - If this gets complicated (more than 2 touched repos, or ordering matters), consider promoting the bug into a full REQ and using
/proceedinstead.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

