Codemod Workflow is an open-source orchestrator, scheduler, and runner for multi-step code transformations. Run it locally via Codemod CLI. It lets you break down migrations into atomic steps, each powered by codemods, CLI commands, custom scripts, or other primitives. Built for reusability, reliability, flexibility, and scale:
  • Single binary, no server — works anywhere you have a shell
  • Schema-validated shared state — tasks share one JSON document
  • Dynamic matrix fan-out — tasks appear/disappear as state arrays change
  • Manual gates — pause tasks until you trigger them
  • Durable & resumable — state survives crashes or reboots
  • Parallel scheduling — independent nodes run when dependencies allow
  • Host-shell execution — commands run directly on your machine (container runtimes on the roadmap)
Codemod Workflows can be run using Codemod CLI or Codemod Platform.

Quick Start

1

Create a new codemod project

npx codemod@next init
When creating a new codemod project, you’ll be prompted for:
  • Project directory
  • Codemod type:
    • Shell command workflow codemod
    • JavaScript ast-grep codemod
    • YAML ast-grep codemod
  • Project name
  • Description
  • Author
  • License type
  • If your codemod is private
This will create a new folder with all the necessary files and structure for your chosen codemod type.
2

Explore the generated project

The generated project structure will differ depending on the codemod type you select:
example-codemod/
├── .gitignore
├── README.md
├── codemod.yaml       # Codemod package manifest and metadata
├── workflow.yaml      # Workflow definition for running the codemod
├── scripts/
│   ├── setup.sh       # Script to set up environment
│   ├── transform.sh   # Script to apply code transformations
│   └── cleanup.sh     # Script to clean up after transformation
You can combine different codemod types in a single package by placing each type under its required directory (e.g., scripts/for shell scripts, rules/for ast-grep rules) and referencing them from workflow.yaml. This allows you to orchestrate complex, multi-step migrations using the best tool for each job.
3

Understand an example workflow

The generated workflow.yaml will also differ depending on the codemod type you select:
version: "1"
nodes:
  - id: setup
    name: Setup Environment
    type: automatic
    steps:
      - id: init
        name: Initialize
        run: ./scripts/setup.sh

  - id: transform
    name: Apply Transformations
    type: automatic
    depends_on: [setup]
    steps:
      - id: apply
        name: Apply Changes
        run: ./scripts/transform.sh

  - id: cleanup
    name: Cleanup
    type: automatic
    depends_on: [transform]
    steps:
      - id: clean
        name: Clean temporary files
        run: ./scripts/cleanup.sh
You can combine different codemod types in a single package by placing each type under its required directory (e.g., scripts/ for shell scripts, rules/ for ast-grep rules) and referencing them from workflow.yaml. This allows you to orchestrate complex, multi-step migrations using the best tool for each job.
4

Understand an example workflow

The generated workflow.yaml (when you choose the YAML-based ast-grep codemod for JavaScript/TypeScript) defines a simple workflow that applies an ast-grep rule to all TypeScript files in the src/ directory (excluding test files):
version: "1"
nodes:
  - id: apply-rules
    name: Apply ast-grep Rules
    steps:
      - name: "Scan TypeScript files only"
        ast-grep:
          include:
            - "**/*.ts"
            - "**/*.tsx"
          exclude:
            - "**/*.test.ts"
            - "**/*.spec.ts"
          base_path: "src"
          config_file: "rules/config.yml"
The referenced rules/config.yml contains an example rule:
id: replace-console-log
language: javascript
rule:
  any:
    - pattern: console.log($ARG)
    - pattern: console.debug($ARG)
fix:
  logger.log($ARG)
This rule will replace all console.log(...) and console.debug(...) calls with logger.log(...) in your TypeScript/JavaScript files.
5

Validate & run your workflow

npx codemod@next workflow validate -w workflow.yaml
npx codemod@next workflow run -w workflow.yaml
This will check your workflow for errors and then run it locally.
The workflow validate command checks syntax and schema compliance, but not logical correctness. Always test your workflows with real data to ensure they behave as expected.Learn more about validating workflows here.

Directory Layout

my-workflow/
├─ workflow.yaml
├─ scripts/
└─ rules/
The folder—called a workflow bundle—is the root when you run npx codemod@next workflow run ./my-workflow/. $CODEMOD_PATH points here inside every task.

Workflow File

workflow.yaml
version: "1"
state:
  schema: []
templates: []
nodes: []
A workflow has four top-level keys:
KeyRequiredPurpose
versionDeclare workflow schema version (default: "1").
stateDeclares shared-state schema.
templatesRe-usable blocks.
nodesExecutable DAG.

Shared State

