From 52e9af11c673df0ceb8ae49a5cba82de5bbb3779 Mon Sep 17 00:00:00 2001 From: Robby Cochran Date: Wed, 17 Jun 2026 17:38:38 -0700 Subject: [PATCH 1/2] feat: add self-improving agent GitHub Action Daily scheduled workflow that runs the harness against this repo: - Guards against PR spam (max 2 open agent PRs) - Authenticates via Workload Identity Federation - Runs harness apply with a review task inside an OpenShell sandbox - Extracts the diff and opens a PR labeled 'agent' - Focus areas: spec drift, test gaps, doc inaccuracy, code simplification Requires GCP_WORKLOAD_IDENTITY_PROVIDER, GCP_SERVICE_ACCOUNT, and GCP_PROJECT_ID secrets configured. --- .github/agent-task.md | 26 +++++++ .github/agent.yaml | 4 + .github/workflows/agent.yml | 143 ++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 .github/agent-task.md create mode 100644 .github/agent.yaml create mode 100644 .github/workflows/agent.yml diff --git a/.github/agent-task.md b/.github/agent-task.md new file mode 100644 index 0000000..924cc6e --- /dev/null +++ b/.github/agent-task.md @@ -0,0 +1,26 @@ +You are reviewing the harness-openshell repository at /sandbox/harness-openshell. + +Your job: identify exactly ONE improvement and implement it. Not a list — one concrete change with a clear diff. + +Priority order (pick the first that applies): + +1. **Spec drift** — a field, command, or behavior documented in SPEC.md that doesn't match the Go code, or code behavior not reflected in the spec +2. **Test gap** — a code path in cmd/ or internal/ that has no test coverage and is easy to test (one test function, not a test suite) +3. **Doc inaccuracy** — something in README.md or profiles/README.md that is wrong or misleading given the current code +4. **Code simplification** — dead code, redundant checks, or unnecessarily complex logic that can be simplified without changing behavior + +Do NOT: +- Touch .github/workflows/ or .goreleaser.yaml +- Add new features or change behavior +- Refactor for style preferences +- Make multiple unrelated changes + +After making the change, run `go build ./...` to verify compilation. If you added or changed Go code, run `go test ./...` to verify tests pass. + +Output the change as a git diff: +``` +cd /sandbox/harness-openshell +git diff +``` + +The last thing you output should be the diff and a one-line summary of what you changed and why. diff --git a/.github/agent.yaml b/.github/agent.yaml new file mode 100644 index 0000000..514d80c --- /dev/null +++ b/.github/agent.yaml @@ -0,0 +1,4 @@ +name: agent-improve +base_agent: default +repo: https://github.com/stackrox/harness-openshell +task: .github/agent-task.md diff --git a/.github/workflows/agent.yml b/.github/workflows/agent.yml new file mode 100644 index 0000000..17f1f2a --- /dev/null +++ b/.github/workflows/agent.yml @@ -0,0 +1,143 @@ +name: Agent + +on: + schedule: + - cron: "23 9 * * 1-5" # weekdays ~9:23am UTC + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + id-token: write # for Workload Identity Federation + +jobs: + improve: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check open agent PRs + id: guard + env: + GH_TOKEN: ${{ github.token }} + run: | + count=$(gh pr list --label agent --state open --json number --jq 'length') + echo "open_prs=$count" + if [ "$count" -ge 2 ]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping: $count agent PRs already open" + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + + - name: Authenticate to GCP + if: steps.guard.outputs.skip != 'true' + uses: google-github-actions/auth@v2 + with: + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} + + - uses: actions/setup-go@v5 + if: steps.guard.outputs.skip != 'true' + with: + go-version-file: go.mod + + - name: Install openshell + if: steps.guard.outputs.skip != 'true' + run: curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh + + - name: Wait for gateway + if: steps.guard.outputs.skip != 'true' + run: | + for i in $(seq 1 30); do + openshell inference get &>/dev/null && break + sleep 1 + done + + - name: Build harness + if: steps.guard.outputs.skip != 'true' + run: CGO_ENABLED=0 go build -ldflags '-s -w -X main.version=ci' -o harness . + + - name: Run agent + if: steps.guard.outputs.skip != 'true' + id: agent + env: + ANTHROPIC_VERTEX_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} + CLOUD_ML_REGION: us-east5 + run: | + SANDBOX_NAME="agent-improve-$(date +%s)" + HARNESS_OS_IMAGE=profiles/images/sandbox-default \ + ./harness apply -f .github/agent.yaml \ + --name "$SANDBOX_NAME" \ + --task @.github/agent-task.md + + # Extract the diff from the sandbox + openshell sandbox exec --name "$SANDBOX_NAME" -- \ + git -C /sandbox/harness-openshell diff > /tmp/agent.patch 2>/dev/null || true + + # Extract the summary (last non-empty line of sandbox output) + openshell sandbox exec --name "$SANDBOX_NAME" -- \ + git -C /sandbox/harness-openshell log --oneline -1 2>/dev/null \ + | tail -1 > /tmp/agent-summary.txt || true + + openshell sandbox delete "$SANDBOX_NAME" || true + + if [ -s /tmp/agent.patch ]; then + echo "has_diff=true" >> "$GITHUB_OUTPUT" + else + echo "has_diff=false" >> "$GITHUB_OUTPUT" + echo "Agent produced no diff" + fi + + - name: Create PR + if: steps.guard.outputs.skip != 'true' && steps.agent.outputs.has_diff == 'true' + env: + GH_TOKEN: ${{ github.token }} + run: | + BRANCH="agent/improve-$(date +%Y%m%d-%H%M)" + SUMMARY=$(cat /tmp/agent-summary.txt 2>/dev/null || echo "Agent improvement") + + git checkout -b "$BRANCH" + git apply /tmp/agent.patch + git add -A + + git config user.name "harness-agent[bot]" + git config user.email "harness-agent[bot]@users.noreply.github.com" + git commit -m "fix: $SUMMARY" + + git push origin "$BRANCH" + + gh pr create \ + --title "fix: $SUMMARY" \ + --label agent \ + --body "$(cat </dev/null || true + cp /tmp/agent-summary.txt /tmp/agent-logs/ 2>/dev/null || true + journalctl --user -u openshell-gateway --no-pager > /tmp/agent-logs/gateway.log 2>/dev/null || true + + - uses: actions/upload-artifact@v4 + if: always() && steps.guard.outputs.skip != 'true' + with: + name: agent-logs + path: /tmp/agent-logs/ From 05683ebc8be9e42b294dc00da806642525db379d Mon Sep 17 00:00:00 2001 From: Robby Cochran Date: Wed, 17 Jun 2026 17:48:29 -0700 Subject: [PATCH 2/2] fix: use ADC service account JSON for now, WIF stubbed for later Store GCP service account JSON as GCP_ADC_JSON secret. Write to /tmp/adc.json and set GOOGLE_APPLICATION_CREDENTIALS. WIF auth is commented out and ready to switch when ITPC registers the org. --- .github/workflows/agent.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/agent.yml b/.github/workflows/agent.yml index 17f1f2a..1bfd192 100644 --- a/.github/workflows/agent.yml +++ b/.github/workflows/agent.yml @@ -8,7 +8,7 @@ on: permissions: contents: write pull-requests: write - id-token: write # for Workload Identity Federation + id-token: write # for Workload Identity Federation (future) jobs: improve: @@ -34,10 +34,14 @@ jobs: - name: Authenticate to GCP if: steps.guard.outputs.skip != 'true' - uses: google-github-actions/auth@v2 - with: - workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} - service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} + run: | + echo '${{ secrets.GCP_ADC_JSON }}' > /tmp/adc.json + echo "GOOGLE_APPLICATION_CREDENTIALS=/tmp/adc.json" >> "$GITHUB_ENV" + # TODO: switch to Workload Identity Federation when ITPC registers stackrox org + # uses: google-github-actions/auth@v2 + # with: + # workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + # service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} - uses: actions/setup-go@v5 if: steps.guard.outputs.skip != 'true'