← Back to Home

Claude Code Workflow Studio Hands-On

ai-codingclaude-codeworkflowautomation

Why This Article

Claude Code excels at single-shot code tasks, but when you need to chain "code review → update docs → submit PR → notify Slack" into an automated pipeline, Workflow Studio is the answer. I hit 7 real pitfalls during setup — here's the complete debrief.

What Is Claude Code Workflow Studio

Workflow Studio (claude workflow subcommand, v0.4+) is the official workflow editor for Claude Code:

Docs: https://docs.anthropic.com/en/docs/claude-code/workflows

Environment Setup

# Verify Claude Code version (requires ≥ 0.4.0)
claude --version
# Claude Code 0.4.2

# Initialize workflow project
claude workflow init my-ci-pipeline
cd my-ci-pipeline
# Creates:
# my-ci-pipeline/
#   workflows/
#     main.yaml
#   steps/
#   shared/

Core Config: Complete main.yaml Example

# workflows/main.yaml
name: ci-code-review
version: "1"

on:
  push:
    branches: [main, develop]

env:
  REVIEWER: "@claude-code/config/team.yml"
  SLACK_WEBHOOK: "${SLACK_WEBHOOK_URL}"

steps:
  - id: lint
    action: run
    command: npm run lint
    continue_on_error: false

  - id: test
    action: run
    command: npm test
    depends_on: [lint]
    timeout: 300

  - id: security-scan
    action: run
    command: npm audit --audit-level=moderate
    depends_on: [lint]

  - id: review
    action: claude
    prompt_file: "./steps/review-prompt.md"
    model: claude-3-5-sonnet-20240620
    max_tokens: 4096
    depends_on: [test, security-scan]

  - id: notify
    action: webhook
    url: "${SLACK_WEBHOOK}"
    condition: "steps.review.status == 'success'"
    payload:
      text: "✅ PR #{context.pr_number} passed review"

🕳️ Pitfall 1: condition Uses `=` Instead of `==`

Wrong:

  - id: notify
    condition: steps.review.status = "success"   # ❌ single = won't parse

Error:

Error: Workflow validation failed: condition expression error
Parse error at line 12, column 14: unexpected token '='

Fix:

  - id: notify
    condition: "steps.review.status == 'success'"   # ✅ double ==

**Note**: The string value inside condition must use double quotes; single quotes cause a parse error.

---

🕳️ Pitfall 2: depends_on Order ≠ Execution Order

**Misconception**: depends_on: [A, B] runs A before B.

Reality: The downstream step triggers when both A and B finish — whichever finishes first doesn't matter.

  - id: downstream
    depends_on: [A, B]
# A and B run in parallel; downstream starts when both complete

For forced serial execution:

  - id: A
    action: run
    command: echo "A done"

  - id: B
    depends_on: [A]   # ✅ explicit dependency forces serial
    action: run
    command: echo "B runs after A"

---

🕳️ Pitfall 3: context Variable Not Persisting Across Steps

**Failure scenario**: Step 1 sets context.branch_name, Step 2 reads empty.

steps:
  - id: get-branch
    action: run
    command: |
      echo "BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)"
    export:
      - BRANCH_NAME  # ❌ won't auto-export

**Result**: steps.show-branch gets an empty string.

**Fix**: Declare outputs explicitly:

  - id: get-branch
    action: run
    command: |
      echo "::set-output name=branch_name::$(git rev-parse --abbrev-ref HEAD)"
    outputs:
      branch_name: "${BRANCH_NAME}"

  - id: show-branch
    action: run
    command: echo "${steps.get-branch.outputs.branch_name}"  # ✅

---

🕳️ Pitfall 4: for_each Loop Doesn't Reference `${item}`

Wrong:

  - id: lint-files
    action: run
    command: npm run lint
    for_each:
      files: ["src/**/*.ts", "src/**/*.tsx", "src/**/*.js"]
    # ❌ item not referenced

Error:

Error: for_each item 'files' not referenced in command
Workflow stopped at step 'lint-files'

Fix:

  - id: lint-files
    action: run
    command: |
      npx eslint ${item} --max-warnings 0
    for_each:
      files: ["src/**/*.ts", "src/**/*.tsx", "src/**/*.js"]

