|
| 1 | +--- |
| 2 | +description: Detailed technical reference for Bugbot (detection, markers, context, intent, autofix, do user request, permissions) |
| 3 | +alwaysApply: false |
| 4 | +--- |
| 5 | + |
| 6 | +# Bugbot – technical reference |
| 7 | + |
| 8 | +Bugbot has two main modes: **detection** (on push or single action) and **fix/do** (on issue comment or PR review comment). All Bugbot code lives under `src/usecase/steps/commit/bugbot/` and `src/usecase/steps/commit/` (DetectPotentialProblemsUseCase, user_request_use_case). |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## 1. Detection flow (push or single action) |
| 13 | + |
| 14 | +**Entry:** `CommitUseCase` (on push) calls `DetectPotentialProblemsUseCase`; or `SingleActionUseCase` when action is `detect_potential_problems_action`. |
| 15 | + |
| 16 | +**Steps:** |
| 17 | + |
| 18 | +1. **Guard:** OpenCode must be configured; `issueNumber !== -1`. |
| 19 | +2. **Load context:** `loadBugbotContext(param)` → issue comments + PR review comments parsed for markers; builds `existingByFindingId`, `issueComments`, `openPrNumbers`, `previousFindingsBlock`, `prContext`, `unresolvedFindingsWithBody`. Branch is `param.commit.branch` (or `options.branchOverride` when provided). PR context includes `prHeadSha`, `prFiles`, `pathToFirstDiffLine` for the first open PR. |
| 20 | +3. **Build prompt:** `buildBugbotPrompt(param, context)` – repo context, head/base branch, issue number, optional `ai-ignore-files`, and `previousFindingsBlock` (task 2: which previous findings are now resolved). OpenCode is asked to compute the diff itself and return `findings` + `resolved_finding_ids`. |
| 21 | +4. **Call OpenCode:** `askAgent(OPENCODE_AGENT_PLAN, prompt, BUGBOT_RESPONSE_SCHEMA)`. |
| 22 | +5. **Process response:** Filter findings: safe path (`isSafeFindingFilePath`), not in `ai-ignore-files` (`fileMatchesIgnorePatterns`), `meetsMinSeverity` (min from `bugbot-severity`), `deduplicateFindings`. Apply `applyCommentLimit(findings, bugbot-comment-limit)` → `toPublish`, `overflowCount`, `overflowTitles`. |
| 23 | +6. **Mark resolved:** `markFindingsResolved(execution, context, resolvedFindingIds, normalizedResolvedIds)` – for each existing finding in context whose id is in resolved set, update issue comment (and PR review comment if any) via `replaceMarkerInBody` to set `resolved:true`; if PR comment, call `resolveReviewThread` when applicable. |
| 24 | +7. **Publish:** `publishFindings(execution, context, toPublish, overflowCount?, overflowTitles?)` – for each finding: add or update **issue comment** (always); add or update **PR review comment** only when `finding.file` is in `prContext.prFiles` (using `pathToFirstDiffLine` when finding has no line). Each comment body is built with `buildCommentBody(finding, resolved)` and includes the **marker** `<!-- copilot-bugbot finding_id:"id" resolved:false -->`. Overflow: one extra issue comment summarizing excess findings. |
| 25 | + |
| 26 | +**Key paths (detection):** |
| 27 | + |
| 28 | +- `detect_potential_problems_use_case.ts` – orchestration |
| 29 | +- `load_bugbot_context_use_case.ts` – issue/PR comments, markers, previousFindingsBlock, prContext |
| 30 | +- `build_bugbot_prompt.ts` – prompt for plan agent (task 1: new findings, task 2: resolved ids) |
| 31 | +- `schema.ts` – BUGBOT_RESPONSE_SCHEMA (findings, resolved_finding_ids) |
| 32 | +- `marker.ts` – BUGBOT_MARKER_PREFIX, buildMarker, parseMarker, replaceMarkerInBody, extractTitleFromBody, buildCommentBody |
| 33 | +- `publish_findings_use_case.ts` – add/update issue comment, create/update PR review comment |
| 34 | +- `mark_findings_resolved_use_case.ts` – update comment body with resolved marker, resolve PR thread |
| 35 | +- `severity.ts`, `file_ignore.ts`, `path_validation.ts`, `limit_comments.ts`, `deduplicate_findings.ts` |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## 2. Marker format and context |
| 40 | + |
| 41 | +**Marker:** Hidden HTML comment in every finding comment (issue and PR): |
| 42 | + |
| 43 | +`<!-- copilot-bugbot finding_id:"<id>" resolved:true|false -->` |
| 44 | + |
| 45 | +- **Parse:** `parseMarker(body)` returns `{ findingId, resolved }[]`. Used when loading context from issue comments and PR review comments. |
| 46 | +- **Build:** `buildMarker(findingId, resolved)`. IDs are sanitized (`sanitizeFindingIdForMarker`) so they cannot break HTML (no `-->`, `<`, `>`, newlines, etc.). |
| 47 | +- **Update:** `replaceMarkerInBody(body, findingId, newResolved)` – used when marking a finding as resolved (same comment, body updated with `resolved:true`). |
| 48 | + |
| 49 | +**Context (`BugbotContext`):** |
| 50 | + |
| 51 | +- `existingByFindingId[id]`: `{ issueCommentId?, prCommentId?, prNumber?, resolved }` – from parsing all issue + PR comments for markers. |
| 52 | +- `issueComments`: raw list from API (for body when building previousFindingsBlock / unresolvedFindingsWithBody). |
| 53 | +- `openPrNumbers`, `previousFindingsBlock`, `prContext` (prHeadSha, prFiles, pathToFirstDiffLine), `unresolvedFindingsWithBody`: `{ id, fullBody }[]` for findings that are not resolved (body truncated to MAX_FINDING_BODY_LENGTH when loading). |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +## 3. Fix intent and file-modifying actions (issue comment / PR review comment) |
| 58 | + |
| 59 | +**Entry:** `IssueCommentUseCase` or `PullRequestReviewCommentUseCase` (after language check). |
| 60 | + |
| 61 | +**Steps:** |
| 62 | + |
| 63 | +1. **Intent:** `DetectBugbotFixIntentUseCase.invoke(param)` |
| 64 | + - Guards: OpenCode configured, issue number set, comment body non-empty, branch (or branchOverride from `getHeadBranchForIssue` when commit.branch empty). |
| 65 | + - `loadBugbotContext(param, { branchOverride })` → unresolved findings. |
| 66 | + - Build `UnresolvedFindingSummary[]` (id, title from `extractTitleFromBody`, description = fullBody.slice(0, 4000)). |
| 67 | + - If PR review comment and `commentInReplyToId`: fetch parent comment body (`getPullRequestReviewCommentBody`), slice(0,1500).trim for prompt. |
| 68 | + - `buildBugbotFixIntentPrompt(commentBody, unresolvedFindings, parentCommentBody?)` → prompt asks: is_fix_request?, target_finding_ids?, is_do_request? |
| 69 | + - `askAgent(OPENCODE_AGENT_PLAN, prompt, BUGBOT_FIX_INTENT_RESPONSE_SCHEMA)` → `{ is_fix_request, target_finding_ids, is_do_request }`. |
| 70 | + - Payload: `isFixRequest`, `isDoRequest`, `targetFindingIds` (filtered to valid unresolved ids), `context`, `branchOverride`. |
| 71 | + |
| 72 | +2. **Permission:** `ProjectRepository.isActorAllowedToModifyFiles(owner, actor, token)`. |
| 73 | + - If owner is Organization: `orgs.checkMembershipForUser` (204 = allowed). |
| 74 | + - If owner is User: allowed only if `actor === owner`. |
| 75 | + |
| 76 | +3. **Branch A – Bugbot autofix** (when `canRunBugbotAutofix(payload)` and `allowedToModifyFiles`): |
| 77 | + - `BugbotAutofixUseCase.invoke({ execution, targetFindingIds, userComment, context, branchOverride })` |
| 78 | + - Load context if not provided; filter targets to valid unresolved ids; `buildBugbotFixPrompt(...)` with repo, findings block (truncated fullBody per finding), user comment, verify commands; `copilotMessage(ai, prompt)` (build agent). |
| 79 | + - If success: `runBugbotAutofixCommitAndPush(execution, { branchOverride, targetFindingIds })` – optional checkout if branchOverride, run verify commands (from `getBugbotFixVerifyCommands`, max 20), git add/commit/push (message `fix(#N): bugbot autofix - resolve ...`). |
| 80 | + - If committed and context: `markFindingsResolved({ execution, context, resolvedFindingIds, normalizedResolvedIds })`. |
| 81 | + |
| 82 | +4. **Branch B – Do user request** (when `!runAutofix && canRunDoUserRequest(payload)` and `allowedToModifyFiles`): |
| 83 | + - `DoUserRequestUseCase.invoke({ execution, userComment, branchOverride })` |
| 84 | + - `buildUserRequestPrompt(execution, userComment)` – repo context + sanitized user request; `copilotMessage(ai, prompt)`. |
| 85 | + - If success: `runUserRequestCommitAndPush(execution, { branchOverride })` – same verify/checkout/add/commit/push with message `chore(#N): apply user request` or `chore: apply user request`. |
| 86 | + |
| 87 | +5. **Think** (when no file-modifying action ran): `ThinkUseCase.invoke(param)` – answers the user (e.g. question). |
| 88 | + |
| 89 | +**Key paths (fix/do):** |
| 90 | + |
| 91 | +- `detect_bugbot_fix_intent_use_case.ts` – intent detection, branch resolution for issue_comment |
| 92 | +- `build_bugbot_fix_intent_prompt.ts` – prompt for is_fix_request / is_do_request / target_finding_ids |
| 93 | +- `bugbot_fix_intent_payload.ts` – getBugbotFixIntentPayload, canRunBugbotAutofix, canRunDoUserRequest |
| 94 | +- `schema.ts` – BUGBOT_FIX_INTENT_RESPONSE_SCHEMA (is_fix_request, target_finding_ids, is_do_request) |
| 95 | +- `bugbot_autofix_use_case.ts` – build prompt, copilotMessage (build agent) |
| 96 | +- `build_bugbot_fix_prompt.ts` – fix prompt (findings block, verify commands, truncate finding body to MAX_FINDING_BODY_LENGTH) |
| 97 | +- `bugbot_autofix_commit.ts` – runBugbotAutofixCommitAndPush, runUserRequestCommitAndPush (checkout, verify commands max 20, git config, add, commit, push) |
| 98 | +- `user_request_use_case.ts` – DoUserRequestUseCase, buildUserRequestPrompt |
| 99 | +- `mark_findings_resolved_use_case.ts` – update issue/PR comment with resolved marker |
| 100 | +- `project_repository.ts` – isActorAllowedToModifyFiles |
| 101 | + |
| 102 | +--- |
| 103 | + |
| 104 | +## 4. Configuration (inputs / Ai model) |
| 105 | + |
| 106 | +- **bugbot-severity:** Minimum severity to publish (info, low, medium, high). Default low. `getBugbotMinSeverity()`, `normalizeMinSeverity`, `meetsMinSeverity`. |
| 107 | +- **bugbot-comment-limit:** Max individual finding comments per issue/PR (overflow gets one summary). Default 20. `getBugbotCommentLimit()`, `applyCommentLimit`. |
| 108 | +- **bugbot-fix-verify-commands:** Comma-separated commands run after autofix (and do user request) before commit. `getBugbotFixVerifyCommands()`, parsed with shell-quote; max 20 executed. Stored in `Ai` model; read in `github_action.ts` / `local_action.ts`. |
| 109 | +- **ai-ignore-files:** Exclude paths from detection (and from reporting). Used in buildBugbotPrompt and in filtering findings. |
| 110 | + |
| 111 | +--- |
| 112 | + |
| 113 | +## 5. Constants and types |
| 114 | + |
| 115 | +- `BUGBOT_MARKER_PREFIX`: `'copilot-bugbot'` |
| 116 | +- `BUGBOT_MAX_COMMENTS`: 20 (default limit) |
| 117 | +- `MAX_FINDING_BODY_LENGTH`: 12000 (truncation when loading context and in build_bugbot_fix_prompt) |
| 118 | +- `MAX_VERIFY_COMMANDS`: 20 (in bugbot_autofix_commit) |
| 119 | +- Types: `BugbotContext`, `BugbotFinding` (id, title, description, file?, line?, severity?, suggestion?), `UnresolvedFindingSummary`, `BugbotFixIntentPayload`. |
| 120 | + |
| 121 | +--- |
| 122 | + |
| 123 | +## 6. Sanitization and safety |
| 124 | + |
| 125 | +- **User comment in prompts:** `sanitizeUserCommentForPrompt(raw)` – trim, escape backslashes, replace `"""`, truncate 4000 with no lone trailing backslash. |
| 126 | +- **Finding body in prompts:** `truncateFindingBody(body, MAX_FINDING_BODY_LENGTH)` with suffix `[... truncated for length ...]` (used in load_bugbot_context and build_bugbot_fix_prompt). |
| 127 | +- **Verify commands:** Parsed with shell-quote; no shell operators (;, |, etc.); max 20 run. |
| 128 | +- **Path:** `isSafeFindingFilePath` (no null byte, no `..`, no absolute); PR review comment only if file in `prFiles`. |
0 commit comments