try-fix
npx skills add https://github.com/dotnet/maui --skill try-fix
Agent 安装分布
Skill 文档
Try Fix Skill
Attempts ONE fix for a given problem. Receives all context upfront, tries a single approach, tests it, and reports what happened.
Core Principles
- Always run – Never question whether to run. The invoker decides WHEN, you decide WHAT alternative to try
- Single-shot – Each invocation = ONE fix idea, tested, reported
- Alternative-focused – Always propose something DIFFERENT from existing fixes (review PR changes first)
- Empirical – Actually implement and test, don’t just theorize
- Context-driven – All information provided upfront; don’t search for additional context
Every invocation: Review existing fixes â Think of DIFFERENT approach â Implement and test â Report results
â ï¸ CRITICAL: Sequential Execution Only
ð¨ Try-fix runs MUST be executed ONE AT A TIME – NEVER in parallel.
Why: Each try-fix run:
- Modifies the same source files (SafeAreaExtensions.cs, etc.)
- Uses the same device/emulator for testing
- Runs EstablishBrokenBaseline.ps1 which reverts files to a known state
If run in parallel:
- Multiple agents will overwrite each other’s code changes
- Device tests will interfere with each other
- Baseline script will conflict, causing unpredictable file states
- Results will be corrupted and unreliable
Correct pattern: Run attempt-1, wait for completion, then run attempt-2, etc.
Inputs
All inputs are provided by the invoker (CI, agent, or user).
| Input | Required | Description |
|---|---|---|
| Problem | Yes | Description of the bug/issue to fix |
| Test command | Yes | Repository-specific script to build, deploy, and test (e.g., pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform android -TestFilter "Issue12345"). ALWAYS use this script – NEVER manually build/compile. |
| Target files | Yes | Files to investigate for the fix |
| Platform | Yes | Target platform (android, ios, windows, maccatalyst) |
| Hints | Optional | Suggested approaches, prior attempts, or areas to focus on |
| Baseline | Optional | Git ref or instructions for establishing broken state (default: current state) |
| state_file | Optional | Path to PR agent state file (e.g., CustomAgentLogsTmp/PRState/pr-12345.md). If provided, try-fix will append its results to the Fix Candidates table. |
Outputs
Results reported back to the invoker:
| Field | Description |
|---|---|
approach |
What fix was attempted (brief description) |
files_changed |
Which files were modified |
result |
Pass, Fail, or Blocked |
analysis |
Why it worked, or why it failed and what was learned |
diff |
The actual code changes made (for review) |
Output Structure (MANDATORY)
FIRST STEP: Create output directory before doing anything else.
# Set issue/PR number explicitly (from branch name, PR context, or manual input)
$IssueNumber = "<ISSUE_OR_PR_NUMBER>" # Replace with actual number
# Find next attempt number
$tryFixDir = "CustomAgentLogsTmp/PRState/$IssueNumber/try-fix"
$existingAttempts = (Get-ChildItem "$tryFixDir/attempt-*" -Directory -ErrorAction SilentlyContinue).Count
$attemptNum = $existingAttempts + 1
# Create output directory
$OUTPUT_DIR = "$tryFixDir/attempt-$attemptNum"
New-Item -ItemType Directory -Path $OUTPUT_DIR -Force | Out-Null
Write-Host "Output directory: $OUTPUT_DIR"
Required files to create in $OUTPUT_DIR:
| File | When to Create | Content |
|---|---|---|
baseline.log |
After Step 2 (Baseline) | Output from EstablishBrokenBaseline.ps1 proving baseline was established |
approach.md |
After Step 4 (Design) | What fix you’re attempting and why it’s different from existing fixes |
result.txt |
After Step 6 (Test) | Single word: Pass, Fail, or Blocked |
fix.diff |
After Step 6 (Test) | Output of git diff showing your changes |
test-output.log |
After Step 6 (Test) | Full output from test command |
analysis.md |
After Step 6 (Test) | Why it worked/failed, insights learned |
Example approach.md:
## Approach: Geometric Off-Screen Check
Skip RequestApplyInsets for views completely off-screen using simple bounds check:
`viewLeft >= screenWidth || viewRight <= 0 || viewTop >= screenHeight || viewBottom <= 0`
**Different from existing fix:** Current fix uses HashSet tracking. This approach uses pure geometry with no state.
Example result.txt:
Pass
Completion Criteria
The skill is complete when:
- Problem understood from provided context
- ONE fix approach designed and implemented
- Fix tested with provided test command (iterated up to 3 times if errors/failures)
- Either: Tests PASS â , or exhausted attempts and documented why approach won’t work â
- Analysis provided (success explanation or failure reasoning with evidence)
- Artifacts saved to output directory
- Baseline restored (working directory clean)
- Results reported to invoker
ð¨ CRITICAL: What counts as “Pass” vs “Fail”
| Scenario | Result | Explanation |
|---|---|---|
| Test command runs, tests pass | â Pass | Actual validation |
| Test command runs, tests fail | â Fail | Fix didn’t work |
| Code compiles but no device available | â ï¸ Blocked | Device/emulator unavailable – report with explanation |
| Code compiles but test command errors | â Fail | Infrastructure issue is still a failure |
| Code doesn’t compile | â Fail | Fix is broken |
NEVER claim “Pass” based on:
- â “Code compiles successfully” alone
- â “Code review validates the logic”
- â “The approach is sound”
- â “Device was unavailable but fix looks correct”
Pass REQUIRES: The test command executed AND reported test success.
If device/emulator is unavailable: Report result.txt = Blocked with explanation. Do NOT manufacture a Pass.
Exhaustion criteria: Stop after 3 iterations if:
- Code compiles but tests consistently fail for same reason
- Root cause analysis reveals fundamental flaw in approach
- Alternative fixes would require completely different strategy
Never stop due to: Compile errors (fix them), infrastructure blame (debug your code), giving up too early.
Workflow
Step 1: Understand the Problem and Review Existing Fixes
MANDATORY: Review what has already been tried:
-
Check for existing PR changes:
git diff origin/main HEAD --name-only- Review what files were changed
- Read the actual code changes to understand the current fix approach
-
If state_file provided, review prior attempts:
- Read the Fix Candidates table
- Note which approaches failed and WHY (the Notes column)
- Note which approaches partially succeeded
-
Identify what makes your approach DIFFERENT:
- Don’t repeat the same logic/pattern as existing fixes
- Think of alternative approaches: different algorithm, different location, different strategy
- If existing fix modifies X, consider modifying Y instead
- If existing fix adds logic, consider removing/simplifying instead
Examples of alternatives:
- Existing fix: Add caching â Alternative: Change when updates happen
- Existing fix: Fix in handler â Alternative: Fix in platform layer
Review the provided context:
- What is the bug/issue?
- What test command verifies the fix?
- What files should be investigated?
- Are there hints about what to try or avoid?
Do NOT search for additional context. Work with what’s provided.
Step 2: Establish Baseline (MANDATORY)
ð¨ ALWAYS use EstablishBrokenBaseline.ps1 – NEVER manually revert files.
# Capture baseline output as proof it was run
pwsh .github/scripts/EstablishBrokenBaseline.ps1 *>&1 | Tee-Object -FilePath "$OUTPUT_DIR/baseline.log"
The script auto-detects and reverts fix files to merge-base state while preserving test files. Will fail fast if no fix files detected – you must be on the actual PR branch. Optional flags: -BaseBranch main, -DryRun.
Verify baseline was established:
# baseline.log should contain "Baseline established" and list of reverted files
Select-String -Path "$OUTPUT_DIR/baseline.log" -Pattern "Baseline established"
If the script fails with “No fix files detected”: You’re likely on the wrong branch. Checkout the actual PR branch with gh pr checkout <PR#> and try again.
If something fails mid-attempt: pwsh .github/scripts/EstablishBrokenBaseline.ps1 -Restore
Step 3: Analyze Target Files
Read the target files to understand the code.
Key questions:
- What is the root cause of this bug?
- Where should the fix go?
- What’s the minimal change needed?
Step 4: Design ONE Fix
Based on your analysis and any provided hints, design a single fix approach:
- Which file(s) to change
- What the change is
- Why you think this will work
If hints suggest specific approaches, prioritize those.
IMMEDIATELY create approach.md in your output directory:
@"
## Approach: [Brief Name]
[Description of what you're changing and why]
**Different from existing fix:** [How this differs from PR's current approach]
"@ | Set-Content "$OUTPUT_DIR/approach.md"
Step 5: Apply the Fix
Implement your fix. Use git status --short and git diff to track changes.
Step 6: Test and Iterate (MANDATORY)
ð¨ CRITICAL: ALWAYS use the provided test command script – NEVER manually build/compile.
For .NET MAUI repository: Use BuildAndRunHostApp.ps1 which handles:
- Building the project
- Deploying to device/simulator
- Running tests
- Capturing logs
# Capture output to test-output.log while also displaying it
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform <platform> -TestFilter "<filter>" *>&1 | Tee-Object -FilePath "$OUTPUT_DIR/test-output.log"
Testing Loop (Iterate until SUCCESS or exhausted):
- Run the test command – It will build, deploy, and test automatically
- Check the result:
- â Tests PASS â Move to Step 7 (Capture Artifacts)
- â Compile errors â Fix compilation issues (see below), go to step 1
- â Tests FAIL (runtime) â Analyze failure, fix code, go to step 1
- Maximum 3 iterations – If still failing after 3 attempts, analyze if approach is fundamentally flawed
- Document why – If exhausted, explain what you learned and why the approach won’t work
Behavioral constraints:
- â ï¸ NEVER blame “test infrastructure” – assume YOUR fix has a bug
- Compile errors mean “work harder” – not “give up”
- DO NOT manually build – always rerun the test command script
See references/compile-errors.md for error patterns and iteration examples.
Step 7: Capture Artifacts (MANDATORY)
Before reverting, save ALL required files to $OUTPUT_DIR:
# 1. Save result (MUST be exactly "Pass", "Fail", or "Blocked")
"Pass" | Set-Content "$OUTPUT_DIR/result.txt" # or "Fail"
# 2. Save the diff
git diff | Set-Content "$OUTPUT_DIR/fix.diff"
# 3. Save test output (should already exist from Step 6)
# Copy-Item "path/to/test-output.log" "$OUTPUT_DIR/test-output.log"
# 4. Save analysis
@"
## Analysis
**Result:** Pass/Fail/Blocked
**What happened:** [Description of test results]
**Why it worked/failed:** [Root cause analysis]
**Insights:** [What was learned that could help future attempts]
"@ | Set-Content "$OUTPUT_DIR/analysis.md"
Verify all required files exist:
@("baseline.log", "approach.md", "result.txt", "fix.diff", "analysis.md", "test-output.log") | ForEach-Object {
if (Test-Path "$OUTPUT_DIR/$_") { Write-Host "â
$_" }
else { Write-Host "â MISSING: $_" }
}
Analysis quality matters. Bad: “Didn’t work”. Good: “Fix attempted to reset state in OnPageSelected, but this fires after layout measurement. The cached value was already used.”
Step 8: Restore Working Directory (MANDATORY)
ALWAYS restore, even if fix failed.
pwsh .github/scripts/EstablishBrokenBaseline.ps1 -Restore
git checkout -- .
Step 9: Report Results
Provide structured output to the invoker:
## Try-Fix Result
**Approach:** [Brief description of what was tried]
**Files Changed:**
- `path/to/file.cs` (+X/-Y lines)
**Result:** â
PASS / â FAIL
**Analysis:**
[Why it worked, or why it failed and what was learned]
**Diff:**
```diff
[The actual changes made]
Exhausted: Yes/No Reasoning: [Why you believe there are/aren’t more viable approaches]
**Determining Exhaustion:** Set `exhausted=true` when you've tried the same fundamental approach multiple times, all hints have been explored, failure analysis reveals the problem is outside target files, or no new ideas remain. Set `exhausted=false` when this is the first attempt, failure analysis suggests a different approach, hints remain unexplored, or the approach was close but needs refinement.
### Step 10: Update State File (if provided)
If `state_file` input was provided and file exists:
1. **Read current Fix Candidates table** from state file
2. **Determine next attempt number** (count existing try-fix rows + 1)
3. **Append new row** with this attempt's results:
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|--------|----------|-------------|---------------|-------|
| N | try-fix #N | [approach] | â
PASS / â FAIL | [files] | [analysis] |
4. **Set exhausted status** based on your determination above
5. **Commit state file:**
```bash
git add "$STATE_FILE" && git commit -m "try-fix: attempt #N (exhausted=$EXHAUSTED)"
If no state file provided: Skip this step (results returned to invoker only).
Ownership rule: try-fix updates its own row AND the exhausted field. Never modify:
- Phase status fields
- “Selected Fix” field
- Other try-fix rows
Error Handling
| Situation | Action |
|---|---|
| Problem unclear | Report “insufficient context” – specify what’s missing |
| Test command fails to run | Report build/setup error with details |
| Test times out | Report timeout, include partial output |
| Can’t determine fix approach | Report “no viable approach identified” with reasoning |
| Git state unrecoverable | Run git checkout -- . and git clean -fd if needed |
Guidelines for Proposing Fixes
Good Fix Approaches
â Null/state checks – Guard against unexpected null or state â Lifecycle timing – Move code to correct lifecycle event â Cache invalidation – Reset stale cached values
Approaches to Avoid
â Massive refactors – Keep changes minimal â Suppressing symptoms – Fix root cause, not symptoms â Multiple unrelated changes – ONE focused fix per invocation
See references/example-invocation.md for a complete example with sample inputs.