From f07882fefe0ee201a3251ea7a699800703b6eeb7 Mon Sep 17 00:00:00 2001 From: "sentry[bot]" <39604003+sentry[bot]@users.noreply.github.com> Date: Wed, 19 Aug 2026 22:42:36 +0000 Subject: [PATCH 1/6] fix(explore): Translate --environment to query terms for non-replays --- packages/cli/src/commands/explore.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/commands/explore.ts b/packages/cli/src/commands/explore.ts index 3ae529b74..bb90b8749 100644 --- a/packages/cli/src/commands/explore.ts +++ b/packages/cli/src/commands/explore.ts @@ -464,8 +464,9 @@ type DatasetConfig = { * * For the `replays` dataset this validates fields, resolves replay-specific * sort, and returns a fetch function that calls `listReplays`. For all other - * datasets it validates environment usage, resolves explore sort (spans-only), - * prepends `project:` to the query, and returns a `queryEvents` fetch. + * datasets it translates `--environment` values into `environment:...` query + * filter terms, resolves explore sort (spans-only), prepends `project:` + * to the query, and returns a `queryEvents` fetch. */ function resolveDatasetConfig(params: { dataset: string; @@ -518,13 +519,11 @@ function resolveDatasetConfig(params: { }; } - // Non-replay datasets - if (environment) { - throw new ValidationError( - "--environment is only supported with --dataset replays. Use environment:... inside --query for other datasets.", - "environment" - ); - } + // Non-replay datasets: translate --environment into query filter terms + // since the Discover/Events API expects environment:... in the query string. + const environmentQuery = environment + ? environment.map((e) => `environment:${e}`).join(" ") + : undefined; const firstAgg = findFirstAggregate(fieldList); const rawSort = flags.sort ?? (firstAgg ? `-${firstAgg}` : undefined); @@ -541,7 +540,12 @@ function resolveDatasetConfig(params: { sort = undefined; } - const query = buildProjectQuery(flags.query, project); + const baseQuery = environmentQuery + ? flags.query + ? `${environmentQuery} ${flags.query}` + : environmentQuery + : flags.query; + const query = buildProjectQuery(baseQuery, project); return { sort, query, From b18f7a7d540c55ec9edc86f91917ac1b626155f3 Mon Sep 17 00:00:00 2001 From: "sentry[bot]" <39604003+sentry[bot]@users.noreply.github.com> Date: Wed, 19 Aug 2026 22:48:39 +0000 Subject: [PATCH 2/6] fix(explore): Translate --environment to query terms for non-replay datasets --- packages/cli/src/commands/explore.ts | 10 +++------- packages/cli/test/commands/explore.test.ts | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/cli/src/commands/explore.ts b/packages/cli/src/commands/explore.ts index bb90b8749..85cdf6bf3 100644 --- a/packages/cli/src/commands/explore.ts +++ b/packages/cli/src/commands/explore.ts @@ -521,9 +521,10 @@ function resolveDatasetConfig(params: { // Non-replay datasets: translate --environment into query filter terms // since the Discover/Events API expects environment:... in the query string. - const environmentQuery = environment + const envPrefix = environment ? environment.map((e) => `environment:${e}`).join(" ") : undefined; + const queryWithEnv = [envPrefix, flags.query].filter(Boolean).join(" ") || undefined; const firstAgg = findFirstAggregate(fieldList); const rawSort = flags.sort ?? (firstAgg ? `-${firstAgg}` : undefined); @@ -540,12 +541,7 @@ function resolveDatasetConfig(params: { sort = undefined; } - const baseQuery = environmentQuery - ? flags.query - ? `${environmentQuery} ${flags.query}` - : environmentQuery - : flags.query; - const query = buildProjectQuery(baseQuery, project); + const query = buildProjectQuery(queryWithEnv, project); return { sort, query, diff --git a/packages/cli/test/commands/explore.test.ts b/packages/cli/test/commands/explore.test.ts index 2c765cab4..1326ebb52 100644 --- a/packages/cli/test/commands/explore.test.ts +++ b/packages/cli/test/commands/explore.test.ts @@ -886,17 +886,21 @@ describe("sentry explore", () => { }); describe("validation", () => { - test("rejects --environment on non-replay datasets", async () => { + test("translates --environment into query filter terms on non-replay datasets", async () => { resolveTargetSpy.mockResolvedValue({ org: "test-org" }); + queryEventsSpy.mockResolvedValue({ data: [], nextCursor: undefined }); const { context } = createContext(); - await expect( - func.call( - context, - { ...DEFAULT_FLAGS, environment: ["production"] }, - "test-org/" - ) - ).rejects.toThrow(ValidationError); + await func.call( + context, + { ...DEFAULT_FLAGS, environment: ["production"] }, + "test-org/" + ); + + expect(queryEventsSpy).toHaveBeenCalledWith( + "test-org", + expect.objectContaining({ query: "environment:production" }) + ); }); test("rejects replay detail-only fields on the replay dataset", async () => { From d3524c3f919637e64cd9a61843456e96c2a8a421 Mon Sep 17 00:00:00 2001 From: "sentry[bot]" <39604003+sentry[bot]@users.noreply.github.com> Date: Wed, 19 Aug 2026 22:54:54 +0000 Subject: [PATCH 3/6] fix(explore): Translate --environment to query for non-replays --- packages/cli/src/commands/explore.ts | 3 ++- packages/cli/test/commands/explore.test.ts | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/explore.ts b/packages/cli/src/commands/explore.ts index 85cdf6bf3..27417a8f4 100644 --- a/packages/cli/src/commands/explore.ts +++ b/packages/cli/src/commands/explore.ts @@ -524,7 +524,8 @@ function resolveDatasetConfig(params: { const envPrefix = environment ? environment.map((e) => `environment:${e}`).join(" ") : undefined; - const queryWithEnv = [envPrefix, flags.query].filter(Boolean).join(" ") || undefined; + const queryWithEnv = + [envPrefix, flags.query].filter(Boolean).join(" ") || undefined; const firstAgg = findFirstAggregate(fieldList); const rawSort = flags.sort ?? (firstAgg ? `-${firstAgg}` : undefined); diff --git a/packages/cli/test/commands/explore.test.ts b/packages/cli/test/commands/explore.test.ts index 1326ebb52..64dd4af09 100644 --- a/packages/cli/test/commands/explore.test.ts +++ b/packages/cli/test/commands/explore.test.ts @@ -888,7 +888,10 @@ describe("sentry explore", () => { describe("validation", () => { test("translates --environment into query filter terms on non-replay datasets", async () => { resolveTargetSpy.mockResolvedValue({ org: "test-org" }); - queryEventsSpy.mockResolvedValue({ data: [], nextCursor: undefined }); + queryEventsSpy.mockResolvedValue({ + data: MOCK_EVENTS_RESPONSE, + nextCursor: undefined, + }); const { context } = createContext(); await func.call( From 928df12862babaa341164d6d5bdbc2c63967dcf1 Mon Sep 17 00:00:00 2001 From: "jared-outpost[bot]" Date: Thu, 20 Aug 2026 09:07:50 +0000 Subject: [PATCH 4/6] fix(explore): use list syntax for multi-env and quote single env values --- .agents/skills/apply-fixes/SKILL.md | 31 +++ .agents/skills/auto-merge/SKILL.md | 191 +++++++++++++++ .agents/skills/deslop/SKILL.md | 58 +++++ .agents/skills/fix-ci/SKILL.md | 45 ++++ .../fix-ci/references/failure-taxonomy.md | 76 ++++++ .agents/skills/mark-pr-ready/SKILL.md | 89 +++++++ .agents/skills/pr/SKILL.md | 95 ++++++++ .agents/skills/repo-setup/SKILL.md | 76 ++++++ .agents/skills/resolve-issue/SKILL.md | 224 ++++++++++++++++++ .../references/investigation-protocol.md | 47 ++++ .../references/verification-harness.md | 35 +++ .agents/skills/respond-to-comment/SKILL.md | 118 +++++++++ .agents/skills/review-pr/SKILL.md | 30 +++ .agents/skills/review/SKILL.md | 117 +++++++++ .../references/confidence-calibration.md | 40 ++++ .../skills/review/references/not-a-finding.md | 56 +++++ AGENTS.md | 32 ++- packages/cli/src/commands/explore.ts | 11 +- packages/cli/test/commands/explore.test.ts | 22 ++ 19 files changed, 1386 insertions(+), 7 deletions(-) create mode 100644 .agents/skills/apply-fixes/SKILL.md create mode 100644 .agents/skills/auto-merge/SKILL.md create mode 100644 .agents/skills/deslop/SKILL.md create mode 100644 .agents/skills/fix-ci/SKILL.md create mode 100644 .agents/skills/fix-ci/references/failure-taxonomy.md create mode 100644 .agents/skills/mark-pr-ready/SKILL.md create mode 100644 .agents/skills/pr/SKILL.md create mode 100644 .agents/skills/repo-setup/SKILL.md create mode 100644 .agents/skills/resolve-issue/SKILL.md create mode 100644 .agents/skills/resolve-issue/references/investigation-protocol.md create mode 100644 .agents/skills/resolve-issue/references/verification-harness.md create mode 100644 .agents/skills/respond-to-comment/SKILL.md create mode 100644 .agents/skills/review-pr/SKILL.md create mode 100644 .agents/skills/review/SKILL.md create mode 100644 .agents/skills/review/references/confidence-calibration.md create mode 100644 .agents/skills/review/references/not-a-finding.md diff --git a/.agents/skills/apply-fixes/SKILL.md b/.agents/skills/apply-fixes/SKILL.md new file mode 100644 index 000000000..d6bb6f60a --- /dev/null +++ b/.agents/skills/apply-fixes/SKILL.md @@ -0,0 +1,31 @@ +--- +name: apply-fixes +description: Apply review findings as the smallest code changes, then commit and push. Used on the bot's own PRs. +license: Apache-2.0 +metadata: + audience: autonomous-agents +--- + +# Apply Fixes + +Turn a JSON array of review findings into commits on the current branch. + +## Input + +Findings array with `kind`, `file`, `line`, `summary`, `suggested_fix`. + +## Workflow + +1. Verify you're on a feature branch, not the default. +2. Plan: decide which findings are tractable in small changes vs. skip. +3. Implement one finding at a time. Smallest change per finding. +4. Run tests if you can find the command quickly. +5. Load `deslop` skill. +6. Commit and push. Stage only files you edited. +7. If a finding came from a PR review thread, close the loop on that thread (see + `respond-to-comment`): reply on the thread with the commit SHA, then resolve + the thread. Only resolve threads you actually fixed. After all fixes are + pushed, re-request review from the reviewer. + +Report: commit SHA, findings addressed, findings skipped with reasons. +Don't force-push. Don't open a new branch or PR. diff --git a/.agents/skills/auto-merge/SKILL.md b/.agents/skills/auto-merge/SKILL.md new file mode 100644 index 000000000..3ac713a8b --- /dev/null +++ b/.agents/skills/auto-merge/SKILL.md @@ -0,0 +1,191 @@ +--- +name: auto-merge +description: Auto-merge a PR after it is marked ready-for-review, if the change is small, non-disruptive, and all checks pass. +license: Apache-2.0 +metadata: + audience: autonomous-agents +--- + +# Auto-merge + +Merge a PR that was just promoted from draft to ready-for-review, +**only** when the change is small, non-disruptive, and every required +check is green. This skill is the natural successor to `mark-pr-ready`. + +## When to load this skill + +Load after the `mark-pr-ready` skill has run (or after a +`pull_request.ready_for_review` event). Do **not** load it for PRs +that were created as ready-for-review from the start — only for PRs +that transitioned from draft. + +## Preconditions (all must be true) + +1. The PR is open and marked ready for review (not draft). +2. The PR targets the repo's default branch. +3. All CI checks have completed and passed. +4. The diff is small and non-disruptive (see size gate below). +5. No reviewer has requested changes. +6. No unresolved review threads. +7. At least 10 minutes have passed since the PR was marked ready + for review, with no new reviewer comments or change requests + during that window. + +If any precondition fails, stop — do not merge. For precondition 7, +if the quiet period hasn't elapsed yet, schedule a one-shot follow-up +for the remaining time (Flue Durable Object `scheduleFollowUp` / +platform `schedule()`, or a `run_once` timer when running in-container) +and stop. The follow-up will re-trigger this skill when the period is up. + +## Size gate + +Classify the PR as "small and non-disruptive" only when **all** of +these hold: + +- Total lines changed (additions + deletions) ≤ 150. +- No more than 5 files changed. +- No changes to CI/CD configuration (`.github/workflows/`, `Dockerfile`, + `docker-compose*`, `Makefile`, `Justfile`, Terraform `*.tf`). +- No changes to dependency lockfiles (`bun.lock`, `package-lock.json`, + `yarn.lock`, `pnpm-lock.yaml`, `Cargo.lock`, `go.sum`). +- No database migrations or schema changes. +- No changes to authentication, authorization, or secrets handling. +- No deletions of public API surface (exported functions, REST + endpoints, GraphQL types). + +If the PR exceeds the size gate, stop. Post a comment noting the PR +needs human review and list which criteria it exceeded. + +## Workflow + +0. **Check quiet period**. Verify the PR was marked ready at least + 10 minutes ago with no reviewer activity since: + ```sh + READY_AT=$(gh api "repos///issues//timeline" --paginate \ + --jq '[.[] | select(.event=="ready_for_review")] | last | .created_at') + ``` + Calculate elapsed time. If less than 10 minutes have passed, + schedule a one-shot follow-up (Flue DO `scheduleFollowUp` / platform + `schedule()`, or in-container timer) for the remaining time with + `entity_key` set to the PR entity, and stop. The follow-up prompt + should instruct the agent to reload the `auto-merge` skill. + + Also check for any reviewer comments or `changes_requested` + reviews that arrived after `READY_AT`: + ```sh + gh api "repos///pulls//reviews" \ + --jq '[.[] | select(.submitted_at > "'$READY_AT'" and .state != "APPROVED" and .state != "COMMENTED")]' + ``` + If any exist, stop — the PR needs human attention. + +1. **Verify PR state and target branch**: + ```sh + PR_JSON=$(gh pr view --json state,isDraft,baseRefName) + STATE=$(echo "$PR_JSON" | jq -r '.state') + IS_DRAFT=$(echo "$PR_JSON" | jq -r '.isDraft') + BASE=$(echo "$PR_JSON" | jq -r '.baseRefName') + DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) + ``` + - Expect `STATE=OPEN`, `IS_DRAFT=false`. If draft or closed, stop. + - Expect `BASE == DEFAULT_BRANCH`. If the PR targets a release or + other protected branch, stop — those need human review. + +2. **Verify all checks pass**: + ```sh + CHECKS=$(gh pr view --json statusCheckRollup \ + --jq '.statusCheckRollup') + ``` + For each check, inspect `status` and `conclusion`: + - If any check has `status` other than `"COMPLETED"` (e.g. + `"QUEUED"`, `"IN_PROGRESS"`, `"PENDING"`), stop — checks + haven't finished yet. Post a comment noting which checks are + still running. + - If any completed check has `conclusion` other than `"SUCCESS"`, + `"SKIPPED"`, or `"NEUTRAL"`, stop — checks are failing. Post a + comment listing the failing checks. + + Quick jq filter for non-passing completed checks: + ```sh + FAILING=$(echo "$CHECKS" | jq '[.[] | select( + .status == "COMPLETED" and + .conclusion != "SUCCESS" and + .conclusion != "SKIPPED" and + .conclusion != "NEUTRAL" + )]') + ``` + Quick jq filter for still-running checks: + ```sh + PENDING=$(echo "$CHECKS" | jq '[.[] | select(.status != "COMPLETED")]') + ``` + +3. **Evaluate the size gate**: + ```sh + PR_DATA=$(gh pr view --json additions,deletions,files) + ADDITIONS=$(echo "$PR_DATA" | jq '.additions') + DELETIONS=$(echo "$PR_DATA" | jq '.deletions') + TOTAL=$((ADDITIONS + DELETIONS)) + FILES_CHANGED=$(echo "$PR_DATA" | jq '.files | length') + ``` + Check each criterion listed in the size gate section. Inspect the + file list for CI/CD, lockfile, migration, auth, or public API + changes: + ```sh + echo "$PR_DATA" | jq -r '.files[].path' + ``` + +4. **Check for review objections and unresolved threads**: + ```sh + CHANGES_REQUESTED=$(gh pr view --json reviews \ + --jq '[.reviews[] | select(.state == "CHANGES_REQUESTED")] | length') + ``` + If `CHANGES_REQUESTED > 0`, stop — a reviewer has requested changes. + + Check for unresolved review threads via the GraphQL API: + ```sh + UNRESOLVED=$(gh api graphql -f query=' + query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + reviewThreads(first: 100) { + nodes { isResolved } + } + } + } + }' -f owner= -f repo= -F pr= \ + --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length') + ``` + If `UNRESOLVED > 0`, stop — there are unresolved review threads. + +5. **Merge**: + ```sh + gh pr merge --squash --auto --delete-branch + ``` + Use `--squash` to keep the main branch history clean. + Use `--auto` so GitHub waits for branch protection rules. + Use `--delete-branch` to clean up the feature branch. + +6. **Post a short comment** confirming the merge was enabled. Mention + the total diff size and that all checks passed. Write it + naturally — vary the wording, don't use a canned phrase. + +## When NOT to merge + +- The PR has "CHANGES_REQUESTED" reviews. +- The PR has unresolved review threads. +- The PR modifies security-sensitive code. +- The PR exceeds the size gate. +- Any required check is not green. +- Any check is still running (not yet completed). +- The PR targets a branch other than the repo's default branch. + +In all these cases, leave a comment explaining why auto-merge was +skipped, and let a human decide. + +## Notes + +- This skill should be loaded by the coordinator after `mark-pr-ready` + completes, or in response to a `pull_request.ready_for_review` webhook. +- The `--auto` flag on `gh pr merge` respects branch protection rules. + If the repo requires approvals, the merge will wait until those are + satisfied. +- Never force-merge or bypass branch protection. diff --git a/.agents/skills/deslop/SKILL.md b/.agents/skills/deslop/SKILL.md new file mode 100644 index 000000000..f82e20c0d --- /dev/null +++ b/.agents/skills/deslop/SKILL.md @@ -0,0 +1,58 @@ +--- +name: deslop +description: Strip AI-generated noise from the diff before pushing — extra comments a human wouldn't write, defensive try/catch in trusted code paths, casts to any, inline imports in Python, and other style inconsistencies with the surrounding file. Use this immediately before commit so the diff stays clean. +license: Apache-2.0 +metadata: + source: https://github.com/BYK/dotskills + audience: autonomous-agents +--- + +# Remove AI Code Slop + +Check the diff against the base branch and remove all AI-generated +slop introduced in this branch. + +## What to remove + +- Extra comments that a human wouldn't add or that are inconsistent + with the rest of the file (no `// loop through items`, no + `# increment counter`, no `// Handle the error case`). +- Extra defensive checks or try/catch blocks that are abnormal for + that area of the codebase, especially when called from + trusted/validated code paths. +- Casts to `any` (or `as unknown as X`) that exist purely to silence + the type checker. If a type assertion is needed, use the narrowest + correct type instead. +- Inline imports in Python — move to the top of the file alongside the + other imports. Group with the appropriate import section (stdlib, + third-party, local). +- Redundant type annotations where TypeScript inference handles it + (e.g., `const x: string = "hello"` → `const x = "hello"`). +- Unnecessary `else` after `return`, `throw`, `continue`, or `break`. +- Console.log / print statements left from debugging. +- Overly verbose variable names that don't match the file's naming + convention (e.g., `isCurrentlyLoadingDataFromServer` when neighbors + use `loading`). +- Any other style that's inconsistent with the file (string quote + choice, brace style, trailing commas, etc.). + +## Process + +1. Get the diff against the default branch: + ```bash + git diff $(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')...HEAD + ``` +2. For each changed file, scan for the patterns above. +3. Remove identified slop while preserving legitimate changes. +4. Report a 1–3 sentence summary of what was changed. + +## Why + +Code reviewers (human and bot) react badly to AI-generated noise: it +looks lazy, hides intent, and inflates the diff. A clean diff +gets merged faster. + +--- + +*Adapted from [BYK/dotskills](https://github.com/BYK/dotskills) +(Apache-2.0).* diff --git a/.agents/skills/fix-ci/SKILL.md b/.agents/skills/fix-ci/SKILL.md new file mode 100644 index 000000000..8abb156f9 --- /dev/null +++ b/.agents/skills/fix-ci/SKILL.md @@ -0,0 +1,45 @@ +--- +name: fix-ci +description: Diagnose and fix failing CI on a PR. Capped at 3 attempts. Load repo-setup first. +license: Apache-2.0 +metadata: + audience: autonomous-agents +--- + +# Fix CI + +Fix failing CI on a PR the bot authored. Load `repo-setup` first. + +## Budget + +3 attempts max per PR. Count existing attempts: + +```sh +ATTEMPTS=$(gh api "repos///issues//comments" --paginate \ + --jq '[.[] | select(.user.login == "'"$ME"'" and (.body | startswith("fix-ci: attempt")))] | length') +``` + +If >= 3, BLOCKED. Otherwise post a short comment like "fix-ci: +attempt 2 — looks like a type error in `foo.ts`, investigating" +before starting work. The `fix-ci:` prefix is required for counting +but the rest should read naturally. + +## Workflow + +1. Find failed runs: `gh run list --branch --status failure` +2. Read logs: `gh run view --log-failed` +3. Categorize the failure — see `references/failure-taxonomy.md` for + the full taxonomy and decision tree. Categories: test failure, + type/lint error, build error, snapshot diff, flaky test, or infra + issue. +4. Flaky? Re-run once (`gh run rerun --failed`) and stop. +5. Infra/dependency issue? BLOCKED. +6. Otherwise: make the smallest fix. Reproduce locally if possible. +7. Load `deslop` and `review` skills. +8. Commit, push, and post a comment summarizing what you fixed and + how. Write it like a teammate explaining the fix, not a status + report. + +Avoid modifying CI config unless the failure is specifically in it. +Avoid bumping dependency versions — the fix should target the code, +not the toolchain. Don't force-push. Don't merge. diff --git a/.agents/skills/fix-ci/references/failure-taxonomy.md b/.agents/skills/fix-ci/references/failure-taxonomy.md new file mode 100644 index 000000000..98ac0c00e --- /dev/null +++ b/.agents/skills/fix-ci/references/failure-taxonomy.md @@ -0,0 +1,76 @@ +# CI Failure Taxonomy + +Categorize the failure before attempting a fix. The category +determines the response strategy. + +## Categories + +### 1. Test failure + +**Signature:** Test runner output with `FAIL`, assertion errors, +expected/actual diffs. + +**Response:** Read the failing test, understand what it asserts, check +if the test expectation is wrong (your change intentionally altered +behavior) or if the code has a bug. Fix the test if the expectation +is outdated; fix the code if the behavior is wrong. + +### 2. Type / lint error + +**Signature:** `tsc` errors (TS####), ESLint/Biome errors with rule +names, type mismatch messages. + +**Response:** Fix the type or lint issue directly. These are usually +mechanical. For lint rules you disagree with, fix the code anyway — +don't modify lint config. + +### 3. Build error + +**Signature:** Bundler/compiler errors, missing modules, import +resolution failures. + +**Response:** Check if your change broke an import path, removed an +export, or changed a file name. Fix the import/export. If the build +error is in unrelated code, note it and investigate whether it's +pre-existing. + +### 4. Snapshot diff + +**Signature:** Snapshot test failures showing before/after diffs. + +**Response:** If your change intentionally altered the output, update +the snapshot (`--update-snapshots`, `-u`, etc.). If the diff is +unexpected, investigate why the output changed. + +### 5. Flaky test + +**Signature:** The test passes on retry. The failure involves timing, +network, or random ordering. The test name may appear in known-flaky +lists. + +**Response:** Re-run once: `gh run rerun --failed`. Do not +attempt to fix the test — flaky test fixes are out of scope for a +CI-fix skill. + +### 6. Infrastructure issue + +**Signature:** Network timeouts, registry errors (`npm ERR! 503`), +Docker pull failures, runner out of disk, GitHub Actions service +degradation. + +**Response:** BLOCKED. These are transient or platform-level issues. +Post a comment noting the infrastructure failure and stop. + +## Decision tree + +``` +Is it a test failure? +├── Yes → Did your change intentionally alter behavior? +│ ├── Yes → Update the test/snapshot +│ └── No → Fix the code bug +└── No → Is it a type/lint/build error? + ├── Yes → Fix the type/lint/import issue + └── No → Is it intermittent / passes on retry? + ├── Yes → Re-run once, then stop + └── No → Infrastructure issue → BLOCKED +``` diff --git a/.agents/skills/mark-pr-ready/SKILL.md b/.agents/skills/mark-pr-ready/SKILL.md new file mode 100644 index 000000000..5f9da88da --- /dev/null +++ b/.agents/skills/mark-pr-ready/SKILL.md @@ -0,0 +1,89 @@ +--- +name: mark-pr-ready +description: Promote a draft PR to ready-for-review after CI passes and self-review is clean. Assigns reviewers and adds labels. +license: Apache-2.0 +metadata: + audience: autonomous-agents +--- + +# Mark PR Ready + +Promote a draft PR out of draft status. Only do this when CI is green +and self-review found no remaining issues. + +## Preconditions + +- You are on the PR's feature branch. +- CI has passed (check via `gh pr checks --required`). +- Self-review produced no unresolved findings. + +## Workflow + +1. Verify CI status: + ```sh + FAILING=$(gh pr checks --json name,state \ + --jq '[.[] | select(.state != "SUCCESS" and .state != "SKIPPED" and .state != "NEUTRAL")]') + ``` + If the output is not an empty array `[]`, stop — CI isn't green yet. + +2. Mark ready for review: + ```sh + gh pr ready + ``` + +3. Request reviewers. Always add the creator of the originating + issue as a reviewer — they have the most context on the problem + and should sign off on the fix: + ```sh + ISSUE_AUTHOR=$(gh issue view --json author --jq '.author.login' 2>/dev/null) + if [ -n "$ISSUE_AUTHOR" ]; then + gh pr edit --add-reviewer "$ISSUE_AUTHOR" 2>/dev/null || true + fi + ``` + Then fall back to CODEOWNERS. GitHub auto-assigns from CODEOWNERS + when a draft PR is marked ready (if branch protection requires + reviews), so explicit assignment is often unnecessary. If the repo + doesn't use branch protection, try to find an owner: + ```sh + CODEOWNERS_FILE="" + for f in .github/CODEOWNERS CODEOWNERS docs/CODEOWNERS; do + [ -f "$f" ] && CODEOWNERS_FILE="$f" && break + done + if [ -n "$CODEOWNERS_FILE" ]; then + OWNERS=$(grep -v '^#' "$CODEOWNERS_FILE" | awk '{for(i=2;i<=NF;i++) print $i}' | sort -u | head -3) + for owner in $OWNERS; do + owner="${owner#@}" + gh pr edit --add-reviewer "$owner" 2>/dev/null || true + done + fi + ``` + If reviewer assignment fails (e.g. the issue author can't review + their own org's PR, or isn't a collaborator), skip silently. + +4. Add labels: + ```sh + gh pr edit --add-label "bot-generated" + ``` + If the original issue had priority labels, propagate them: + ```sh + ISSUE_LABELS=$(gh issue view --json labels --jq '.labels[].name' 2>/dev/null) + for label in $ISSUE_LABELS; do + case "$label" in priority*|P0|P1|P2|P3|critical|high|medium|low) + gh pr edit --add-label "$label" 2>/dev/null || true + ;; + esac + done + ``` + +5. Post a short comment noting the PR is ready. Mention what CI + checks passed and that self-review found no issues. Write it + naturally — vary the wording, don't use a canned phrase. + +## Notes + +- Don't merge the PR. This skill only marks the PR ready — the + coordinator may load `auto-merge` next if the PR qualifies. +- If label creation fails (label doesn't exist in the repo), skip + silently — don't create labels. +- This skill is typically loaded by the coordinator agent after a + `check_suite` or `workflow_run` event with conclusion `success`. diff --git a/.agents/skills/pr/SKILL.md b/.agents/skills/pr/SKILL.md new file mode 100644 index 000000000..20578a393 --- /dev/null +++ b/.agents/skills/pr/SKILL.md @@ -0,0 +1,95 @@ +--- +name: pr +description: Create a draft PR for the current branch following repo conventions. Writes a concise PR description from the implementation plan, embeds the full plan as a hidden HTML comment so reviewers can read it without leaving GitHub, and reuses an existing branch when one is already checked out. Use this once your implementation is committed and pushed. +license: Apache-2.0 +metadata: + source: https://github.com/BYK/dotskills + audience: autonomous-agents +--- + +# Create a PR + +Create a **draft** PR from the current branch's changes. Follow the repo's +conventions for branch name and commit title. The PR description should +be based on the implementation plan and the changes summary, but kept +short and to the point — not overly long or detailed. + +## Preconditions + +- The branch you want to PR is already committed. +- The branch is already pushed to `origin` (the caller is expected to + do this; the agent's workflow handles it before invoking the skill). + +## Steps + +1. **Check the branch**. If you're already on a relevant feature branch + (i.e. not the repo's default branch), reuse it. Don't create a new + one on top. + +2. **Open the PR** with `gh pr create --draft`. Title should follow + the repo's commit convention. If the repo uses conventional commits + (check recent history with `git log --oneline -10`), use the format + `(): ` where type is `fix`, `feat`, `chore`, + `refactor`, `docs`, `test`, etc. Do not include AI-attribution + labels like `[bot]`, `[claude]`, or `[ai]` in the title. Body + should be a 1–3 sentence summary plus a "Testing" line if relevant + — followed by the full implementation plan inside a hidden HTML + comment so reviewers can read it without leaving GitHub but it + doesn't bloat the visible description: + + ```sh + gh pr create --draft \ + --title "" \ + --body "$(cat <<'EOF' + <1–3 sentence summary> + + ## Testing + + + Closes # + + + EOF + )" + ``` + + The heredoc is important — it preserves multi-line plans, special + characters, and quotes without escaping headaches. + +3. **Print the PR URL** as the final line of your reply. + +CI status will be monitored via webhook events — when a `check_suite` +or `workflow_run` event arrives with `conclusion: success`, the agent +will load `mark-pr-ready` to promote the draft. + +## Notes + +- This skill creates a *draft* PR by design. A separate review/iterate + step should mark it ready-for-review once self-review and CI pass. + This is handled automatically via webhook events for CI completion. +- Don't include diagrams, lengthy "context" sections, or duplicated + information that's already on the issue. The reader can follow the + link. +- If the caller specifically wants the plan attached as a `git note` + instead of an HTML comment (BYK/dotskills' original design), use: + ```sh + git notes add -F - HEAD <<'EOF' + + EOF + git push origin refs/notes/commits + ``` + Without the explicit `git push refs/notes/commits`, the note exists + only in the local clone. + +--- + +*Adapted from [BYK/dotskills](https://github.com/BYK/dotskills) +(Apache-2.0). Where the original used `git notes` as the primary +attachment mechanism, this version uses an HTML comment in the PR +body for reviewer visibility, with `git notes` documented as an +alternative.* diff --git a/.agents/skills/repo-setup/SKILL.md b/.agents/skills/repo-setup/SKILL.md new file mode 100644 index 000000000..6e4bbde86 --- /dev/null +++ b/.agents/skills/repo-setup/SKILL.md @@ -0,0 +1,76 @@ +--- +name: repo-setup +description: Refresh /workspace/repo and prepare the correct branch. Load this before any situation skill. +license: Apache-2.0 +metadata: + audience: autonomous-agents +--- + +# Repository Setup + +The target repository is already cloned by the container runtime at +`/workspace/repo`. Work directly in that checkout — do not create git +worktrees or clone a second copy of the target repo. Each issue/PR gets its +own container, so `/workspace/repo` is already isolated. + +## Steps + +1. **Enter the repository and refresh refs**: + ```sh + cd /workspace/repo + git fetch --all --prune + ``` + +2. **Determine the branch name**: + - **New issue**: `issue--` (e.g. `issue-42-fix-login`) + - **Existing PR**: get the PR head branch with: + ```sh + BRANCH=$(gh pr view --json headRefName --jq .headRefName) + ``` + - **Operator chat** (a `New operator chat` turn — a repo but no issue/PR): + there is nothing to branch from yet. Stay on the default branch for + read-only exploration and answering questions. Only create a branch once + the operator asks for a change that needs a PR, and name it for the work + (e.g. `chat-`); don't invent an `issue-*` branch for a chat. + +3. **Preserve in-progress follow-up work**. If `/workspace/repo` is already on + the intended branch and has uncommitted changes, keep them and skip branch + reset/checkout. The previous event may have left in-progress changes that the + current follow-up event needs to continue. If there are uncommitted changes + on a different branch, stop and inspect before switching — do not risk + carrying changes to the wrong branch or discarding work. + ```sh + git status --short + git branch --show-current + ``` + +4. **Prepare the branch in `/workspace/repo`** if step 3 did not already find + the right branch with in-progress changes: + + - **New issue** — create or reset the issue branch from the default branch: + ```sh + DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) + git switch -C "origin/$DEFAULT_BRANCH" + ``` + + - **Existing PR** — check out the PR branch: + ```sh + gh pr checkout + ``` + If `gh pr checkout` fails, fall back to: + ```sh + git fetch origin "$BRANCH:$BRANCH" 2>/dev/null || true + git switch "$BRANCH" + git pull --ff-only origin "$BRANCH" 2>/dev/null || true + ``` + +5. **Run all subsequent commands from `/workspace/repo`**. + +## Important + +- Never push to or force-push the default branch. +- Never `git reset --hard` or `git clean -fd` when there are uncommitted + changes unless the situation skill explicitly determines those changes are + disposable. +- Multi-repo investigation may clone **other** repositories under `~/dev/...`, + but the target repo for this issue/PR stays `/workspace/repo`. diff --git a/.agents/skills/resolve-issue/SKILL.md b/.agents/skills/resolve-issue/SKILL.md new file mode 100644 index 000000000..ce9bef330 --- /dev/null +++ b/.agents/skills/resolve-issue/SKILL.md @@ -0,0 +1,224 @@ +--- +name: resolve-issue +description: Resolve a GitHub issue end-to-end — explore, plan, implement, clean up, and open a draft PR. +license: Apache-2.0 +metadata: + audience: autonomous-agents +--- + +# Resolve Issue + +Take an issue from labeled to "draft PR opened." Load `repo-setup` +first to prepare `/workspace/repo` on a feature branch. + +**Default to shipping a draft PR.** A best-effort first cut is more +valuable than a "too big" comment. Other agents will review it, fix CI, +and respond to feedback. + +## Workflow + +### Phase 1: Context Gathering + +1. **Read the issue.** Lean toward the smallest interpretation. + +2. **Check for existing PRs** that reference this issue: + ```sh + gh api "repos///issues//timeline" --paginate \ + --jq '[.[] | select(.event=="cross-referenced" and .source.issue.pull_request != null) | {number: .source.issue.number, state: .source.issue.state, title: .source.issue.title, url: .source.issue.html_url}]' + ``` + Also search PR titles and bodies for the issue number: + ```sh + gh pr list --search "" --repo / --json number,title,state,headRefName,url + ``` + - **Open PR exists** → check it out (`gh pr checkout `), + review what's done, and continue from there instead of starting + fresh. Load `review` skill to assess quality first. + - **Draft/stale PR exists** → same as above. Rebase onto the + default branch if needed (see conflict resolution below). + - **Only closed/merged PRs** → the issue may already be resolved. + Verify before starting new work. + - **No linked PRs** → proceed with fresh implementation. + +3. **Understand repo conventions.** Delegate this survey to the + `explore` subagent (read-only, cheaper model) and use its brief; ask + it to report: + - `CONTRIBUTING.md`, `AGENTS.md`, `DEVELOPMENT.md`, or similar docs + - Recent commit history: `git log --oneline -20` (commit style) + - Linter config: `biome.json`, `.eslintrc*`, `.prettierrc*`, + `ruff.toml`, `pyproject.toml [tool.ruff]`, `.golangci.yml`, etc. + - Test framework config: `jest.config*`, `vitest.config*`, + `pytest.ini`, `pyproject.toml [tool.pytest]`, `go.mod`, etc. + - CI workflow files: `.github/workflows/*.yml` — note the test + command and count the number of check/job names + - Existing utility functions relevant to the issue + Note for later: coding conventions, test command, lint command, + PR template path (if any), and CI check count. + +### Phase 2: Bug Verification + +4. **Classify the issue**: bug report or feature request. + - **Feature request** → skip to step 6 (planning). + - **Bug report** → continue to verification. + +5. **Verify the bug exists.** You may delegate the code-path *reading* + to `explore` (e.g. "find and summarize the code paths involved in + "), but make the root-cause judgment yourself: + a. Read the relevant code paths identified in the issue body. + b. Cross-check against the default branch HEAD — is the described + behavior actually present in the current code? + c. Try to write a minimal reproduction: a test case, a script, or + a specific input that triggers the bug. + d. If reproducible: report the root cause ("This breaks because + **X**, in **Y** path, after **Z** condition."). + e. If not reproducible: report what was tried and why it failed. + + If the bug **cannot be reproduced**: + - Post a comment on the issue asking for specific details: + reproduction steps, environment, version, logs, or a minimal + example. Be specific about what you tried. + - **Stop.** Do not attempt a fix. A follow-up `issue_comment` + webhook will arrive in this session when the reporter replies, + and work will resume from this step. + +### Phase 3: Planning + +6. **Create a detailed plan.** Based on the root cause (from step 5) or the feature + scope (from step 4), produce a plan that includes: + - The root cause or feature scope summary. + - Every file to change and what each change does. + - What tests to add or modify (if the repo has a test suite). + - The verification method: which test to run, which script to + execute, or what behavior to check. + This plan will be embedded in the PR description. + +### Phase 4: Implementation + +7. **Implement the plan.** Once your plan from step 6 is precise, hand + the first-pass edits to the `implement` subagent (cheaper coding model), + giving it: the full plan, the working directory (`/workspace/repo`), the + coding conventions from step 3, and the exact files/changes/tests to write. + Then **review `implement`'s output yourself** before trusting it — the + correctness judgment stays with you. For small or subtle changes, + just do them directly. + +8. **Verify the implementation.** + - Check that every item in the plan was implemented (your judgment). + - Run the test suite (use the test command from step 3) — you may + delegate the test run + failure summary to `implement`. + - If this was a bug fix, run the reproduction from step 5. + +9. **Loop if failing.** If tests fail or the issue isn't resolved: + - Return to step 6: re-plan with the new information (test output, + error messages, what the implementation got wrong). + - Maximum **2 retries** (3 total attempts including the first). + - After 3 failed attempts, commit what you have and note the + remaining issues in the PR description. + +### Phase 5: Cleanup and PR + +10. **Clean up.** + - Load `deslop` skill — strip AI noise from the diff. + - Load `review` skill — self-review. If findings exist, fix them, + re-run `deslop` and `review`. Repeat at most **3 rounds**. + - Run the lint command from step 3 (if one was found). Fix lint + issues before committing. + +11. **Commit and push.** + - Commit with `Fixes #` in the message. + - Check for conflicts with the default branch and rebase if + needed (see conflict resolution below). + - Push. + +12. **Open a draft PR.** Load `pr` skill with: + - The implementation summary from step 6. + - What was tested (test command, results). + - The CI check count from step 3 (for dynamic cron scheduling). + - The issue number for linking (`Closes #`). + +## Conflict resolution + +Before pushing, check for conflicts with the default branch: + +```sh +DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) +git fetch origin "$DEFAULT_BRANCH" +git rebase "origin/$DEFAULT_BRANCH" +``` + +If the rebase has conflicts: + +1. Check `git diff --name-only --diff-filter=U` for conflicted files. +2. For each file, read the conflict markers (`<<<<<<<`, `=======`, + `>>>>>>>`), understand both sides, and resolve. +3. `git add ` then `git rebase --continue`. +4. If the conflict is too complex to resolve confidently, abort with + `git rebase --abort` and note it in the PR description. + +Never force-push to someone else's branch. On your own feature branch, +a rebase followed by `git push --force-with-lease` is acceptable. + +## Test discovery + +Before committing, find and run the project's test suite. Check these +locations in order and use the first match: + +1. **package.json** (Node/JS/TS): + ```sh + jq -r '.scripts.test // empty' package.json + ``` + Run with `npm test`, `bun test`, `pnpm test`, or `yarn test` + depending on the lockfile present. + +2. **Makefile / Justfile**: + ```sh + grep -E '^test[ :]' Makefile Justfile 2>/dev/null + ``` + Run with `make test` or `just test`. + +3. **Python** (pytest / unittest): + ```sh + test -f pytest.ini || test -f pyproject.toml || test -f setup.cfg + ``` + Run with `pytest` or `python -m pytest`. + +4. **Go**: + ```sh + test -f go.mod + ``` + Run with `go test ./...`. + +5. **CI workflows** (fallback): + ```sh + grep -r 'run:.*test' .github/workflows/ 2>/dev/null | head -5 + ``` + Extract the test command from the workflow file. + +If no test command is found within 30 seconds of searching, skip and +note "no test suite found" in the PR description. Don't spend more +than 2 minutes on a failing test suite that's unrelated to your +changes — note it and move on. + +## Command timeouts + +**Always set a timeout on bash commands that might hang.** Use the +`timeout` parameter (milliseconds) on every `bash` tool call that +runs tests, builds, or installs dependencies: + +- `pnpm install` / `npm install` / `bun install`: **120000** (2 min) +- `tsc --noEmit` / typecheck: **120000** (2 min) +- `vitest run` / `jest` / test suites: **180000** (3 min) +- `biome check` / `eslint` / lint: **60000** (1 min) + +If a command times out, that's fine — note it in the PR description +and move on. **Never run test/build commands without a timeout.** + +Also: many repos require a codegen or build step before typecheck/tests +work (e.g. `pnpm run generate:sdk`, `pnpm run build`). Check +`package.json` scripts for `generate*`, `codegen*`, or `prebuild*` +scripts and run them first. If they fail or are slow, skip them — the +typecheck/test failures from missing generated files are pre-existing +and not your fault. + +Reserve BLOCKED for genuine impossibility (missing auth, deleted repo, +contradictory requirements). A best-effort draft PR is almost always +better than blocking. diff --git a/.agents/skills/resolve-issue/references/investigation-protocol.md b/.agents/skills/resolve-issue/references/investigation-protocol.md new file mode 100644 index 000000000..ac9eb32b2 --- /dev/null +++ b/.agents/skills/resolve-issue/references/investigation-protocol.md @@ -0,0 +1,47 @@ +# Investigation Protocol + +Before editing any code, you should be able to articulate: + +> "This breaks because **X**, in **Y** path, after **Z** condition." + +If you cannot fill in X, Y, and Z, keep investigating. + +## Steps + +1. **Reproduce the problem.** Find the code path described in the + issue. Trace it from entry point to the failure site. If the issue + includes an error message or stack trace, locate the exact line. + +2. **Understand the current behavior.** Read the code, not just the + function — read its callers and the data flowing into it. Check + tests (if any) to see what the expected behavior was. + +3. **Identify the root cause.** Distinguish between: + - The **symptom** (what the user sees) + - The **proximate cause** (what line/condition triggers it) + - The **root cause** (why that condition exists) + + Fix the root cause when possible. Fix the proximate cause only when + the root cause is out of scope. + +4. **State the fix hypothesis.** Before writing code, state in one + sentence what you plan to change and why it addresses the root + cause. This becomes part of the commit message. + +## When investigation is blocked + +- **Missing reproduction context**: if the issue lacks enough detail + to identify the code path, ask via a PR comment (not a blocking + question — ship what you can). +- **External dependencies**: if the root cause is in a dependency or + external service, note it in the PR description and fix what's + within scope. +- **Multiple possible causes**: if you find several plausible causes, + fix the most likely one and note the alternatives in the PR. + +## Anti-patterns + +- Starting to code before understanding the failure path +- Reading only the function mentioned in the issue without checking callers +- Guessing based on function names without reading the implementation +- Fixing the symptom while leaving the root cause intact diff --git a/.agents/skills/resolve-issue/references/verification-harness.md b/.agents/skills/resolve-issue/references/verification-harness.md new file mode 100644 index 000000000..4d74b4bfc --- /dev/null +++ b/.agents/skills/resolve-issue/references/verification-harness.md @@ -0,0 +1,35 @@ +# Verification Harness Selection + +Match the shape of the change to the right verification method. +Use the first row that fits. + +| Change shape | Verification method | Example | +|---|---|---| +| Logic bug in a pure function | Unit test targeting the fixed path | `expect(parse("")).toBe(null)` | +| State management / data flow | Integration test with real data flow | Test the full handler, not just the helper | +| CLI command behavior | Run the actual command | `bun run cli --flag` and check output | +| HTTP endpoint | `curl` or test client against dev server | `curl localhost:3000/api/health` | +| Build / compilation | Full build | `bun run build` or `npm run build` | +| Type error fix | Type checker | `tsc --noEmit` or `bunx tsc --noEmit` | +| Lint / format fix | Linter | `bunx biome check` or project lint command | +| Config change | Smoke test the affected system | Start the server, run the workflow | +| UI component | Browser test or visual check | Storybook, Playwright, or manual | +| CI workflow change | Dry-run where possible | `act` for GitHub Actions, or push and observe | + +## Principles + +- **Run the existing test suite first.** If it passes, your change + didn't break existing behavior. If it fails on unrelated code, + note it and move on. + +- **Verify the fix, not just the absence of error.** A test that + previously crashed and now doesn't crash might be passing for the + wrong reason. Assert the expected output. + +- **Prefer the project's own verification tools.** If the repo has + `make test`, use it. Don't introduce new test infrastructure for + a single fix. + +- **Time-box verification.** Spend up to 2 minutes finding and + running tests. If the project has no test suite and the change is + simple, note "no test suite found" and move on. diff --git a/.agents/skills/respond-to-comment/SKILL.md b/.agents/skills/respond-to-comment/SKILL.md new file mode 100644 index 000000000..340391fe6 --- /dev/null +++ b/.agents/skills/respond-to-comment/SKILL.md @@ -0,0 +1,118 @@ +--- +name: respond-to-comment +description: Triage and respond to comments on a PR. Fix if actionable, reply either way. Load repo-setup first. +license: Apache-2.0 +metadata: + audience: autonomous-agents +--- + +# Respond to Comment + +Triage a comment on a PR the bot is involved in. Load `repo-setup` first. + +## Addressing guard + +Before triaging, confirm the comment is actually for you: + +- If the comment author equals your identity (`$ME` — see agent identity + setup), stop: `SKIPPED: own comment`. +- If the body explicitly `@`-mentions a specific other user and does NOT + `@`-mention `$ME`, the question is aimed at someone else — stop: + `SKIPPED: directed at @`. Applies to inline and top-level + comments alike. Exceptions (keep going): the comment also `@`-mentions + `$ME`, it's a direct reply to one of your own comments, or it's a + comment on a `jared`-labeled issue (the router resumes `resolve-issue` + for those, so answers to your own questions are never dropped even if + they `@`-mention a helper). +- A comment with no `@`-mention of another user is not affected by this + guard — proceed to triage as normal. + +## Triage + +- **Actionable**: real bug, missing test, valid concern → fix it +- **Not actionable**: style preference, out of scope, already handled → reply with reason +- **Approval thumbs-up** (short body, no code refs): don't reply, stop + +## Workflow + +1. Check PR authorship — only push to your own PR's branch. +2. If actionable on your own PR: implement the fix, load `deslop`, commit, + push, then reply on the thread with the commit SHA and resolve the thread + (see below). After all fixes, re-request review. +3. If actionable on someone else's PR: reply with a `suggestion` block + or description. Don't push. +4. If not actionable: reply on the thread with the reason and leave it open + for a human to resolve. + +## Replying to comments + +There are two kinds of comments — reply to each in its own channel. **Never +use `gh pr comment` to answer an inline review comment**; that posts a +top-level PR comment that isn't attached to the thread. + +**Inline review comment** (`pull_request_review_comment`, or a comment inside a +`pull_request_review`) — reply on the thread via the replies endpoint: + +```sh +gh api -X POST \ + "repos///pulls//comments//replies" \ + -f body="Fixed in ." +``` + +`` is the review comment's `id` from the event payload (use the +top-level comment of the thread — the one with `in_reply_to_id` unset). + +**Top-level PR comment** (`issue_comment` on a PR, not tied to a line) — reply +with: + +```sh +gh pr comment --body "..." +``` + +## Resolving a thread (only after you fixed it) + +Resolve a review thread **only** when you pushed a code change that addresses +it. Leave won't-fix / not-actionable threads open with an explanatory reply. + +1. Find the thread node id for the comment you addressed: + + ```sh + THREAD_ID=$(gh api graphql -f query=' + query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + reviewThreads(first: 100) { + nodes { id isResolved comments(first: 1) { nodes { databaseId } } } + } + } + } + }' -f owner= -f repo= -F pr= \ + --jq '.data.repository.pullRequest.reviewThreads.nodes[] + | select(.comments.nodes[0].databaseId == ) | .id') + ``` + +2. Resolve it: + + ```sh + gh api graphql -f query=' + mutation($threadId: ID!) { + resolveReviewThread(input: { threadId: $threadId }) { + thread { isResolved } + } + }' -f threadId="$THREAD_ID" + ``` + +## Re-requesting review + +After pushing fixes for a reviewer's feedback, re-request their review so they +see the PR is ready again: + +```sh +gh api -X POST "repos///pulls//requested_reviewers" \ + -f "reviewers[]=" +``` + +Keep replies concise and natural — write like a teammate, not a +support bot. No filler phrases, no emoji unless the thread uses them. + +Don't push to others' branches. Don't force-push. Don't merge. diff --git a/.agents/skills/review-pr/SKILL.md b/.agents/skills/review-pr/SKILL.md new file mode 100644 index 000000000..4ea6e3e24 --- /dev/null +++ b/.agents/skills/review-pr/SKILL.md @@ -0,0 +1,30 @@ +--- +name: review-pr +description: Review a pull request. Self-fix on own PRs, post a review on others'. Load repo-setup first. +license: Apache-2.0 +metadata: + audience: autonomous-agents +--- + +# Review PR + +Review a PR the bot is involved in. Load `repo-setup` first. + +## Workflow + +1. Check authorship: `gh pr view --json author --jq .author.login` + vs `$ME` (your identity). Skip drafts unless it's your own PR. +2. Read the PR's intent (body, linked issues, commit log). +3. Load `review` skill. +4. Act on findings: + - **No findings**: post a `--comment` review (reserve `--approve` + for when you can vouch for correctness). + - **Findings on own PR**: load `apply-fixes` skill to push fixes. + - **Findings on others' PR**: post `--request-changes` or + `--comment` review via `gh pr review`. Don't push to their branch. + +Write review comments like a senior dev — direct, specific, no +filler. "this will panic on nil" not "I noticed that this could +potentially cause a nil pointer dereference." + +Don't approve trivially. Don't merge. diff --git a/.agents/skills/review/SKILL.md b/.agents/skills/review/SKILL.md new file mode 100644 index 000000000..abd685875 --- /dev/null +++ b/.agents/skills/review/SKILL.md @@ -0,0 +1,117 @@ +--- +name: review +description: Review the current branch's changes against intent. Returns a structured list of findings the caller can hand to a fix-applier, or an empty list when there's nothing to address. Use this for both self-review of your own work and reviewing someone else's PR. +license: Apache-2.0 +metadata: + source: https://github.com/BYK/dotskills + audience: autonomous-agents +--- + +# Review changes + +Read the diff against the default branch and produce a structured list +of findings. The caller decides what to do with them — apply fixes +directly, post a review on GitHub, or both. + +## Process + +1. Resolve the default branch and diff: + ```sh + DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) + git diff "$DEFAULT_BRANCH"...HEAD + ``` + Three-dot syntax shows just what this branch added, not unrelated + changes that landed on the default branch since branching. + +2. For larger diffs, read the changed files top to bottom before + judging, so you don't carry the implementation's "obvious in + context" bias. You may delegate the read-and-summarize pass to the + `explore` subagent (cheaper, read-only) to get a structured rundown + of what changed — but make every review *judgment* (is this a real + finding?) yourself. + +3. If a test suite exists, run it to verify the changes don't break + anything. Check `package.json` scripts, `Makefile`, `pytest.ini`, + `go.mod`, or CI workflow files for the test command. If tests fail + on code unrelated to the diff, note it but don't flag it. If tests + fail on changed code, add a `bug` finding. + +4. Read every change against the PR's stated intent (PR body + linked + issues via `gh issue view`). For each concern, classify it: + + - **bug** — logic doesn't match intent, broken edge case (null, + empty, concurrency), incorrect assumption, factual error. + - **test-gap** — new behavior added without test coverage on a + critical path. + - **style** — inconsistent with surrounding code (string quotes, + brace style, naming). + - **scope** — diff includes changes unrelated to the stated intent. + - **docs** — stale comments or PR description doesn't match diff. + +## Output format + +Emit a JSON block as the FINAL part of your reply, exactly: + +```json +{ + "findings": [ + { + "kind": "bug" | "test-gap" | "style" | "scope" | "docs", + "file": "", + "line": , + "summary": "", + "suggested_fix": "" + } + ] +} +``` + +If there's nothing to address, return `{ "findings": [] }`. + +Keep `summary` and `suggested_fix` terse — one or two sentences each. +The fix-applier reading these has the file open already; don't restate +context the diff already carries. + +## Confidence calibration + +Assign a confidence level to each potential finding before including +it. See `references/confidence-calibration.md` for the full table. + +- **HIGH** — you traced the code path and verified the issue. Report it. +- **MEDIUM** — the pattern is suspicious and likely wrong. Report it, + noting uncertainty in `summary` if relevant. +- **LOW** — the code looks unusual but could be intentional. Do **not** + report it. + +Bug findings should almost always be HIGH. If you can't trace the +code path to confirm the issue, it's speculation — downgrade or drop. + +## When to flag vs. not + +- A `style` finding only counts if the PR's *neighbouring* code uses a + different convention. Don't flag general taste preferences. +- A `test-gap` finding only counts when the missing test would have + caught a real bug class — not "every new function needs a test." +- A `scope` finding is high-confidence: the diff demonstrably includes + a change unrelated to the issue. When in doubt, don't flag. +- Don't include "everything looks good" notes in `findings`. Empty + array is the correct positive signal. + +## Not a finding + +Before reporting, check `references/not-a-finding.md` for patterns +that look suspicious but are typically correct. Common examples: + +- Null checks on values that "should" be set (defensive, valid if + function is public or called from multiple sites) +- Empty catch blocks in error boundaries (framework convention) +- Trivial getters/setters (not worth a test-gap finding) +- Fixing a typo adjacent to changed code (not scope creep) +- TODO comments describing known limitations (not stale docs) + +--- + +*Adapted from [BYK/dotskills](https://github.com/BYK/dotskills) +(Apache-2.0). The original was prose-only; this version produces +structured output so a downstream fix-applier can act on findings +mechanically.* diff --git a/.agents/skills/review/references/confidence-calibration.md b/.agents/skills/review/references/confidence-calibration.md new file mode 100644 index 000000000..d42bc0369 --- /dev/null +++ b/.agents/skills/review/references/confidence-calibration.md @@ -0,0 +1,40 @@ +# Confidence Calibration + +Assign a confidence level to each finding before including it in the +output. Only report findings at HIGH or MEDIUM confidence. + +## Levels + +| Level | Criteria | Action | +|---|---|---| +| **HIGH** | You traced the code path and verified the issue exists. The finding is demonstrably wrong, not hypothetically wrong. | Report as a finding. | +| **MEDIUM** | The pattern is suspicious and likely a problem, but you haven't fully traced every code path. The surrounding code suggests this wasn't intentional. | Report as a finding. Note uncertainty in `summary` if relevant. | +| **LOW** | The code looks unusual but could be intentional. You can construct a scenario where it breaks, but it requires unlikely inputs or specific timing. | Do **not** report. | + +## Calibration guidelines + +- **Bug findings should almost always be HIGH.** If you can't trace + the code path to confirm the bug, it's not a bug finding — it's + speculation. Downgrade to MEDIUM or drop it. + +- **Test-gap findings are typically MEDIUM.** You can see the behavior + isn't tested but can't always prove it would catch a real bug class. + +- **Style findings should be HIGH** (you can see the neighboring code + uses a different convention) or dropped (it's a taste preference). + +- **Scope findings should be HIGH.** The change is demonstrably + unrelated to the stated intent, or it isn't. + +- **Docs findings are typically HIGH.** The comment is stale or it isn't. + +## Common false positive patterns + +Before reporting, check whether the "issue" is actually: + +- **Intentional defensive code.** The function is called from multiple + sites and the check is valid for some of them. +- **Framework convention.** The pattern looks unusual but is standard + for the framework (e.g., empty catch blocks in error boundaries). +- **Existing behavior, not new.** The "issue" exists in the base + branch too — the PR didn't introduce it. diff --git a/.agents/skills/review/references/not-a-finding.md b/.agents/skills/review/references/not-a-finding.md new file mode 100644 index 000000000..2d5313a34 --- /dev/null +++ b/.agents/skills/review/references/not-a-finding.md @@ -0,0 +1,56 @@ +# Not a Finding + +These patterns look suspicious but are typically correct. Do not +report them unless you have specific evidence they cause a problem +in this codebase. + +## By category + +### Bug — safe patterns + +- **Null/undefined checks on values that "should" be set.** If the + function is public or called from multiple sites, defensive checks + are reasonable. +- **Empty catch blocks in error boundaries** (React, Express, Hono). + The framework expects them. Only flag if the error is silently + swallowed in a non-boundary context. +- **Loose equality (`==`) in JavaScript** when comparing to `null` to + catch both `null` and `undefined`. This is an intentional pattern. +- **Re-throwing the same error.** Sometimes done to add context or + trigger a different catch block. + +### Test-gap — not worth flagging + +- **Trivial getters/setters** that delegate directly to another + property or method. +- **Type-only changes** (adding/removing TypeScript types) that don't + affect runtime behavior. +- **Log/telemetry additions** that don't change control flow. +- **Comment or documentation updates.** + +### Style — taste preferences, not findings + +- **Named vs. default exports.** Both are valid; flag only if the + file's neighbors are consistent and this one breaks the pattern. +- **Arrow functions vs. function declarations.** Same rule — only + flag if the file is inconsistent with itself. +- **Trailing commas.** Unless the formatter config enforces one way. +- **Single vs. double quotes.** Unless the formatter config enforces + one way. +- **Import ordering.** Unless an auto-sorter is configured. + +### Scope — not unrelated + +- **Fixing a typo in a comment** adjacent to the changed code. This + is a natural drive-by fix, not scope creep. +- **Renaming a variable** in the same function being modified. This + improves readability of the change. +- **Updating a type** that the changed code depends on. This is a + necessary part of the change. + +### Docs — not stale + +- **TODO comments** that describe known limitations. These are + intentional markers, not stale documentation. +- **Comments explaining "why"** (not "what"). Even if the code + changes, the reasoning may still be valid. diff --git a/AGENTS.md b/AGENTS.md index 3316fa78e..0141e32f4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,29 @@ - -## Long-term Knowledge +# Jared (Outpost agent) -For long-term knowledge entries managed by [lore](https://github.com/BYK/loreai) (gotchas, patterns, decisions, architecture), see [`.lore.md`](.lore.md) in the project root. - +Autonomous GitHub coding agent. Work in `/workspace/repo`. + +## Model tiers + +The primary model is chosen per event (see `src/agents/models.ts`): heavy for +code-producing situations, cheaper for lightweight ones. + +| Role | Subagent | Model | +| --- | --- | --- | +| Triage / plan / review (heavy) | (primary Jared) | Claude Opus 4.8 | +| Triage / plan / review (light) | (primary Jared) | xAI Grok 4.3 | +| Explore | `explore` | OpenAI gpt-5-mini | +| Implement | `implement` | Moonshot kimi-k2.7-code | +| Ship (commit/push/PR) | `ship` | xAI Grok (`grok-build-0.1`) | + +Pipeline: triage → explore → plan → implement → review → ship. +(`worker` is a deprecated alias of `implement`.) + +Operators also talk to Jared directly from the Outpost dashboard. Those turns +(`New operator chat` / `Operator guidance:`) skip triage — treat the request as +the task and answer in the conversation. + +Long-term project knowledge for *this* Outpost repo lives in `.lore.md` when present. +For target repositories, read their `AGENTS.md` / `CONTRIBUTING.md` first. + +Skills are under `.agents/skills/`, generated from the canonical `skills/` tree +by `scripts/sync-skills.mjs`. Always load `repo-setup` before situation skills. diff --git a/packages/cli/src/commands/explore.ts b/packages/cli/src/commands/explore.ts index 27417a8f4..5f894d335 100644 --- a/packages/cli/src/commands/explore.ts +++ b/packages/cli/src/commands/explore.ts @@ -521,9 +521,14 @@ function resolveDatasetConfig(params: { // Non-replay datasets: translate --environment into query filter terms // since the Discover/Events API expects environment:... in the query string. - const envPrefix = environment - ? environment.map((e) => `environment:${e}`).join(" ") - : undefined; + let envPrefix: string | undefined; + if (environment && environment.length > 0) { + if (environment.length === 1) { + envPrefix = `environment:${environment[0]}`; + } else { + envPrefix = `environment:[${environment.join(",")}]`; + } + } const queryWithEnv = [envPrefix, flags.query].filter(Boolean).join(" ") || undefined; diff --git a/packages/cli/test/commands/explore.test.ts b/packages/cli/test/commands/explore.test.ts index 64dd4af09..bfc94adf5 100644 --- a/packages/cli/test/commands/explore.test.ts +++ b/packages/cli/test/commands/explore.test.ts @@ -906,6 +906,28 @@ describe("sentry explore", () => { ); }); + test("translates multiple --environment values into environment:[...] syntax", async () => { + resolveTargetSpy.mockResolvedValue({ org: "test-org" }); + queryEventsSpy.mockResolvedValue({ + data: MOCK_EVENTS_RESPONSE, + nextCursor: undefined, + }); + const { context } = createContext(); + + await func.call( + context, + { ...DEFAULT_FLAGS, environment: ["production", "canary"] }, + "test-org/" + ); + + expect(queryEventsSpy).toHaveBeenCalledWith( + "test-org", + expect.objectContaining({ + query: "environment:[production,canary]", + }) + ); + }); + test("rejects replay detail-only fields on the replay dataset", async () => { resolveTargetSpy.mockResolvedValue({ org: "test-org" }); const { context } = createContext(); From 4c2f21741695f6a24c3c2d42d955e5cca4a31816 Mon Sep 17 00:00:00 2001 From: "jared-outpost[bot]" Date: Thu, 20 Aug 2026 09:14:59 +0000 Subject: [PATCH 5/6] refactor(explore): extract buildEnvironmentQuery to reduce complexity --- packages/cli/src/commands/explore.ts | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/commands/explore.ts b/packages/cli/src/commands/explore.ts index 5f894d335..41b23f957 100644 --- a/packages/cli/src/commands/explore.ts +++ b/packages/cli/src/commands/explore.ts @@ -459,6 +459,23 @@ type DatasetConfig = { }>; }; +/** + * Translate `--environment` values into a query filter term. A single value + * becomes `environment:foo`; multiple values use the `environment:[a,b]` list + * syntax so they are ORed rather than ANDed. + */ +function buildEnvironmentQuery( + environment: string[] | undefined +): string | undefined { + if (!environment || environment.length === 0) { + return; + } + if (environment.length === 1) { + return `environment:${environment[0]}`; + } + return `environment:[${environment.join(",")}]`; +} + /** * Resolve dataset-specific configuration: sort, query, validation, and fetch. * @@ -521,14 +538,7 @@ function resolveDatasetConfig(params: { // Non-replay datasets: translate --environment into query filter terms // since the Discover/Events API expects environment:... in the query string. - let envPrefix: string | undefined; - if (environment && environment.length > 0) { - if (environment.length === 1) { - envPrefix = `environment:${environment[0]}`; - } else { - envPrefix = `environment:[${environment.join(",")}]`; - } - } + const envPrefix = buildEnvironmentQuery(environment); const queryWithEnv = [envPrefix, flags.query].filter(Boolean).join(" ") || undefined; From 8bd2ee6c9f307ef89eb3fd66e179784073a5be22 Mon Sep 17 00:00:00 2001 From: "jared-outpost[bot]" Date: Thu, 20 Aug 2026 09:35:22 +0000 Subject: [PATCH 6/6] chore: revert AGENTS.md and .agents (operator request) --- .agents/skills/apply-fixes/SKILL.md | 31 --- .agents/skills/auto-merge/SKILL.md | 191 --------------- .agents/skills/deslop/SKILL.md | 58 ----- .agents/skills/fix-ci/SKILL.md | 45 ---- .../fix-ci/references/failure-taxonomy.md | 76 ------ .agents/skills/mark-pr-ready/SKILL.md | 89 ------- .agents/skills/pr/SKILL.md | 95 -------- .agents/skills/repo-setup/SKILL.md | 76 ------ .agents/skills/resolve-issue/SKILL.md | 224 ------------------ .../references/investigation-protocol.md | 47 ---- .../references/verification-harness.md | 35 --- .agents/skills/respond-to-comment/SKILL.md | 118 --------- .agents/skills/review-pr/SKILL.md | 30 --- .agents/skills/review/SKILL.md | 117 --------- .../references/confidence-calibration.md | 40 ---- .../skills/review/references/not-a-finding.md | 56 ----- AGENTS.md | 32 +-- 17 files changed, 4 insertions(+), 1356 deletions(-) delete mode 100644 .agents/skills/apply-fixes/SKILL.md delete mode 100644 .agents/skills/auto-merge/SKILL.md delete mode 100644 .agents/skills/deslop/SKILL.md delete mode 100644 .agents/skills/fix-ci/SKILL.md delete mode 100644 .agents/skills/fix-ci/references/failure-taxonomy.md delete mode 100644 .agents/skills/mark-pr-ready/SKILL.md delete mode 100644 .agents/skills/pr/SKILL.md delete mode 100644 .agents/skills/repo-setup/SKILL.md delete mode 100644 .agents/skills/resolve-issue/SKILL.md delete mode 100644 .agents/skills/resolve-issue/references/investigation-protocol.md delete mode 100644 .agents/skills/resolve-issue/references/verification-harness.md delete mode 100644 .agents/skills/respond-to-comment/SKILL.md delete mode 100644 .agents/skills/review-pr/SKILL.md delete mode 100644 .agents/skills/review/SKILL.md delete mode 100644 .agents/skills/review/references/confidence-calibration.md delete mode 100644 .agents/skills/review/references/not-a-finding.md diff --git a/.agents/skills/apply-fixes/SKILL.md b/.agents/skills/apply-fixes/SKILL.md deleted file mode 100644 index d6bb6f60a..000000000 --- a/.agents/skills/apply-fixes/SKILL.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: apply-fixes -description: Apply review findings as the smallest code changes, then commit and push. Used on the bot's own PRs. -license: Apache-2.0 -metadata: - audience: autonomous-agents ---- - -# Apply Fixes - -Turn a JSON array of review findings into commits on the current branch. - -## Input - -Findings array with `kind`, `file`, `line`, `summary`, `suggested_fix`. - -## Workflow - -1. Verify you're on a feature branch, not the default. -2. Plan: decide which findings are tractable in small changes vs. skip. -3. Implement one finding at a time. Smallest change per finding. -4. Run tests if you can find the command quickly. -5. Load `deslop` skill. -6. Commit and push. Stage only files you edited. -7. If a finding came from a PR review thread, close the loop on that thread (see - `respond-to-comment`): reply on the thread with the commit SHA, then resolve - the thread. Only resolve threads you actually fixed. After all fixes are - pushed, re-request review from the reviewer. - -Report: commit SHA, findings addressed, findings skipped with reasons. -Don't force-push. Don't open a new branch or PR. diff --git a/.agents/skills/auto-merge/SKILL.md b/.agents/skills/auto-merge/SKILL.md deleted file mode 100644 index 3ac713a8b..000000000 --- a/.agents/skills/auto-merge/SKILL.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -name: auto-merge -description: Auto-merge a PR after it is marked ready-for-review, if the change is small, non-disruptive, and all checks pass. -license: Apache-2.0 -metadata: - audience: autonomous-agents ---- - -# Auto-merge - -Merge a PR that was just promoted from draft to ready-for-review, -**only** when the change is small, non-disruptive, and every required -check is green. This skill is the natural successor to `mark-pr-ready`. - -## When to load this skill - -Load after the `mark-pr-ready` skill has run (or after a -`pull_request.ready_for_review` event). Do **not** load it for PRs -that were created as ready-for-review from the start — only for PRs -that transitioned from draft. - -## Preconditions (all must be true) - -1. The PR is open and marked ready for review (not draft). -2. The PR targets the repo's default branch. -3. All CI checks have completed and passed. -4. The diff is small and non-disruptive (see size gate below). -5. No reviewer has requested changes. -6. No unresolved review threads. -7. At least 10 minutes have passed since the PR was marked ready - for review, with no new reviewer comments or change requests - during that window. - -If any precondition fails, stop — do not merge. For precondition 7, -if the quiet period hasn't elapsed yet, schedule a one-shot follow-up -for the remaining time (Flue Durable Object `scheduleFollowUp` / -platform `schedule()`, or a `run_once` timer when running in-container) -and stop. The follow-up will re-trigger this skill when the period is up. - -## Size gate - -Classify the PR as "small and non-disruptive" only when **all** of -these hold: - -- Total lines changed (additions + deletions) ≤ 150. -- No more than 5 files changed. -- No changes to CI/CD configuration (`.github/workflows/`, `Dockerfile`, - `docker-compose*`, `Makefile`, `Justfile`, Terraform `*.tf`). -- No changes to dependency lockfiles (`bun.lock`, `package-lock.json`, - `yarn.lock`, `pnpm-lock.yaml`, `Cargo.lock`, `go.sum`). -- No database migrations or schema changes. -- No changes to authentication, authorization, or secrets handling. -- No deletions of public API surface (exported functions, REST - endpoints, GraphQL types). - -If the PR exceeds the size gate, stop. Post a comment noting the PR -needs human review and list which criteria it exceeded. - -## Workflow - -0. **Check quiet period**. Verify the PR was marked ready at least - 10 minutes ago with no reviewer activity since: - ```sh - READY_AT=$(gh api "repos///issues//timeline" --paginate \ - --jq '[.[] | select(.event=="ready_for_review")] | last | .created_at') - ``` - Calculate elapsed time. If less than 10 minutes have passed, - schedule a one-shot follow-up (Flue DO `scheduleFollowUp` / platform - `schedule()`, or in-container timer) for the remaining time with - `entity_key` set to the PR entity, and stop. The follow-up prompt - should instruct the agent to reload the `auto-merge` skill. - - Also check for any reviewer comments or `changes_requested` - reviews that arrived after `READY_AT`: - ```sh - gh api "repos///pulls//reviews" \ - --jq '[.[] | select(.submitted_at > "'$READY_AT'" and .state != "APPROVED" and .state != "COMMENTED")]' - ``` - If any exist, stop — the PR needs human attention. - -1. **Verify PR state and target branch**: - ```sh - PR_JSON=$(gh pr view --json state,isDraft,baseRefName) - STATE=$(echo "$PR_JSON" | jq -r '.state') - IS_DRAFT=$(echo "$PR_JSON" | jq -r '.isDraft') - BASE=$(echo "$PR_JSON" | jq -r '.baseRefName') - DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) - ``` - - Expect `STATE=OPEN`, `IS_DRAFT=false`. If draft or closed, stop. - - Expect `BASE == DEFAULT_BRANCH`. If the PR targets a release or - other protected branch, stop — those need human review. - -2. **Verify all checks pass**: - ```sh - CHECKS=$(gh pr view --json statusCheckRollup \ - --jq '.statusCheckRollup') - ``` - For each check, inspect `status` and `conclusion`: - - If any check has `status` other than `"COMPLETED"` (e.g. - `"QUEUED"`, `"IN_PROGRESS"`, `"PENDING"`), stop — checks - haven't finished yet. Post a comment noting which checks are - still running. - - If any completed check has `conclusion` other than `"SUCCESS"`, - `"SKIPPED"`, or `"NEUTRAL"`, stop — checks are failing. Post a - comment listing the failing checks. - - Quick jq filter for non-passing completed checks: - ```sh - FAILING=$(echo "$CHECKS" | jq '[.[] | select( - .status == "COMPLETED" and - .conclusion != "SUCCESS" and - .conclusion != "SKIPPED" and - .conclusion != "NEUTRAL" - )]') - ``` - Quick jq filter for still-running checks: - ```sh - PENDING=$(echo "$CHECKS" | jq '[.[] | select(.status != "COMPLETED")]') - ``` - -3. **Evaluate the size gate**: - ```sh - PR_DATA=$(gh pr view --json additions,deletions,files) - ADDITIONS=$(echo "$PR_DATA" | jq '.additions') - DELETIONS=$(echo "$PR_DATA" | jq '.deletions') - TOTAL=$((ADDITIONS + DELETIONS)) - FILES_CHANGED=$(echo "$PR_DATA" | jq '.files | length') - ``` - Check each criterion listed in the size gate section. Inspect the - file list for CI/CD, lockfile, migration, auth, or public API - changes: - ```sh - echo "$PR_DATA" | jq -r '.files[].path' - ``` - -4. **Check for review objections and unresolved threads**: - ```sh - CHANGES_REQUESTED=$(gh pr view --json reviews \ - --jq '[.reviews[] | select(.state == "CHANGES_REQUESTED")] | length') - ``` - If `CHANGES_REQUESTED > 0`, stop — a reviewer has requested changes. - - Check for unresolved review threads via the GraphQL API: - ```sh - UNRESOLVED=$(gh api graphql -f query=' - query($owner: String!, $repo: String!, $pr: Int!) { - repository(owner: $owner, name: $repo) { - pullRequest(number: $pr) { - reviewThreads(first: 100) { - nodes { isResolved } - } - } - } - }' -f owner= -f repo= -F pr= \ - --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length') - ``` - If `UNRESOLVED > 0`, stop — there are unresolved review threads. - -5. **Merge**: - ```sh - gh pr merge --squash --auto --delete-branch - ``` - Use `--squash` to keep the main branch history clean. - Use `--auto` so GitHub waits for branch protection rules. - Use `--delete-branch` to clean up the feature branch. - -6. **Post a short comment** confirming the merge was enabled. Mention - the total diff size and that all checks passed. Write it - naturally — vary the wording, don't use a canned phrase. - -## When NOT to merge - -- The PR has "CHANGES_REQUESTED" reviews. -- The PR has unresolved review threads. -- The PR modifies security-sensitive code. -- The PR exceeds the size gate. -- Any required check is not green. -- Any check is still running (not yet completed). -- The PR targets a branch other than the repo's default branch. - -In all these cases, leave a comment explaining why auto-merge was -skipped, and let a human decide. - -## Notes - -- This skill should be loaded by the coordinator after `mark-pr-ready` - completes, or in response to a `pull_request.ready_for_review` webhook. -- The `--auto` flag on `gh pr merge` respects branch protection rules. - If the repo requires approvals, the merge will wait until those are - satisfied. -- Never force-merge or bypass branch protection. diff --git a/.agents/skills/deslop/SKILL.md b/.agents/skills/deslop/SKILL.md deleted file mode 100644 index f82e20c0d..000000000 --- a/.agents/skills/deslop/SKILL.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: deslop -description: Strip AI-generated noise from the diff before pushing — extra comments a human wouldn't write, defensive try/catch in trusted code paths, casts to any, inline imports in Python, and other style inconsistencies with the surrounding file. Use this immediately before commit so the diff stays clean. -license: Apache-2.0 -metadata: - source: https://github.com/BYK/dotskills - audience: autonomous-agents ---- - -# Remove AI Code Slop - -Check the diff against the base branch and remove all AI-generated -slop introduced in this branch. - -## What to remove - -- Extra comments that a human wouldn't add or that are inconsistent - with the rest of the file (no `// loop through items`, no - `# increment counter`, no `// Handle the error case`). -- Extra defensive checks or try/catch blocks that are abnormal for - that area of the codebase, especially when called from - trusted/validated code paths. -- Casts to `any` (or `as unknown as X`) that exist purely to silence - the type checker. If a type assertion is needed, use the narrowest - correct type instead. -- Inline imports in Python — move to the top of the file alongside the - other imports. Group with the appropriate import section (stdlib, - third-party, local). -- Redundant type annotations where TypeScript inference handles it - (e.g., `const x: string = "hello"` → `const x = "hello"`). -- Unnecessary `else` after `return`, `throw`, `continue`, or `break`. -- Console.log / print statements left from debugging. -- Overly verbose variable names that don't match the file's naming - convention (e.g., `isCurrentlyLoadingDataFromServer` when neighbors - use `loading`). -- Any other style that's inconsistent with the file (string quote - choice, brace style, trailing commas, etc.). - -## Process - -1. Get the diff against the default branch: - ```bash - git diff $(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')...HEAD - ``` -2. For each changed file, scan for the patterns above. -3. Remove identified slop while preserving legitimate changes. -4. Report a 1–3 sentence summary of what was changed. - -## Why - -Code reviewers (human and bot) react badly to AI-generated noise: it -looks lazy, hides intent, and inflates the diff. A clean diff -gets merged faster. - ---- - -*Adapted from [BYK/dotskills](https://github.com/BYK/dotskills) -(Apache-2.0).* diff --git a/.agents/skills/fix-ci/SKILL.md b/.agents/skills/fix-ci/SKILL.md deleted file mode 100644 index 8abb156f9..000000000 --- a/.agents/skills/fix-ci/SKILL.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: fix-ci -description: Diagnose and fix failing CI on a PR. Capped at 3 attempts. Load repo-setup first. -license: Apache-2.0 -metadata: - audience: autonomous-agents ---- - -# Fix CI - -Fix failing CI on a PR the bot authored. Load `repo-setup` first. - -## Budget - -3 attempts max per PR. Count existing attempts: - -```sh -ATTEMPTS=$(gh api "repos///issues//comments" --paginate \ - --jq '[.[] | select(.user.login == "'"$ME"'" and (.body | startswith("fix-ci: attempt")))] | length') -``` - -If >= 3, BLOCKED. Otherwise post a short comment like "fix-ci: -attempt 2 — looks like a type error in `foo.ts`, investigating" -before starting work. The `fix-ci:` prefix is required for counting -but the rest should read naturally. - -## Workflow - -1. Find failed runs: `gh run list --branch --status failure` -2. Read logs: `gh run view --log-failed` -3. Categorize the failure — see `references/failure-taxonomy.md` for - the full taxonomy and decision tree. Categories: test failure, - type/lint error, build error, snapshot diff, flaky test, or infra - issue. -4. Flaky? Re-run once (`gh run rerun --failed`) and stop. -5. Infra/dependency issue? BLOCKED. -6. Otherwise: make the smallest fix. Reproduce locally if possible. -7. Load `deslop` and `review` skills. -8. Commit, push, and post a comment summarizing what you fixed and - how. Write it like a teammate explaining the fix, not a status - report. - -Avoid modifying CI config unless the failure is specifically in it. -Avoid bumping dependency versions — the fix should target the code, -not the toolchain. Don't force-push. Don't merge. diff --git a/.agents/skills/fix-ci/references/failure-taxonomy.md b/.agents/skills/fix-ci/references/failure-taxonomy.md deleted file mode 100644 index 98ac0c00e..000000000 --- a/.agents/skills/fix-ci/references/failure-taxonomy.md +++ /dev/null @@ -1,76 +0,0 @@ -# CI Failure Taxonomy - -Categorize the failure before attempting a fix. The category -determines the response strategy. - -## Categories - -### 1. Test failure - -**Signature:** Test runner output with `FAIL`, assertion errors, -expected/actual diffs. - -**Response:** Read the failing test, understand what it asserts, check -if the test expectation is wrong (your change intentionally altered -behavior) or if the code has a bug. Fix the test if the expectation -is outdated; fix the code if the behavior is wrong. - -### 2. Type / lint error - -**Signature:** `tsc` errors (TS####), ESLint/Biome errors with rule -names, type mismatch messages. - -**Response:** Fix the type or lint issue directly. These are usually -mechanical. For lint rules you disagree with, fix the code anyway — -don't modify lint config. - -### 3. Build error - -**Signature:** Bundler/compiler errors, missing modules, import -resolution failures. - -**Response:** Check if your change broke an import path, removed an -export, or changed a file name. Fix the import/export. If the build -error is in unrelated code, note it and investigate whether it's -pre-existing. - -### 4. Snapshot diff - -**Signature:** Snapshot test failures showing before/after diffs. - -**Response:** If your change intentionally altered the output, update -the snapshot (`--update-snapshots`, `-u`, etc.). If the diff is -unexpected, investigate why the output changed. - -### 5. Flaky test - -**Signature:** The test passes on retry. The failure involves timing, -network, or random ordering. The test name may appear in known-flaky -lists. - -**Response:** Re-run once: `gh run rerun --failed`. Do not -attempt to fix the test — flaky test fixes are out of scope for a -CI-fix skill. - -### 6. Infrastructure issue - -**Signature:** Network timeouts, registry errors (`npm ERR! 503`), -Docker pull failures, runner out of disk, GitHub Actions service -degradation. - -**Response:** BLOCKED. These are transient or platform-level issues. -Post a comment noting the infrastructure failure and stop. - -## Decision tree - -``` -Is it a test failure? -├── Yes → Did your change intentionally alter behavior? -│ ├── Yes → Update the test/snapshot -│ └── No → Fix the code bug -└── No → Is it a type/lint/build error? - ├── Yes → Fix the type/lint/import issue - └── No → Is it intermittent / passes on retry? - ├── Yes → Re-run once, then stop - └── No → Infrastructure issue → BLOCKED -``` diff --git a/.agents/skills/mark-pr-ready/SKILL.md b/.agents/skills/mark-pr-ready/SKILL.md deleted file mode 100644 index 5f9da88da..000000000 --- a/.agents/skills/mark-pr-ready/SKILL.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -name: mark-pr-ready -description: Promote a draft PR to ready-for-review after CI passes and self-review is clean. Assigns reviewers and adds labels. -license: Apache-2.0 -metadata: - audience: autonomous-agents ---- - -# Mark PR Ready - -Promote a draft PR out of draft status. Only do this when CI is green -and self-review found no remaining issues. - -## Preconditions - -- You are on the PR's feature branch. -- CI has passed (check via `gh pr checks --required`). -- Self-review produced no unresolved findings. - -## Workflow - -1. Verify CI status: - ```sh - FAILING=$(gh pr checks --json name,state \ - --jq '[.[] | select(.state != "SUCCESS" and .state != "SKIPPED" and .state != "NEUTRAL")]') - ``` - If the output is not an empty array `[]`, stop — CI isn't green yet. - -2. Mark ready for review: - ```sh - gh pr ready - ``` - -3. Request reviewers. Always add the creator of the originating - issue as a reviewer — they have the most context on the problem - and should sign off on the fix: - ```sh - ISSUE_AUTHOR=$(gh issue view --json author --jq '.author.login' 2>/dev/null) - if [ -n "$ISSUE_AUTHOR" ]; then - gh pr edit --add-reviewer "$ISSUE_AUTHOR" 2>/dev/null || true - fi - ``` - Then fall back to CODEOWNERS. GitHub auto-assigns from CODEOWNERS - when a draft PR is marked ready (if branch protection requires - reviews), so explicit assignment is often unnecessary. If the repo - doesn't use branch protection, try to find an owner: - ```sh - CODEOWNERS_FILE="" - for f in .github/CODEOWNERS CODEOWNERS docs/CODEOWNERS; do - [ -f "$f" ] && CODEOWNERS_FILE="$f" && break - done - if [ -n "$CODEOWNERS_FILE" ]; then - OWNERS=$(grep -v '^#' "$CODEOWNERS_FILE" | awk '{for(i=2;i<=NF;i++) print $i}' | sort -u | head -3) - for owner in $OWNERS; do - owner="${owner#@}" - gh pr edit --add-reviewer "$owner" 2>/dev/null || true - done - fi - ``` - If reviewer assignment fails (e.g. the issue author can't review - their own org's PR, or isn't a collaborator), skip silently. - -4. Add labels: - ```sh - gh pr edit --add-label "bot-generated" - ``` - If the original issue had priority labels, propagate them: - ```sh - ISSUE_LABELS=$(gh issue view --json labels --jq '.labels[].name' 2>/dev/null) - for label in $ISSUE_LABELS; do - case "$label" in priority*|P0|P1|P2|P3|critical|high|medium|low) - gh pr edit --add-label "$label" 2>/dev/null || true - ;; - esac - done - ``` - -5. Post a short comment noting the PR is ready. Mention what CI - checks passed and that self-review found no issues. Write it - naturally — vary the wording, don't use a canned phrase. - -## Notes - -- Don't merge the PR. This skill only marks the PR ready — the - coordinator may load `auto-merge` next if the PR qualifies. -- If label creation fails (label doesn't exist in the repo), skip - silently — don't create labels. -- This skill is typically loaded by the coordinator agent after a - `check_suite` or `workflow_run` event with conclusion `success`. diff --git a/.agents/skills/pr/SKILL.md b/.agents/skills/pr/SKILL.md deleted file mode 100644 index 20578a393..000000000 --- a/.agents/skills/pr/SKILL.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -name: pr -description: Create a draft PR for the current branch following repo conventions. Writes a concise PR description from the implementation plan, embeds the full plan as a hidden HTML comment so reviewers can read it without leaving GitHub, and reuses an existing branch when one is already checked out. Use this once your implementation is committed and pushed. -license: Apache-2.0 -metadata: - source: https://github.com/BYK/dotskills - audience: autonomous-agents ---- - -# Create a PR - -Create a **draft** PR from the current branch's changes. Follow the repo's -conventions for branch name and commit title. The PR description should -be based on the implementation plan and the changes summary, but kept -short and to the point — not overly long or detailed. - -## Preconditions - -- The branch you want to PR is already committed. -- The branch is already pushed to `origin` (the caller is expected to - do this; the agent's workflow handles it before invoking the skill). - -## Steps - -1. **Check the branch**. If you're already on a relevant feature branch - (i.e. not the repo's default branch), reuse it. Don't create a new - one on top. - -2. **Open the PR** with `gh pr create --draft`. Title should follow - the repo's commit convention. If the repo uses conventional commits - (check recent history with `git log --oneline -10`), use the format - `(): ` where type is `fix`, `feat`, `chore`, - `refactor`, `docs`, `test`, etc. Do not include AI-attribution - labels like `[bot]`, `[claude]`, or `[ai]` in the title. Body - should be a 1–3 sentence summary plus a "Testing" line if relevant - — followed by the full implementation plan inside a hidden HTML - comment so reviewers can read it without leaving GitHub but it - doesn't bloat the visible description: - - ```sh - gh pr create --draft \ - --title "" \ - --body "$(cat <<'EOF' - <1–3 sentence summary> - - ## Testing - - - Closes # - - - EOF - )" - ``` - - The heredoc is important — it preserves multi-line plans, special - characters, and quotes without escaping headaches. - -3. **Print the PR URL** as the final line of your reply. - -CI status will be monitored via webhook events — when a `check_suite` -or `workflow_run` event arrives with `conclusion: success`, the agent -will load `mark-pr-ready` to promote the draft. - -## Notes - -- This skill creates a *draft* PR by design. A separate review/iterate - step should mark it ready-for-review once self-review and CI pass. - This is handled automatically via webhook events for CI completion. -- Don't include diagrams, lengthy "context" sections, or duplicated - information that's already on the issue. The reader can follow the - link. -- If the caller specifically wants the plan attached as a `git note` - instead of an HTML comment (BYK/dotskills' original design), use: - ```sh - git notes add -F - HEAD <<'EOF' - - EOF - git push origin refs/notes/commits - ``` - Without the explicit `git push refs/notes/commits`, the note exists - only in the local clone. - ---- - -*Adapted from [BYK/dotskills](https://github.com/BYK/dotskills) -(Apache-2.0). Where the original used `git notes` as the primary -attachment mechanism, this version uses an HTML comment in the PR -body for reviewer visibility, with `git notes` documented as an -alternative.* diff --git a/.agents/skills/repo-setup/SKILL.md b/.agents/skills/repo-setup/SKILL.md deleted file mode 100644 index 6e4bbde86..000000000 --- a/.agents/skills/repo-setup/SKILL.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -name: repo-setup -description: Refresh /workspace/repo and prepare the correct branch. Load this before any situation skill. -license: Apache-2.0 -metadata: - audience: autonomous-agents ---- - -# Repository Setup - -The target repository is already cloned by the container runtime at -`/workspace/repo`. Work directly in that checkout — do not create git -worktrees or clone a second copy of the target repo. Each issue/PR gets its -own container, so `/workspace/repo` is already isolated. - -## Steps - -1. **Enter the repository and refresh refs**: - ```sh - cd /workspace/repo - git fetch --all --prune - ``` - -2. **Determine the branch name**: - - **New issue**: `issue--` (e.g. `issue-42-fix-login`) - - **Existing PR**: get the PR head branch with: - ```sh - BRANCH=$(gh pr view --json headRefName --jq .headRefName) - ``` - - **Operator chat** (a `New operator chat` turn — a repo but no issue/PR): - there is nothing to branch from yet. Stay on the default branch for - read-only exploration and answering questions. Only create a branch once - the operator asks for a change that needs a PR, and name it for the work - (e.g. `chat-`); don't invent an `issue-*` branch for a chat. - -3. **Preserve in-progress follow-up work**. If `/workspace/repo` is already on - the intended branch and has uncommitted changes, keep them and skip branch - reset/checkout. The previous event may have left in-progress changes that the - current follow-up event needs to continue. If there are uncommitted changes - on a different branch, stop and inspect before switching — do not risk - carrying changes to the wrong branch or discarding work. - ```sh - git status --short - git branch --show-current - ``` - -4. **Prepare the branch in `/workspace/repo`** if step 3 did not already find - the right branch with in-progress changes: - - - **New issue** — create or reset the issue branch from the default branch: - ```sh - DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) - git switch -C "origin/$DEFAULT_BRANCH" - ``` - - - **Existing PR** — check out the PR branch: - ```sh - gh pr checkout - ``` - If `gh pr checkout` fails, fall back to: - ```sh - git fetch origin "$BRANCH:$BRANCH" 2>/dev/null || true - git switch "$BRANCH" - git pull --ff-only origin "$BRANCH" 2>/dev/null || true - ``` - -5. **Run all subsequent commands from `/workspace/repo`**. - -## Important - -- Never push to or force-push the default branch. -- Never `git reset --hard` or `git clean -fd` when there are uncommitted - changes unless the situation skill explicitly determines those changes are - disposable. -- Multi-repo investigation may clone **other** repositories under `~/dev/...`, - but the target repo for this issue/PR stays `/workspace/repo`. diff --git a/.agents/skills/resolve-issue/SKILL.md b/.agents/skills/resolve-issue/SKILL.md deleted file mode 100644 index ce9bef330..000000000 --- a/.agents/skills/resolve-issue/SKILL.md +++ /dev/null @@ -1,224 +0,0 @@ ---- -name: resolve-issue -description: Resolve a GitHub issue end-to-end — explore, plan, implement, clean up, and open a draft PR. -license: Apache-2.0 -metadata: - audience: autonomous-agents ---- - -# Resolve Issue - -Take an issue from labeled to "draft PR opened." Load `repo-setup` -first to prepare `/workspace/repo` on a feature branch. - -**Default to shipping a draft PR.** A best-effort first cut is more -valuable than a "too big" comment. Other agents will review it, fix CI, -and respond to feedback. - -## Workflow - -### Phase 1: Context Gathering - -1. **Read the issue.** Lean toward the smallest interpretation. - -2. **Check for existing PRs** that reference this issue: - ```sh - gh api "repos///issues//timeline" --paginate \ - --jq '[.[] | select(.event=="cross-referenced" and .source.issue.pull_request != null) | {number: .source.issue.number, state: .source.issue.state, title: .source.issue.title, url: .source.issue.html_url}]' - ``` - Also search PR titles and bodies for the issue number: - ```sh - gh pr list --search "" --repo / --json number,title,state,headRefName,url - ``` - - **Open PR exists** → check it out (`gh pr checkout `), - review what's done, and continue from there instead of starting - fresh. Load `review` skill to assess quality first. - - **Draft/stale PR exists** → same as above. Rebase onto the - default branch if needed (see conflict resolution below). - - **Only closed/merged PRs** → the issue may already be resolved. - Verify before starting new work. - - **No linked PRs** → proceed with fresh implementation. - -3. **Understand repo conventions.** Delegate this survey to the - `explore` subagent (read-only, cheaper model) and use its brief; ask - it to report: - - `CONTRIBUTING.md`, `AGENTS.md`, `DEVELOPMENT.md`, or similar docs - - Recent commit history: `git log --oneline -20` (commit style) - - Linter config: `biome.json`, `.eslintrc*`, `.prettierrc*`, - `ruff.toml`, `pyproject.toml [tool.ruff]`, `.golangci.yml`, etc. - - Test framework config: `jest.config*`, `vitest.config*`, - `pytest.ini`, `pyproject.toml [tool.pytest]`, `go.mod`, etc. - - CI workflow files: `.github/workflows/*.yml` — note the test - command and count the number of check/job names - - Existing utility functions relevant to the issue - Note for later: coding conventions, test command, lint command, - PR template path (if any), and CI check count. - -### Phase 2: Bug Verification - -4. **Classify the issue**: bug report or feature request. - - **Feature request** → skip to step 6 (planning). - - **Bug report** → continue to verification. - -5. **Verify the bug exists.** You may delegate the code-path *reading* - to `explore` (e.g. "find and summarize the code paths involved in - "), but make the root-cause judgment yourself: - a. Read the relevant code paths identified in the issue body. - b. Cross-check against the default branch HEAD — is the described - behavior actually present in the current code? - c. Try to write a minimal reproduction: a test case, a script, or - a specific input that triggers the bug. - d. If reproducible: report the root cause ("This breaks because - **X**, in **Y** path, after **Z** condition."). - e. If not reproducible: report what was tried and why it failed. - - If the bug **cannot be reproduced**: - - Post a comment on the issue asking for specific details: - reproduction steps, environment, version, logs, or a minimal - example. Be specific about what you tried. - - **Stop.** Do not attempt a fix. A follow-up `issue_comment` - webhook will arrive in this session when the reporter replies, - and work will resume from this step. - -### Phase 3: Planning - -6. **Create a detailed plan.** Based on the root cause (from step 5) or the feature - scope (from step 4), produce a plan that includes: - - The root cause or feature scope summary. - - Every file to change and what each change does. - - What tests to add or modify (if the repo has a test suite). - - The verification method: which test to run, which script to - execute, or what behavior to check. - This plan will be embedded in the PR description. - -### Phase 4: Implementation - -7. **Implement the plan.** Once your plan from step 6 is precise, hand - the first-pass edits to the `implement` subagent (cheaper coding model), - giving it: the full plan, the working directory (`/workspace/repo`), the - coding conventions from step 3, and the exact files/changes/tests to write. - Then **review `implement`'s output yourself** before trusting it — the - correctness judgment stays with you. For small or subtle changes, - just do them directly. - -8. **Verify the implementation.** - - Check that every item in the plan was implemented (your judgment). - - Run the test suite (use the test command from step 3) — you may - delegate the test run + failure summary to `implement`. - - If this was a bug fix, run the reproduction from step 5. - -9. **Loop if failing.** If tests fail or the issue isn't resolved: - - Return to step 6: re-plan with the new information (test output, - error messages, what the implementation got wrong). - - Maximum **2 retries** (3 total attempts including the first). - - After 3 failed attempts, commit what you have and note the - remaining issues in the PR description. - -### Phase 5: Cleanup and PR - -10. **Clean up.** - - Load `deslop` skill — strip AI noise from the diff. - - Load `review` skill — self-review. If findings exist, fix them, - re-run `deslop` and `review`. Repeat at most **3 rounds**. - - Run the lint command from step 3 (if one was found). Fix lint - issues before committing. - -11. **Commit and push.** - - Commit with `Fixes #` in the message. - - Check for conflicts with the default branch and rebase if - needed (see conflict resolution below). - - Push. - -12. **Open a draft PR.** Load `pr` skill with: - - The implementation summary from step 6. - - What was tested (test command, results). - - The CI check count from step 3 (for dynamic cron scheduling). - - The issue number for linking (`Closes #`). - -## Conflict resolution - -Before pushing, check for conflicts with the default branch: - -```sh -DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) -git fetch origin "$DEFAULT_BRANCH" -git rebase "origin/$DEFAULT_BRANCH" -``` - -If the rebase has conflicts: - -1. Check `git diff --name-only --diff-filter=U` for conflicted files. -2. For each file, read the conflict markers (`<<<<<<<`, `=======`, - `>>>>>>>`), understand both sides, and resolve. -3. `git add ` then `git rebase --continue`. -4. If the conflict is too complex to resolve confidently, abort with - `git rebase --abort` and note it in the PR description. - -Never force-push to someone else's branch. On your own feature branch, -a rebase followed by `git push --force-with-lease` is acceptable. - -## Test discovery - -Before committing, find and run the project's test suite. Check these -locations in order and use the first match: - -1. **package.json** (Node/JS/TS): - ```sh - jq -r '.scripts.test // empty' package.json - ``` - Run with `npm test`, `bun test`, `pnpm test`, or `yarn test` - depending on the lockfile present. - -2. **Makefile / Justfile**: - ```sh - grep -E '^test[ :]' Makefile Justfile 2>/dev/null - ``` - Run with `make test` or `just test`. - -3. **Python** (pytest / unittest): - ```sh - test -f pytest.ini || test -f pyproject.toml || test -f setup.cfg - ``` - Run with `pytest` or `python -m pytest`. - -4. **Go**: - ```sh - test -f go.mod - ``` - Run with `go test ./...`. - -5. **CI workflows** (fallback): - ```sh - grep -r 'run:.*test' .github/workflows/ 2>/dev/null | head -5 - ``` - Extract the test command from the workflow file. - -If no test command is found within 30 seconds of searching, skip and -note "no test suite found" in the PR description. Don't spend more -than 2 minutes on a failing test suite that's unrelated to your -changes — note it and move on. - -## Command timeouts - -**Always set a timeout on bash commands that might hang.** Use the -`timeout` parameter (milliseconds) on every `bash` tool call that -runs tests, builds, or installs dependencies: - -- `pnpm install` / `npm install` / `bun install`: **120000** (2 min) -- `tsc --noEmit` / typecheck: **120000** (2 min) -- `vitest run` / `jest` / test suites: **180000** (3 min) -- `biome check` / `eslint` / lint: **60000** (1 min) - -If a command times out, that's fine — note it in the PR description -and move on. **Never run test/build commands without a timeout.** - -Also: many repos require a codegen or build step before typecheck/tests -work (e.g. `pnpm run generate:sdk`, `pnpm run build`). Check -`package.json` scripts for `generate*`, `codegen*`, or `prebuild*` -scripts and run them first. If they fail or are slow, skip them — the -typecheck/test failures from missing generated files are pre-existing -and not your fault. - -Reserve BLOCKED for genuine impossibility (missing auth, deleted repo, -contradictory requirements). A best-effort draft PR is almost always -better than blocking. diff --git a/.agents/skills/resolve-issue/references/investigation-protocol.md b/.agents/skills/resolve-issue/references/investigation-protocol.md deleted file mode 100644 index ac9eb32b2..000000000 --- a/.agents/skills/resolve-issue/references/investigation-protocol.md +++ /dev/null @@ -1,47 +0,0 @@ -# Investigation Protocol - -Before editing any code, you should be able to articulate: - -> "This breaks because **X**, in **Y** path, after **Z** condition." - -If you cannot fill in X, Y, and Z, keep investigating. - -## Steps - -1. **Reproduce the problem.** Find the code path described in the - issue. Trace it from entry point to the failure site. If the issue - includes an error message or stack trace, locate the exact line. - -2. **Understand the current behavior.** Read the code, not just the - function — read its callers and the data flowing into it. Check - tests (if any) to see what the expected behavior was. - -3. **Identify the root cause.** Distinguish between: - - The **symptom** (what the user sees) - - The **proximate cause** (what line/condition triggers it) - - The **root cause** (why that condition exists) - - Fix the root cause when possible. Fix the proximate cause only when - the root cause is out of scope. - -4. **State the fix hypothesis.** Before writing code, state in one - sentence what you plan to change and why it addresses the root - cause. This becomes part of the commit message. - -## When investigation is blocked - -- **Missing reproduction context**: if the issue lacks enough detail - to identify the code path, ask via a PR comment (not a blocking - question — ship what you can). -- **External dependencies**: if the root cause is in a dependency or - external service, note it in the PR description and fix what's - within scope. -- **Multiple possible causes**: if you find several plausible causes, - fix the most likely one and note the alternatives in the PR. - -## Anti-patterns - -- Starting to code before understanding the failure path -- Reading only the function mentioned in the issue without checking callers -- Guessing based on function names without reading the implementation -- Fixing the symptom while leaving the root cause intact diff --git a/.agents/skills/resolve-issue/references/verification-harness.md b/.agents/skills/resolve-issue/references/verification-harness.md deleted file mode 100644 index 4d74b4bfc..000000000 --- a/.agents/skills/resolve-issue/references/verification-harness.md +++ /dev/null @@ -1,35 +0,0 @@ -# Verification Harness Selection - -Match the shape of the change to the right verification method. -Use the first row that fits. - -| Change shape | Verification method | Example | -|---|---|---| -| Logic bug in a pure function | Unit test targeting the fixed path | `expect(parse("")).toBe(null)` | -| State management / data flow | Integration test with real data flow | Test the full handler, not just the helper | -| CLI command behavior | Run the actual command | `bun run cli --flag` and check output | -| HTTP endpoint | `curl` or test client against dev server | `curl localhost:3000/api/health` | -| Build / compilation | Full build | `bun run build` or `npm run build` | -| Type error fix | Type checker | `tsc --noEmit` or `bunx tsc --noEmit` | -| Lint / format fix | Linter | `bunx biome check` or project lint command | -| Config change | Smoke test the affected system | Start the server, run the workflow | -| UI component | Browser test or visual check | Storybook, Playwright, or manual | -| CI workflow change | Dry-run where possible | `act` for GitHub Actions, or push and observe | - -## Principles - -- **Run the existing test suite first.** If it passes, your change - didn't break existing behavior. If it fails on unrelated code, - note it and move on. - -- **Verify the fix, not just the absence of error.** A test that - previously crashed and now doesn't crash might be passing for the - wrong reason. Assert the expected output. - -- **Prefer the project's own verification tools.** If the repo has - `make test`, use it. Don't introduce new test infrastructure for - a single fix. - -- **Time-box verification.** Spend up to 2 minutes finding and - running tests. If the project has no test suite and the change is - simple, note "no test suite found" and move on. diff --git a/.agents/skills/respond-to-comment/SKILL.md b/.agents/skills/respond-to-comment/SKILL.md deleted file mode 100644 index 340391fe6..000000000 --- a/.agents/skills/respond-to-comment/SKILL.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -name: respond-to-comment -description: Triage and respond to comments on a PR. Fix if actionable, reply either way. Load repo-setup first. -license: Apache-2.0 -metadata: - audience: autonomous-agents ---- - -# Respond to Comment - -Triage a comment on a PR the bot is involved in. Load `repo-setup` first. - -## Addressing guard - -Before triaging, confirm the comment is actually for you: - -- If the comment author equals your identity (`$ME` — see agent identity - setup), stop: `SKIPPED: own comment`. -- If the body explicitly `@`-mentions a specific other user and does NOT - `@`-mention `$ME`, the question is aimed at someone else — stop: - `SKIPPED: directed at @`. Applies to inline and top-level - comments alike. Exceptions (keep going): the comment also `@`-mentions - `$ME`, it's a direct reply to one of your own comments, or it's a - comment on a `jared`-labeled issue (the router resumes `resolve-issue` - for those, so answers to your own questions are never dropped even if - they `@`-mention a helper). -- A comment with no `@`-mention of another user is not affected by this - guard — proceed to triage as normal. - -## Triage - -- **Actionable**: real bug, missing test, valid concern → fix it -- **Not actionable**: style preference, out of scope, already handled → reply with reason -- **Approval thumbs-up** (short body, no code refs): don't reply, stop - -## Workflow - -1. Check PR authorship — only push to your own PR's branch. -2. If actionable on your own PR: implement the fix, load `deslop`, commit, - push, then reply on the thread with the commit SHA and resolve the thread - (see below). After all fixes, re-request review. -3. If actionable on someone else's PR: reply with a `suggestion` block - or description. Don't push. -4. If not actionable: reply on the thread with the reason and leave it open - for a human to resolve. - -## Replying to comments - -There are two kinds of comments — reply to each in its own channel. **Never -use `gh pr comment` to answer an inline review comment**; that posts a -top-level PR comment that isn't attached to the thread. - -**Inline review comment** (`pull_request_review_comment`, or a comment inside a -`pull_request_review`) — reply on the thread via the replies endpoint: - -```sh -gh api -X POST \ - "repos///pulls//comments//replies" \ - -f body="Fixed in ." -``` - -`` is the review comment's `id` from the event payload (use the -top-level comment of the thread — the one with `in_reply_to_id` unset). - -**Top-level PR comment** (`issue_comment` on a PR, not tied to a line) — reply -with: - -```sh -gh pr comment --body "..." -``` - -## Resolving a thread (only after you fixed it) - -Resolve a review thread **only** when you pushed a code change that addresses -it. Leave won't-fix / not-actionable threads open with an explanatory reply. - -1. Find the thread node id for the comment you addressed: - - ```sh - THREAD_ID=$(gh api graphql -f query=' - query($owner: String!, $repo: String!, $pr: Int!) { - repository(owner: $owner, name: $repo) { - pullRequest(number: $pr) { - reviewThreads(first: 100) { - nodes { id isResolved comments(first: 1) { nodes { databaseId } } } - } - } - } - }' -f owner= -f repo= -F pr= \ - --jq '.data.repository.pullRequest.reviewThreads.nodes[] - | select(.comments.nodes[0].databaseId == ) | .id') - ``` - -2. Resolve it: - - ```sh - gh api graphql -f query=' - mutation($threadId: ID!) { - resolveReviewThread(input: { threadId: $threadId }) { - thread { isResolved } - } - }' -f threadId="$THREAD_ID" - ``` - -## Re-requesting review - -After pushing fixes for a reviewer's feedback, re-request their review so they -see the PR is ready again: - -```sh -gh api -X POST "repos///pulls//requested_reviewers" \ - -f "reviewers[]=" -``` - -Keep replies concise and natural — write like a teammate, not a -support bot. No filler phrases, no emoji unless the thread uses them. - -Don't push to others' branches. Don't force-push. Don't merge. diff --git a/.agents/skills/review-pr/SKILL.md b/.agents/skills/review-pr/SKILL.md deleted file mode 100644 index 4ea6e3e24..000000000 --- a/.agents/skills/review-pr/SKILL.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: review-pr -description: Review a pull request. Self-fix on own PRs, post a review on others'. Load repo-setup first. -license: Apache-2.0 -metadata: - audience: autonomous-agents ---- - -# Review PR - -Review a PR the bot is involved in. Load `repo-setup` first. - -## Workflow - -1. Check authorship: `gh pr view --json author --jq .author.login` - vs `$ME` (your identity). Skip drafts unless it's your own PR. -2. Read the PR's intent (body, linked issues, commit log). -3. Load `review` skill. -4. Act on findings: - - **No findings**: post a `--comment` review (reserve `--approve` - for when you can vouch for correctness). - - **Findings on own PR**: load `apply-fixes` skill to push fixes. - - **Findings on others' PR**: post `--request-changes` or - `--comment` review via `gh pr review`. Don't push to their branch. - -Write review comments like a senior dev — direct, specific, no -filler. "this will panic on nil" not "I noticed that this could -potentially cause a nil pointer dereference." - -Don't approve trivially. Don't merge. diff --git a/.agents/skills/review/SKILL.md b/.agents/skills/review/SKILL.md deleted file mode 100644 index abd685875..000000000 --- a/.agents/skills/review/SKILL.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -name: review -description: Review the current branch's changes against intent. Returns a structured list of findings the caller can hand to a fix-applier, or an empty list when there's nothing to address. Use this for both self-review of your own work and reviewing someone else's PR. -license: Apache-2.0 -metadata: - source: https://github.com/BYK/dotskills - audience: autonomous-agents ---- - -# Review changes - -Read the diff against the default branch and produce a structured list -of findings. The caller decides what to do with them — apply fixes -directly, post a review on GitHub, or both. - -## Process - -1. Resolve the default branch and diff: - ```sh - DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) - git diff "$DEFAULT_BRANCH"...HEAD - ``` - Three-dot syntax shows just what this branch added, not unrelated - changes that landed on the default branch since branching. - -2. For larger diffs, read the changed files top to bottom before - judging, so you don't carry the implementation's "obvious in - context" bias. You may delegate the read-and-summarize pass to the - `explore` subagent (cheaper, read-only) to get a structured rundown - of what changed — but make every review *judgment* (is this a real - finding?) yourself. - -3. If a test suite exists, run it to verify the changes don't break - anything. Check `package.json` scripts, `Makefile`, `pytest.ini`, - `go.mod`, or CI workflow files for the test command. If tests fail - on code unrelated to the diff, note it but don't flag it. If tests - fail on changed code, add a `bug` finding. - -4. Read every change against the PR's stated intent (PR body + linked - issues via `gh issue view`). For each concern, classify it: - - - **bug** — logic doesn't match intent, broken edge case (null, - empty, concurrency), incorrect assumption, factual error. - - **test-gap** — new behavior added without test coverage on a - critical path. - - **style** — inconsistent with surrounding code (string quotes, - brace style, naming). - - **scope** — diff includes changes unrelated to the stated intent. - - **docs** — stale comments or PR description doesn't match diff. - -## Output format - -Emit a JSON block as the FINAL part of your reply, exactly: - -```json -{ - "findings": [ - { - "kind": "bug" | "test-gap" | "style" | "scope" | "docs", - "file": "", - "line": , - "summary": "", - "suggested_fix": "" - } - ] -} -``` - -If there's nothing to address, return `{ "findings": [] }`. - -Keep `summary` and `suggested_fix` terse — one or two sentences each. -The fix-applier reading these has the file open already; don't restate -context the diff already carries. - -## Confidence calibration - -Assign a confidence level to each potential finding before including -it. See `references/confidence-calibration.md` for the full table. - -- **HIGH** — you traced the code path and verified the issue. Report it. -- **MEDIUM** — the pattern is suspicious and likely wrong. Report it, - noting uncertainty in `summary` if relevant. -- **LOW** — the code looks unusual but could be intentional. Do **not** - report it. - -Bug findings should almost always be HIGH. If you can't trace the -code path to confirm the issue, it's speculation — downgrade or drop. - -## When to flag vs. not - -- A `style` finding only counts if the PR's *neighbouring* code uses a - different convention. Don't flag general taste preferences. -- A `test-gap` finding only counts when the missing test would have - caught a real bug class — not "every new function needs a test." -- A `scope` finding is high-confidence: the diff demonstrably includes - a change unrelated to the issue. When in doubt, don't flag. -- Don't include "everything looks good" notes in `findings`. Empty - array is the correct positive signal. - -## Not a finding - -Before reporting, check `references/not-a-finding.md` for patterns -that look suspicious but are typically correct. Common examples: - -- Null checks on values that "should" be set (defensive, valid if - function is public or called from multiple sites) -- Empty catch blocks in error boundaries (framework convention) -- Trivial getters/setters (not worth a test-gap finding) -- Fixing a typo adjacent to changed code (not scope creep) -- TODO comments describing known limitations (not stale docs) - ---- - -*Adapted from [BYK/dotskills](https://github.com/BYK/dotskills) -(Apache-2.0). The original was prose-only; this version produces -structured output so a downstream fix-applier can act on findings -mechanically.* diff --git a/.agents/skills/review/references/confidence-calibration.md b/.agents/skills/review/references/confidence-calibration.md deleted file mode 100644 index d42bc0369..000000000 --- a/.agents/skills/review/references/confidence-calibration.md +++ /dev/null @@ -1,40 +0,0 @@ -# Confidence Calibration - -Assign a confidence level to each finding before including it in the -output. Only report findings at HIGH or MEDIUM confidence. - -## Levels - -| Level | Criteria | Action | -|---|---|---| -| **HIGH** | You traced the code path and verified the issue exists. The finding is demonstrably wrong, not hypothetically wrong. | Report as a finding. | -| **MEDIUM** | The pattern is suspicious and likely a problem, but you haven't fully traced every code path. The surrounding code suggests this wasn't intentional. | Report as a finding. Note uncertainty in `summary` if relevant. | -| **LOW** | The code looks unusual but could be intentional. You can construct a scenario where it breaks, but it requires unlikely inputs or specific timing. | Do **not** report. | - -## Calibration guidelines - -- **Bug findings should almost always be HIGH.** If you can't trace - the code path to confirm the bug, it's not a bug finding — it's - speculation. Downgrade to MEDIUM or drop it. - -- **Test-gap findings are typically MEDIUM.** You can see the behavior - isn't tested but can't always prove it would catch a real bug class. - -- **Style findings should be HIGH** (you can see the neighboring code - uses a different convention) or dropped (it's a taste preference). - -- **Scope findings should be HIGH.** The change is demonstrably - unrelated to the stated intent, or it isn't. - -- **Docs findings are typically HIGH.** The comment is stale or it isn't. - -## Common false positive patterns - -Before reporting, check whether the "issue" is actually: - -- **Intentional defensive code.** The function is called from multiple - sites and the check is valid for some of them. -- **Framework convention.** The pattern looks unusual but is standard - for the framework (e.g., empty catch blocks in error boundaries). -- **Existing behavior, not new.** The "issue" exists in the base - branch too — the PR didn't introduce it. diff --git a/.agents/skills/review/references/not-a-finding.md b/.agents/skills/review/references/not-a-finding.md deleted file mode 100644 index 2d5313a34..000000000 --- a/.agents/skills/review/references/not-a-finding.md +++ /dev/null @@ -1,56 +0,0 @@ -# Not a Finding - -These patterns look suspicious but are typically correct. Do not -report them unless you have specific evidence they cause a problem -in this codebase. - -## By category - -### Bug — safe patterns - -- **Null/undefined checks on values that "should" be set.** If the - function is public or called from multiple sites, defensive checks - are reasonable. -- **Empty catch blocks in error boundaries** (React, Express, Hono). - The framework expects them. Only flag if the error is silently - swallowed in a non-boundary context. -- **Loose equality (`==`) in JavaScript** when comparing to `null` to - catch both `null` and `undefined`. This is an intentional pattern. -- **Re-throwing the same error.** Sometimes done to add context or - trigger a different catch block. - -### Test-gap — not worth flagging - -- **Trivial getters/setters** that delegate directly to another - property or method. -- **Type-only changes** (adding/removing TypeScript types) that don't - affect runtime behavior. -- **Log/telemetry additions** that don't change control flow. -- **Comment or documentation updates.** - -### Style — taste preferences, not findings - -- **Named vs. default exports.** Both are valid; flag only if the - file's neighbors are consistent and this one breaks the pattern. -- **Arrow functions vs. function declarations.** Same rule — only - flag if the file is inconsistent with itself. -- **Trailing commas.** Unless the formatter config enforces one way. -- **Single vs. double quotes.** Unless the formatter config enforces - one way. -- **Import ordering.** Unless an auto-sorter is configured. - -### Scope — not unrelated - -- **Fixing a typo in a comment** adjacent to the changed code. This - is a natural drive-by fix, not scope creep. -- **Renaming a variable** in the same function being modified. This - improves readability of the change. -- **Updating a type** that the changed code depends on. This is a - necessary part of the change. - -### Docs — not stale - -- **TODO comments** that describe known limitations. These are - intentional markers, not stale documentation. -- **Comments explaining "why"** (not "what"). Even if the code - changes, the reasoning may still be valid. diff --git a/AGENTS.md b/AGENTS.md index 0141e32f4..3316fa78e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,29 +1,5 @@ -# Jared (Outpost agent) + +## Long-term Knowledge -Autonomous GitHub coding agent. Work in `/workspace/repo`. - -## Model tiers - -The primary model is chosen per event (see `src/agents/models.ts`): heavy for -code-producing situations, cheaper for lightweight ones. - -| Role | Subagent | Model | -| --- | --- | --- | -| Triage / plan / review (heavy) | (primary Jared) | Claude Opus 4.8 | -| Triage / plan / review (light) | (primary Jared) | xAI Grok 4.3 | -| Explore | `explore` | OpenAI gpt-5-mini | -| Implement | `implement` | Moonshot kimi-k2.7-code | -| Ship (commit/push/PR) | `ship` | xAI Grok (`grok-build-0.1`) | - -Pipeline: triage → explore → plan → implement → review → ship. -(`worker` is a deprecated alias of `implement`.) - -Operators also talk to Jared directly from the Outpost dashboard. Those turns -(`New operator chat` / `Operator guidance:`) skip triage — treat the request as -the task and answer in the conversation. - -Long-term project knowledge for *this* Outpost repo lives in `.lore.md` when present. -For target repositories, read their `AGENTS.md` / `CONTRIBUTING.md` first. - -Skills are under `.agents/skills/`, generated from the canonical `skills/` tree -by `scripts/sync-skills.mjs`. Always load `repo-setup` before situation skills. +For long-term knowledge entries managed by [lore](https://github.com/BYK/loreai) (gotchas, patterns, decisions, architecture), see [`.lore.md`](.lore.md) in the project root. +