Plugin skill command block (```!) executes but file writes don't persist to filesystem

Resolved πŸ’¬ 3 comments Opened Mar 5, 2026 by solomon-b Closed Mar 9, 2026

Summary

Plugin skill command blocks (` `! ) execute and produce stdout, but filesystem side effects (file creation via mkdir, cat >`, etc.) do not persist to the project directory. This breaks plugins that depend on command blocks creating state files.

Environment

  • Claude Code: 2.1.52 and 2.1.69 (confirmed on both)
  • OS: Ubuntu 22.04, Linux 6.8.0-101-generic x86_64
  • Node: v20.19.5
  • Plugin: ralph-loop@claude-plugins-official (cache version 55b58ec6e564)
  • Sandbox: Not explicitly enabled in any settings file

Reproduction Steps

  1. Have the ralph-loop plugin installed and enabled
  2. Run /ralph-loop "/review last commit"
  3. The skill ralph-loop.md contains a command block:

```
`!
"${CLAUDE_PLUGIN_ROOT}/scripts/setup-ralph-loop.sh" $ARGUMENTS
`
```

  1. The setup script (setup-ralph-loop.sh) runs mkdir -p .claude and writes .claude/ralph-loop.local.md via heredoc
  2. The script's stdout appears in the conversation β€” including the full activation message with iteration count, max iterations, prompt text, etc.
  3. But .claude/ralph-loop.local.md does not exist on disk

Expected Behavior

The setup script's file writes should persist to the project's working directory, creating .claude/ralph-loop.local.md. The plugin's Stop hook reads this file to determine whether to block session exit and feed the prompt back β€” without it, the loop never engages.

Actual Behavior

  • Script stdout: captured and displayed in conversation (works)
  • Script file writes (mkdir -p .claude && cat > .claude/ralph-loop.local.md <<EOF ...): silently lost (doesn't persist)

This means:

  • The Stop hook checks for .claude/ralph-loop.local.md, finds nothing, and allows exit
  • The ralph loop never activates despite the setup script reporting success

Evidence

The conversation displays this output from the script (confirming execution with correct arguments):

πŸ”„ Ralph loop activated in this session!

Iteration: 1
Max iterations: unlimited
Completion promise: none (runs forever)

The stop hook is now active. When you try to exit, the SAME PROMPT will be
fed back to you. You'll see your previous work in files, creating a
self-referential loop where you iteratively improve on the same task.

To monitor: head -10 .claude/ralph-loop.local.md

⚠️  WARNING: This loop cannot be stopped manually! It will run infinitely
    unless you set --max-iterations or --completion-promise.

πŸ”„

/review last commit

But verifying on disk:

$ ls -la .claude/ralph-loop.local.md
# File not found

$ ls -la .claude/
# Only settings.json, settings.local.json, plan.md exist

Impact

Any plugin that uses ` `! ` command blocks to create state files for hooks to read is broken. The ralph-loop plugin is the primary affected plugin β€” its core loop mechanism depends on the setup script persisting a state file that the Stop hook reads.

Related Issues

  • #18044 β€” $ARGUMENTS not populated (different issue; arguments ARE populated here based on stdout)
  • #4462, #13890 β€” Subagent file writes not persisting (similar symptom, different mechanism β€” those are Task tool agents, this is skill command block execution)
  • #28189 β€” Sandbox/bubblewrap creating stub files in .claude/ (related sandbox filesystem behavior on Linux)

View original on GitHub β†—

This issue has 3 comments on GitHub. Read the full discussion on GitHub β†—