Actual behavior: Runs 3 times, linting one glob pattern per iteration.

---

🕳️ Pitfall 5: webhook Action 10s Default Timeout Fails on Large Payloads

Scenario: 5000-character review result → POST to Slack → truncated.

  - id: notify
    action: webhook
    url: "${SLACK_WEBHOOK}"
    payload:
      text: "${steps.review.outputs.summary}"
    # ❌ default timeout: 10, large payload times out

Fix:

  - id: notify
    action: webhook
    url: "${SLACK_WEBHOOK}"
    timeout: 30   # ✅ explicit timeout
    payload:
      text: "${steps.review.outputs.summary}"

Rule of thumb: Payloads > 3000 chars should write to file first and pass a URL.

---

🕳️ Pitfall 6: model Alias Doesn't Accept Date-Stamped Versions

Wrong:

  - id: review
    action: claude
    model: claude-3-5-sonnet-4-20250514   # ❌ date-stamped alias not supported
    prompt_file: "./steps/review-prompt.md"

Error:

Error: Unknown model 'claude-3-5-sonnet-4-20250514'
Available: claude-opus-4-5, claude-3-5-sonnet-20240620, claude-3-haiku-20240307

Fix: Use the full version tag:

  - id: review
    action: claude
    model: claude-3-5-sonnet-20240620   # ✅ full version tag
    # Or use short alias:
    # model: sonnet

---

🕳️ Pitfall 7: on.push.branches Glob Pattern Only Matches Literals

Wrong:

on:
  push:
    branches:
      - "feature/**"   # ❌ glob not supported

Actual behavior: All branches triggered the workflow, including main and develop.

Fix: List branches explicitly or filter inside the step:

on:
  push:
    branches:
      - main
      - develop

# Then in the step:
  - id: feature-only
    action: run
    command: |
      if [[ "${context.branch}" == feature/* ]]; then
        echo "Running feature checks..."
      fi

---

5-Step Production Checklist

1. **Version check**: claude --version → must be ≥ 0.4.0

2. **Syntax validation**: claude workflow validate workflows/main.yaml (no execution)

3. **Dry run**: claude workflow run --dry-run ci-code-review

4. **Single-step test**: claude workflow step test lint

5. **Log audit**: claude workflow logs --tail 100

Workflow Studio vs Traditional Scripts: When to Use Which

ScenarioTool
Single code generation/refactorClaude Code direct
Multi-step with persistent stateWorkflow Studio
GUI drag-and-drop neededn8n / Make
Complex branching + loopsWorkflow Studio
Simple cron jobsCron + Shell
Visual monitoring UIn8n (built-in UI)

Conclusion

Workflow Studio upgrades Claude Code from single-shot interactions to automated pipelines. The key is getting the YAML right — conditions use ==, loops reference ${item}, models need full version tags. The 7 pitfalls above cost me enough time to write 3 production workflows; this checklist will save you that detour.

Related Reading:

👉 Join MiniMax Token Plan: AI coding acceleration for businesses

👉 Join Zhipu Coding Plan: GLM-4.6/GLM-5 coding packages, China-stable, pay-per-token unlimited

👉 Join Aliyun AI: Top AI products with exclusive coupons for business innovation

📌 This article was AI-assisted generated and human-reviewed | TechPassive — An AI-driven content testing site focused on real tool reviews

🔗 Recommended Tools

These are carefully selected tools. Using our affiliate links supports us to keep producing quality content:

☁️ DigitalOcean Cloud ⚡ Vultr VPS ⭐ MiniMax Token Plan 🧩 Zhipu Coding Plan 🎁 Zhipu 20M Tokens Gift 🤖 QoderWork CN (Refer & Earn) ☁️ Aliyun AI Products 📚 WordPress Books 🔍 WordPress SEO Books 🌐 Web Hosting Books 🐳 Docker Books 🐧 Linux Books 🐍 Python Books 💰 Affiliate Marketing 💵 Passive Income Books 🖥️ Server Books ☁️ Cloud Computing Books 🚀 DevOps Books
← Back to Home