Skip to content
199 changes: 199 additions & 0 deletions .github/workflows/goose-issue-solver.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
name: goose Issue Solver

on:
issue_comment:
types: [created]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to solve'
required: true
type: string

env:
GOOSE_RECIPE: |
version: "1.0.0"
title: "Solve GitHub Issue"
description: "Solve GitHub issue #${ISSUE_NUMBER}"

extensions:
- type: builtin
name: developer
- type: platform
name: todo

instructions: |
Principles:
- Extract all requirements before coding. Missing one means failure.
- Understand before changing. Research the code first.
- Follow existing patterns and AGENTS.md if it exists.
- Stop when requirements are met. Nothing more.
- Verify through deterministic means.
- Your context degrades. The TODO is your memory. Update it after each step.

prompt: |
Solve GitHub issue #${ISSUE_NUMBER}: ${ISSUE_TITLE}

The issue is saved at /tmp/issue.json

Trigger comment:
${TRIGGER_COMMENT}

Write this to your TODO immediately and update as you progress:

## Phase 1: Understand
- [ ] Read /tmp/issue.json
- [ ] Write all requirements (explicit + implicit) to /tmp/requirements.md
- [ ] Read AGENTS.md if it exists

## Phase 2: Research
- [ ] Explore codebase with analyze and rg
- [ ] Identify files that need to change
- [ ] Update TODO with findings

## Phase 3: Plan
- [ ] Decide on implementation approach
- [ ] For nontrivial issues, use subagents to evaluate architecture or implementation choices
- [ ] Update TODO with specific changes to make

## Phase 4: Implement
- [ ] Implement minimal fix per /tmp/requirements.md
- [ ] Before adding anything, check: is it in the requirements? If not, don't.
- [ ] No .github/, no lock files, no secrets

## Phase 5: Verify
- [ ] source bin/activate-hermit
- [ ] cargo check
- [ ] cargo test (affected crates)
- [ ] cargo fmt
- [ ] ./scripts/clippy-lint.sh
- [ ] Fix failures, retry up to 3 times

## Phase 6: Confirm (MANDATORY)
- [ ] Reread /tmp/issue.json
- [ ] Reread /tmp/requirements.md
- [ ] Confirm all requirements met, nothing extra added
- [ ] Write a summary of changes to /tmp/issue_summary.txt

The Phase 6 "Reread" steps MUST appear in your updated TODO. Skipping them is failure.

Only write /tmp/issue_summary.txt if the fix is complete and verified.
Run `git add` for any new files required for the fix.
Do NOT commit. Leave changes in the working directory for the workflow to handle.

permissions:
contents: write
pull-requests: write
issues: read

concurrency:
group: goose-issue-${{ github.event.issue.number || github.event.inputs.issue_number }}
cancel-in-progress: false

jobs:
solve-issue:
if: |
github.event_name == 'workflow_dispatch' ||
(!github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/goose') &&
contains(fromJSON('["OWNER", "MEMBER"]'), github.event.comment.author_association))

runs-on: ubuntu-latest
timeout-minutes: 30

container:
image: ghcr.io/block/goose:latest
options: --user root
env:
GOOSE_PROVIDER: ${{ vars.GOOSE_PROVIDER || 'openai' }}
GOOSE_MODEL: ${{ vars.GOOSE_MODEL || 'gpt-5.1' }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
HOME: /tmp/goose-home

steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4
with:
fetch-depth: 0

- name: Install tools
run: |
apt-get update
apt-get install -y jq gettext curl build-essential pkg-config libssl-dev
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null
apt-get update
apt-get install -y gh

- name: Get issue details (issue_comment)
if: github.event_name == 'issue_comment'
env:
ISSUE_JSON: ${{ toJSON(github.event.issue) }}
run: printenv ISSUE_JSON > /tmp/issue.json

- name: Get issue details (workflow_dispatch)
if: github.event_name == 'workflow_dispatch'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh api /repos/${{ github.repository }}/issues/${{ github.event.inputs.issue_number }} > /tmp/issue.json

- name: Set issue outputs
id: issue
run: |
echo "number=$(jq -r '.number' /tmp/issue.json)" >> $GITHUB_OUTPUT

echo "title<<TITLE_EOF" >> $GITHUB_OUTPUT
jq -r '.title' /tmp/issue.json >> $GITHUB_OUTPUT
echo "TITLE_EOF" >> $GITHUB_OUTPUT

- name: Run goose
id: goose
env:
ISSUE_NUMBER: ${{ steps.issue.outputs.number }}
ISSUE_TITLE: ${{ steps.issue.outputs.title }}
TRIGGER_COMMENT: ${{ github.event.comment.body || 'Triggered via workflow_dispatch' }}
run: |
mkdir -p $HOME/.local/share/goose/sessions
mkdir -p $HOME/.config/goose
git config --global --add safe.directory "$GITHUB_WORKSPACE"

echo "$GOOSE_RECIPE" | envsubst '$ISSUE_NUMBER $ISSUE_TITLE $TRIGGER_COMMENT' > /tmp/recipe.yaml

goose run --recipe /tmp/recipe.yaml

if [ -n "$(git status --porcelain)" ] && [ -f /tmp/issue_summary.txt ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "summary<<SUMMARY_EOF" >> $GITHUB_OUTPUT
cat /tmp/issue_summary.txt >> $GITHUB_OUTPUT
echo "SUMMARY_EOF" >> $GITHUB_OUTPUT
else
echo "has_changes=false" >> $GITHUB_OUTPUT
fi

- name: Verify no workflow changes
if: steps.goose.outputs.has_changes == 'true'
run: |
if git diff --name-only | grep -q "^\.github/"; then
echo "::error::Changes to .github/ are not allowed"
git checkout -- .github/
fi

- name: Create Pull Request
if: steps.goose.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # [email protected]
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "fix: ${{ steps.issue.outputs.title }}"
title: "fix: ${{ steps.issue.outputs.title }}"
branch: goose/issue-${{ steps.issue.outputs.number }}
delete-branch: true
draft: true
labels: goose-generated
body: |
Closes #${{ steps.issue.outputs.number }}

## Summary
${{ steps.goose.outputs.summary || 'See commits for details.' }}

---
*Generated by goose Issue Solver*
Loading