Fix a bug or problem. Supports fix-now or plan-first; no args executes FIX_PLAN.md. When a regression check is needed, reproduce first, then implement and rerun it. Adds logging and suggests extra coverage.
58
68%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./skills/aif-fix/SKILL.mdFix a specific bug or problem in the codebase. Supports two modes: immediate fix or plan-first approach. The default workflow is regression-first whenever a regression check is needed: reproduce the problem, confirm the reported behavior, implement the fix, then verify the same check passes.
A regression check is the smallest useful test, command, fixture, API call, browser scenario, script, or documented manual/runtime reproduction that proves the reported bug or validates the expected behavior.
When a bug needs regression coverage, every workflow path (fix-now, plan-first, and existing-plan execution) follows this policy:
Fallback behavior:
HANDOFF_MODE=1, continue only when investigation found a plausible root cause that can be fixed safely; otherwise report the task as blocked/unreproducible and stop without changing implementation code. In manual mode, ask whether to proceed with the likely fix, adjust reproduction, or investigate further.HANDOFF_MODE=1 or manual-mode fallback above.Do not duplicate or weaken this policy in later workflow sections. Later steps should reference this section and add only local execution details.
Determine Handoff mode, task ID, and skip-review flag. If the caller passed HANDOFF_MODE, HANDOFF_TASK_ID, and HANDOFF_SKIP_REVIEW as explicit text in the prompt, use those values. Otherwise, use the Bash tool:
Bash: printenv HANDOFF_MODE || true
Bash: printenv HANDOFF_TASK_ID || true
Bash: printenv HANDOFF_SKIP_REVIEW || trueThen check HANDOFF_MODE:
HANDOFF_MODE is 1 (autonomous Handoff agent)The Handoff coordinator already manages status transitions and DB writes directly. Do NOT call MCP tools. Instead:
AskUserQuestion. If $ARGUMENTS contains --plan-first, use "Plan first" mode. Otherwise default to "Fix now" mode. When a regression check is needed for the bug, include regression-first handling and logging.HANDOFF_TASK_ID is non-empty, you MUST insert <!-- handoff:task:<HANDOFF_TASK_ID> --> as the very first line of the fix plan file, before the title. Omitting this annotation when HANDOFF_TASK_ID is set is a bug — verify before completing. This applies to both Step 1.1 (creating new plan) and any plan rewrite.HANDOFF_MODE is NOT 1 (manual Claude Code session)Handoff sync is handled inline — see Step 0.1 (after reading the fix plan file) for the task ID extraction and MCP sync trigger. The sync points are:
"planning" → "plan_ready" (after save)"implementing" (Step 2 entry) → "done" if HANDOFF_SKIP_REVIEW=1, else "review" (Step 5)"implementing" (Step 0.1) → "done" if HANDOFF_SKIP_REVIEW=1, else "review" (Step 5)CRITICAL: Always pass paused: true with every handoff_sync_status call except done.
When creating a new FIX_PLAN.md: if there is no existing annotation and no Handoff context, do not add the annotation.
FIRST: Read .ai-factory/config.yaml if it exists to resolve:
paths.description, paths.architecture, paths.rules_file, paths.rules, paths.research, paths.fix_plan, and paths.patches; derive research_bundles_dir = <parent directory of paths.research>/research/language.ui for prompts and summaries, language.artifacts for FIX_PLAN.md and patch artifacts, and language.technical_terms for human-readable technical terminology in artifactsrules.base plus any named rules.<area> entriesIf config.yaml doesn't exist, use defaults:
.ai-factory/DESCRIPTION.md.ai-factory/ARCHITECTURE.md.ai-factory/RULES.md.ai-factory/rules/.ai-factory/RESEARCH.md.ai-factory/FIX_PLAN.md.ai-factory/patches/ui_language: enartifact_language: entechnical_terms_policy: keepResolved language values:
ui_language = language.ui || "en"artifact_language = language.artifacts || language.ui || "en"technical_terms_policy = language.technical_terms || "keep"If technical_terms_policy is not one of keep, translate, or mixed, treat it as keep. Legacy values such as english also behave like keep.
All AskUserQuestion prompts, progress updates, fix summaries, test prompts, and next-step guidance MUST be written in ui_language.
Generated FIX_PLAN.md and self-improvement patch files under paths.patches MUST be written in artifact_language.
Templates and examples define structure, not fixed English output. If artifact_language is not en, translate human-readable headings, labels, analysis text, fix checklist entries, risks, prevention notes, and patch prose before saving. Preserve Handoff annotations, markdown structure, checkbox syntax, paths, commands, config keys, code identifiers, package names, API names, raw error messages, code snippets, log prefixes such as [FIX], and patch tags unchanged. Keep ## Research Context, Source:, Active Summary, Updated:, and SHA256: exact because downstream research drift checks parse them as compatibility tokens. Apply technical_terms_policy to other human-readable terminology.
BEFORE anything else after config resolution, check the resolved fix plan path (default: .ai-factory/FIX_PLAN.md).
If the file EXISTS:
## Research Context, treat its embedded copy as the committed requirements snapshot. Parse the first Source: / Reference: line with canonical ^(?:Source|Reference):\s+\x60([^\x60]+)\x60\s+\( syntax; for older bare-path lines, fall back to ^(?:Source|Reference):\s+(.+?)\s+\(. Fall back to configured paths.research only when neither form identifies a usable path.research_bundles_dir, require its sibling INDEX.md to contain <!-- aif:research-mode:ultra --> exactly once and link that RESEARCH.md from ## Artifact Index; otherwise emit WARN [research-drift]. Valid sibling C4/ADR/dependency artifacts are rationale only.SHA256: is present, extract the current source text strictly between <!-- aif:active-summary:start --> and <!-- aif:active-summary:end -->, remove HTML comment blocks, preserve line order and leading whitespace, trim trailing spaces from every line, use LF endings, and end with one newline. Hash through stdin with shasum -a 256 or sha256sum; the digest is authoritative. Use Updated: only as a legacy fallback when SHA256: is absent. A missing/invalid source or revision mismatch emits WARN [research-drift]; execute against the embedded Research Context unless the user explicitly requests a rebase.<!-- handoff:task:<uuid> -->:
HANDOFF_MODE is NOT 1 (manual session): extract the task ID. Call handoff_sync_status with { taskId: <extracted-id>, newStatus: "implementing", sourceTimestamp: "<current UTC time in ISO 8601 format>", direction: "aif_to_handoff", paused: true }. (Status is "implementing" because we are executing an existing plan, not creating one.)HANDOFF_MODE is 1: the Handoff coordinator handles sync — do nothing..ai-factory/FIX_PLAN.md:
rm .ai-factory/FIX_PLAN.mdpaths.fix_plan value, an explicitly supplied custom plan path, or any non-default fix plan location, do not delete it. Leave it in place and mention in the final summary that the custom fix plan was preserved.If the file DOES NOT exist AND $ARGUMENTS is empty:
/aif-fix <description>) or create a fix plan first."If the file DOES NOT exist AND $ARGUMENTS is provided:
THEN: Read .ai-factory/DESCRIPTION.md (use path from config) if it exists to understand:
Also read .ai-factory/ARCHITECTURE.md (use path from config), the resolved RULES.md path, and the configured rules hierarchy when present to avoid fixes that violate project structure or local conventions.
Read .ai-factory/skill-context/aif-fix/SKILL.md — MANDATORY if the file exists.
This file contains project-specific rules accumulated by /aif-evolve from patches,
codebase conventions, and tech-stack analysis. These rules are tailored to the current project.
How to apply skill-context rules:
Enforcement: After generating any output artifact, verify it against all skill-context rules. If any rule is violated — fix the output before presenting it to the user.
Patch fallback (limited, only when skill-context is missing):
.ai-factory/skill-context/aif-fix/SKILL.md does not exist and the resolved patches dir exists:
Glob to find *.md files in <resolved patches dir>From $ARGUMENTS, identify:
If unclear, ask:
To fix this effectively, I need more context:
1. What is the expected behavior?
2. What actually happens?
3. Can you share the error message/stack trace?
4. When did this start happening?After understanding the problem, ask the user to choose a mode using AskUserQuestion:
Question: "How would you like to proceed with the fix?"
Options:
Based on choice:
Handoff sync (manual mode only): If a Handoff task ID is known (from HANDOFF_TASK_ID or an existing annotation) AND HANDOFF_MODE is NOT 1, call handoff_sync_status with { taskId: <id>, newStatus: "planning", sourceTimestamp: "<current UTC time in ISO 8601 format>", direction: "aif_to_handoff", paused: true }.
Investigate the codebase enough to understand the problem and create a plan.
Use the same parallel exploration approach as Step 2 — launch Explore agents to investigate the problem area, related code, and past patterns simultaneously.
If the resolved research path exists, read it before creating the fix plan. Also check direct child bundles under research_bundles_dir, but recognize one as active only when INDEX.md contains <!-- aif:research-mode:ultra --> exactly once, declares Status: active, and links its RESEARCH.md from ## Artifact Index. Select at most one clearly bug-relevant source: explicit concrete path, then exact slug, normalized Topic:, or unique semantic match, then the relevant legacy file; never use recency. When the selected Active Summary influences the planned fix, copy it into ## Research Context and include Source: `<selected research path>` (Active Summary, Updated: <research Updated timestamp>, SHA256: <sha256 of copied Active Summary>). If research is unrelated, omit the section.
When adding ## Research Context to a fix plan, use the same normalization algorithm as the drift check. Calculate the digest without a temporary repository artifact: feed the normalized text through stdin / inline shell input to shasum -a 256; if unavailable, use sha256sum. Use the first output field as SHA256:.
After agents return, synthesize findings to:
Then create the resolved fix plan file (default: .ai-factory/FIX_PLAN.md).
Write the fix plan in artifact_language. The template below is the required structure only; translate human-readable headings, labels, and prose before saving when artifact_language is not en, while preserving stable technical tokens from Step 0.
Before writing: If HANDOFF_MODE is 1 and HANDOFF_TASK_ID is non-empty, the very first line of the file MUST be <!-- handoff:task:<HANDOFF_TASK_ID> --> followed by a blank line, then the plan content below. If in manual mode and a task ID was extracted from an existing annotation, preserve it.
Structure:
# Fix Plan: [Brief title]
**Problem:** [What's broken — from user's description]
**Created:** YYYY-MM-DD HH:mm
## Analysis
What was found during investigation:
- Root cause (or suspected root cause)
- Affected files and functions
- Impact scope
## Fix Checklist
Checklist entries for implementing the fix:
1. [ ] Apply the Canonical Regression-First Policy: add or identify the minimal regression check, or record why no useful check exists
2. [ ] Run the regression check and confirm it reproduces the reported problem, or record the fallback outcome from the policy
3. [ ] Implement the smallest fix for the root cause
4. [ ] Rerun the same regression check and confirm it passes when a rerunnable check exists
5. [ ] Run the closest related existing checks when practical
## Files to Modify
- `path/to/file.ts` — what changes are needed
- `path/to/another.ts` — what changes are needed
## Risks & Considerations
- Potential side effects
- Things to verify after the fix
- Edge cases to watch for
## Test Coverage
- Minimal regression check to confirm the bug before implementation
- Command/check to run before and after the fix
- Additional edge cases worth covering after the regression check passes
## Research Context (optional)
Include only when this fix plan is based on `RESEARCH.md`.
Source: `<selected research path>` (Active Summary, Updated: YYYY-MM-DD HH:MM, SHA256: <active-summary-sha256>)Use the normalization and stdin hashing rules from Step 1.1 when filling SHA256:.
After creating the plan, output:
## Fix Plan Created ✅
Plan saved to the resolved fix plan path.
Review the plan and when you're ready to execute, run:
/aif-fixHandoff sync (manual mode only): If a Handoff task ID is known AND HANDOFF_MODE is NOT 1, call handoff_push_plan with { taskId: <id>, planContent: <full fix plan text> }, then handoff_sync_status with { taskId: <id>, newStatus: "plan_ready", sourceTimestamp: "<current UTC time in ISO 8601 format>", direction: "aif_to_handoff", paused: true }.
STOP here. Do NOT apply the fix.
Handoff sync (manual mode, "Fix now" path only): If a Handoff task ID is known AND HANDOFF_MODE is NOT 1, call handoff_sync_status with { taskId: <id>, newStatus: "implementing", sourceTimestamp: "<current UTC time in ISO 8601 format>", direction: "aif_to_handoff", paused: true }.
Use Task tool with subagent_type: Explore to investigate the problem in parallel. This keeps the main context clean and allows simultaneous investigation of multiple angles.
Launch 2-3 Explore agents simultaneously:
Agent 1 — Locate the problem area:
Task(subagent_type: Explore, model: sonnet, prompt:
"Find code related to [error location / affected functionality].
Read the relevant functions, trace the data flow.
Thoroughness: medium.")
Agent 2 — Related code & side effects:
Task(subagent_type: Explore, model: sonnet, prompt:
"Find all callers/consumers of [affected function/module].
Identify what else might break or be affected.
Thoroughness: medium.")
Agent 3 — Similar past patterns (if patches exist):
Task(subagent_type: Explore, model: sonnet, prompt:
"Search for similar error patterns or related fixes in the codebase.
Check git log for recent changes to [affected files].
Thoroughness: quick.")After agents return, synthesize findings to identify:
Fallback: If Task tool is unavailable, investigate directly:
Apply the Canonical Regression-First Policy before changing implementation code. Prefer a regression check for behavior bugs, parsing/validation bugs, API/data bugs, crashes, and regressions. If the change is a non-bug cleanup, purely static correction, or investigation-only request, record why the policy does not apply and continue with the normal fix workflow.
Anti-gaming rule: Do not tailor the test to the implementation you plan to write. The test must describe the externally expected behavior or the reported failure condition. If the test passes before any fix, either the reproduction is wrong, the bug is stale, or the environment differs; handle that mismatch through the fallback behavior in the Canonical Regression-First Policy before changing implementation code.
Record the selected regression check, pre-fix result, and any fallback decision in your working notes so Step 4 can rerun or revisit the same check after the fix.
Apply the fix with logging:
// ✅ REQUIRED: Add logging around the fix
console.log("[FIX] Processing user input", { userId, input });
try {
// The actual fix
const result = fixedLogic(input);
console.log("[FIX] Success", { userId, result });
return result;
} catch (error) {
console.error("[FIX] Error in fixedLogic", {
userId,
input,
error: error.message,
stack: error.stack,
});
throw error;
}Logging is MANDATORY because:
Handoff sync (manual mode ONLY — skip entirely when HANDOFF_MODE is 1): If a Handoff task ID is known AND HANDOFF_MODE is NOT 1:
handoff_push_plan with { taskId: <id>, planContent: <fix summary or updated plan> }.HANDOFF_SKIP_REVIEW is 1: call handoff_sync_status with { taskId: <id>, newStatus: "done", sourceTimestamp: "<current UTC time in ISO 8601 format>", direction: "aif_to_handoff", paused: false }.handoff_sync_status with { taskId: <id>, newStatus: "review", sourceTimestamp: "<current UTC time in ISO 8601 format>", direction: "aif_to_handoff", paused: true }.ALWAYS suggest additional test coverage:
The Step 5 and After Fixing output templates define structure only. Render all human-readable text in these user-facing responses in ui_language. Preserve code snippets, commands, file paths, line references, log prefixes such as [FIX], and AskUserQuestion option structure unchanged.
## Fix Applied ✅
The issue was: [brief explanation]
Fixed by: [what was changed]
### Logging Added
The fix includes logging with prefix `[FIX]`.
Please test and share any logs if issues persist.
### Recommended: Add More Test Coverage
If a regression check was created or identified in Step 2.5, this bug is now covered. Consider adding broader coverage to prevent nearby regressions:
\`\`\`typescript
describe('functionName', () => {
it('should handle [the edge case that caused the bug]', () => {
// Arrange
const input = /* the problematic input */;
// Act
const result = functionName(input);
// Assert
expect(result).toBe(/* expected */);
});
});
\`\`\`
AskUserQuestion: Would you like me to create the additional test coverage?
Options:
1. Yes, create the test
2. No, skip for nowHandling the user's response:
If "Yes, create the test":
If "No, skip for now":
All fixes MUST include logging:
[FIX] or [FIX:<issue-id>] for easy filtering// Pattern for fixes
const LOG_FIX = process.env.LOG_LEVEL === "debug" || process.env.DEBUG_FIX;
function fixedFunction(input) {
if (LOG_FIX) console.log("[FIX] Input:", input);
// ... fix logic ...
if (LOG_FIX) console.log("[FIX] Output:", result);
return result;
}User: /aif-fix TypeError: Cannot read property 'name' of undefined in UserProfile
Actions:
.name is accessedUser: /aif-fix /api/orders returns empty array for authenticated users
Actions:
User: /aif-fix email validation accepts invalid emails
Actions:
.ai-factory/FIX_PLAN.md; preserve custom/non-default fix plan files./aif-fix owns paths.fix_plan and paths.patches; treat .ai-factory/DESCRIPTION.md, roadmap, rules, and architecture context artifacts as read-only unless the user explicitly requests otherwise[FIX] logging requirements for fixes; context-gate outputs in this command should use WARN/ERROR and must not change global logging policy in other skillsUse this output template in Step 5 (before the AskUserQuestion about additional tests):
## Fix Applied ✅
**Issue:** [what was broken]
**Cause:** [why it was broken]
**Fix:** [what was changed]
**Regression check:** [command/check and result, manual/runtime reproduction result, or "not available: <reason>"]
**Files modified:**
- path/to/file.ts (line X)
**Logging added:** Yes, prefix `[FIX]`ALWAYS create a patch after every fix. This builds a knowledge base for future fixes.
Create the patch:
Create directory if it doesn't exist:
mkdir -p <resolved patches dir>Create a patch file with the current timestamp as filename.
Format: YYYY-MM-DD-HH.mm.md (e.g., 2026-02-07-14.30.md)
Use this template:
Write the patch artifact in artifact_language. The template below is the required structure only; translate human-readable headings, labels, root-cause text, solution text, and prevention text before saving when artifact_language is not en, while preserving stable technical tokens from Step 0.
# [Brief title describing the fix]
**Date:** YYYY-MM-DD HH:mm
**Files:** list of modified files
**Severity:** low | medium | high | critical
## Problem
What was broken. How it manifested (error message, wrong behavior).
Be specific — include the actual error or symptom.
## Root Cause
WHY the problem occurred. This is the most valuable part.
Not "what was wrong" but "why it was wrong":
- Logic error? Why was the logic incorrect?
- Missing check? Why was it missing?
- Wrong assumption? What was assumed?
- Race condition? What sequence caused it?
## Solution
How the fix was implemented. Key code changes and reasoning.
Include the approach, not just "changed line X".
## Prevention
How to prevent this class of problems in the future:
- What pattern/practice should be followed?
- What should be checked during code review?
- What test would catch this?
## Tags
Space-separated tags for categorization, e.g.:
`#null-check` `#async` `#validation` `#typescript` `#api` `#database`Example patch:
# Null reference in UserProfile when user has no avatar
**Date:** 2026-02-07 14:30
**Files:** src/components/UserProfile.tsx
**Severity:** medium
## Problem
TypeError: Cannot read property 'url' of undefined when rendering
UserProfile for users without an uploaded avatar.
## Root Cause
The `user.avatar` field is optional in the database schema but the
component accessed `user.avatar.url` without a null check. This was
introduced in commit abc123 when avatar display was added — the
developer tested only with users that had avatars.
## Solution
Added optional chaining: `user.avatar?.url` with a fallback to a
default avatar URL. Also added a null check in the Avatar sub-component.
## Prevention
- Always check if database fields marked as `nullable` / `optional`
are handled with null checks in the UI layer
- Add test cases for "empty state" — user with minimal data
- Consider a lint rule for accessing nested optional properties
## Tags
`#null-check` `#react` `#optional-field` `#typescript`This is NOT optional. Every fix generates a patch. The patch is your learning.
Suggest the user to free up context space if needed: /clear (full reset) or /compact (compress history).
DO NOT:
.ai-factory/FIX_PLAN.md after successful fix executionac92beb
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.