version: "1"
state:
  schema:
    - name: shards
      type: array
      items:
        type: object
        properties:
          team:    { type: string }
          shardId: { type: string }
nodes: []

Templates

version: "1"
templates:
  - id: checkout-repo
    name: Checkout Repository
    inputs:
      - name: repo_url
        type: string
        required: true
    steps:
      - name: Clone
        run: git clone ${{inputs.repo_url}} repo
Template Inputs & Usage: Templates can define required or optional inputs, which are referenced in their steps.
Template usage in node steps is planned for future releases. For now, templates serve as reusable workflow components that can be referenced in documentation and examples.

Nodes & Steps

Nodes

version: "1"
nodes:
  - id: build
    name: Build
    type: automatic
    steps:
      - name: npm install
        run: npm ci
id
string
required
Unique within the workflow.
name
string
required
Display name.
type
string
required
automatic (default) or manual.
depends_on
string[]
Upstream node IDs.
trigger
object
{ type: manual } → approval gate.
strategy
object
Matrix configuration.
steps
array
required
Ordered list of steps.
runtime
object
Container/runtime configuration (e.g., Docker).
env
object
Environment variables for the node or step.

Step

name
string
required
Step label.
run
string
Inline shell command to execute.Provide either run or uses, not both.
uses
object
Template call(s).Provide either run or uses, not both.

Matrix Strategy

version: "1"
state:
  schema:
    - name: shards
      type: array
      items:
        type: object
        properties:
          team: { type: string }
          shardId: { type: string }
nodes:
  - id: matrix-codemod
    name: Matrix Codemod
    strategy:
      type: matrix
      from_state: shards
    steps:
      - name: Codemod
        run: node codemod.js --team=$team --shard=$shardId

Manual Trigger

version: "1"
nodes:
  - id: manual-approval
    name: Manual Approval
    trigger:
      type: manual
    steps:
      - name: Wait for approval
        run: echo "Waiting for manual approval"

State Updates

SyntaxMeaningExample
KEY=VALSet state key to valuecount=10
KEY@=VALAppend value to array at state keyshards@={"team":"core","shardId":"1"}
Dot notationSet nested state fieldsconfig.retries=5
JSON valuesUse valid JSON for objects/arraysuser={"name":"Alice","id":123}
All state updates must be valid JSON if not a primitive. Updates are applied only if the task exits successfully.

End-to-End Example

This comprehensive workflow demonstrates state management, templates, matrix strategies, and manual triggers:
version: "1"
state:
  schema:
    - name: shards
      type: array
      items:
        type: object
        properties:
          team: { type: string }
          shardId: { type: string }
templates:
  - id: checkout-repo
    name: Checkout Repository
    inputs:
      - name: repo_url
        type: string
        required: true
    steps:
      - name: Clone
        run: git clone ${{inputs.repo_url}} repo
nodes:
  - id: make-shards
    name: Make Shards
    type: automatic
    steps:
      - name: Write shards
        run: echo 'shards@={"team":"core","shardId":"1"}' >> "$STATE_OUTPUTS"
  - id: matrix-codemod
    name: Matrix Codemod
    strategy:
      type: matrix
      from_state: shards
    trigger:
      type: manual
    steps:
      - name: Codemod
        run: node codemod.js --team=$team --shard=$shardId
      - name: PR
        run: codemodctl pr create
What this workflow does:
  1. State Management: Defines a shards array to store team and shard information
  2. Template Reuse: Creates a reusable checkout-repo template for cloning repositories
  3. Dynamic State: The make-shards node populates the state with shard data
  4. Matrix Execution: The matrix-codemod node creates parallel tasks for each shard
  5. Manual Gates: Requires approval before running the codemod on each shard
  6. Multi-step Tasks: Each matrix task runs both the codemod and creates a PR

Task Statuses

Pending
Queued; waiting for runner.
Running
Currently executing.
Completed
Succeeded; diff applied.
Failed
Script exited non-zero; diff discarded.
AwaitingTrigger
Waiting for manual approval.
Blocked
Dependencies not finished.
WontDo
Matrix item removed; task skipped.

Variable Resolution

  • Parameter: ${{params.branch}} — Supplied at runtime
  • Environment: ${{env.CI}} — Host env var
  • Shared State: ${{state.counter}} — Live JSON value
In matrix tasks, each object key becomes an environment variable (e.g., $team, $shardId, …).

Roadmap

Container runtime support
Support for runtime: docker and other container runtimes, allowing tasks to run in isolated environments.
Parameter flags
Ability to pass parameters to workflows via --param key=value flags.
Nested matrix strategies
Support for matrix strategies within matrix strategies, enabling more complex task fan-out.

Next Steps