From 8fc29dd7f1bfb0f3f56ff1553470a6a67b22d74a Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 20:39:07 +0000 Subject: [PATCH 1/4] fix: unbound PR_REF crashes Claude runner diagnostics step The diagnostic block added in PR #1643 references PR_REF to show unpushed commits, but PR_REF is only in the commit step's env block, not the run step's. Under set -euo pipefail the unbound variable crashes the entire step, preventing Claude's output from being captured and the commit step from running. This is why PR #220's Claude runs produced zero output despite the runner fixes being present. Fix: use ${PR_REF:-} to safely handle the missing variable. Also add artifact upload step (mirrors reusable-codex-run.yml) so Claude's session JSONL, output, and analysis files are preserved for debugging even when the run fails. https://claude.ai/code/session_012WnYCcttvFEY3FETnhVcNL --- .github/workflows/reusable-claude-run.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-claude-run.yml b/.github/workflows/reusable-claude-run.yml index c3673ef56..630f94a08 100644 --- a/.github/workflows/reusable-claude-run.yml +++ b/.github/workflows/reusable-claude-run.yml @@ -893,7 +893,8 @@ jobs: echo "Git status after Claude run:" git status --short || true echo "Unpushed commits (if any):" - diag_branch="${PR_REF#refs/heads/}" + diag_branch="${PR_REF:-}" + diag_branch="${diag_branch#refs/heads/}" git log --oneline "origin/${diag_branch:-HEAD}"..HEAD 2>/dev/null || \ git log --oneline -5 2>/dev/null || true echo "::endgroup::" @@ -1116,6 +1117,17 @@ jobs: echo "::error::Failed to push after 3 attempts." exit 1 + - name: Upload Claude output + if: always() + uses: actions/upload-artifact@v6 + with: + name: claude-output-${{ inputs.pr_number || github.run_id }} + path: | + claude-output*.md + claude-session*.jsonl + claude-analysis*.json + if-no-files-found: ignore + - name: Compatibility outputs (LLM analysis placeholders) id: compat if: always() From f3c87907667a64fecc3df262d89ace96952e86fe Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 04:05:17 +0000 Subject: [PATCH 2/4] fix: remove invalid --output-file flag and align Claude runner with Codex The --output-file flag does not exist in the Claude CLI, causing it to exit immediately with code 1 (unknown option). This was introduced in PR #1643 and is the root cause of Claude runs failing on PR #220. Changes to reusable-claude-run.yml: - Remove invalid --output-file and --output-format stream-json flags - Use shell redirect with tee for session logging + output capture - Use PIPESTATUS[0] to capture Claude exit code through the pipe - Rename session files from .jsonl to .log (Claude text != JSONL) - Add agents/*.md bootstrap file exclusion (matches Codex pattern) - Add cross-agent artifact exclusion (codex-session/analysis files) Changes to reusable-codex-run.yml: - Add cross-agent artifact exclusion for claude-* files so shared workspace artifacts don't leak into Codex commits https://claude.ai/code/session_012WnYCcttvFEY3FETnhVcNL --- .github/workflows/reusable-claude-run.yml | 48 +++++++++++++++-------- .github/workflows/reusable-codex-run.yml | 7 +++- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/.github/workflows/reusable-claude-run.yml b/.github/workflows/reusable-claude-run.yml index 630f94a08..fb22dfe2e 100644 --- a/.github/workflows/reusable-claude-run.yml +++ b/.github/workflows/reusable-claude-run.yml @@ -634,7 +634,7 @@ jobs: fi echo "Removing stale workflow artifact files..." - rm -f claude-output*.md claude-session*.jsonl claude-analysis*.json 2>/dev/null || true + rm -f claude-output*.md claude-session*.log claude-session*.jsonl claude-analysis*.json 2>/dev/null || true echo "Git status after cleanup:" git status --short || true @@ -859,32 +859,29 @@ jobs: perm_flag=("--dangerously-skip-permissions") fi - # Use PR-specific session JSONL filename (mirrors Codex runner pattern) + # Use PR-specific session log filename (mirrors Codex runner pattern) if [ -n "${PR_NUMBER:-}" ]; then - SESSION_JSONL="claude-session-${PR_NUMBER}.jsonl" + SESSION_LOG="claude-session-${PR_NUMBER}.log" else - SESSION_JSONL="claude-session.jsonl" + SESSION_LOG="claude-session.log" fi echo "Running Claude Code in agentic mode..." echo "Prompt file: $PROMPT_FILE" echo "Output file: $output_file" - echo "Session log: $SESSION_JSONL" - - # Build the command. claude -p (--print) runs in non-interactive - # agentic mode: tools execute on disk and the final text response - # goes to stdout. --output-format stream-json writes structured - # JSONL events (including tool calls) to stdout so we can capture - # them for debugging, while --output-file captures the final - # human-readable response separately. + echo "Session log: $SESSION_LOG" + + # claude -p (--print) runs in non-interactive agentic mode: + # all tools execute, and the final text response goes to stdout. + # Note: --output-file does NOT exist in Claude CLI; use shell + # redirection. Tee to $SESSION_LOG so we have a debug artifact + # even if the run fails. set +e claude -p "$prompt_content" \ "${perm_flag[@]}" \ "${extra_args[@]}" \ - --output-format stream-json \ - --output-file "$output_file" \ - > "$SESSION_JSONL" 2>&1 - status=$? + 2>&1 | tee "$SESSION_LOG" > "$output_file" + status=${PIPESTATUS[0]} set -e # Diagnostic: show what Claude did to the workspace @@ -1012,16 +1009,33 @@ jobs: git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + # Check if only agents/*.md bootstrap files changed — skip commit + # to reduce noise. Mirrors reusable-codex-run.yml pattern. + STATUS_ONLY_CHANGES=$( + git status --porcelain | + grep -cvE '^\S+\s+agents/.*\.md$' || echo "0" + ) + if [ "$STATUS_ONLY_CHANGES" -eq 0 ] && [ "$CHANGED_FILES" -gt 0 ]; then + echo "Only agent bootstrap files changed - skipping commit to reduce noise." + echo "changes-made=false" >> "$GITHUB_OUTPUT" + echo "commit-sha=" >> "$GITHUB_OUTPUT" + git checkout -- agents/ 2>/dev/null || true + exit 0 + fi + git add -A # Unstage non-agent artifacts to prevent committing workflow noise. # Mirrors the exclusion list from reusable-codex-run.yml. git reset HEAD -- \ claude-output*.md \ claude-prompt*.md \ + claude-session*.log \ claude-session*.jsonl \ claude-analysis*.json \ codex-output*.md \ codex-prompt*.md \ + codex-session-*.jsonl \ + codex-analysis-*.json \ .coverage \ .workflows-lib \ .github/scripts/node_modules \ @@ -1124,8 +1138,8 @@ jobs: name: claude-output-${{ inputs.pr_number || github.run_id }} path: | claude-output*.md + claude-session*.log claude-session*.jsonl - claude-analysis*.json if-no-files-found: ignore - name: Compatibility outputs (LLM analysis placeholders) diff --git a/.github/workflows/reusable-codex-run.yml b/.github/workflows/reusable-codex-run.yml index dcf0f698c..3ea3b85f6 100644 --- a/.github/workflows/reusable-codex-run.yml +++ b/.github/workflows/reusable-codex-run.yml @@ -1298,7 +1298,7 @@ jobs: git add -A # Exclude generated artifacts that cause merge conflicts between concurrent PRs. # These files are auto-generated and should never be committed: - # - codex-*: Codex workflow artifacts + # - codex-*/claude-*: Agent workflow artifacts (cross-agent exclusion) # - coverage.xml, .coverage: CI test coverage reports # - pr_body.md: Agent-generated PR metadata # - autofix_report_enriched.json: Autofix workflow artifact @@ -1310,6 +1310,11 @@ jobs: codex-prompt*.md \ codex-session-*.jsonl \ codex-analysis-*.json \ + claude-output*.md \ + claude-prompt*.md \ + claude-session*.log \ + claude-session*.jsonl \ + claude-analysis*.json \ .coverage \ .workflows-lib \ .github/scripts/node_modules \ From 32b82b025aace8d4a0ce6d9f96f1d6b6b2a6fb80 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 04:27:10 +0000 Subject: [PATCH 3/4] fix: pass PR_REF into Run Claude step so diagnostics resolve the correct branch The post-run "Unpushed commits" diagnostic used ${PR_REF:-} but the Run Claude step's env block never set PR_REF, so diag_branch was always empty and the git-log range fell back to origin/HEAD..HEAD. Add PR_REF: ${{ inputs.pr_ref }} to the env block so the diagnostic shows commits relative to the actual PR branch. Addresses review feedback from Copilot on PR #1645. https://claude.ai/code/session_012WnYCcttvFEY3FETnhVcNL --- .github/workflows/reusable-claude-run.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/reusable-claude-run.yml b/.github/workflows/reusable-claude-run.yml index fb22dfe2e..771d794aa 100644 --- a/.github/workflows/reusable-claude-run.yml +++ b/.github/workflows/reusable-claude-run.yml @@ -783,6 +783,7 @@ jobs: PR_NUMBER: ${{ inputs.pr_number }} SKIP_PERMISSIONS: ${{ inputs.skip_permissions }} CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN || '' }} + PR_REF: ${{ inputs.pr_ref }} run: | set -euo pipefail From bb4c686d0d7f1d14f49e551c477cd78eae6680fb Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 04:46:33 +0000 Subject: [PATCH 4/4] fix: quote $status to satisfy shellcheck SC2086 actionlint/shellcheck flagged unquoted $status in the [ -ne ] test and exit command. Quote both to prevent globbing and word splitting. https://claude.ai/code/session_012WnYCcttvFEY3FETnhVcNL --- .github/workflows/reusable-claude-run.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-claude-run.yml b/.github/workflows/reusable-claude-run.yml index 771d794aa..f8630d8e1 100644 --- a/.github/workflows/reusable-claude-run.yml +++ b/.github/workflows/reusable-claude-run.yml @@ -918,8 +918,8 @@ jobs: echo "final-message=${encoded}" >> "$GITHUB_OUTPUT" echo "final-message-summary=${summary}" >> "$GITHUB_OUTPUT" - if [ $status -ne 0 ]; then - exit $status + if [ "$status" -ne 0 ]; then + exit "$status" fi - name: Commit and push changes