Skip to content

Agent mode wipe of claude-prompts/ (PR #1288) breaks composite actions that pre-write claude-user-request.txt #1427

Description

@ncaq

Summary

PR #1288 added an unconditional await rm(promptDir, { recursive: true, force: true }) at the start of agent mode in src/modes/agent/index.ts. This breaks any composite action that wraps claude-code-action and pre-writes claude-user-request.txt in an earlier step, because that pre-written file is deleted before the SDK ever sees it.

For my use case (kyosei-action, a code-review composite action), this means /kyosei <PR_URL> is no longer processed as a slash command, the skill never starts, and reviews stop firing entirely on v1.0.146+. I had to pin to v1.0.145 as a workaround (ncaq/kyosei-action#173).

Why we can't just put the slash command in the prompt: input

This was our original approach, and it doesn't work. The dispatch in base-action/src/run-claude-sdk.ts deliberately branches on whether claude-user-request.txt exists:

if (!hasUserRequest) {
  // No user request file - use simple string prompt
  return promptContent;
}
// User request file exists - create multi-block message
...
content: [
  { type: "text", text: promptContent }, // Instructions + GitHub context
  { type: "text", text: userRequest },   // User's request (may be a slash command)
],

The in-source comment is explicit that only the multi-block branch "allows the CLI to detect and process slash commands in the user request". The simple-string branch delivers the prompt verbatim and the CLI does NOT preprocess /foo slash commands or perform $ARGUMENTS substitution from the skill's frontmatter.

In a composite action whose purpose is "run a specific skill on every PR", the only stable way to get slash-command processing today is to write claude-user-request.txt so the SDK takes the multi-block branch.

Why losing the file breaks us

A composite action can run steps before the uses: anthropics/claude-code-action@... step or after it. There is no hook in the middle for downstream code to inject a file between the wipe inside prepareAgentMode and the SDK invocation. So a downstream pre-write pattern like:

- name: Write user request for slash command support
  shell: bash
  run: |
    mkdir -p "${RUNNER_TEMP}/claude-prompts"
    echo "/kyosei ${{ github.event.pull_request.html_url }}" \
      > "${RUNNER_TEMP}/claude-prompts/claude-user-request.txt"

- uses: anthropics/claude-code-action@v1
  with:
    prompt: "Follow the user request."

worked on ≤ v1.0.145, and silently no-ops on ≥ v1.0.146: the file is wiped, the SDK takes the simple-string branch, and Claude only sees "Follow the user request." with no /kyosei ever processed.

Suggested fixes

In rough order of preference / lowest blast radius:

  1. Add a user_request (or user_request_file) input to agent mode. When set, write the value to claude-user-request.txt after the wipe so the SDK takes the multi-block path. This gives composite actions a sanctioned way to drive a slash command, without depending on a file-system side channel.
  2. Switch to per-invocation subdirectory keyed by ${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-${GITHUB_JOB} — this is exactly alternative 1 in PR fix: clear stale claude-prompts dir before each write #1288's own description. Solves the original cross-job leak without nuking files an outer step intentionally placed.
  3. Scope the wipe to known filenames (claude-prompt.txt, claude-user-request.txt) rather than the whole directory. Preserves any new files an outer step might leave while still preventing the specific stale-file leak that Stale prompt files in ${RUNNER_TEMP}/claude-prompts/ leak between jobs on non-ephemeral self-hosted runners #1287 reported.

The current rm -rf is overbroad: it solves #1287 but at the cost of denying downstream composite actions a way to communicate with the SDK.

Reproduction

  • Composite action writes ${RUNNER_TEMP}/claude-prompts/claude-user-request.txt before uses: anthropics/claude-code-action@v1.0.146 (or any later version).
  • Set prompt: to something generic like "Follow the user request.".
  • Observe that the slash command in claude-user-request.txt is never processed (vs. v1.0.145 where it is).

Concrete repro: kyosei-action @v2.2.4 + claude-code-action @v1.0.146..v1.0.153. Real failed run: https://github.com/ncaq/dotfiles/actions/runs/27996821836. The action log shows Context prompt: Follow the user request. and no /kyosei ever appears.

Environment

  • claude-code-action: v1.0.146 through v1.0.153 (regression introduced in v1.0.146)
  • Runner: ubuntu-24.04 (GitHub-hosted)
  • API Provider: Anthropic First-Party API

Happy to send a PR for option 1 if that direction sounds acceptable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdev-experiencep2Non-showstopper bug or popular feature request

    Type

    No type

    Fields

    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