Self-Healing
Pilot automatically learns from failures, retries intelligently, and prevents duplicate work β closing the loop between CI errors and fixes.
Self-healing combines CI pattern learning, automatic retry with decomposition, and merged PR detection to create a closed-loop fix pipeline.
CI Error Pattern Learning
When CI fails, Pilot extracts error patterns from logs and stores them for future reference. On subsequent failures, high-confidence patterns are injected into fix issue prompts β so Pilot doesnβt repeat the same mistakes.
How It Works
CI Failure β Extract Patterns β Store in PatternDB β Annotate Fix Issues β Smarter Fixes- Pattern extraction β
PatternExtractoranalyzes CI logs using 16 pre-compiled regex matchers - Categorization β errors are classified into categories (compilation, test, lint, dependency, runtime)
- Confidence boosting β recurring patterns get a 1.5Γ confidence boost (capped at 0.95)
- Injection β patterns with β₯0.75 confidence and β₯5 occurrences surface in fix issue bodies
Error Categories
| Category | Examples |
|---|---|
| Compilation | Type mismatches, undefined identifiers, syntax errors |
| Test Failures | Assertion failures, test timeouts, missing fixtures |
| Lint | Unused imports, unchecked errors, style violations |
| Dependency | Missing modules, version conflicts |
| Runtime | Nil pointer dereference, panics, deadlocks |
Pattern Lifecycle
Patterns start at 0.5 confidence when first extracted from CI logs. Each recurrence boosts confidence by 1.5Γ. Once a pattern reaches β₯0.75 confidence with β₯5 occurrences, it becomes a βhigh-value patternβ and is automatically included in fix issue prompts.
Anti-patterns (common mistakes found in review comments) are also tracked and injected to prevent regression.
Configuration
learning:
enabled: true
feedback_weight: 0.1 # Weight for new pattern observations
decay_rate: 0.01 # Confidence decay over timeRetry with Decomposition
When a task is killed (signal:killed) β typically due to running out of memory or exceeding time limits β Pilot can automatically decompose it into smaller subtasks and retry.
This feature is opt-in. Set retry.decompose_on_kill: true in your config to enable it.
How It Works
Task Killed β DecomposeForRetry() β Split into Subtasks β Re-executeDecomposeForRetry() bypasses all normal complexity gates β execution failure is proof the task is too large. It analyzes the task description for structural split points:
- Numbered steps β
1. ... 2. ... 3. ... - Bullet points β
- item,* item - Acceptance criteria β
[ ] checkbox items - File/module groups β groups by file extension or directory
Safeguards
- The
no-decomposelabel on an issue prevents decomposition (even on retry) - Maximum subtask count is configurable (default: 5, range: 2β10)
- Only the final subtask creates a PR β earlier subtasks commit to the same branch
Configuration
decompose:
enabled: true
min_complexity: complex # Minimum level to trigger (complex or epic)
max_subtasks: 5 # Maximum subtasks per decomposition
min_description_words: 50 # Word count gate (skipped when LLM confirms complexity)
retry:
decompose_on_kill: true # Enable retry-with-decomposition on signal:killedMerged PR Guard
Before dispatching a retry for a failed issue, Pilot checks whether work has already been merged. This prevents the infinite retry loop where Pilot keeps re-processing an issue whose PR was already merged but the issue was never closed.
How It Works
Issue Retry β hasMergedWork() β Search GitHub API β Skip if merged PR foundThe poller calls SearchMergedPRsForIssue() which queries the GitHub Search API:
repo:owner/repo GH-{issue_number} in:title is:pr is:mergedIf at least one merged PR matches, the issue is marked as done and skipped.
This guard catches the common case where a PR was merged but the originating issue was never closed β either due to a race condition, webhook failure, or manual merge without issue linking.
No Configuration Required
The merged PR guard runs automatically as part of the polling pipeline. No configuration is needed β it activates whenever the GitHub poller processes an issue.
Full Self-Healing Pipeline
These three mechanisms work together to create a closed-loop system:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Self-Healing Pipeline β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Issue β Execute β CI Fails β
β β β
β βββ Extract patterns from CI logs β
β β Store in PatternDB β
β β β
β βββ Create fix issue β
β β Annotate with learned patterns β
β β β
β βββ Pilot picks up fix issue β
β Uses patterns to avoid repeats β
β β
β Task Killed β DecomposeForRetry() β
β Split into smaller subtasks β
β Re-execute sequentially β
β β
β Retry Check β hasMergedWork() β
β Skip if PR already merged β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββDECLINED: Unactionable Task Handling
When Pilot determines that an issue cannot be implemented as written β for example, it contradicts the codebase design, references missing context, or is too ambiguous to act on safely β the executor emits a DECLINED result instead of creating a partial or broken PR. Pilot adds the pilot-needs-clarification label to the issue and posts a comment explaining what information is needed. The GitHub poller treats pilot-needs-clarification as a permanent skip: the issue will not be dispatched again until a human removes the label. Once removed, the issue re-enters the normal dispatch queue on the next poll cycle.
Related Features
- Autopilot β CI monitoring and auto-merge
- Epic Decomposition β task splitting for large issues
- Quality Gates β test/lint/build verification
- Memory & Learning β pattern storage and knowledge graph