terramend 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +145 -0
- package/dist/agents/claude.d.ts +73 -0
- package/dist/agents/claudePretoolGate.d.ts +99 -0
- package/dist/agents/gateServer.d.ts +7 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/nativeFsDenies.d.ts +28 -0
- package/dist/agents/opencode.d.ts +231 -0
- package/dist/agents/opencodePlugin.d.ts +85 -0
- package/dist/agents/opencodeShared.d.ts +40 -0
- package/dist/agents/postRun.d.ts +132 -0
- package/dist/agents/reviewer.d.ts +38 -0
- package/dist/agents/sessionLabeler.d.ts +97 -0
- package/dist/agents/shared.d.ts +189 -0
- package/dist/agents/subagentModels.d.ts +19 -0
- package/dist/agents/subagentToolGates.d.ts +55 -0
- package/dist/cli.mjs +197426 -0
- package/dist/external.d.ts +227 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +196783 -0
- package/dist/internal/index.d.ts +18 -0
- package/dist/internal.js +1714 -0
- package/dist/lifecycle.d.ts +2 -0
- package/dist/main.d.ts +8 -0
- package/dist/mcp/arkConfig.d.ts +1 -0
- package/dist/mcp/checkSuite.d.ts +25 -0
- package/dist/mcp/checkout.d.ts +77 -0
- package/dist/mcp/comment.d.ts +119 -0
- package/dist/mcp/commitInfo.d.ts +9 -0
- package/dist/mcp/crosswalk.d.ts +105 -0
- package/dist/mcp/dependencies.d.ts +8 -0
- package/dist/mcp/geminiSanitizer.d.ts +28 -0
- package/dist/mcp/git.d.ts +46 -0
- package/dist/mcp/guardrails.d.ts +104 -0
- package/dist/mcp/issue.d.ts +18 -0
- package/dist/mcp/issueComments.d.ts +9 -0
- package/dist/mcp/issueEvents.d.ts +9 -0
- package/dist/mcp/issueInfo.d.ts +9 -0
- package/dist/mcp/labels.d.ts +12 -0
- package/dist/mcp/localContext.d.ts +19 -0
- package/dist/mcp/moduleExtraction.d.ts +71 -0
- package/dist/mcp/moduleTests.d.ts +104 -0
- package/dist/mcp/modules.d.ts +179 -0
- package/dist/mcp/output.d.ts +12 -0
- package/dist/mcp/pathSafety.d.ts +14 -0
- package/dist/mcp/policy.d.ts +48 -0
- package/dist/mcp/pr.d.ts +49 -0
- package/dist/mcp/prInfo.d.ts +9 -0
- package/dist/mcp/providerSchema.d.ts +50 -0
- package/dist/mcp/review.d.ts +199 -0
- package/dist/mcp/reviewComments.d.ts +178 -0
- package/dist/mcp/roots.d.ts +58 -0
- package/dist/mcp/scope.d.ts +15 -0
- package/dist/mcp/selectMode.d.ts +18 -0
- package/dist/mcp/server.d.ts +48 -0
- package/dist/mcp/shared.d.ts +47 -0
- package/dist/mcp/shell.d.ts +37 -0
- package/dist/mcp/staleFix.d.ts +51 -0
- package/dist/mcp/terraform/cost.d.ts +55 -0
- package/dist/mcp/terraform/currency.d.ts +94 -0
- package/dist/mcp/terraform/decisions.d.ts +178 -0
- package/dist/mcp/terraform/findings.d.ts +75 -0
- package/dist/mcp/terraform/plan.d.ts +157 -0
- package/dist/mcp/terraform/scanners.d.ts +131 -0
- package/dist/mcp/terraform/tools.d.ts +63 -0
- package/dist/mcp/terraform/types.d.ts +172 -0
- package/dist/mcp/terraform.d.ts +22 -0
- package/dist/mcp/terratest.d.ts +83 -0
- package/dist/mcp/upload.d.ts +6 -0
- package/dist/models.d.ts +171 -0
- package/dist/modes.d.ts +26 -0
- package/dist/prep/index.d.ts +7 -0
- package/dist/prep/installNodeDependencies.d.ts +2 -0
- package/dist/prep/installPythonDependencies.d.ts +2 -0
- package/dist/prep/types.d.ts +31 -0
- package/dist/reviewQuality.d.ts +64 -0
- package/dist/skills/terraform-best-practices/SKILL.md +369 -0
- package/dist/toolState.d.ts +135 -0
- package/dist/utils/activity.d.ts +40 -0
- package/dist/utils/agent.d.ts +20 -0
- package/dist/utils/agentHangReport.d.ts +38 -0
- package/dist/utils/apiFetch.d.ts +19 -0
- package/dist/utils/apiKeys.d.ts +41 -0
- package/dist/utils/apiUrl.d.ts +20 -0
- package/dist/utils/assets.d.ts +8 -0
- package/dist/utils/billingErrors.d.ts +85 -0
- package/dist/utils/body.d.ts +34 -0
- package/dist/utils/buildTerramendFooter.d.ts +25 -0
- package/dist/utils/byokFallback.d.ts +85 -0
- package/dist/utils/claudeSubscription.d.ts +30 -0
- package/dist/utils/cli.d.ts +10 -0
- package/dist/utils/codexHome.d.ts +29 -0
- package/dist/utils/codexOAuth.d.ts +60 -0
- package/dist/utils/diffCoverage.d.ts +63 -0
- package/dist/utils/errorReport.d.ts +17 -0
- package/dist/utils/exitHandler.d.ts +8 -0
- package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
- package/dist/utils/gitAuth.d.ts +84 -0
- package/dist/utils/gitAuthServer.d.ts +24 -0
- package/dist/utils/github.d.ts +78 -0
- package/dist/utils/globals.d.ts +3 -0
- package/dist/utils/install.d.ts +60 -0
- package/dist/utils/instructions.d.ts +48 -0
- package/dist/utils/leapingComment.d.ts +11 -0
- package/dist/utils/learnings.d.ts +62 -0
- package/dist/utils/learningsTruncate.d.ts +25 -0
- package/dist/utils/lifecycle.d.ts +57 -0
- package/dist/utils/log.d.ts +111 -0
- package/dist/utils/normalizeEnv.d.ts +30 -0
- package/dist/utils/openCodeModels.d.ts +11 -0
- package/dist/utils/overrides.d.ts +40 -0
- package/dist/utils/packageManager.d.ts +49 -0
- package/dist/utils/patchWorkflowRunFields.d.ts +29 -0
- package/dist/utils/payload.d.ts +105 -0
- package/dist/utils/prSummary.d.ts +61 -0
- package/dist/utils/progressComment.d.ts +146 -0
- package/dist/utils/providerErrors.d.ts +31 -0
- package/dist/utils/rangeDiff.d.ts +51 -0
- package/dist/utils/remediationCommand.d.ts +55 -0
- package/dist/utils/retry.d.ts +13 -0
- package/dist/utils/reviewCleanup.d.ts +14 -0
- package/dist/utils/run.d.ts +9 -0
- package/dist/utils/runContext.d.ts +60 -0
- package/dist/utils/runContextData.d.ts +23 -0
- package/dist/utils/runErrorRenderer.d.ts +64 -0
- package/dist/utils/runLifecycle.d.ts +86 -0
- package/dist/utils/runStartupLog.d.ts +15 -0
- package/dist/utils/secrets.d.ts +22 -0
- package/dist/utils/setup.d.ts +90 -0
- package/dist/utils/shell.d.ts +32 -0
- package/dist/utils/skills.d.ts +10 -0
- package/dist/utils/subprocess.d.ts +80 -0
- package/dist/utils/terraformMcp.d.ts +42 -0
- package/dist/utils/time.d.ts +15 -0
- package/dist/utils/timer.d.ts +23 -0
- package/dist/utils/todoTracking.d.ts +16 -0
- package/dist/utils/token.d.ts +39 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/versioning.d.ts +7 -0
- package/dist/utils/vertex.d.ts +16 -0
- package/dist/utils/workflow.d.ts +13 -0
- package/package.json +119 -0
- package/src/agents/claude.test.ts +1016 -0
- package/src/agents/claude.ts +1246 -0
- package/src/agents/claudePretoolGate.test.ts +28 -0
- package/src/agents/claudePretoolGate.ts +173 -0
- package/src/agents/gateServer.test.ts +204 -0
- package/src/agents/gateServer.ts +124 -0
- package/src/agents/index.ts +10 -0
- package/src/agents/nativeFsDenies.ts +82 -0
- package/src/agents/opencode.test.ts +1440 -0
- package/src/agents/opencode.ts +1312 -0
- package/src/agents/opencodePlugin.ts +222 -0
- package/src/agents/opencodeShared.test.ts +34 -0
- package/src/agents/opencodeShared.ts +121 -0
- package/src/agents/postRun.test.ts +549 -0
- package/src/agents/postRun.ts +535 -0
- package/src/agents/reviewer.ts +104 -0
- package/src/agents/sessionLabeler.test.ts +247 -0
- package/src/agents/sessionLabeler.ts +178 -0
- package/src/agents/shared.test.ts +76 -0
- package/src/agents/shared.ts +292 -0
- package/src/agents/subagentModels.test.ts +113 -0
- package/src/agents/subagentModels.ts +40 -0
- package/src/agents/subagentRegistration.test.ts +41 -0
- package/src/agents/subagentToolGates.ts +114 -0
- package/src/cli.test.ts +129 -0
- package/src/cli.ts +105 -0
- package/src/commands/gha.test.ts +192 -0
- package/src/commands/gha.ts +188 -0
- package/src/commands/mcp.ts +122 -0
- package/src/config.ts +1 -0
- package/src/entry.ts +7 -0
- package/src/entryPost.stdlibOnly.test.ts +109 -0
- package/src/entryPost.ts +99 -0
- package/src/external.test.ts +16 -0
- package/src/external.ts +302 -0
- package/src/index.ts +11 -0
- package/src/internal/index.ts +71 -0
- package/src/lifecycle.ts +2 -0
- package/src/main.test.ts +873 -0
- package/src/main.ts +712 -0
- package/src/mcp/__fixtures__/terramend-scratch-pr-49-review-3485940013.json +110 -0
- package/src/mcp/__fixtures__/terramend-scratch-pr-64-review-3531000326.json +14 -0
- package/src/mcp/__fixtures__/terramend-test-repo-pr-1.diff.json +67 -0
- package/src/mcp/__snapshots__/checkout.test.ts.snap +109 -0
- package/src/mcp/__snapshots__/reviewComments.test.ts.snap +71 -0
- package/src/mcp/arkConfig.ts +7 -0
- package/src/mcp/checkSuite.test.ts +245 -0
- package/src/mcp/checkSuite.ts +255 -0
- package/src/mcp/checkout.test.ts +752 -0
- package/src/mcp/checkout.ts +886 -0
- package/src/mcp/comment.test.ts +772 -0
- package/src/mcp/comment.ts +582 -0
- package/src/mcp/commitInfo.test.ts +127 -0
- package/src/mcp/commitInfo.ts +61 -0
- package/src/mcp/crosswalk.test.ts +106 -0
- package/src/mcp/crosswalk.ts +339 -0
- package/src/mcp/dependencies.test.ts +309 -0
- package/src/mcp/dependencies.ts +189 -0
- package/src/mcp/geminiSanitizer.test.ts +287 -0
- package/src/mcp/geminiSanitizer.ts +207 -0
- package/src/mcp/git.test.ts +1083 -0
- package/src/mcp/git.ts +890 -0
- package/src/mcp/guardrails.test.ts +705 -0
- package/src/mcp/guardrails.ts +465 -0
- package/src/mcp/issue.test.ts +113 -0
- package/src/mcp/issue.ts +73 -0
- package/src/mcp/issueComments.test.ts +69 -0
- package/src/mcp/issueComments.ts +48 -0
- package/src/mcp/issueEvents.test.ts +134 -0
- package/src/mcp/issueEvents.ts +100 -0
- package/src/mcp/issueInfo.test.ts +104 -0
- package/src/mcp/issueInfo.ts +72 -0
- package/src/mcp/labels.test.ts +52 -0
- package/src/mcp/labels.ts +34 -0
- package/src/mcp/localContext.ts +28 -0
- package/src/mcp/localServer.test.ts +75 -0
- package/src/mcp/localServer.ts +131 -0
- package/src/mcp/moduleExtraction.test.ts +261 -0
- package/src/mcp/moduleExtraction.ts +313 -0
- package/src/mcp/moduleTests.test.ts +269 -0
- package/src/mcp/moduleTests.ts +421 -0
- package/src/mcp/modules.test.ts +640 -0
- package/src/mcp/modules.ts +696 -0
- package/src/mcp/output.test.ts +96 -0
- package/src/mcp/output.ts +70 -0
- package/src/mcp/pathSafety.test.ts +44 -0
- package/src/mcp/pathSafety.ts +28 -0
- package/src/mcp/policy.test.ts +282 -0
- package/src/mcp/policy.ts +199 -0
- package/src/mcp/pr.test.ts +387 -0
- package/src/mcp/pr.ts +194 -0
- package/src/mcp/prInfo.test.ts +96 -0
- package/src/mcp/prInfo.ts +91 -0
- package/src/mcp/providerSchema.test.ts +85 -0
- package/src/mcp/providerSchema.ts +175 -0
- package/src/mcp/review.test.ts +936 -0
- package/src/mcp/review.ts +923 -0
- package/src/mcp/reviewComments.test.ts +549 -0
- package/src/mcp/reviewComments.ts +896 -0
- package/src/mcp/roots.test.ts +175 -0
- package/src/mcp/roots.ts +217 -0
- package/src/mcp/scope.test.ts +59 -0
- package/src/mcp/scope.ts +65 -0
- package/src/mcp/security.test.ts +720 -0
- package/src/mcp/selectMode.test.ts +210 -0
- package/src/mcp/selectMode.ts +181 -0
- package/src/mcp/server.test.ts +292 -0
- package/src/mcp/server.ts +403 -0
- package/src/mcp/shared.ts +100 -0
- package/src/mcp/shell.test.ts +520 -0
- package/src/mcp/shell.ts +505 -0
- package/src/mcp/staleFix.test.ts +237 -0
- package/src/mcp/staleFix.ts +277 -0
- package/src/mcp/terraform/cost.ts +163 -0
- package/src/mcp/terraform/currency.test.ts +338 -0
- package/src/mcp/terraform/currency.ts +336 -0
- package/src/mcp/terraform/decisions.ts +527 -0
- package/src/mcp/terraform/findings.ts +333 -0
- package/src/mcp/terraform/plan.ts +348 -0
- package/src/mcp/terraform/scanners.ts +809 -0
- package/src/mcp/terraform/tools.test.ts +1071 -0
- package/src/mcp/terraform/tools.ts +908 -0
- package/src/mcp/terraform/types.ts +305 -0
- package/src/mcp/terraform.test.ts +1957 -0
- package/src/mcp/terraform.ts +23 -0
- package/src/mcp/terratest.test.ts +105 -0
- package/src/mcp/terratest.ts +196 -0
- package/src/mcp/toolFiltering.test.ts +85 -0
- package/src/mcp/upload.test.ts +180 -0
- package/src/mcp/upload.ts +112 -0
- package/src/models.test.ts +300 -0
- package/src/models.ts +708 -0
- package/src/modes.test.ts +107 -0
- package/src/modes.ts +880 -0
- package/src/prep/index.ts +43 -0
- package/src/prep/installNodeDependencies.test.ts +298 -0
- package/src/prep/installNodeDependencies.ts +196 -0
- package/src/prep/installPythonDependencies.test.ts +268 -0
- package/src/prep/installPythonDependencies.ts +199 -0
- package/src/prep/types.ts +38 -0
- package/src/reviewQuality.test.ts +63 -0
- package/src/reviewQuality.ts +134 -0
- package/src/runCli.test.ts +214 -0
- package/src/runCli.ts +282 -0
- package/src/skills/terraform-best-practices/SKILL.md +369 -0
- package/src/toolState.test.ts +45 -0
- package/src/toolState.ts +252 -0
- package/src/utils/activity.test.ts +188 -0
- package/src/utils/activity.ts +210 -0
- package/src/utils/agent.test.ts +251 -0
- package/src/utils/agent.ts +139 -0
- package/src/utils/agentHangReport.test.ts +203 -0
- package/src/utils/agentHangReport.ts +170 -0
- package/src/utils/apiFetch.test.ts +115 -0
- package/src/utils/apiFetch.ts +62 -0
- package/src/utils/apiKeys.test.ts +344 -0
- package/src/utils/apiKeys.ts +206 -0
- package/src/utils/apiUrl.test.ts +30 -0
- package/src/utils/apiUrl.ts +59 -0
- package/src/utils/assets.test.ts +153 -0
- package/src/utils/assets.ts +107 -0
- package/src/utils/billingErrors.test.ts +121 -0
- package/src/utils/billingErrors.ts +189 -0
- package/src/utils/body.test.ts +217 -0
- package/src/utils/body.ts +168 -0
- package/src/utils/buildTerramendFooter.test.ts +38 -0
- package/src/utils/buildTerramendFooter.ts +82 -0
- package/src/utils/byokFallback.test.ts +205 -0
- package/src/utils/byokFallback.ts +128 -0
- package/src/utils/claudeSubscription.test.ts +179 -0
- package/src/utils/claudeSubscription.ts +93 -0
- package/src/utils/cli.ts +31 -0
- package/src/utils/codexHome.test.ts +190 -0
- package/src/utils/codexHome.ts +191 -0
- package/src/utils/codexOAuth.ts +147 -0
- package/src/utils/codexRefreshDetect.test.ts +85 -0
- package/src/utils/codexRefreshDetect.ts +35 -0
- package/src/utils/diffCoverage.test.ts +468 -0
- package/src/utils/diffCoverage.ts +404 -0
- package/src/utils/errorReport.test.ts +135 -0
- package/src/utils/errorReport.ts +83 -0
- package/src/utils/exitHandler.ts +35 -0
- package/src/utils/fixDoubleEscapedString.ts +9 -0
- package/src/utils/ghaCore.ts +13 -0
- package/src/utils/gitAuth.test.ts +322 -0
- package/src/utils/gitAuth.ts +263 -0
- package/src/utils/gitAuthServer.test.ts +260 -0
- package/src/utils/gitAuthServer.ts +182 -0
- package/src/utils/github.test.ts +615 -0
- package/src/utils/github.ts +538 -0
- package/src/utils/globals.ts +9 -0
- package/src/utils/humanEditCapture.test.ts +100 -0
- package/src/utils/humanEditCapture.ts +193 -0
- package/src/utils/install.test.ts +768 -0
- package/src/utils/install.ts +492 -0
- package/src/utils/instructions.test.ts +240 -0
- package/src/utils/instructions.ts +543 -0
- package/src/utils/leapingComment.test.ts +51 -0
- package/src/utils/leapingComment.ts +18 -0
- package/src/utils/learnings.test.ts +87 -0
- package/src/utils/learnings.ts +138 -0
- package/src/utils/learningsTocRender.test.ts +116 -0
- package/src/utils/learningsTruncate.test.ts +39 -0
- package/src/utils/learningsTruncate.ts +42 -0
- package/src/utils/lifecycle.test.ts +195 -0
- package/src/utils/lifecycle.ts +198 -0
- package/src/utils/log.test.ts +402 -0
- package/src/utils/log.ts +432 -0
- package/src/utils/normalizeEnv.test.ts +91 -0
- package/src/utils/normalizeEnv.ts +106 -0
- package/src/utils/openCodeModels.ts +82 -0
- package/src/utils/overrides.test.ts +89 -0
- package/src/utils/overrides.ts +98 -0
- package/src/utils/packageManager.test.ts +321 -0
- package/src/utils/packageManager.ts +257 -0
- package/src/utils/patchWorkflowRunFields.test.ts +92 -0
- package/src/utils/patchWorkflowRunFields.ts +150 -0
- package/src/utils/payload.test.ts +497 -0
- package/src/utils/payload.ts +371 -0
- package/src/utils/postApiFetch.ts +51 -0
- package/src/utils/prSummary.test.ts +224 -0
- package/src/utils/prSummary.ts +147 -0
- package/src/utils/progressComment.ts +261 -0
- package/src/utils/providerErrors.test.ts +315 -0
- package/src/utils/providerErrors.ts +172 -0
- package/src/utils/rangeDiff.test.ts +236 -0
- package/src/utils/rangeDiff.ts +182 -0
- package/src/utils/remediationCommand.test.ts +163 -0
- package/src/utils/remediationCommand.ts +119 -0
- package/src/utils/retry.test.ts +153 -0
- package/src/utils/retry.ts +58 -0
- package/src/utils/reviewCleanup.ts +106 -0
- package/src/utils/run.ts +99 -0
- package/src/utils/runContext.ts +145 -0
- package/src/utils/runContextData.ts +58 -0
- package/src/utils/runErrorRenderer.test.ts +95 -0
- package/src/utils/runErrorRenderer.ts +259 -0
- package/src/utils/runFixture.ts +76 -0
- package/src/utils/runLifecycle.ts +237 -0
- package/src/utils/runStartupLog.ts +60 -0
- package/src/utils/secrets.test.ts +103 -0
- package/src/utils/secrets.ts +177 -0
- package/src/utils/setup.test.ts +509 -0
- package/src/utils/setup.ts +352 -0
- package/src/utils/shell.ts +103 -0
- package/src/utils/skills.test.ts +46 -0
- package/src/utils/skills.ts +67 -0
- package/src/utils/subprocess.test.ts +170 -0
- package/src/utils/subprocess.ts +438 -0
- package/src/utils/terraformMcp.test.ts +63 -0
- package/src/utils/terraformMcp.ts +83 -0
- package/src/utils/time.test.ts +105 -0
- package/src/utils/time.ts +59 -0
- package/src/utils/timer.test.ts +91 -0
- package/src/utils/timer.ts +72 -0
- package/src/utils/todoTracking.test.ts +223 -0
- package/src/utils/todoTracking.ts +167 -0
- package/src/utils/token.test.ts +239 -0
- package/src/utils/token.ts +186 -0
- package/src/utils/version.ts +10 -0
- package/src/utils/versioning.test.ts +34 -0
- package/src/utils/versioning.ts +44 -0
- package/src/utils/vertex.ts +85 -0
- package/src/utils/workflow.ts +25 -0
package/src/modes.ts
ADDED
|
@@ -0,0 +1,880 @@
|
|
|
1
|
+
// changes to mode definitions should be reflected in docs/modes.mdx
|
|
2
|
+
import { REVIEWER_AGENT_NAME } from "#app/agents/reviewer";
|
|
3
|
+
import { type AgentId, formatMcpToolRef, terramendMcpName } from "#app/external";
|
|
4
|
+
import { FINDING_VERIFICATION_PASS, REVIEW_FINDING_PRECEDENTS } from "#app/reviewQuality";
|
|
5
|
+
|
|
6
|
+
export interface Mode {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
// step-by-step guidance returned when the agent calls select_mode.
|
|
10
|
+
// custom user-defined modes supply this; built-in modes define it here.
|
|
11
|
+
prompt?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Default user-facing summary format embedded in BOTH Review and
|
|
15
|
+
// IncrementalReview review bodies. The two modes share the preamble +
|
|
16
|
+
// cross-cutting + nitpicks shape; the only difference is scope (full PR for
|
|
17
|
+
// Review vs delta against the prior terramend review for IncrementalReview).
|
|
18
|
+
// Distinct from the agent-internal snapshot (action/utils/prSummary.ts) which
|
|
19
|
+
// has its own stable scaffold and is never shaped by user instructions โ see
|
|
20
|
+
// selectMode.ts for the firewall.
|
|
21
|
+
export const PR_SUMMARY_FORMAT = `### Default format
|
|
22
|
+
|
|
23
|
+
The body has at most four parts in this exact order:
|
|
24
|
+
|
|
25
|
+
1. **Reviewed changes preamble** โ one bolded inline lead-in describing what was reviewed in this run, a bullet list of the substantive changes, and an HTML comment carrying review metadata for downstream agents.
|
|
26
|
+
2. **Cross-cutting issue sections** (zero or more) โ one \`### \` heading per concern, with a human-readable problem write-up and a collapsed \`<details>Technical details</details>\` block underneath.
|
|
27
|
+
3. **\`### โน๏ธ Nitpicks\`** (only if there are nits worth surfacing in the body) โ a flat bullet list, no technical-details block.
|
|
28
|
+
4. **\`Suppressed findings\` collapsed block** at the very bottom (only when the adversarial verification pass suppressed at least one ๐จ/โ ๏ธ candidate) โ the one-line-per-finding audit trail for the false-positive filter.
|
|
29
|
+
|
|
30
|
+
Inline-vs-body split: concerns that anchor to a specific line go inline (use the \`comments\` parameter). Body \`### \` sections are reserved for concerns that **have no line to anchor to** โ typically because the concern is about *absence* (something the diff should have done but didn't), *sequencing* (rollout / deletion / migration order), *design decisions only the human can make*, or *scope questions the diff implicitly raises but doesn't address*. A concern that anchors to a line but has broad implications still goes inline (use the technical-details block there to capture the implications โ see Inline technical details below). If you found no non-anchorable concerns, the body has zero \`### \` issue sections โ just the preamble + metadata.
|
|
31
|
+
|
|
32
|
+
## 1. Reviewed changes preamble
|
|
33
|
+
|
|
34
|
+
Open with a single bolded inline lead-in followed immediately by the bullet list (no \`### Key changes\` heading, no \`<b>TL;DR</b>\`):
|
|
35
|
+
|
|
36
|
+
\`\`\`
|
|
37
|
+
**Reviewed changes** โ one sentence on what was reviewed in this run. For Review (initial), this is what the PR does and why. For IncrementalReview, this is what changed since the prior terramend review. Focus on intent, not mechanics.
|
|
38
|
+
|
|
39
|
+
- **Short human-readable title** โ 1 sentence per substantive change. Write a short prose phrase; when you name a file, type, or function, put that name in backticks (e.g. **Add \\\`TodoTracker\\\` for live checklists**). A reviewer should understand the full reviewed scope from this list alone โ this IS the dispassionate "what was reviewed and what changed" overview, so cover the substantive changes, not just the loudest ones.
|
|
40
|
+
|
|
41
|
+
<!--
|
|
42
|
+
Terramend review metadata โ for any agent (or human-with-agent) reading this
|
|
43
|
+
review. Incorporate the fields below into your understanding of the context
|
|
44
|
+
this review was made in. The findings below were written against
|
|
45
|
+
{head_sha_short}; if new commits have landed on {head_ref} since this review
|
|
46
|
+
was submitted, treat any specific bug, file, or line callout as POTENTIALLY
|
|
47
|
+
STALE โ re-diff against {head_sha_short} (or trigger a fresh review) and
|
|
48
|
+
factor commits past {head_sha_short} into your understanding of the current
|
|
49
|
+
state before acting on findings.
|
|
50
|
+
|
|
51
|
+
- Mode: Review (initial) or IncrementalReview (delta against prior terramend review)
|
|
52
|
+
- Files reviewed: {file_count}
|
|
53
|
+
- Commits reviewed: {commit_count}
|
|
54
|
+
- Base: {base_ref} ({base_sha_short})
|
|
55
|
+
- Head: {head_ref} ({head_sha_short})
|
|
56
|
+
- Reviewed commits:
|
|
57
|
+
- {sha_short} โ {commit_subject}
|
|
58
|
+
- ...
|
|
59
|
+
- Prior terramend review: none or {prior_sha_short} ({prior_review_html_url})
|
|
60
|
+
- Submitted at: {iso_timestamp}
|
|
61
|
+
-->
|
|
62
|
+
\`\`\`
|
|
63
|
+
|
|
64
|
+
Pull every metadata field from the \`checkout_pr\` tool's response โ file count, commit count, base/head ref + SHA, the commit list. For \`IncrementalReview\` runs, populate \`Prior terramend review\` with the prior review's commit_id (short SHA) and \`html_url\` from \`list_pull_request_reviews\`.
|
|
65
|
+
|
|
66
|
+
## 2. Cross-cutting issue sections (zero or more)
|
|
67
|
+
|
|
68
|
+
For each cross-cutting concern, one \`### \` section. Use this exact shape:
|
|
69
|
+
|
|
70
|
+
\`\`\`
|
|
71
|
+
### {emoji} {short, descriptive title โ what's wrong, not what to do}
|
|
72
|
+
|
|
73
|
+
{Human-readable problem write-up. Describes the PROBLEM only โ what's broken, what the symptom is, what the blast radius is. NO asks, NO suggested fixes, NO "the right thing to do is...". Asks and fixes live in the technical-details block below; the visible part is for the human to *understand* the problem, not to implement it.}
|
|
74
|
+
|
|
75
|
+
<details><summary>Technical details</summary>
|
|
76
|
+
|
|
77
|
+
\\\`\\\`\\\`\\\`markdown
|
|
78
|
+
# {title repeated}
|
|
79
|
+
|
|
80
|
+
## Affected sites
|
|
81
|
+
- {file path:line} โ {what's wrong there}
|
|
82
|
+
- ...
|
|
83
|
+
|
|
84
|
+
## Required outcome
|
|
85
|
+
- {what the fix needs to achieve, not how to achieve it}
|
|
86
|
+
- ...
|
|
87
|
+
|
|
88
|
+
## Suggested approach (optional)
|
|
89
|
+
{When the fix shape is non-obvious, sketch one or more reasonable directions. Skip when the outcome alone makes the fix obvious.}
|
|
90
|
+
|
|
91
|
+
## Open questions for the human (optional)
|
|
92
|
+
- {Any decision an implementing agent shouldn't make unilaterally โ pricing thresholds, breaking-change policy, naming, scope of follow-up.}
|
|
93
|
+
\\\`\\\`\\\`\\\`
|
|
94
|
+
|
|
95
|
+
</details>
|
|
96
|
+
\`\`\`
|
|
97
|
+
|
|
98
|
+
Concrete example of the visible part of a non-anchored section (technical-details block unchanged from the template above):
|
|
99
|
+
|
|
100
|
+
\`\`\`
|
|
101
|
+
### โน๏ธ Legacy \`opencode.ts\` has no documented deletion plan
|
|
102
|
+
|
|
103
|
+
The v2 harness lands alongside the v1 file and imports one helper from it. Worth a follow-up issue or a TODO so the next maintainer doesn't have to re-derive the cleanup plan.
|
|
104
|
+
\`\`\`
|
|
105
|
+
|
|
106
|
+
The example's value is its *shape*: a finding about absence (no deletion plan), not a line-anchored bug. Body sections live or die on whether the concern genuinely doesn't fit on a line.
|
|
107
|
+
|
|
108
|
+
**Heading severity emoji** โ every \`### \` heading carries one:
|
|
109
|
+
|
|
110
|
+
- ๐จ critical โ blocks merge (data loss, security, broken core flow)
|
|
111
|
+
- โ ๏ธ important โ must address before merging (regression, missing validation, incorrect behavior)
|
|
112
|
+
- โน๏ธ informational โ surfaced for awareness; mergeable as-is
|
|
113
|
+
|
|
114
|
+
**Visible problem write-up rules:**
|
|
115
|
+
|
|
116
|
+
- **No asks, no suggested fixes** in the visible part. The visible portion describes the problem; the technical-details block describes the fix shape and any open questions. The exception: a fix so self-evident that NOT stating it would be weird (e.g. "the typo is missing an 'r'") โ in that case, fold it into the problem statement and skip the suggested-approach block in technical details too.
|
|
117
|
+
- **Never two successive plain paragraphs.** Every transition between block-level elements must alternate prose with structure: paragraph โ bullet list โ paragraph; paragraph โ code fence โ bullet list; paragraph โ table โ paragraph. Two consecutive paragraphs in a row create a wall of text that's impossible to digest. If you catch yourself writing one, find a way to split it: pull a list out of it, drop a 2-3 line code fence between them, or merge them into a single tighter paragraph.
|
|
118
|
+
- **Per-paragraph budget:** ~3 sentences max. Past that, you're explaining where you should be structuring.
|
|
119
|
+
- **Identifier discipline still applies** in the visible part. Lead with behavior in plain English; name an identifier only when it's the subject of the concern or a public surface a reader would recognize. The technical-details block is where dense identifier references belong.
|
|
120
|
+
|
|
121
|
+
**Technical-details block rules:**
|
|
122
|
+
|
|
123
|
+
- Wrapped in a 4-backtick markdown fence (\`\\\`\\\`\\\`\\\`markdown ... \\\`\\\`\\\`\\\`\`) so it's visually distinct, one-click copyable, and can contain its own 3-backtick code fences without escape gymnastics. The contents are agent-readable โ a fix-agent will pull the body down and use this block as the brief.
|
|
124
|
+
- File paths and \`file:line\` refs are encouraged (and necessary) โ the next agent uses these to navigate. Identifier density is fine here.
|
|
125
|
+
- Slightly more verbose than the absolute minimum is OK when it materially helps the next agent: a small code snippet showing the symptom, a short table of mismatched key/column pairs, a one-paragraph "why CI doesn't catch it" note. Skip massive regression-test scaffolding or full route rewrites โ the implementing agent writes those.
|
|
126
|
+
- Use the four standard sections (\`Affected sites\`, \`Required outcome\`, optional \`Suggested approach\`, optional \`Open questions for the human\`). Skip the optional sections when they wouldn't add anything.
|
|
127
|
+
|
|
128
|
+
## Inline technical details
|
|
129
|
+
|
|
130
|
+
Inline comments are short (~2-3 sentences) by default. When an inline finding has broader implications worth recording for a fix-agent โ e.g. a localized bug whose proper fix requires touching several files, or where the right fix depends on a design decision the human needs to make โ append a collapsed \`<details><summary>Technical details</summary>\` block to the inline comment's body. Same shape as the body-section technical-details block (4-backtick fenced markdown, \`## Affected sites\` / \`## Required outcome\` / optional \`## Suggested approach\` / optional \`## Open questions for the human\`).
|
|
131
|
+
|
|
132
|
+
GitHub renders the same markdown parser in inline comments as in the review body, so the collapsed-details affordance works the same way. The visible part of the inline comment stays scannable; the depth is one click away for any agent that needs it.
|
|
133
|
+
|
|
134
|
+
## 3. \`### โน๏ธ Nitpicks\` (optional, last content section)
|
|
135
|
+
|
|
136
|
+
Only when there are nits that for some reason can't be inlined. Filepaths in nit text are fine โ these are simple enough that a human or agent reads once and acts. No technical-details block.
|
|
137
|
+
|
|
138
|
+
\`\`\`
|
|
139
|
+
### โน๏ธ Nitpicks
|
|
140
|
+
|
|
141
|
+
- {nit, with file path inline if useful, โค ~200 chars}
|
|
142
|
+
- ...
|
|
143
|
+
\`\`\`
|
|
144
|
+
|
|
145
|
+
## 4. \`Suppressed findings\` (optional, very last)
|
|
146
|
+
|
|
147
|
+
Only when the adversarial verification pass (see the checklist) suppressed at least one ๐จ/โ ๏ธ candidate. One collapsed block, always the last element in the body, with the count in the summary line:
|
|
148
|
+
|
|
149
|
+
\`\`\`
|
|
150
|
+
<details><summary>๐๏ธ Suppressed findings (2)</summary>
|
|
151
|
+
|
|
152
|
+
- โ ๏ธ \`networking/main.tf:42\` โ claimed the subnet exposes the DB publicly โ refuted: \`publicly_accessible = false\` at \`db.tf:18\`.
|
|
153
|
+
- ๐จ \`api/auth.ts:77\` โ claimed JWT signature bypass โ refuted: the unverified decode is dev-only, gated by the \`NODE_ENV\` check two lines above.
|
|
154
|
+
|
|
155
|
+
</details>
|
|
156
|
+
\`\`\`
|
|
157
|
+
|
|
158
|
+
One bullet per suppressed finding: severity emoji, \`file:line\`, the claim in a few words, the refutation in a few words. One line each โ the block exists for auditability (a human catching the false-positive filter being wrong), not re-litigation. Omit the block entirely when nothing was suppressed.
|
|
159
|
+
|
|
160
|
+
## Inline comment shape
|
|
161
|
+
|
|
162
|
+
Inline comments use the same severity framing as body \`### \` sections, scaled down for line-anchored use:
|
|
163
|
+
|
|
164
|
+
- **Lead with a 1-2 sentence problem statement.** The reader is looking at the line in question, so don't restate what the line says โ describe what's wrong with it. Optionally prefix the visible line with a severity emoji (๐จ / โ ๏ธ / โน๏ธ) when severity isn't obvious from context.
|
|
165
|
+
- **Optional \`<details><summary>Technical details</summary>...</details>\` collapsible** for findings whose technical context (longer file:line references, related-code snippets, suggested approach, regression-risk notes) would overwhelm the human-readable lead-in. Same agent-readable purpose, same 4-backtick fence shape, and same 4-section structure as the body's technical-details block โ see *Inline technical details* above. Encouraged whenever the depth helps a downstream fix-agent; don't force one when the inline lead-in already says everything.
|
|
166
|
+
- **Visible portion โค 2-3 sentences.** If you find yourself writing more, that's the cue to split the depth into the \`Technical details\` collapsible.
|
|
167
|
+
|
|
168
|
+
## Body-wide rules
|
|
169
|
+
|
|
170
|
+
- **Inline-vs-body discipline (repeated for emphasis):** anything that anchors to a specific line goes inline (with a \`<details>Technical details</details>\` block when the implications are broad). The body is for non-anchorable concerns only โ absence, sequencing, design decisions, scope questions, architectural risk.
|
|
171
|
+
- **No \`### Issues found\` heading** above the issue sections โ each \`### \` heading IS the issue.
|
|
172
|
+
- **Severity emoji on every \`### \` heading** (๐จ / โ ๏ธ / โน๏ธ). No emoji on the preamble lead-in or anywhere else.
|
|
173
|
+
- **GitHub block-level rendering**: GitHub's markdown parser requires a blank line between ALL block-level elements (HTML tags like \`<br/>\`, \`<sub>\`, \`<details>\`, \`<b>\` and markdown syntax like headings, lists, blockquotes, code fences, paragraphs). Without a blank line, GitHub treats following content as a continuation of the HTML block and renders markdown syntax as literal text. ALWAYS separate block-level elements with a blank line.
|
|
174
|
+
- **Backtick-wrap** every variable, identifier, or file name when you mention one (in either visible or technical-details portions).
|
|
175
|
+
- **Don't repeat diff content**, don't include raw \`+123 / -45\` stats, don't include a changelog section, don't use horizontal rules (\`---\`).
|
|
176
|
+
- **Pull file/commit counts from \`checkout_pr\` metadata** โ never count manually.
|
|
177
|
+
- **Legacy headings REMOVED.** Do not use \`### Key changes\`, \`### Issues found\`, \`<b>TL;DR</b>\`, or \`<sub><b>Summary</b>\`. The new structure subsumes them.`;
|
|
178
|
+
|
|
179
|
+
// Canonical body format for a Terramend REMEDIATION / GENERATION pull request.
|
|
180
|
+
// Distinct from PR_SUMMARY_FORMAT (which shapes a *review* body): this is the
|
|
181
|
+
// body of a PR Terramend OPENS. Every field maps to a deterministic tool result
|
|
182
|
+
// (terraform_scan / _validate / _plan / _verify_remediation / infracost_diff),
|
|
183
|
+
// so the body is evidence-built, never self-reported. Append this to the
|
|
184
|
+
// Remediate + GenerateTerraform prompts so every Terramend PR looks identical
|
|
185
|
+
// and a reviewer can scan it top-to-bottom in seconds.
|
|
186
|
+
export const REMEDIATION_PR_FORMAT = `### Remediation PR format
|
|
187
|
+
|
|
188
|
+
**Minimum (ALWAYS include, even under tight budget):** a one-paragraph plain-English summary of *what was wrong and what you changed*, then a \`## What changed\` list with one *Was / Changed / Safe because* note per concern, then the \`## Validation (โ โ โ)\` list. If you produce nothing else, produce these three โ a PR a human can't understand from its body alone has failed its job. Everything below enriches this minimum; it does not replace it.
|
|
189
|
+
|
|
190
|
+
Build the PR body in this EXACT order. Every line is backed by a tool result โ never write a status you didn't get from a tool. Omit a whole section only when its tool didn't run (e.g. no plan without cloud creds); never fabricate it. Keep a blank line between every block-level element (GitHub needs it to render).
|
|
191
|
+
|
|
192
|
+
#### 1. Status banner (first line)
|
|
193
|
+
|
|
194
|
+
One GitHub alert blockquote that sets the reviewer's expectation, picked from the verification evidence:
|
|
195
|
+
|
|
196
|
+
- \`> [!CAUTION]\` โ a \`needs-human\` signal fired: a regression (\`has_regressions\`), a stateful destroy/replace, a high blast radius, a non-deterministic plan, or a cost escalation. One sentence naming the reason.
|
|
197
|
+
- \`> [!WARNING]\` โ verified but with a caveat (medium blast radius, a still-\`remaining\` concern, baseline-unavailable cost).
|
|
198
|
+
- \`> [!NOTE]\` โ clean: \`verified: true\`, no regressions, low blast radius. One sentence: what was hardened.
|
|
199
|
+
|
|
200
|
+
#### 2. Title line + badges
|
|
201
|
+
|
|
202
|
+
A single bolded sentence naming the file/group and what was fixed, then a one-line badge row built from the tool results (drop any badge whose tool didn't run):
|
|
203
|
+
|
|
204
|
+
\`\`\`
|
|
205
|
+
**Hardened \\\`main.tf\\\` โ S3 encryption + public-access block.**
|
|
206
|
+
|
|
207
|
+
\`Confidence: high\` ยท \`Blast radius: low (1 resource)\` ยท \`Plan: +0 ~1 -0\` ยท \`Idempotent: yes\` ยท \`Cost: +$0.00/mo\`
|
|
208
|
+
\`\`\`
|
|
209
|
+
|
|
210
|
+
Render \`Confidence\` verbatim from \`terraform_verify_remediation.confidence\` โ never inflate it. Use \`ยท\` separators, backtick-wrap each badge.
|
|
211
|
+
|
|
212
|
+
#### 3. \`## What changed\`
|
|
213
|
+
|
|
214
|
+
One \`### \` subsection per resolved concern (or one per rule for a by-rule group), each with the ยง5.17 three-line micro-template and the rule linked to its docs (\`doc_url\`, else \`remediation_hint\`):
|
|
215
|
+
|
|
216
|
+
\`\`\`
|
|
217
|
+
### ๐ [\\\`trivy:AVD-AWS-0088\\\`](https://avd.aquasec.com/misconfig/avd-aws-0088) โ S3 bucket not encrypted
|
|
218
|
+
|
|
219
|
+
- **Was** โ {the scanner's \`evidence\`, in plain English}.
|
|
220
|
+
- **Changed** โ {what the fix did, one sentence}.
|
|
221
|
+
- **Safe because** โ {why it's correct and non-breaking}.
|
|
222
|
+
\`\`\`
|
|
223
|
+
|
|
224
|
+
Lead each heading with a severity emoji (๐จ critical ยท โ ๏ธ high ยท ๐ security ยท โน๏ธ low/info). Backtick-wrap every identifier. No raw diff dumps โ the Files tab shows the diff.
|
|
225
|
+
|
|
226
|
+
#### 4. \`## Validation (โ โ โ)\`
|
|
227
|
+
|
|
228
|
+
Built ONLY from \`terraform_verify_remediation\`'s result โ this is the proof, not a self-report. One line per id in \`resolved\`, then any still-open id honestly:
|
|
229
|
+
|
|
230
|
+
\`\`\`
|
|
231
|
+
## Validation (โ โ โ)
|
|
232
|
+
|
|
233
|
+
- โ โ โ \\\`trivy:AVD-AWS-0088\\\` resolved
|
|
234
|
+
- โ โ โ \\\`checkov:CKV_AWS_19\\\` resolved
|
|
235
|
+
- โ ๏ธ still open: \\\`tflint:...\\\` โ {why it couldn't be cleared}
|
|
236
|
+
\`\`\`
|
|
237
|
+
|
|
238
|
+
If \`has_regressions\` is true, add a \`> [!CAUTION]\` **Regression** callout listing each new concern id BEFORE this list, and ensure the \`needs-human\` label is set. Never mark an id โ unless the tool returned it in \`resolved\`.
|
|
239
|
+
|
|
240
|
+
#### 5. \`<details><summary>Plan</summary>\` (when \`terraform_plan\` ran)
|
|
241
|
+
|
|
242
|
+
Attach the full \`plan_text\` in a collapsed code block so a reviewer sees the exact change without re-running it:
|
|
243
|
+
|
|
244
|
+
\`\`\`
|
|
245
|
+
<details><summary>Terraform plan</summary>
|
|
246
|
+
|
|
247
|
+
\\\`\\\`\\\`
|
|
248
|
+
{plan_text}
|
|
249
|
+
\\\`\\\`\\\`
|
|
250
|
+
|
|
251
|
+
</details>
|
|
252
|
+
\`\`\`
|
|
253
|
+
|
|
254
|
+
When \`needs_human\` is true, surface \`needs_human_reasons\` as a visible bullet list above the \`<details>\` โ don't bury an escalation in a collapsed block.
|
|
255
|
+
|
|
256
|
+
#### 6. \`## ๐ก๏ธ Prevent recurrence\` (optional follow-up)
|
|
257
|
+
|
|
258
|
+
From the scan's \`prevention\` map โ the CI guardrail that stops this class of concern coming back. Clearly marked **not part of this PR's diff**: a short intro sentence then the \`mechanism\` + a fenced \`snippet\`. One entry per distinct rule.
|
|
259
|
+
|
|
260
|
+
#### 7. \`## Compliance\` (optional, when a crosswalk was run)
|
|
261
|
+
|
|
262
|
+
When \`terraform_compliance_crosswalk\` was called, add a short auditor-facing note: the frameworks/controls this fix touches (from \`by_framework\`), prefixed "Indicative alignment (crosswalk v{version}) โ not an audit verdict." Skip entirely when the crosswalk wasn't run.
|
|
263
|
+
|
|
264
|
+
#### Body-wide rules
|
|
265
|
+
|
|
266
|
+
- **Evidence-built, never self-reported** โ every badge, โ, and count comes from a tool result. If a tool didn't run, omit its section; don't guess.
|
|
267
|
+
- **Blank line between ALL block-level elements** (callouts, headings, lists, code fences, \`<details>\`) โ GitHub renders markdown as literal text otherwise.
|
|
268
|
+
- **Backtick-wrap** every file, rule id, resource address, and identifier.
|
|
269
|
+
- **No raw \`+N/-M\` diff stats, no horizontal rules (\`---\`), no changelog section.** The footer is appended automatically โ don't add your own.
|
|
270
|
+
- **One scoped group per PR.** The body describes this group's fix only.`;
|
|
271
|
+
|
|
272
|
+
export function computeModes(agentId: AgentId): Mode[] {
|
|
273
|
+
const t = (toolName: string) => formatMcpToolRef(agentId, toolName);
|
|
274
|
+
return [
|
|
275
|
+
{
|
|
276
|
+
name: "Build",
|
|
277
|
+
description:
|
|
278
|
+
"Implement, build, create, or develop code changes; make specific changes to files or features; execute a plan; or handle tasks with specific implementation details",
|
|
279
|
+
prompt: `### Checklist
|
|
280
|
+
|
|
281
|
+
1. **task list**: create your task list for this run as your first action.
|
|
282
|
+
|
|
283
|
+
2. **plan** (optional, for complex tasks): analyze requirements, read AGENTS.md and relevant code, produce a step-by-step implementation plan.
|
|
284
|
+
|
|
285
|
+
3. **setup**: checkout or create the branch:
|
|
286
|
+
- **PR event, modifying the existing PR**: call \`${t("checkout_pr")}\`
|
|
287
|
+
- **new branch**: use \`${t("git")}\` to create a branch (\`git checkout -b terramend/branch-name\`)
|
|
288
|
+
|
|
289
|
+
4. **build**: implement changes using your native file and shell tools:
|
|
290
|
+
- follow the plan (if you ran a plan phase)
|
|
291
|
+
- plan your approach before writing code: identify which files need to change, key design decisions, and edge cases. for non-trivial changes, consider whether there's a more elegant approach.
|
|
292
|
+
- run relevant tests/lints before committing
|
|
293
|
+
|
|
294
|
+
5. **self-review**: judgment call โ does YOUR diff warrant a fresh-eyes pass?
|
|
295
|
+
|
|
296
|
+
Skip self-review (commit directly) when the diff is **genuinely trivial**:
|
|
297
|
+
- doc typos, comment-only edits, whitespace/format-only, import reordering
|
|
298
|
+
- lockfile or generated-code regeneration, mechanical rename whose only effect is import-path updates (size of diff is irrelevant โ read the *shape*, not the line count)
|
|
299
|
+
- low-risk dep patch bump from a trusted source
|
|
300
|
+
|
|
301
|
+
Run self-review when the diff has **any behavioral surface, however small**:
|
|
302
|
+
- 1-line changes to SQL operators / comparison logic / regexes / redirects / HTTP methods / response codes
|
|
303
|
+
- any change to money / tax / currency / billing / fee / refund / payout calculations or constants
|
|
304
|
+
- any change to auth / permissions / roles / sessions / tokens / signature verification
|
|
305
|
+
- any change to feature-flag defaults, retry counts, timeouts, rate limits, batch sizes
|
|
306
|
+
- new endpoints, new code paths, new error branches โ even small ones
|
|
307
|
+
- mixed diffs (whitespace + a single semantic line) โ the semantic line still triggers self-review
|
|
308
|
+
- anything you're uncertain about
|
|
309
|
+
|
|
310
|
+
Tie-breaker: when in doubt, run self-review. One false-positive subagent dispatch costs cents; one false-negative shipped bug costs much more. There's no value in dispatching for a typo, but there's also no excuse for skipping on a 1-line change to a billing path.
|
|
311
|
+
|
|
312
|
+
Otherwise delegate the \`${REVIEWER_AGENT_NAME}\` subagent to review your diff with fresh eyes against YOUR TASK. The subagent's baked-in system prompt enforces a non-mutative + non-recursive contract: read-only file/search/web tools and read-only MCP queries only; no writes, shell side effects, state-changing MCP calls, or nested subagent dispatch. Enforcement is prose-only โ restate the constraint in your dispatch instructions and do not relax it.
|
|
313
|
+
|
|
314
|
+
Before dispatching, ensure \`origin/<base>\` is locally available โ the runner is often a shallow single-branch \`actions/checkout\` (depth=1, head-only refspec), and the reviewer's \`git diff --merge-base origin/<base>\` will fail with \`ambiguous argument\` or \`no merge base\` otherwise. Run \`git fetch --no-tags --deepen=1000 origin <base>:refs/remotes/origin/<base>\` once (the explicit destination refspec is required โ a shallow single-branch checkout configures a head-only refspec, so a bare \`origin <base>\` only updates \`FETCH_HEAD\` and never creates the \`origin/<base>\` tracking ref); it's a no-op if the ref already has enough history. (The reviewer is read-only by contract, so it cannot do this itself โ fetching is the orchestrator's job.)
|
|
315
|
+
|
|
316
|
+
Compose your \`${REVIEWER_AGENT_NAME}\` dispatch prompt using this template verbatim, substituting the \`<...>\` placeholders. The preamble aligns the orchestrator side of the dispatch contract with the reviewer's baked-in system prompt โ both ends say the same thing about where the work lives and what to do on an empty diff.
|
|
317
|
+
|
|
318
|
+
\`\`\`
|
|
319
|
+
## What you're reviewing
|
|
320
|
+
This is a PRE-COMMIT Build-mode self-review. The work to review lives in the working tree (uncommitted), NOT in committed history.
|
|
321
|
+
|
|
322
|
+
Branch: <branch> (off <base>)
|
|
323
|
+
Canonical diff command: git diff --merge-base origin/<base>
|
|
324
|
+
|
|
325
|
+
Use \`--merge-base\` (single MCP \`git\` call, no shell substitution required). NOT bare \`git diff origin/<base>\` or two-dot \`git diff origin/<base>..HEAD\` โ the symmetric forms include the inverse of every commit landed on \`<base>\` since this branch forked, which is noise (and the git tool will reject those forms when the divergence is detected). \`origin/<base>...HEAD\` (three-dot) and \`--cached\` both miss the uncommitted edits self-review runs on, so they're also wrong here.
|
|
326
|
+
|
|
327
|
+
If the merge-base diff returns empty, treat it as "no changes โ nothing to review" and stop per your system prompt. Do not search for the work elsewhere.
|
|
328
|
+
|
|
329
|
+
## Your task
|
|
330
|
+
<YOUR TASK content>
|
|
331
|
+
|
|
332
|
+
## Build-phase failures
|
|
333
|
+
<tight summary โ what broke, root cause, the fix โ or "no build-phase failures">
|
|
334
|
+
\`\`\`
|
|
335
|
+
|
|
336
|
+
Follow the template with the diff content (\`git diff --merge-base origin/<base-branch>\` โ single MCP \`git\` call, captures committed + staged + unstaged, excludes base-branch progress) and your task brief. Instruct the subagent to flag bugs, logic errors, missing edge cases, gaps between request and diff, and unintended changes.
|
|
337
|
+
|
|
338
|
+
Delegation + research discipline (distilled from \`/anneal\` canonical โ these are codified learnings from many review rounds, not theoretical best practices):
|
|
339
|
+
- Do NOT summarize what you implemented โ that biases the subagent toward validating the shape of your solution rather than questioning it.
|
|
340
|
+
- Do NOT curate a reading list of files. Let the subagent discover scope from the diff and codebase.
|
|
341
|
+
- Do NOT pre-shape output with a severity / category schema. That leaks your hypotheses; severity is your call during evaluation.
|
|
342
|
+
- Do NOT defect-hunt the diff yourself in parallel with the subagent. Your role is dispatch + evaluation; doing the review yourself reintroduces the implementation bias the subagent is meant to mitigate.
|
|
343
|
+
- For diffs that rely on third-party API contracts, SDK semantics, framework directives, or DB engine specifics, instruct the subagent to verify load-bearing claims via web search and quote source URLs rather than trust training data โ this is the single most common review-quality failure mode.
|
|
344
|
+
|
|
345
|
+
Be **discerning** about what comes back. The reviewer is an AI subagent and is fallible โ treat every finding as a hypothesis, not a directive, and **verify each one yourself** against the diff and the code before deciding whether to apply. You are searching for a solution that is **complete, minimal, and elegant** โ you may need to think hard to find it. Do not over-engineer, do not be over-defensive, **do not write AI slop**. Reviewers bias toward *recommending additions*, and that bias has a recognizable slop texture: defensive checks for cases that cannot happen, extra logging, new abstractions used once, comments restating code, tests asserting tautologies, "just-in-case" guards, error handlers for cases the type system already rules out. Reject those. For each surviving finding, ask: would applying it leave the code more sound, correct, AND elegant? Two-out-of-three means look harder for a fix that gets all three before settling. After applying the fixes you accept, re-read your diff and be discerning about what *you just changed*: if any fix turned out to be bloat in context, revert it. Then verify only intended changes are present, no debug artifacts or commented-out code remain, no unrelated files were modified. Commit locally via shell (\`git add . && git commit -m "..."\`).
|
|
346
|
+
|
|
347
|
+
6. **finalize**:
|
|
348
|
+
- confirm a clean working tree, then push via \`${t("push_branch")}\` (see *SYSTEM* Git rules if this fails โ prepush errors are usually the repo's tests/lint, not infra timeouts)
|
|
349
|
+
- create a PR via \`${t("create_pull_request")}\`
|
|
350
|
+
- call \`${t("report_progress")}\` with the PR link or the exact error if push/PR failed
|
|
351
|
+
|
|
352
|
+
### Notes
|
|
353
|
+
|
|
354
|
+
For simple, well-defined tasks, skip the plan phase and go straight to build.`,
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
name: "AddressReviews",
|
|
358
|
+
description:
|
|
359
|
+
"Address PR review feedback; respond to reviewer comments; make requested changes to an existing PR",
|
|
360
|
+
prompt: `### Checklist
|
|
361
|
+
|
|
362
|
+
1. **task list**: create your task list for this run as your first action.
|
|
363
|
+
|
|
364
|
+
2. Checkout the PR branch via \`${t("checkout_pr")}\`.
|
|
365
|
+
|
|
366
|
+
3. Fetch review comments via \`${t("get_review_comments")}\`.
|
|
367
|
+
|
|
368
|
+
4. For each comment:
|
|
369
|
+
- understand the feedback
|
|
370
|
+
- **verify the finding yourself** against the actual code before deciding whether to apply โ every comment (human or agent) is a hypothesis, not a directive. agent reviewers especially are fallible.
|
|
371
|
+
- you are searching for a solution that is **complete, minimal, and elegant** โ you may need to think hard to find it. do not over-engineer, do not be over-defensive, **do not write AI slop**. reviewers bias toward *recommending additions*, and that bias has a recognizable slop texture: defensive checks for impossible cases, extra abstractions used once, comments restating obvious code, tests asserting tautologies, "just-in-case" guards, error handlers for cases the type system already rules out. reject those. evaluate whether applying the finding would leave the code more **sound, correct, AND elegant**; two-out-of-three is a signal to look harder for a fix that gets all three. if a request would add bloat โ ceremony without commensurate correctness benefit โ push back in your reply rather than mechanically applying it.
|
|
372
|
+
- if the request stands, make the code change using your native tools; otherwise reply explaining why
|
|
373
|
+
- record what was done (or why nothing was done)
|
|
374
|
+
|
|
375
|
+
5. Quality check:
|
|
376
|
+
- test changes, then review the diff before committing โ verify only intended changes are present, no debug artifacts remain, no fix turned out to be bloat in context (revert any that did), and the changes are clean enough that a senior engineer would approve without hesitation
|
|
377
|
+
- commit locally via shell (\`git add . && git commit -m "..."\`)
|
|
378
|
+
|
|
379
|
+
6. Finalize. Reply + resolve are paired write actions: do BOTH or NEITHER for each thread.
|
|
380
|
+
- confirm a clean working tree, then push via \`${t("push_branch")}\` (same push/prepush guidance as Build mode in *SYSTEM*)
|
|
381
|
+
- **if push fails**, call \`${t("report_progress")}\` with the exact error and STOP โ do NOT reply or resolve any thread until the fix is live on the remote. Resolving a thread without the fix landing misleads the reviewer.
|
|
382
|
+
- **on push success**, for each thread you acted on:
|
|
383
|
+
- reply ONCE via \`${t("reply_to_review_comment")}\`. The \`comment_id\` parameter takes the root comment's numeric \`id=\` (from the first \`comment author=...\` tag in the \`${t("get_review_comments")}\` output) โ NOT the \`thread=\` value; that's a separate GraphQL ID used by resolve. The runtime dedupes identical bodies within a session.
|
|
384
|
+
- **immediately** call \`${t("resolve_review_thread")}\` with that thread's \`thread=\` value as \`thread_id\`. Resolve every thread where you (a) made the requested code change in full โ partial fixes leave the thread open โ OR (b) replied with a substantive answer the user explicitly asked for. Do NOT resolve threads where you pushed back on the request and the disagreement is unresolved; leave those open for the human to mediate.
|
|
385
|
+
- call \`${t("report_progress")}\` with a brief summary`,
|
|
386
|
+
},
|
|
387
|
+
// Review and IncrementalReview use a 0-or-2+ lens pattern. The default is
|
|
388
|
+
// 0 lenses (orchestrator handles the review solo). Multi-lens (2+
|
|
389
|
+
// reviewfrog subagents in parallel) only fires for substantive PRs or
|
|
390
|
+
// high-stakes-subsystem touches โ and when it fires, ALL lenses must
|
|
391
|
+
// dispatch in a single assistant turn or the parallelism win disappears.
|
|
392
|
+
// We never dispatch exactly one lens: a single lens is just a worse,
|
|
393
|
+
// slower version of doing the work yourself.
|
|
394
|
+
//
|
|
395
|
+
// Build mode self-review is a different problem shape: the orchestrator
|
|
396
|
+
// wrote the code, so bias-mitigation comes from delegating to one
|
|
397
|
+
// fresh-eyes subagent that doesn't share the implementation context. A
|
|
398
|
+
// single subagent there is appropriate; the 0-or-2+ rule applies only to
|
|
399
|
+
// the Review/IncrementalReview lens fan-out where independence between
|
|
400
|
+
// perspectives is what's being purchased.
|
|
401
|
+
//
|
|
402
|
+
// Severity categorization is split across two surfaces: the opening
|
|
403
|
+
// callout (CAUTION/IMPORTANT/โน๏ธ/โ
) sets the review's overall tier, and
|
|
404
|
+
// per-bullet emoji prefixes (๐จ/โ ๏ธ/โน๏ธ in PR_SUMMARY_FORMAT) tag
|
|
405
|
+
// individual points inside summary sections โ scoping severity to the
|
|
406
|
+
// specific bullet rather than the whole section keeps a section that
|
|
407
|
+
// mixes a ๐จ and an โน๏ธ from being mislabeled by either of them.
|
|
408
|
+
{
|
|
409
|
+
name: "Review",
|
|
410
|
+
description:
|
|
411
|
+
"Review code, PRs, or implementations; provide feedback or suggestions; identify issues; or check code quality, style, and correctness",
|
|
412
|
+
prompt: `### Checklist
|
|
413
|
+
|
|
414
|
+
1. **task list**: create your task list for this run as your first action.
|
|
415
|
+
|
|
416
|
+
2. **checkout**: call \`${t("checkout_pr")}\` โ this returns PR metadata and a \`diffPath\`. read the diff TOC end-to-end and treat its file line ranges as your coverage checklist.
|
|
417
|
+
|
|
418
|
+
3. **triage**: orient yourself on the PR โ identify *what kind of thing this is* (domain it touches, seams it crosses, external contracts it depends on, user-facing surfaces it changes). pull as much context as you need to render a confident, well-grounded review: read related files, grep for callers of changed symbols, check tests that exercise the touched paths, fetch related GitHub state. **you are the synthesizer** โ never delegate understanding to subagents.
|
|
419
|
+
|
|
420
|
+
if the PR is **genuinely trivial**, skip the fan-out entirely and submit a \`No new issues found.\` review per step 7.
|
|
421
|
+
|
|
422
|
+
"Genuinely trivial" (skip):
|
|
423
|
+
- single-word doc typo, whitespace/format-only, comment-only across any number of files
|
|
424
|
+
- lockfile or generated-code regeneration (size of diff is irrelevant โ read the *shape*)
|
|
425
|
+
- mechanical rename whose only effect is import-path updates
|
|
426
|
+
- low-risk dep patch bump
|
|
427
|
+
|
|
428
|
+
"Looks trivial but isn't" (do **NOT** skip โ small diff, big blast radius):
|
|
429
|
+
- any 1-line change to SQL / regex / auth / billing / permission / signature-verification code
|
|
430
|
+
- flipping a feature-flag default, default config value, or retry/timeout constant
|
|
431
|
+
- changing a money/tax/currency/fee constant by any amount
|
|
432
|
+
- changing an HTTP method, redirect URL, response code, or status enum
|
|
433
|
+
- tightening or loosening a comparison operator (\`<\` โ \`<=\`, \`==\` โ \`!=\`)
|
|
434
|
+
- renaming a public API surface (still trivial in shape, but needs an impact lens)
|
|
435
|
+
- adding a new direct dependency (supply-chain surface)
|
|
436
|
+
- any "typo fix" in user-facing copy that changes meaning ("approved" โ "denied")
|
|
437
|
+
- mixed diffs where a semantic 1-liner is buried in whitespace/formatting changes
|
|
438
|
+
|
|
439
|
+
4. **lens decision โ 0 or 2+, NEVER 1**.
|
|
440
|
+
|
|
441
|
+
The default is **0 lenses**: handle the review yourself end-to-end. Most PRs land here.
|
|
442
|
+
|
|
443
|
+
Dispatch **2+ \`${REVIEWER_AGENT_NAME}\` lenses in parallel** ONLY when ALL of the following are true:
|
|
444
|
+
- the PR is substantive (>5 files changed AND >200 net lines), OR touches a high-stakes subsystem (auth, billing, payments, schema migration, webhooks, secrets, RBAC, multi-tenant isolation, cron/scheduling)
|
|
445
|
+
- you can name 2+ distinct concrete failure modes that warrant independent lenses (one lens per failure mode; orthogonal, not overlapping)
|
|
446
|
+
- parallel-orchestrated independent perspectives meaningfully outperform what you'd find solo
|
|
447
|
+
|
|
448
|
+
**NEVER dispatch exactly one lens.** A single lens is just a more expensive version of doing the work yourself with a worse model โ it adds wall time and a context-handoff for no orthogonality benefit. Either you have at least two genuinely independent failure-mode hypotheses (dispatch all in one turn), or you don't (do the review yourself).
|
|
449
|
+
|
|
450
|
+
When you do go multi-lens, lens framings come in two flavors:
|
|
451
|
+
- **themed lenses** โ a perspective applied across the whole diff (correctness, security, user-journey, performance, etc.).
|
|
452
|
+
- **subsystem lenses** โ a domain-scoped frame for high-stakes subsystems the PR touches (e.g. "the auth lens", "the billing lens", "the schema-migration lens"). **for high-stakes domains, lead with the subsystem lens rather than the generic themed equivalent** โ "billing-subsystem" outperforms "correctness on billing code" because the framing primes the subagent to remember domain-specific failure modes (double-charges, refund races, currency rounding, dispute flows) the generic lens misses.
|
|
453
|
+
|
|
454
|
+
starter menu (combine, omit, or invent your own):
|
|
455
|
+
- **correctness & invariants** โ bugs, races, error handling, edge cases, state-machine boundaries
|
|
456
|
+
- **impact** โ stale references in code/tests/docs/configs/UI after rename/remove
|
|
457
|
+
- **research-validated assumptions** โ third-party API contracts, SDK semantics, framework directives, version-gated behavior. **only pick when the PR's correctness depends on the contract behaving a specific way** โ not when the API is merely used. The bar is "if the third-party contract differs from what the diff assumes, the PR is incorrect." When dispatched, the subagent must verify load-bearing claims via web search and quote source URLs.
|
|
458
|
+
- **security** โ new endpoints, authZ, input validation, secrets handling, replay/CSRF/injection, cross-tenant isolation
|
|
459
|
+
- **user-journey** โ UX-touching flows: walk through happy path and failure modes as a user
|
|
460
|
+
- **operational readiness** โ observability, alerting, migrations (forward + rollback), feature flags, on-call burden
|
|
461
|
+
- **integration & cross-cutting** โ API contracts between modules, backward-compat of public surfaces, multi-service ordering
|
|
462
|
+
- **test integrity** โ meaningful coverage for the changed behavior; deterministic; no shared-state pollution
|
|
463
|
+
- **performance** โ N+1 queries, hot-path allocation, latency budgets, index coverage
|
|
464
|
+
- **holistic** โ does the PR make sense as a whole? symmetric flows (delete for every create, rollback for every migration)?
|
|
465
|
+
- **subsystem lenses** (invent as the PR demands) โ auth, billing, payments, schema migration, webhooks, secrets, RBAC, multi-tenant isolation, cron/scheduling, etc.
|
|
466
|
+
|
|
467
|
+
The only subagent type is \`${REVIEWER_AGENT_NAME}\` โ used for lens judgment work ("is this safe / correct / well-tested?"), runs on a mid-tier model.
|
|
468
|
+
|
|
469
|
+
5. **fan out (only if step 4 said 2+ lenses)**: dispatch every \`${REVIEWER_AGENT_NAME}\` subagent for this run **IN A SINGLE ASSISTANT TURN, AS MULTIPLE PARALLEL TASK TOOL_USE BLOCKS IN ONE MESSAGE.**
|
|
470
|
+
|
|
471
|
+
โ ๏ธ CRITICAL โ PARALLELISM IS THE ONLY REASON LENSES EXIST. โ ๏ธ
|
|
472
|
+
The default tool-call behavior of Claude Code (and most agent runtimes) is **serial dispatch**: emit one Task call, await result, emit next, await, etc. This collapses your fan-out into a sequential review where each lens adds N ร (orchestrator-think-time + lens-execution-time) to wall time. **YOU MUST OVERRIDE THIS DEFAULT.** Emit ALL of your Task tool_use blocks in the SAME assistant message, BEFORE you read ANY result from ANY of them. If you find yourself emitting one Task call, then thinking about the result, then emitting another โ STOP and re-issue them all together. The whole point of going multi-lens is the wall-clock speedup from parallel execution; serial dispatch defeats it entirely.
|
|
473
|
+
|
|
474
|
+
โ
Right pattern: one assistant turn with N Task tool_use blocks โ wait โ N results arrive together โ aggregate.
|
|
475
|
+
โ Wrong pattern: turn 1 = Task(lens A) โ turn 2 (after A's result) = Task(lens B) โ turn 3 (after B's result) = Task(lens C). This is the failure mode. Do not do this.
|
|
476
|
+
|
|
477
|
+
You can also include your own \`read\` / \`grep\` / \`webfetch\` calls in the SAME turn as the parallel \`${REVIEWER_AGENT_NAME}\` dispatches โ concurrent context-pulling on the orchestrator side runs in parallel with the lens fan-out and costs zero extra wall time.
|
|
478
|
+
|
|
479
|
+
if a subagent errors out, times out, or returns nothing usable, retry once with the same lens; if it still fails, proceed with partial coverage and note the missing lens in the review body โ do not skip the fan-out entirely on a single subagent failure. each subagent gets:
|
|
480
|
+
- **the absolute \`diffPath\` (and \`incrementalDiffPath\` if available) from step 2's \`${t("checkout_pr")}\` return, named verbatim in the dispatch prompt** (e.g. \`diffPath: /tmp/terramend-XXXX/pr-NNN-SHA.diff\`). the reviewer's baked-in system prompt selects its FIRST action on this token โ paraphrasing ("review the diff", "look at this PR") sends it down the \`git diff origin/<base>\` fallback, which fails on shallow GHA checkouts. the subagent \`read\`s those files for scope; it must NOT re-derive the diff via \`git diff\` (bare \`git diff origin/<base>\` is symmetric and pulls in the inverse of any commits that landed on \`<base>\` since the branch forked โ pure noise, and the git tool rejects it). reading and codebase exploration are still its job.
|
|
481
|
+
- **only one lens** โ never a multi-section "review for X, Y, and Z" prompt
|
|
482
|
+
- **a Task \`description\` set to the lens name** (e.g. \`"security"\`, \`"correctness"\`, \`"billing-subsystem"\`) โ the harness reads this field to label the subagent's log lines so parallel runs can be told apart in CI output. without it, every subagent shows up as \`subagent#N\`.
|
|
483
|
+
- if the lens touches external contracts, instruct the subagent to verify load-bearing claims via web search rather than trust training data, and to quote source URLs in its reasoning. action runs are non-interactive โ there's no human in the loop to catch "I'm pretty sure Stripe does X."
|
|
484
|
+
- ask the subagent to report findings with file paths and NEW line numbers from the diff so you can anchor inline comments without re-reading the entire diff.
|
|
485
|
+
|
|
486
|
+
delegation discipline:
|
|
487
|
+
- do NOT summarize the PR for them (biases toward a validation frame)
|
|
488
|
+
- do NOT hand them a curated reading list (let them discover scope)
|
|
489
|
+
- do NOT pre-shape their output with a finding schema
|
|
490
|
+
- do NOT mention the other lenses (independence is the point โ overlapping findings are a strong signal)
|
|
491
|
+
|
|
492
|
+
6. **aggregate & draft**: when the fan-out lands, merge findings; de-dup overlaps (two lenses catching the same issue = higher-confidence signal); trace each finding yourself before accepting it. drop praise, style preferences, speculative/unverified claims, findings about pre-existing code unrelated to the PR (heuristic: if the finding's root cause lives in lines this PR added or modified, it's in scope; otherwise drop unless the PR plausibly introduced or amplified the regression), and anything not actionable. also drop **bloat-shaped findings** โ proposed fixes that would add defensive checks for cases that can't happen, abstractions used once, comments restating obvious code, tests asserting tautologies, or "just-in-case" guards. subagents are fallible and bias toward recommending changes; the bar for an actionable inline comment is sound + correct + elegant. recommending a change that improves only one of the three (or worse, degrades elegance to nominally improve correctness) makes the codebase worse, not better.
|
|
493
|
+
|
|
494
|
+
Apply the **Finding precedents** (defined after this checklist, before the body format) to every candidate โ a precedent match means drop, unless you have specific evidence the precedent does not apply here.
|
|
495
|
+
|
|
496
|
+
**Hunt for non-anchored concerns before drafting.** After collecting your anchored findings, deliberately scan for concerns that have no specific line to point at โ typically: deletion / cleanup plans for code the diff replaces or shadows; rollout sequencing (what happens to in-flight state during deploy / revert?); coverage gaps the diff implies but doesn't add; scope questions that only the human can answer (e.g. is the legacy path going away or is this a long-term dual track?); architectural risks the diff opens up that aren't a single-line bug. On substantial PRs (migrations, refactors, multi-file rewrites, version bumps that change runtime semantics), at least one such concern almost always exists; if you can't think of any, your bar is probably too high.
|
|
497
|
+
|
|
498
|
+
${FINDING_VERIFICATION_PASS}
|
|
499
|
+
|
|
500
|
+
for surviving findings, draft inline comments with NEW line numbers from the diff โ attach a \`<details>Technical details</details>\` block to any inline comment whose fix is non-trivial or has cross-file implications (see Inline technical details in the format below). every comment must be actionable, 2-3 sentences max in the visible part. use GitHub permalink format for code references. for impact-analysis findings (stale references after rename/remove), report them in the review body ordered by severity (runtime breakage > incorrect docs > stale comments) rather than as inline comments unless they're anchored to a specific line.
|
|
501
|
+
|
|
502
|
+
7. **submit**: ALWAYS submit exactly one review via \`${t("create_pull_request_review")}\`. Do NOT call \`report_progress\` โ the review is the final record and the progress comment will be cleaned up automatically.
|
|
503
|
+
|
|
504
|
+
note: the first create_pull_request_review submission may error with a one-time diff-coverage nudge listing unread TOC regions. retry the same call to proceed โ optionally after reading the listed ranges. the pre-flight will not block again this session.
|
|
505
|
+
|
|
506
|
+
The review body is structured as: \`[optional alert blockquote]\` โ \`[PR summary using the default format below]\`. Inline comments are passed via the \`comments\` parameter, not in the body.
|
|
507
|
+
|
|
508
|
+
The opening callout is what the author sees first โ pick the one that matches what you want them to do. Five tiers, from loudest to friendliest:
|
|
509
|
+
|
|
510
|
+
- \`[!CAUTION]\` โ large red banner. Reads as "this will break something."
|
|
511
|
+
- \`[!IMPORTANT]\` โ large purple banner. Reads as "you need to look at this before merging."
|
|
512
|
+
- \`> โน๏ธ ...\` โ informational blockquote. Reads as "minor suggestions, nothing blocking."
|
|
513
|
+
- \`> โ
...\` โ green friendly blockquote. Reads as "no concerns, mergeable."
|
|
514
|
+
|
|
515
|
+
Two reinforcing levers: callout intensity (above) and \`approved\` (which gates the footer Fix-button affordance โ Fix renders on every non-approving review, so \`approved: true\` suppresses it). Wrapping mergeable feedback in \`[!IMPORTANT]\` trains users to click Fix on reviews that don't need fixing. Pick the tier the author's actual next action justifies.
|
|
516
|
+
|
|
517
|
+
- **critical issues** (blocks merge โ bugs, security, data loss, broken core flows):
|
|
518
|
+
\`approved: false\`. Body opens with \`> [!CAUTION]\\n> This PR introduces ...\`, followed by the PR summary. Include all inline comments via \`comments\`.
|
|
519
|
+
- **must-address non-critical findings** (real consequences if shipped โ incorrect behavior in non-critical paths, missing validation on user input, regressions the author should fix before merge):
|
|
520
|
+
\`approved: false\`. Body opens with \`> [!IMPORTANT]\\n> ...\`, followed by the PR summary. Reserve this tier for findings with concrete fallout โ do NOT use \`[!IMPORTANT]\` for nits, style preferences, or "consider also" suggestions. Include all inline comments via \`comments\`.
|
|
521
|
+
- **minor suggestions only** (single-line nits, doc/comment polish, defer-able observations, "rough edges"):
|
|
522
|
+
\`approved: false\`. Body opens with \`> โน๏ธ No critical issues โ minor suggestions inline.\\n\\n\` followed by the PR summary. Include all inline comments via \`comments\`. Vary the wording after the emoji to fit the review (e.g. "Minor suggestions only.", "Two rough edges worth a look."), but always keep the โน๏ธ prefix and keep it short.
|
|
523
|
+
- **informational observations** (mergeable as-is, nothing actionable โ e.g. prior feedback addressed cleanly, surfacing a minor stale doc reference, calling out something noteworthy without recommending a change):
|
|
524
|
+
\`approved: true\`. Body opens with \`> โ
No new issues found.\\n\\n\` followed by the PR summary. Do NOT include inline \`comments\` โ the โ
signals "no action needed", which contradicts an actionable anchor; if a point is concrete enough to anchor to a line, downgrade the whole review to "minor suggestions only" (\`approved: false\`) instead.
|
|
525
|
+
- **no actionable issues**:
|
|
526
|
+
\`approved: true\`. Body opens with \`> โ
No new issues found.\\n\\n\` followed by the PR summary.
|
|
527
|
+
|
|
528
|
+
${REVIEW_FINDING_PRECEDENTS}
|
|
529
|
+
|
|
530
|
+
${PR_SUMMARY_FORMAT}`,
|
|
531
|
+
},
|
|
532
|
+
// IncrementalReview shares Review's 0-or-2+ lens pattern AND its body
|
|
533
|
+
// format (PR_SUMMARY_FORMAT), scoped to the incremental delta against the
|
|
534
|
+
// prior terramend review. The "issues must be NEW since the last Terramend
|
|
535
|
+
// review" filter lives at aggregation time (step 8), NOT in the subagent
|
|
536
|
+
// prompt โ pushing the filter into subagents matches the canonical anneal
|
|
537
|
+
// anti-pattern of "list known pre-existing failures โ don't flag these"
|
|
538
|
+
// and suppresses signal on regressions the new commits amplified. A
|
|
539
|
+
// separate "Prior review feedback" checklist would duplicate the rolling
|
|
540
|
+
// PR summary snapshot's record of what earlier runs already addressed and
|
|
541
|
+
// add noise to the user-facing body. Same opening-callout + per-bullet
|
|
542
|
+
// emoji severity split as Review.
|
|
543
|
+
{
|
|
544
|
+
name: "IncrementalReview",
|
|
545
|
+
description:
|
|
546
|
+
"Re-review a PR after new commits are pushed; focus on new changes since the last review",
|
|
547
|
+
prompt: `### Checklist
|
|
548
|
+
|
|
549
|
+
1. **task list**: create your task list for this run as your first action.
|
|
550
|
+
|
|
551
|
+
2. **checkout**: call \`${t("checkout_pr")}\` โ this returns PR metadata, \`diffPath\` (full diff), and \`incrementalDiffPath\` (changes since last reviewed version, if available). read the diff TOC first and use its line ranges as your coverage checklist.
|
|
552
|
+
|
|
553
|
+
3. **incremental scope**: if \`incrementalDiffPath\` is present, read it to see what changed since the last review. this is a range-diff that isolates the net changes, filtering out base branch noise. if not present, fall back to reviewing the full PR diff and determine what changed since Terramend's most recent review.
|
|
554
|
+
|
|
555
|
+
4. **prior feedback โ read AND retire it**: fetch previous reviews via \`${t("list_pull_request_reviews")}\`, then call \`${t("get_review_comments")}\` on each prior Terramend review. Each thread renders as a section whose first line is a fenced tag \`comment author=<login> id=<fullDatabaseId> review=<reviewId> thread=<graphqlId>\`; section headers carry \`[RESOLVED]\` / \`[OUTDATED]\` when relevant. For every **open, Terramend-originated** thread, decide and act:
|
|
556
|
+
|
|
557
|
+
- **Terramend-originated** means the FIRST \`comment author=...\` tag in the section is \`author=terramend[bot]\`. The \`*\` marker on individual comments is unrelated โ it flags whether a comment belongs to the queried review, not whether it is the thread root.
|
|
558
|
+
- **addressed?** read the file at the thread's anchor and judge whether the substantive concern is now resolved by the new commits. Lines being modified isn't enough: reformatting, renaming, or moving the same code elsewhere doesn't address a concern. If the comment raised multiple distinct concerns, ALL must be addressed. The \`[OUTDATED]\` tag means GitHub moved the anchor (line shift, force-push, rename) โ it does NOT mean the concern was addressed; re-read the code at its new location before deciding.
|
|
559
|
+
- **if addressed**: call \`${t("reply_to_review_comment")}\` with the root tag's numeric \`id=\` as \`comment_id\` (NOT the \`thread=\` value โ that's a separate GraphQL ID used only by resolve) and a one-line body (e.g. \`Addressed in <short-sha>.\`), then call \`${t("resolve_review_thread")}\` with the root tag's \`thread=\` value as \`thread_id\`. Do this BEFORE drafting the new review so the GitHub thread state aligns with the new review by the time it lands.
|
|
560
|
+
- **if uncertain or partially addressed**: leave open. False-positive resolutions erode trust faster than false negatives.
|
|
561
|
+
- **scope**: only retire Terramend-originated threads. Threads from human reviewers belong to those humans to resolve, even if the commit happened to address them.
|
|
562
|
+
- **reaction signal**: comment tags may carry \`reactions=๐N,๐N\` โ human votes on the finding. A ๐ on a Terramend-originated root comment is the human telling you the finding was wrong or unwanted: do NOT re-raise that finding class in this review, and treat it as false-positive feedback โ when a LEARNINGS file is configured, record the rejected finding class (rule/pattern + why the human rejected it, if discernible) so future reviews stop flagging it. A ๐ confirms the finding class is valued; no action needed beyond noting it. Reactions never override the addressed/unaddressed judgment for retiring threads โ a ๐ on an unfixed finding does not make it addressed.
|
|
563
|
+
|
|
564
|
+
The remaining open threads feed step 8's dedup filter โ anything already flagged and unchanged by the new commits should not be re-raised. The rolling PR summary snapshot is the durable record of retire activity; you don't need to surface it in the review body.
|
|
565
|
+
|
|
566
|
+
5. **triage**: orient on the *incremental* changes โ domain, seams, external contracts, user-facing surfaces. pull as much context as you need to render a confident review: read related files, grep for callers of changed symbols, check tests that exercise the touched paths. **you are the synthesizer.**
|
|
567
|
+
|
|
568
|
+
if the incremental changes are **genuinely trivial**, skip the fan-out entirely and jump to step 10's non-substantive path (do NOT submit a review).
|
|
569
|
+
|
|
570
|
+
"Genuinely trivial" (skip): formatting/comment tweaks, import reordering, lockfile regen, mechanical rename of import paths, whitespace-only.
|
|
571
|
+
"Looks trivial but isn't" (do NOT skip โ same anti-patterns as Review mode): 1-line changes to SQL/regex/auth/billing/permissions/signature-verification code; flipping feature-flag defaults or retry/timeout constants; money/tax/HTTP-method/redirect changes; tightening or loosening a comparison operator; mixed diffs with a semantic line buried in formatting.
|
|
572
|
+
When unsure, treat as non-trivial.
|
|
573
|
+
|
|
574
|
+
6. **lens decision โ 0 or 2+, NEVER 1**.
|
|
575
|
+
|
|
576
|
+
The default is **0 lenses**: handle the re-review yourself end-to-end. Most incremental reviews land here โ especially thread-reply re-reviews where the user is asking "did you address X?" rather than "review the diff again."
|
|
577
|
+
|
|
578
|
+
Dispatch **2+ \`${REVIEWER_AGENT_NAME}\` lenses in parallel** ONLY when ALL of the following are true:
|
|
579
|
+
- the incremental changes are substantive (>5 files changed AND >200 net new lines), OR touch a high-stakes subsystem (auth, billing, payments, schema migration, webhooks, secrets, RBAC, multi-tenant isolation, cron/scheduling)
|
|
580
|
+
- you can name 2+ distinct concrete failure modes the new commits plausibly introduce that warrant independent lenses
|
|
581
|
+
- parallel-orchestrated independent perspectives meaningfully outperform what you'd find solo
|
|
582
|
+
|
|
583
|
+
**NEVER dispatch exactly one lens.** Single-lens dispatch adds wall time and cost for no orthogonality benefit. Either go multi-lens (โฅ2 in parallel) or do the re-review yourself.
|
|
584
|
+
|
|
585
|
+
Lens framing follows Review mode: themed lenses (correctness, security, etc.) and subsystem lenses (auth, billing, schema-migration, etc.) โ for high-stakes domains lead with the subsystem lens.
|
|
586
|
+
|
|
587
|
+
7. **fan out (only if step 6 said 2+ lenses)**: dispatch every \`${REVIEWER_AGENT_NAME}\` subagent for this run **IN A SINGLE ASSISTANT TURN, AS MULTIPLE PARALLEL TASK TOOL_USE BLOCKS IN ONE MESSAGE.**
|
|
588
|
+
|
|
589
|
+
โ ๏ธ CRITICAL โ PARALLELISM IS THE ONLY REASON LENSES EXIST. โ ๏ธ
|
|
590
|
+
Default tool-call behavior is **serial dispatch**: emit one Task call, await result, emit next, await, etc. This collapses your fan-out into a sequential review where each lens adds N ร (orchestrator-think-time + lens-execution-time) to wall time. **YOU MUST OVERRIDE THIS DEFAULT.** Emit ALL of your Task tool_use blocks in the SAME assistant message, BEFORE you read ANY result from ANY of them.
|
|
591
|
+
|
|
592
|
+
โ
Right pattern: one assistant turn with N Task tool_use blocks โ wait โ N results arrive together โ aggregate.
|
|
593
|
+
โ Wrong pattern: turn 1 = Task(lens A) โ turn 2 (after A's result) = Task(lens B). This is the failure mode.
|
|
594
|
+
|
|
595
|
+
You can also include your own \`read\` / \`grep\` / \`webfetch\` calls in the SAME turn as the parallel \`${REVIEWER_AGENT_NAME}\` dispatches.
|
|
596
|
+
|
|
597
|
+
if a subagent errors out, times out, or returns nothing usable, retry once with the same lens; if it still fails, proceed with partial coverage and note the missing lens in the review body. each subagent gets:
|
|
598
|
+
- **the absolute diff path(s) from step 2's \`${t("checkout_pr")}\` return, named verbatim in the dispatch prompt.** when \`incrementalDiffPath\` is present, name BOTH (\`incrementalDiffPath: /tmp/.../pr-NNN-SHA-incremental.diff\` then \`diffPath: /tmp/.../pr-NNN-SHA.diff\`) โ the reviewer's baked-in prompt reads incremental first and uses full for context; when only \`diffPath\` exists, name it alone. the subagent \`read\`s those files; it must NOT re-derive via \`git diff\` (bare \`git diff origin/<base>\` is symmetric and pulls in the inverse of base-branch progress โ pure noise, and the git tool rejects it), and paraphrasing ("review the new commits") sends it down that fallback, which also fails on shallow GHA checkouts. do NOT tell them to skip pre-existing issues โ that suppresses regressions the new commits amplified; the "issues must be NEW" filter lives at aggregation time (step 8), not in the subagent prompt.
|
|
599
|
+
- **only one lens** โ never a multi-section "review for X, Y, and Z" prompt
|
|
600
|
+
- **a Task \`description\` set to the lens name** โ the harness reads this field to label log lines so parallel runs can be told apart.
|
|
601
|
+
- if the lens touches external contracts, instruct the subagent to verify load-bearing claims via web search and quote source URLs.
|
|
602
|
+
- ask the subagent to report findings with file paths and NEW line numbers from the full PR diff so you can anchor inline comments.
|
|
603
|
+
|
|
604
|
+
delegation discipline:
|
|
605
|
+
- do NOT summarize the changes for them (biases toward validation frame)
|
|
606
|
+
- do NOT hand them a curated reading list (let them discover scope)
|
|
607
|
+
- do NOT pre-shape their output with a finding schema
|
|
608
|
+
- do NOT mention the other lenses (independence is the point)
|
|
609
|
+
|
|
610
|
+
8. **aggregate, draft, self-critique**: merge findings (yours + any subagent output if you went multi-lens); de-dup overlaps; trace each finding yourself. drop praise, style preferences, speculative/unverified claims, findings about pre-existing code unrelated to the new commits, anything not actionable, and anything that re-states prior review feedback (heuristic: if the finding's root cause lives in lines the *new commits* added or modified, it's in scope; otherwise drop). also drop **bloat-shaped findings** โ proposed fixes that would add defensive checks for cases that can't happen, abstractions used once, comments restating obvious code, tests asserting tautologies, or "just-in-case" guards. subagents are fallible and bias toward recommending changes; the bar for an actionable inline comment is sound + correct + elegant. recommending a change that improves only one of the three (or degrades elegance to nominally improve correctness) makes the codebase worse, not better. To compute "lines the new commits added or modified": if \`incrementalDiffPath\` from step 2 is present, use it directly. Otherwise, take the prior Terramend review's \`commit_id\` (returned alongside each entry from \`${t("list_pull_request_reviews")}\` in step 4) and run \`git diff <prior-review-sha>..HEAD\` to isolate the lines added since that review.
|
|
611
|
+
|
|
612
|
+
Apply the **Finding precedents** (defined after this checklist, before the body format) to every candidate โ a precedent match means drop, unless you have specific evidence the precedent does not apply here.
|
|
613
|
+
|
|
614
|
+
**Hunt for non-anchored concerns before drafting.** After collecting your anchored findings, deliberately scan for concerns that have no specific line to point at โ typically: deletion / cleanup plans for code the new commits replace or shadow; rollout sequencing (what happens to in-flight state during deploy / revert?); coverage gaps the new commits imply but don't add; scope questions that only the human can answer (e.g. is the legacy path going away or is this a long-term dual track?); architectural risks the new commits open up that aren't a single-line bug. On substantial incremental diffs (migrations, refactors, multi-file rewrites, version bumps that change runtime semantics), at least one such concern almost always exists; if you can't think of any, your bar is probably too high.
|
|
615
|
+
|
|
616
|
+
${FINDING_VERIFICATION_PASS}
|
|
617
|
+
|
|
618
|
+
draft inline comments with NEW line numbers from the full PR diff โ attach a \`<details>Technical details</details>\` block to any inline comment whose fix is non-trivial or has cross-file implications (see Inline technical details in the format below). every comment must be actionable, 2-3 sentences max in the visible part.
|
|
619
|
+
|
|
620
|
+
9. **build the review body**: use the same default format as Review mode (preamble + optional cross-cutting \`### \` sections + optional \`### โน๏ธ Nitpicks\` + optional suppressed-findings block) โ scoped to the **incremental delta**, not the full PR. The "Reviewed changes" bullets describe what changed since the prior terramend review (each bullet starts with a past-tense verb, e.g. \`- Extracted shared CLI runtime into a single module\`). Do NOT include a separate "Prior review feedback" checklist โ that's tracked in the rolling PR summary snapshot for the next agent run, and surfacing it in the user-facing body is noise (changes that addressed prior feedback are already covered by the Reviewed-changes bullets). In some cases you may receive a complete diff for the whole PR instead of an incremental one; when this happens, determine what changed since Terramend's most recent review yourself before drafting bullets.
|
|
621
|
+
|
|
622
|
+
10. Submit โ every run must end with EXACTLY ONE of \`${t("create_pull_request_review")}\` (substantive review) or \`${t("report_progress")}\` (no-review acknowledgement). do NOT call \`create_issue_comment\` for review output.
|
|
623
|
+
|
|
624
|
+
Same callout ladder as Review mode โ \`[!CAUTION]\` (red, "will break") โ \`[!IMPORTANT]\` (purple, "must address before merging") โ \`> โน๏ธ ...\` (informational, "minor suggestions only") โ \`> โ
...\` (green friendly, "no concerns"). Same Fix-button lever: the footer renders a Fix button on every non-approving review, so \`approved: true\` suppresses it. Wrapping mergeable feedback in \`[!IMPORTANT]\` trains users to click Fix on reviews that don't need fixing โ pick the tier the author's actual next action justifies.
|
|
625
|
+
|
|
626
|
+
Follow these rules:
|
|
627
|
+
- note: the first create_pull_request_review submission may error with a one-time diff-coverage nudge listing unread TOC regions. retry the same call to proceed โ optionally after reading the listed ranges. the pre-flight will not block again this session.
|
|
628
|
+
- IF NO NEW ISSUES, NON-SUBSTANTIVE CHANGES ONLY (trivial formatting, import reordering, comment tweaks): do NOT submit a review. Instead call \`${t("report_progress")}\` with a 1-2 sentence note explaining no review was warranted (e.g. "No new issues. Changes since last review are formatting-only."). this leaves a visible signal that the run completed.
|
|
629
|
+
- ELSE IF NEW CRITICAL ISSUES (blocks merge โ bugs, security, data loss, broken core flows): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> [!CAUTION]\\n> This PR introduces ...\`, followed by the PR summary using the default format below.
|
|
630
|
+
- ELSE IF NEW MUST-ADDRESS NON-CRITICAL FINDINGS (real consequences if shipped โ incorrect behavior, missing validation, regressions the author should fix before merge): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> [!IMPORTANT]\\n> ...\`, followed by the PR summary using the default format below. Do NOT use this tier for nits, style preferences, or "consider also" suggestions.
|
|
631
|
+
- ELSE IF NEW MINOR SUGGESTIONS ONLY (single-line nits, doc/comment polish, defer-able observations, "rough edges"): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> โน๏ธ No critical issues โ minor suggestions inline.\\n\\n\` (vary the wording after โน๏ธ to fit the review), followed by the PR summary using the default format below.
|
|
632
|
+
- ELSE IF INFORMATIONAL OBSERVATIONS (mergeable as-is, but worth surfacing โ e.g. prior feedback addressed cleanly with one minor stale doc reference, or a noteworthy positive observation): call \`${t("create_pull_request_review")}\` with \`approved: true\`, NO inline comments, and the review body. body opens with \`> โ
No new issues found.\\n\\n\` (or similar friendly green opener), followed by the PR summary using the default format below. If a point is concrete enough to anchor to a line, downgrade the whole review to "minor suggestions only" (\`approved: false\`) instead โ the โ
signals "no action needed", which contradicts an actionable anchor.
|
|
633
|
+
- ELSE IF NO NEW ISSUES, SUBSTANTIVE CHANGES (new functionality, behavior changes, or fixes to prior review feedback): call \`${t("create_pull_request_review")}\` to create a PR review. If all previous reviews have been properly addressed and no new issues were discovered, set \`approved: true\`. body opens with \`> โ
No new issues found.\\n\\n\`, followed by the PR summary using the default format below.
|
|
634
|
+
|
|
635
|
+
${REVIEW_FINDING_PRECEDENTS}
|
|
636
|
+
|
|
637
|
+
${PR_SUMMARY_FORMAT}`,
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
name: "Plan",
|
|
641
|
+
description:
|
|
642
|
+
"Create plans, break down tasks, outline steps, analyze requirements, understand scope of work, or provide task breakdowns",
|
|
643
|
+
prompt: `### Checklist
|
|
644
|
+
|
|
645
|
+
1. **task list**: create your task list for this run as your first action.
|
|
646
|
+
|
|
647
|
+
2. Analyze the task and gather context:
|
|
648
|
+
- read AGENTS.md and relevant codebase files
|
|
649
|
+
- understand the architecture and constraints
|
|
650
|
+
|
|
651
|
+
3. Produce a structured, actionable plan with clear milestones.
|
|
652
|
+
|
|
653
|
+
4. Call \`${t("report_progress")}\` with the plan body. Do NOT set \`target_plan_comment\` โ that flag is exclusively for revising an existing plan, and \`${t("select_mode")}\` will route you to a separate PlanEdit checklist when a prior plan comment exists for this issue.`,
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
name: "Fix",
|
|
657
|
+
description:
|
|
658
|
+
"Fix CI failures; debug failing tests or builds; investigate and resolve check suite failures",
|
|
659
|
+
prompt: `### Checklist
|
|
660
|
+
|
|
661
|
+
1. **task list**: create your task list for this run as your first action.
|
|
662
|
+
|
|
663
|
+
2. Checkout the PR branch via \`${t("checkout_pr")}\`.
|
|
664
|
+
|
|
665
|
+
3. Fetch check suite logs via \`${t("get_check_suite_logs")}\`.
|
|
666
|
+
|
|
667
|
+
4. **CRITICAL**: verify the failure was INTRODUCED BY THIS PR before fixing. If unrelated, abort and report.
|
|
668
|
+
|
|
669
|
+
5. Diagnose and fix:
|
|
670
|
+
- read the workflow file, reproduce locally with the EXACT same commands CI runs
|
|
671
|
+
- fix the issue using your native file and shell tools
|
|
672
|
+
- verify the fix by re-running the exact CI command
|
|
673
|
+
- review the diff before committing โ verify only the fix is present, no debug artifacts, no unrelated changes. the fix should be clean enough that a senior engineer would approve without hesitation.
|
|
674
|
+
- commit locally via shell (\`git add . && git commit -m "..."\`)
|
|
675
|
+
|
|
676
|
+
6. Finalize:
|
|
677
|
+
- confirm a clean working tree, then push via \`${t("push_branch")}\` (same push/prepush guidance as Build mode in *SYSTEM*)
|
|
678
|
+
- call \`${t("report_progress")}\` with the diagnosis and fix summary (or the exact push error if push failed)`,
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
name: "ResolveConflicts",
|
|
682
|
+
description: "Resolve merge conflicts in a PR branch against the base branch",
|
|
683
|
+
prompt: `### Checklist
|
|
684
|
+
|
|
685
|
+
1. **task list**: create your task list for this run as your first action.
|
|
686
|
+
|
|
687
|
+
2. **Setup**:
|
|
688
|
+
- Call \`${t("checkout_pr")}\` to get the PR branch.
|
|
689
|
+
- Call \`${t("get_pull_request")}\` to identify the base branch (e.g., 'main').
|
|
690
|
+
- Call \`${t("git_fetch")}\` to fetch the base branch.
|
|
691
|
+
|
|
692
|
+
3. **Merge Attempt**:
|
|
693
|
+
- Run \`git merge origin/<base_branch>\` via shell.
|
|
694
|
+
- If it succeeds automatically, confirm a clean working tree, push via \`${t("push_branch")}\` (same push/prepush guidance as Build mode in *SYSTEM*), and call \`${t("report_progress")}\` with a brief success note or the exact push error if push failed โ **then stop; do not run steps 4โ5.**
|
|
695
|
+
- If it fails (conflicts), resolve them manually (continue to steps 4โ5).
|
|
696
|
+
|
|
697
|
+
4. **Resolve Conflicts**:
|
|
698
|
+
- Run \`git status\` or parse the merge output to find the list of conflicting files.
|
|
699
|
+
- For each conflicting file: read it, find the conflict markers (\`<<<<<<<\`, \`=======\`, \`>>>>>>>\`), understand the code context, and rewrite the file with the correct resolution. Remove all markers.
|
|
700
|
+
- Verify the file syntax is correct after resolution.
|
|
701
|
+
|
|
702
|
+
5. **Finalize**:
|
|
703
|
+
- Run a final verification (build/test) to ensure the resolution works.
|
|
704
|
+
- \`git add . && git commit -m "resolve merge conflicts"\`
|
|
705
|
+
- confirm a clean working tree, then push via \`${t("push_branch")}\` (same push/prepush guidance as Build mode in *SYSTEM*)
|
|
706
|
+
- Call \`${t("report_progress")}\` with a summary of what was resolved (or the exact push error if push failed)`,
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
name: "Remediate",
|
|
710
|
+
description:
|
|
711
|
+
"Bring a repository's Terraform up to best practice: scan with the deterministic check tools, then open one scoped, reviewable PR per concern that fixes it and proves it fixed (โโโ).",
|
|
712
|
+
prompt: `### Checklist
|
|
713
|
+
|
|
714
|
+
1. **task list**: create your task list for this run as your first action.
|
|
715
|
+
|
|
716
|
+
2. **scan**: call \`${t("terraform_scan")}\` to get the best-practice \`concerns\` plus \`groups\` โ one group per file, each with a stable \`id\`, its \`file\`, the group \`severity\` (highest in the file), the distinct \`rule_ids\`, and the \`concern_ids\` it covers. If it reports zero concerns, call \`${t("report_progress")}\` with "Terraform already follows best practice โ nothing to remediate." and **stop**.
|
|
717
|
+
|
|
718
|
+
*Alternative concern source:* if the Assessor (terraform-reviewer) has already produced a \`findings.json\` **or a SARIF report** (Trivy/Checkov/tflint \`-o sarif\`) for this repo (one exists in the workspace, or \`$TERRAMEND_FINDINGS_PATH\` is set), call \`${t("read_findings")}\` instead โ it auto-detects the format and returns the **same** \`{concerns, groups}\` shape, so the rest of this checklist is unchanged. Default to \`${t("terraform_scan")}\`; only use \`${t("read_findings")}\` when such a file is present (it returns \`found: false\` otherwise). Note that reviewer-exclusive findings (source \`reviewer\`) can't be re-verified by Terramend's scanners โ see the prove-it step.
|
|
719
|
+
|
|
720
|
+
*Multi-root repos (ยงMCP):* \`${t("terraform_validate")}\` and \`${t("terraform_plan")}\` are now **multi-root aware** โ they automatically validate/plan **every** Terraform root in the repo (e.g. hepcare's \`terraform/\` + \`terraform/core/\`) and aggregate the result (see \`roots_validated\` / \`roots_planned\`), so you do **not** need to loop per-root yourself. Call \`${t("terraform_roots")}\` only when you want to see the root layout (or fix a concern that lives in one specific root).
|
|
721
|
+
|
|
722
|
+
3. **pick scope**: act on **one group per PR** (a group is all of one file's concerns โ different scanners flag the same defect under different rules, so fixing per-file avoids a flood of near-duplicate PRs). Take the **highest-severity group first**. Unless the task explicitly asks for more, open **at most one PR this run**. Skip groups whose severity is only \`info\` unless asked. Use the \`terraform-best-practices\` skill for how to read each concern and apply the *minimal* fix.
|
|
723
|
+
|
|
724
|
+
**Autonomy (ยง3.9)**: each group carries an \`autonomy\` field โ \`auto\` (fix and open a normal PR) or \`needs-human\` (a security finding at/above the \`autonomy_threshold\`, or โ once plan runs โ a high blast radius). You still fix and open a PR for a \`needs-human\` group, but you MUST add the \`needs-human\` label (\`${t("add_labels")}\`), open the PR with \`approved: false\` framing, and put a prominent **โ ๏ธ Needs human review** callout at the top of the body listing the group's \`autonomy_reasons\`. Never batch a \`needs-human\` group with others.
|
|
725
|
+
|
|
726
|
+
**Dependency order & environment twins (ยง24 / ยง22)**: when a repo has local modules, \`${t("terraform_module_graph")}\` returns \`dependency_order\` โ fix a shared/depended-on module BEFORE its dependents so sequenced PRs don't conflict. \`${t("terraform_roots")}\` returns \`environment_twins\` โ parallel \`dev\`/\`staging\`/\`prod\` (or per-region) stacks that differ only by an environment segment; when the fixed file is one twin, note in the PR that the same fix should be offered for its twins (a separate PR per twin, honouring \`max_prs\`).
|
|
727
|
+
|
|
728
|
+
**Grouping & batching (ยง3.11 / ยง3.10)**: groups default to one-per-file. When a single rule dominates across many files (e.g. "add \`tags\` everywhere"), re-scan with \`group_by: "rule"\` so it becomes ONE coherent group/PR instead of many. The scan's \`batch_plan\` tells you which low-risk groups are \`batchable\` (combine them into the single \`batch_plan.batch_branch\` PR when \`max_prs\` would otherwise be exceeded) and which are \`isolated\` (each gets its own PR for independent review/revert). Still honour \`max_prs\` and never batch a \`needs-human\` group.
|
|
729
|
+
|
|
730
|
+
**Comment command (ยง3.12)**: when this run was triggered by a \`@terramend fix โฆ\` comment, the triggering body is in your prompt โ honour the requested scope INSTEAD of "highest-severity group": \`fix #<concern-id>\` โ act only on the group containing that concern id; \`fix all <severity>-severity\` โ set the scan \`severity_threshold\` to that level and act on those groups (up to \`max_prs\`); \`fix <file>.tf\` โ act on that file's group; \`fix all\` โ act on the highest-severity groups up to \`max_prs\`. If the comment isn't a recognised fix command, fall back to the default scope. A **strategy suffix** โ \`fix #<concern-id> with strategy B\` (or a bare \`strategy B\` reply on a proposal thread) โ additionally tells you **which** fix to apply: see ยง26 in step 4.
|
|
731
|
+
|
|
732
|
+
4. **for the chosen group**:
|
|
733
|
+
- **base branch**: this run's base branch is resolved deterministically โ \`${t("create_pull_request")}\` targets the \`base_branch\` input if set, else the repository's default branch (\`main\`, or \`master\`). You do not choose it; just **omit** the \`base\` argument when opening the PR (below) and it is filled in.
|
|
734
|
+
- **idempotency**: the remediation branch is \`remediate/<group-id>\`. Before doing anything, check whether that branch or an open PR for it already exists (\`${t("git")}\` / \`${t("get_pull_request")}\`). If one exists, update it rather than opening a duplicate.
|
|
735
|
+
- **branch**: create \`remediate/<group-id>\` from the **current HEAD** (the checkout that was just scanned) via \`${t("git")}\` (\`git checkout -b remediate/<group-id>\`). Do NOT switch to a different base first โ branching from the scanned checkout keeps the PR diff to exactly your fix.
|
|
736
|
+
- **honest refusal (ยง29 โ decide BEFORE fixing)**: if the group's concerns appear in the scan's \`refusal_candidates\` (the fix needs a human decision โ narrowing an IAM wildcard, a KMS key policy, a real ingress CIDR), do **not** guess a fix that could break the stack. Instead open a structured issue (\`${t("create_issue")}\`) describing the concern, why it isn't auto-fixed, and what a human should do, and skip the PR for that group. A proven fix or an honest refusal โ never a guessed, unverifiable PR.
|
|
737
|
+
- **propose, then let me steer (ยง26 โ when there's no single right fix)**: distinct from ยง29 (which refuses a fix a human must *decide*), ยง26 is for a finding with **2โ3 genuinely distinct, defensible fixes** that differ in trade-offs, not correctness (e.g. encrypt with an AWS-managed key **vs** a customer-managed KMS key; a narrow security-group rule **vs** a prefix list **vs** a VPC endpoint). When such a fork exists **and the triggering comment did not already select a strategy**, do **not** silently pick for the reviewer: via \`${t("create_issue_comment")}\` post one short comment listing the options as **A / B / C** โ each a single line (what it does + its trade-off) โ and ask the reviewer to reply \`@terramend fix #<concern-id> with strategy <A|B|C>\`. Then **skip the PR for this group** this run and note it in your final report (it resumes when the reviewer replies). When the comment **did** select one (\`fix #<id> with strategy B\`, or a bare \`strategy B\` reply on the proposal thread), apply **exactly** that strategy โ don't second-guess it. Reserve this for real forks in the road; a fix with one obvious correct answer just gets made.
|
|
738
|
+
- **fix**: edit the group's file(s), using your native file tools. For a by-file group that's the single \`file\`; for a **by-rule group (ยง3.11)** it's every entry in \`files\` (fix the one rule everywhere it fires). Resolve **every** concern in the group โ when the scan's \`co_located\` shows several scanners flagged the same \`file:line\` (ยง30), they're one underlying defect: write ONE canonical fix and one explanation, not separate edits. **Only touch \`*.tf\` / \`*.tfvars\` files.** Make the smallest changes that clear the concerns โ do NOT reformat or refactor unrelated code (see *SYSTEM* surgical-change rules). **Module-source awareness (ยง4.14):** call \`${t("terraform_module_graph")}\` first โ if the concern's file is inside a \`local_module_dir\`, fix it ONCE at the module source (it propagates to all callers; note them in the PR); if the fix would require editing a registry/git/remote module, you can't fix it here โ report it (open an issue naming the upstream module + version) instead. **Approved modules (ยง4.14):** call \`${t("list_modules")}\` and prefer a catalogue module (registry or house, pinned) when the fix is genuinely a module swap โ but for a one-line fix on an existing raw resource, fix it in place. **Provider-major awareness (ยง4.15):** before introducing an argument or block, check \`terraform_validate\`'s \`providers\` list for the pinned \`major\` โ argument names and valid blocks differ across majors. After the dir is init-ed (validate/plan ran), you can **verify an argument exists** for the installed provider with \`${t("terraform_provider_schema")}\` (pass the resource type + the arg names you added; it returns any \`unknown_args\` that would break \`plan\`). **Reusing a module?** call \`${t("terraform_module_interface")}\` on its dir to get its real \`variable\` names + which are required, so the \`module\` block you write is correct.
|
|
739
|
+
- **keep the module's tests/examples consistent (ยง28 โ only when you fixed a reusable module)**: if the file(s) you changed live inside a \`local_module_dir\` (from \`${t("terraform_module_graph")}\`) AND your fix changed the module's public interface (added/removed/renamed a \`variable\`, tightened a type), call \`${t("terraform_module_tests")}\` with that module dir. It returns the module's existing \`examples/\` fixtures + \`terraform test\` (\`*.tftest.hcl\`) / Go Terratest files and the \`drift\` per asset โ \`missing_required\` (a variable the asset must now set) and \`unknown_set\` (a variable the asset references that no longer exists). Update **exactly** the drifting assets so they match the new interface; **never weaken, delete, or comment out an assertion just to make a test pass** โ a fix that breaks a module's contract is the test doing its job, so correct the fix or the fixture, not the assertion. \`examples/\` are \`*.tf\` (always within the push allow-list); native \`*.tftest.hcl\` / Go \`*_test.go\` files are only pushable when the \`terratest\` input is enabled โ when it isn't and only those drift, note the needed test update in the PR body for a human rather than leaving the module's own tests broken. Skip this entirely for a one-off raw-resource fix that doesn't touch a module interface.
|
|
740
|
+
- **validate**: call \`${t("terraform_validate")}\`. If it does not pass, fix what it reports or abandon this group โ **never open a PR whose validate did not pass**. Its \`providers\` field carries the pinned provider majors (use them as above). It also returns \`unknown_arguments\` (ยง4.15-next): arguments you wrote that are NOT in the installed provider's schema and would break \`plan\` โ treat any entry as a must-fix (correct the argument for the pinned major) even though \`passed\` doesn't gate on it. \`schema_checked: false\` means the schema wasn't available (rely on \`${t("terraform_plan")}\` then).
|
|
741
|
+
- **policy gate (optional, ยง3.5)**: if the repo ships policy-as-code (a \`policy/\`, \`policies/\`, or \`.conftest\` dir of Rego), call \`${t("policy_check")}\` โ it runs \`conftest\` against the plan JSON. It degrades green (\`ok: false\`) when conftest or a policy dir is absent. When it returns \`passed: false\`, treat it exactly like a failed validate: fix the violation (listed in \`failures\`) or label the PR \`needs-human\` and surface it โ never push past a policy denial.
|
|
742
|
+
- **plan (safety gate โ do this BEFORE pushing)**: call \`${t("terraform_plan")}\`. It auto-skips (returns \`ran: false\`) when no cloud credentials / the terraform CLI are present, or init/plan can't complete โ then carry on. When it returns \`ran: true\`, add a one-line **Plan** note to the PR body (e.g. \`Plan: +0 ~1 -0\`) and act on three signals:
|
|
743
|
+
- **destroy/replace (\`has_destroy_or_replace\`)**: treat it as a stop sign โ a best-practice remediation should rarely destroy or replace a resource. Any entry in \`stateful_destructive\` (a data-bearing resource: RDS, S3, EBS, a SQL database, โฆ) will be **hard-blocked at \`${t("push_branch")}\`** by a code-level guardrail unless the operator set the \`allow_replace\` input for that address โ so do not rely on narration: if the change would destroy/replace a stateful resource and that is not clearly intended, **abandon this group** and report it rather than attempting the push. List the \`destructive\` resources in your report either way.
|
|
744
|
+
- **blast radius (\`blast_radius.tier\`)**: add it to the PR body (e.g. \`Blast radius: low (1 resource)\`). When the tier is \`high\` (more than 10 resources, or the change spans more than one module), add a prominent **โ ๏ธ Large blast radius โ review carefully** callout to the PR body so a reviewer knows this is not a one-line change.
|
|
745
|
+
- **idempotency (\`idempotent\`)**: when it is \`false\`, the second plan disagreed with the first โ a perpetual-diff smell (a non-deterministic value such as \`timestamp()\`/\`uuid()\`/an unkeyed \`random_*\`). **Prefer to fix the non-determinism or abandon the group**; if you still open the PR, surface \`idempotency_warning\` prominently as a **โ ๏ธ Non-deterministic plan** caveat. (Note: this catches in-config non-determinism only โ Terramend never applies, so a provider-normalisation perpetual diff can't be detected here.)
|
|
746
|
+
- **needs-human (\`needs_human\`, ยง2.6โยง3.9)**: when \`true\`, the plan crossed a deterministic escalation line (high blast radius, a stateful destroy/replace, or a non-deterministic plan โ see \`needs_human_reasons\`). Add the \`needs-human\` label (\`${t("add_labels")}\`) and a louder callout.
|
|
747
|
+
- **full plan (\`plan_text\`, ยง1.2)**: when present, attach it to the PR body as a collapsed \`<details><summary>Plan</summary>\\n\\n\\\`\\\`\\\`\\nโฆ\\n\\\`\\\`\\\`\\n</details>\` block so a reviewer can see the exact planned change without re-running it.
|
|
748
|
+
- **commit + push**: \`git add\` only the file you changed, commit with a message naming the file and the key rules (e.g. \`fix(tf): harden main.tf โ S3 encryption + block public access\`), then \`${t("push_branch")}\` (same push/prepush guidance as Build mode in *SYSTEM*).
|
|
749
|
+
- **open PR โ with a COMPLETE body (MANDATORY)**: \`${t("create_pull_request")}\` (omit \`base\` โ it resolves to the run's base branch above). The PR body is the primary deliverable a human reviews โ open the PR **with a full body**, never a placeholder you intend to fill in later. At an absolute minimum the body MUST explain, in plain English: (a) **what was wrong** โ each concern by \`rule_id\` + its \`evidence\`; and (b) **what you changed** to fix each one, and why it's safe. Build it with the **Remediation PR format** at the end of this checklist (status banner โ title + badges โ \`## What changed\` with the ยง5.17 *Was / Changed / Safe because* note per concern). โ ๏ธ \`${t("report_progress")}\` writes the GitHub Actions **job summary**, which is NOT the PR body โ a good job summary does **not** substitute for a complete PR body. If you only have time/budget for one, the PR body wins.
|
|
750
|
+
- **prove it (โโโ)**: call \`${t("terraform_verify_remediation")}\` with the group's \`concern_ids\`. It re-runs the scanners and returns the authoritative \`resolved\` / \`remaining\` sets and a \`verified\` flag โ this is the proof, do NOT eyeball a scan or self-report. Then \`${t("update_pull_request_body")}\` to add a "Validation" section built **from that result**: one \`โ โ โ <rule_id> resolved\` line per id in \`resolved\`, and list every id in \`remaining\` honestly as still-open. Never mark a concern โ unless the tool returned it in \`resolved\`. Act on two more fields it returns:
|
|
751
|
+
- **regressions (ยง1.4)**: when \`has_regressions\` is true, the fix INTRODUCED new concerns (listed in \`regressions\`) that weren't there before โ it traded one defect for another. Add a prominent **โ ๏ธ Regression** callout listing them, add the \`needs-human\` label (\`${t("add_labels")}\`), and prefer reworking the fix to remove the regression before relying on the PR.
|
|
752
|
+
- **confidence (ยง5.19)**: render the returned \`confidence\` (high/medium/low) as a one-line badge in the PR body (e.g. \`Confidence: high\`) with its \`confidence_reasons\`. It is computed deterministically from the verification evidence (verified + no regressions + plan idempotency + blast radius + cost) โ report it verbatim, do NOT inflate it.
|
|
753
|
+
- **per-finding explanation (ยง5.17)**: in the PR body, give each resolved concern a short three-line note โ **Was** (what the scanner flagged, from its \`evidence\`), **Changed** (what your fix did), **Safe because** (why it's correct/non-breaking) โ and hyperlink the \`rule_id\` to its documentation. The scan output carries a \`doc_url\` per concern (and \`doc_urls\` per group); use it, falling back to the concern's \`remediation_hint\` when no \`doc_url\` is present.
|
|
754
|
+
- **compliance crosswalk (optional, ยง23)**: for a security-relevant fix, call \`${t("terraform_compliance_crosswalk")}\` with the group's \`concerns\` to get the UK/general frameworks + controls it touches (NCSC Cloud Principles, Cyber Essentials, NHS DSPT, Secure by Design, CIS, SOC 2). Add a short **## Compliance** note from \`by_framework\`, prefixed "Indicative alignment (crosswalk v{version}) โ not an audit verdict." Skip when nothing maps.
|
|
755
|
+
- **prevent recurrence (ยง21)**: the scan's \`prevention\` map gives a CI guardrail per \`rule_id\` (a Checkov hard-fail entry, a tflint rule, a \`trivy config\` gate, an \`fmt -check\` step). Add a short **๐ก๏ธ Prevent recurrence** note to the PR body with the suggested \`mechanism\` + \`snippet\` so the team can stop this class of concern coming back โ clearly marked as an optional follow-up, not part of this PR's diff.
|
|
756
|
+
- **cost impact (optional)**: call \`${t("infracost_diff")}\` to estimate the monthly cost change the fix introduces. It auto-skips (returns \`ran: false\`) when \`INFRACOST_API_KEY\` or the infracost CLI is absent โ in that case add nothing. When it returns \`ran: true\`, add a one-line **Cost impact** note to the PR body from its result: e.g. \`๐ฐ Cost impact: +$12.40/mo\` for an increase, \`-$3.10/mo\` for a decrease, \`no change\` when \`monthly_delta\` is 0, or \`~$X/mo (baseline unavailable)\` when \`monthly_delta\` is null. When it returns \`needs_human: true\` (ยง4.16 โ the increase crossed the \`cost_increase_block_usd\` threshold), add the \`needs-human\` label (\`${t("add_labels")}\`) and surface \`cost_escalation_reason\` prominently so a large spend increase isn't merged blindly.
|
|
757
|
+
|
|
758
|
+
5. **guardrails** (always): one scoped PR per group, never a mega-PR spanning multiple files; **never auto-merge** and always leave the PR for human review; never modify files outside \`*.tf\` / \`*.tfvars\`.
|
|
759
|
+
|
|
760
|
+
6. **finalize**: call \`${t("report_progress")}\` once with a summary โ which file/group was fixed, the PR link, and the โโโ result (or the exact tool error if push/PR creation failed).
|
|
761
|
+
|
|
762
|
+
**SARIF for code-scanning (optional, ยง3.5)**: when the workflow has a SARIF upload step (it grants \`security-events: write\` and runs \`github/codeql-action/upload-sarif\` on a \`terramend.sarif\`), call \`${t("terraform_emit_sarif")}\` once at the end so the full scan also lands in the repo's Security tab โ complementary to the fix PR, not a replacement for it.
|
|
763
|
+
|
|
764
|
+
${REMEDIATION_PR_FORMAT}`,
|
|
765
|
+
},
|
|
766
|
+
{
|
|
767
|
+
name: "RefreshRemediation",
|
|
768
|
+
description:
|
|
769
|
+
"Self-heal stale Terramend remediation PRs (ยง27): when a remediation PR's base branch has moved, re-derive the fix on the current base and force-update it, or close it if the concern is already resolved upstream. Best run on a schedule.",
|
|
770
|
+
prompt: `### Checklist
|
|
771
|
+
|
|
772
|
+
This mode keeps already-open Terramend remediation PRs healthy. A remediation PR is "the current base + a minimal, proven fix"; when the base advances, the PR's diff is computed against an old base and the concern may have been resolved upstream. This sweep re-derives each stale fix on the **current** base (it never \`git merge\`s the base in โ re-deriving avoids conflict resolution and keeps the PR diff to exactly the fix). The run starts checked out on the base/default branch.
|
|
773
|
+
|
|
774
|
+
1. **task list**: create your task list for this run as your first action.
|
|
775
|
+
|
|
776
|
+
2. **find stale PRs**: call \`${t("list_remediation_prs")}\`. It returns each open \`remediate/<id>\` / \`terramend/generate-<slug>\` PR with a \`recommended_action\`:
|
|
777
|
+
- \`skip\` โ the base hasn't moved; the fix is still current. Do nothing.
|
|
778
|
+
- \`escalate\` โ a human pushed commits to the branch; auto-refresh would overwrite their work. Add the \`needs-human\` label (\`${t("add_labels")}\`) and post ONE short comment (\`${t("create_issue_comment")}\`) noting the base moved and a manual rebase is needed. Never touch the branch.
|
|
779
|
+
- \`refresh\` โ the base advanced; act on it in step 4.
|
|
780
|
+
|
|
781
|
+
If there are zero \`refresh\`/\`escalate\` PRs, call \`${t("report_progress")}\` with "No stale Terramend remediation PRs โ all open fixes are current." and **stop**.
|
|
782
|
+
|
|
783
|
+
3. **scan the current base once**: call \`${t("terraform_scan")}\` (the checkout is on the base). This is the authoritative current-base concern set โ you use it both to decide whether a stale PR's concern is already resolved and to re-derive the fix. Note each group's stable \`id\` (it matches the PR branch's \`<id>\`).
|
|
784
|
+
|
|
785
|
+
4. **for each \`refresh\` PR** (act on at most \`max_prs\` of them this run โ process the highest-severity groups first; report the rest as deferred):
|
|
786
|
+
- **do NOT \`${t("checkout_pr")}\`** the stale PR โ you are re-deriving from the current base, not editing the old branch. Read the PR with \`${t("get_pull_request")}\` if you need its body/number.
|
|
787
|
+
- **resolved-on-base? โ close it**: look for a group in step 3's scan whose \`id\` equals the PR's \`group_id\` (for a by-rule/batch PR, match on the concern ids it covered). If **no** current group/concern corresponds, the concern was already fixed on the base (a human fix, or a base change removed the file) โ the PR is redundant. Call \`${t("close_pull_request")}\` with a one-line \`comment\` explaining it's resolved on the base. Do not push anything for this PR.
|
|
788
|
+
- **still present โ re-derive the fix on the current base**:
|
|
789
|
+
- **branch**: recreate the remediation branch at the current base HEAD via \`${t("git")}\` (\`git checkout -B remediate/<id>\`) โ \`-B\` force-resets it to the just-scanned base so the diff is only your fix.
|
|
790
|
+
- **fix โ validate โ plan โ keep tests consistent (ยง28) โ prove it**: apply the minimal fix for that group exactly as in **Remediate** step 4 (same \`${t("terraform_validate")}\`, \`${t("terraform_plan")}\`, \`${t("terraform_module_tests")}\`, and \`${t("terraform_verify_remediation")}\` gates, and the same guardrails โ never open/keep a PR whose validate didn't pass, abandon a group that would destroy a stateful resource, etc.).
|
|
791
|
+
- **force-update the PR branch**: \`${t("push_branch")}\` with \`force: true\` (the PR already exists; force-updating its branch refreshes it in place โ do NOT open a second PR). The Terraform-only / secret / destroy guardrails still run at push time.
|
|
792
|
+
- **refresh the body**: \`${t("update_pull_request_body")}\` rebuilt from the fresh \`${t("terraform_verify_remediation")}\` result (the Remediation PR format below), and add a one-line note that it was rebased onto the current base (\`<short-sha>\`) on this run.
|
|
793
|
+
- Honour every Remediate guardrail: one scoped group per PR, never auto-merge, never modify non-\`*.tf\`/\`*.tfvars\` files.
|
|
794
|
+
|
|
795
|
+
5. **finalize**: call \`${t("report_progress")}\` once with a summary โ how many PRs were refreshed, closed-as-resolved, or escalated, with their links (or the exact tool error if a push/close failed).
|
|
796
|
+
|
|
797
|
+
${REMEDIATION_PR_FORMAT}`,
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
name: "GenerateTerraform",
|
|
801
|
+
description:
|
|
802
|
+
"Generate new Terraform from a plain-English requirement (or a description of desired infrastructure) so it starts best-practice: secure defaults, pinned versions, parameterised, validated, and opened as one reviewable PR.",
|
|
803
|
+
prompt: `### Checklist
|
|
804
|
+
|
|
805
|
+
1. **task list**: create your task list for this run as your first action.
|
|
806
|
+
|
|
807
|
+
2. **understand the requirement**: read the prompt / issue body and restate, in your task list, exactly what infrastructure is being asked for (provider, resources, environment, constraints). If something that materially changes the Terraform is ambiguous (region, sizing, public vs private, naming), make the **most secure, conventional** choice and record the assumption for the PR body โ do NOT invent unrequested resources or scope-creep.
|
|
808
|
+
|
|
809
|
+
3. **branch**: create \`terramend/generate-<short-slug>\` from the **current HEAD** via \`${t("git")}\` (\`git checkout -b terramend/generate-<short-slug>\`; slug from the requirement, e.g. \`terramend/generate-s3-static-site\`). The PR's base branch is resolved deterministically by \`${t("create_pull_request")}\` (the \`base_branch\` input, else the repository's default branch โ \`main\`, or \`master\`) โ you do not choose it; just omit the \`base\` argument when opening the PR.
|
|
810
|
+
|
|
811
|
+
4. **generate (best practice from the first line)**: write the Terraform with your native file tools, guided by the \`terraform-best-practices\` skill. Requirements:
|
|
812
|
+
- **Only create \`*.tf\` / \`*.tfvars\` files** (a code-level guardrail blocks the push otherwise). Split conventionally โ \`main.tf\` (resources), \`variables.tf\`, \`outputs.tf\`, \`versions.tf\` (pin \`required_version\` + \`required_providers\` with version constraints). Match the repo's existing layout when one exists.
|
|
813
|
+
- **Secure by default, not as an afterthought**: encryption at rest and in transit, block public access, least-privilege IAM (no wildcard actions/resources), IMDSv2, private networking, logging/versioning where supported. No \`0.0.0.0/0\` to admin/database ports. No plaintext secrets.
|
|
814
|
+
- **Parameterise**: expose environment-specific / likely-to-change values as typed \`variable\`s with \`description\`s and safe defaults; use \`locals\` for derived values. Never hardcode magic values.
|
|
815
|
+
- **Prefer modules**: call \`${t("list_modules")}\` first โ it returns the operator's \`module_catalogue\` AND \`discovered_house_modules\` (local modules already used in this repo). Build on those (registry, a private git module library, or a house module), using their exact variable names and pinning the \`version\` (a git module's pin is its \`?ref=\`). Otherwise use a well-maintained public registry module (e.g. the \`terraform-aws-modules\` collection, pinned) over hand-rolled resources when one cleanly fits.
|
|
816
|
+
- **Module layout (ยง28)**: when you generate a **reusable module**, follow the standard layout (\`main.tf\` / \`variables.tf\` (typed + \`description\` + validation) / \`outputs.tf\` / \`versions.tf\` / \`README.md\`). Do **not** generate \`examples/\` fixtures. When building a \`module\` block that consumes an EXISTING module, call \`${t("terraform_module_interface")}\` on its dir first to use its real variable names. When the \`terratest\` input is enabled, also call \`${t("scaffold_terratest")}\` (module name + its dir; pass the module's variables from \`${t("terraform_module_interface")}\`) to generate a plan-only Go Terratest test **and** a Terraform-native \`*.tftest.hcl\` โ both plan the module directly โ and write the returned files. Terramend never runs the tests (no cloud creds) โ note in the PR that they should be run in the user's pipeline.
|
|
817
|
+
- **Tag** resources consistently where the provider supports it.
|
|
818
|
+
|
|
819
|
+
5. **validate (must pass before any PR)**: call \`${t("terraform_validate")}\` (fmt + validate + tflint). Fix whatever it reports โ **never open a PR whose validate did not pass.**
|
|
820
|
+
|
|
821
|
+
6. **self-scan (the generated code must itself be clean)**: call \`${t("terraform_scan")}\`. Generated Terraform is meant to START best-practice, so the scan should report zero concerns in the files you wrote. If it surfaces any, fix them and re-scan until clean โ or, if a concern is a deliberate, justified exception, call it out explicitly in the PR body. Do not ship generated code that trips the scanners.
|
|
822
|
+
|
|
823
|
+
7. **cost (optional)**: call \`${t("infracost_diff")}\` to estimate the monthly cost of what you're creating. It auto-skips when \`INFRACOST_API_KEY\` / the infracost CLI is absent. When it returns \`ran: true\`, add a one-line **๐ฐ Cost impact** note to the PR body (for new infra the \`monthly_delta\` is the full cost of the addition).
|
|
824
|
+
|
|
825
|
+
8. **finalize**:
|
|
826
|
+
- confirm a clean working tree (only your new \`*.tf\`/\`*.tfvars\` files), then push via \`${t("push_branch")}\` (same push/prepush guidance as Build mode in *SYSTEM*).
|
|
827
|
+
- open a PR via \`${t("create_pull_request")}\` (omit \`base\` โ it resolves to the run's base branch above). Use the **Remediation PR format** conventions (the same status banner + badge row + \`## What changed\` shape, and the body-wide rules) ADAPTED for generation: the body states the requirement, what was generated, the key best-practice choices (security defaults, parameters, modules, pinned versions) and any assumptions; the badge row carries \`Plan\`/\`Cost\` when those tools ran; and in place of the \`## Validation (โ โ โ)\` section put a \`## Validation\` line stating \`terraform_validate\` passed and \`terraform_scan\` is clean (self-scan: 0 concerns).
|
|
828
|
+
- **never auto-merge** โ leave the PR for human review.
|
|
829
|
+
- call \`${t("report_progress")}\` once with the PR link (or the exact tool error if push/PR creation failed).
|
|
830
|
+
|
|
831
|
+
${REMEDIATION_PR_FORMAT}`,
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
name: "Task",
|
|
835
|
+
description:
|
|
836
|
+
"General-purpose tasks that don't fit other modes: answering questions, adding comments, labeling, running ad-hoc commands, or any direct request",
|
|
837
|
+
prompt: `### Checklist
|
|
838
|
+
|
|
839
|
+
1. **task list**: create your task list for this run as your first action.
|
|
840
|
+
|
|
841
|
+
2. Analyze the task. For simple operations (labeling, commenting, answering questions, running a single command), handle directly โ but your answer only reaches the user through \`${t("report_progress")}\` (step 4); raw assistant text is discarded.
|
|
842
|
+
|
|
843
|
+
3. For substantial work โ code changes across multiple files, multi-step investigations:
|
|
844
|
+
- plan your approach before starting
|
|
845
|
+
- use native file and shell tools for local operations
|
|
846
|
+
- use ${terramendMcpName} MCP tools for GitHub/git operations
|
|
847
|
+
- if code changes are needed: review your own diff before committing โ verify only intended changes are present, no debug artifacts remain, and the changes are clean enough that a senior engineer would approve without hesitation
|
|
848
|
+
|
|
849
|
+
4. Finalize:
|
|
850
|
+
- if code changes were made, push to a pull request (new or existing) using \`${t("push_branch")}\` and \`${t("create_pull_request")}\` as needed. \`git status\` must be clean before you finish (see *SYSTEM* Git rules if push fails).
|
|
851
|
+
- call \`${t("report_progress")}\` once with results โ include exact tool errors if push or PR creation failed
|
|
852
|
+
- if the task involved labeling, commenting, or other GitHub operations, perform those directly`,
|
|
853
|
+
},
|
|
854
|
+
];
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// static export for UI display โ uses opencode format as the readable default
|
|
858
|
+
export const modes: Mode[] = computeModes("opencode");
|
|
859
|
+
|
|
860
|
+
/** built-in mode names in canonical casing. used to validate / canonicalize the
|
|
861
|
+
* `mode` action input so a CI run can pin a mode deterministically instead of
|
|
862
|
+
* relying on the agent's prompt-driven `select_mode` choice. mode names are
|
|
863
|
+
* agent-independent (only the embedded tool refs differ per agent), so the
|
|
864
|
+
* opencode-rendered list is the authoritative name set. */
|
|
865
|
+
export const BUILTIN_MODE_NAMES: readonly string[] = modes.map((m) => m.name);
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* modes that legitimately never modify the working tree. used by the post-run
|
|
869
|
+
* dirty-tree gate to suppress the "commit and push" nudge โ those modes
|
|
870
|
+
* complete by submitting a review (`Review` / `IncrementalReview`) or by
|
|
871
|
+
* posting a Plan comment (`Plan`), not by touching files. any leftover in the
|
|
872
|
+
* tree at end-of-run is incidental tool noise (e.g. a `node_modules/` from a
|
|
873
|
+
* stray install attempt) on an ephemeral worktree; nudging the agent to
|
|
874
|
+
* commit it would produce a spurious PR.
|
|
875
|
+
*/
|
|
876
|
+
export const NON_COMMITTING_MODES: ReadonlySet<string> = new Set([
|
|
877
|
+
"Review",
|
|
878
|
+
"IncrementalReview",
|
|
879
|
+
"Plan",
|
|
880
|
+
]);
|