Skip to content

feat: expose final assistant message as step output (like codex-action's final-message) #1317

@nsportsman

Description

@nsportsman

Problem

When using claude-code-action in a read-only review workflow with defense-in-depth job separation (AI job produces content, separate job posts it), there's no clean way to capture Claude's final response text as a step output.

The current outputs are:

  • execution_file — path to the full execution log (undocumented format, fragile to parse)

By contrast, openai/codex-action exposes a final-message output that contains just the agent's final text response, making it trivial to pipe into a separate posting job.

Use case

We run Claude as a PR reviewer with a hardened, read-only tool surface:

claude_args: |
  --allowedTools "Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Read,Grep,Glob"

To achieve Codex-style defense-in-depth, we want to:

  1. Job 1 (AI, contents: read only): Claude produces the review text
  2. Job 2 (no AI, pull-requests: write): Posts the review via pulls.createReview

This separation ensures that even if the AI sandbox is compromised via prompt injection, it cannot write to the PR or exfiltrate the GITHUB_TOKEN. The AI job would only need contents: read — no pull-requests: write at all.

Currently, we have to either:

  • Give Claude pull-requests: write + Bash(gh pr comment:*) so it posts directly (current approach — works but gives the AI agent write access)
  • Parse execution_file with grep/sed to extract the review text (fragile, undocumented format)
  • Use a post-processing step that finds Claude's issue comment and converts it (our current workaround — extra API calls, brief duplicate window)

Proposed solution

Add a final-message output (or similar) to the action that contains the agent's final assistant text response:

- name: Run Claude PR Action
  id: claude-review
  uses: anthropics/claude-code-action@<SHA>
  with:
    anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
    # ... config ...

- name: Post review
  uses: actions/github-script@v7
  env:
    REVIEW_TEXT: ${{ steps.claude-review.outputs.final-message }}
  with:
    script: |
      await github.rest.pulls.createReview({
        owner: context.repo.owner,
        repo: context.repo.repo,
        pull_number: context.payload.pull_request.number,
        body: process.env.REVIEW_TEXT,
        event: 'COMMENT',
      });

This would enable the same defense-in-depth pattern that openai/codex-action already supports, and allow workflows to remove pull-requests: write from the AI job entirely.

Security context

This is a defense-in-depth improvement for hardened review workflows. The AI job having pull-requests: write is the current workaround, but it means a prompt-injected agent could potentially approve PRs (if gh pr review were in the allowlist) or post misleading comments. Separating the AI sandbox from the posting step eliminates this class of risk entirely.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions