Skip to main content
ClaudeWave
Skill89 repo starsupdated 1mo ago

dry-run

Preview command effects without making changes. Simulates file writes, git operations, agent spawns, and state changes. All reads execute normally for accurate preview. Use --dry-run flag on any command.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/marcusgoll/Spec-Flow /tmp/dry-run && cp -r /tmp/dry-run/.claude/skills/dry-run ~/.claude/skills/dry-run
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

<objective>
The dry-run skill enables safe command testing by simulating all side effects without execution.

**Problem**: Commands make real changes - creating files, spawning agents, modifying state, executing git operations. Testing commands on production workflows risks unintended modifications.

**Solution**: Add `--dry-run` flag that:
1. Executes all **read** operations (for accurate analysis)
2. Simulates all **write** operations (shows what would change)
3. Previews **agent spawns** (shows what Task() calls would occur)
4. Reports **state changes** (shows YAML mutations)
5. Outputs **standardized summary** (consistent format across commands)

The result: Safe command testing with full visibility into intended effects.
</objective>

<quick_start>
<flag_detection>
**Detect --dry-run in command arguments:**

```bash
# In command process section
DRY_RUN=false
if echo "$ARGUMENTS" | grep -q -- "--dry-run"; then
  DRY_RUN=true
  # Remove flag from arguments for processing
  ARGUMENTS=$(echo "$ARGUMENTS" | sed 's/--dry-run//g' | xargs)
fi
```

**Checking in command logic:**
```markdown
If DRY_RUN is true:
  - Collect intended operations in simulation log
  - Skip actual Write/Edit tool calls
  - Skip actual Task() spawns (log them instead)
  - Skip actual Bash commands with side effects
  - Execute Read/Grep/Glob normally
  - Output dry-run summary at end
```
</flag_detection>

<simulation_output_format>
**Standard dry-run output format:**

```
════════════════════════════════════════════════════════════════════════════════
DRY-RUN MODE: No changes will be made
════════════════════════════════════════════════════════════════════════════════

📁 FILES THAT WOULD BE CREATED:
  ✚ specs/004-auth/spec.md (estimated ~150 lines)
  ✚ specs/004-auth/state.yaml (workflow state)
  ✚ specs/004-auth/NOTES.md (session notes)

📝 FILES THAT WOULD BE MODIFIED:
  ✎ specs/004-auth/state.yaml
    - phase: init → spec
    - status: pending → in_progress

🤖 AGENTS THAT WOULD BE SPAWNED:
  1. spec-phase-agent: "Execute spec phase for user authentication"
  2. clarify-phase-agent: "Clarify requirements"
  3. plan-phase-agent: "Generate implementation plan"

🔀 GIT OPERATIONS THAT WOULD OCCUR:
  • git checkout -b feature/004-auth
  • git add specs/004-auth/
  • git commit -m "feat: initialize auth feature workspace"

📊 STATE CHANGES:
  state.yaml:
    phase: spec → plan → tasks → implement
    status: pending → in_progress → completed

════════════════════════════════════════════════════════════════════════════════
DRY-RUN COMPLETE: 0 actual changes made
Run without --dry-run to execute these operations
════════════════════════════════════════════════════════════════════════════════
```
</simulation_output_format>

<immediate_value>
**Why use dry-run:**

| Scenario | Without --dry-run | With --dry-run |
|----------|-------------------|----------------|
| Testing new feature | Creates real workspace | Shows what would be created |
| Debugging workflow | May corrupt state | Safe preview of operations |
| Learning commands | Trial and error cleanup | Zero-risk exploration |
| CI/CD validation | Real side effects | Validates without changes |
| Training/demos | Need fresh environment | Repeatable demonstrations |
</immediate_value>
</quick_start>

<workflow>
<step number="1">
**Detect dry-run flag**

At command start, check for `--dry-run` in arguments:

```markdown
### Step 0: Dry-Run Detection

Check for --dry-run flag:
```bash
DRY_RUN="false"
if [[ "$ARGUMENTS" == *"--dry-run"* ]]; then
  DRY_RUN="true"
  echo "DRY-RUN MODE ENABLED"
fi
```

If DRY_RUN is true:
- Initialize simulation log array
- Proceed with analysis but skip execution
- Collect all intended operations
```

**Important**: Remove `--dry-run` from arguments before parsing other flags to avoid conflicts.
</step>

<step number="2">
**Execute reads normally**

Read operations are safe and necessary for accurate simulation:

```markdown
**Safe operations (execute normally in dry-run):**
- Read tool: `Read file_path=...`
- Grep tool: `Grep pattern=...`
- Glob tool: `Glob pattern=...`
- Bash (read-only): `ls`, `cat`, `git status`, `git log`, `test -f`
- WebFetch: Documentation/API lookups
- WebSearch: Research queries

**Why**: Accurate simulation requires understanding current state.
```
</step>

<step number="3">
**Simulate write operations**

Intercept and log write operations without executing:

```markdown
**Write operations to simulate:**

**File writes** (Write tool):
```
Instead of: Write file_path="specs/001/spec.md" content="..."
Log: "WOULD CREATE: specs/001/spec.md (~150 lines)"
```

**File edits** (Edit tool):
```
Instead of: Edit file_path="state.yaml" old_string="..." new_string="..."
Log: "WOULD MODIFY: state.yaml (phase: init → spec)"
```

**Bash writes** (Bash tool with side effects):
```
Instead of: Bash command="mkdir -p specs/001"
Log: "WOULD EXECUTE: mkdir -p specs/001"

Instead of: Bash command="git commit -m '...'"
Log: "WOULD EXECUTE: git commit -m '...'"
```
```
</step>

<step number="4">
**Simulate agent spawns**

Log Task() calls without spawning:

```markdown
**Agent spawn simulation:**

Instead of:
```
Task tool call:
  subagent_type: "spec-phase-agent"
  description: "Execute spec phase"
  prompt: "..."
```

Log:
```
WOULD SPAWN AGENT:
  Type: spec-phase-agent
  Description: Execute spec phase
  Expected outputs: spec.md, updated state.yaml
```

**Why not spawn**: Agents perform real work. Dry-run must prevent cascading side effects.
```
</step>

<step number="5">
**Track state changes**

Analyze YAML state mutations:

```markdown
**State change tracking:**

Read current state.yaml, then log intended mutations:

```yaml
# Current state
phase: init
status: pending

# After command (simulated)
phase: spec
status: in_progress
phases:
  spec: completed
```

Log as:
```
STATE CHANGES (state.yaml):
  - phase: init → spec
  - status: pending → in_progress
  - phases.spec: (new) → completed
```
```
</step>

<step number="6">
*