anthropics / anthropics/claude-code-action

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

Open
#1,317 0 comments 0 reactions 0 assignees View on GitHub
dev-experience enhancement feature-request p3
Dominant language
TypeScript
Stars
8.9k
Forks
2.1k
Avg merge
3d 9h
Merged PRs (30d)
10

Description

## 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:
```yaml
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:

```yaml
- name: Run Claude PR Action
id: claude-review
uses: anthropics/claude-code-action@
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.

Contributor guide

Open the contributing guide

Research direction

Start by tracing how the action currently publishes the execution_file output and how Claude's final assistant response is made available. Add a final-message output containing only that response, then verify it can be consumed by a later github-script step in the read-only review workflow described here.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, typescript
Domain
ci-cd, devops
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.