Skip to main content
Wire a transform into a workflow: user parameters, matrix sharding values, cross-file state, and structured runtime signals.

Parameters and Configuration

Parameters make your codemods flexible and reusable by allowing you to pass configuration values at runtime. This enables you to create codemods that adapt their behavior based on user input or different execution contexts.
Enterprise Features: In the Codemod app, parameters are configured through a visual UI. The Codemod app provides centralized state management for large-scale refactoring across many repos.
You can access parameters via options.params.
How to pass params when executing your workflow: Passing parameters (—param).

Matrix Strategy Integration

Matrix strategies enable you to run the same codemod with different configurations or to split large codebases into manageable chunks for parallel processing. Matrix values are particularly useful for:
  • Sharding: Distributing work across multiple processes or machines
  • Multi-variant transforms: Running the same logic with different parameters
  • Team-based processing: Applying different rules based on team ownership

Accessing Matrix Values

Access matrix values via options.matrixValues:
options.matrixValues is only defined when your workflow uses a matrix strategy. Otherwise it is undefined.
Prefer checking sharding against a project-relative path (e.g., path.relative(process.cwd(), root.filename())) to avoid mismatches across environments.

Matrix Strategy Configuration

Matrix strategy is defined in your workflow:
workflow.yaml
Parameters vs Matrix Values: options.params contains user-configured workflow settings, while options.matrixValues contains values from matrix strategy (e.g., team, shard, shardId from the shards state array). See Matrix Strategy for details.

State Management

The codemod:workflow module provides shared state that is accessible across all parallel file executions within a step, and can be persisted across workflow steps.

API Reference

<T>(name: string, value: T, persist?: boolean) => void
Sets a named state value. Values are stored as native JavaScript objects (no manual JSON serialization needed). When persist is true (the default), the value is saved at the end of the execution batch and available to subsequent workflow steps.
<T>(name: string) => T | undefined
Gets a named state value, or undefined if it doesn’t exist.
(name: string) => void
Removes a named state value. If the key was persisted, a removal is propagated to persistent storage.
(name: string) => () => void
Acquires a named mutex lock. Returns a release function that must be called when done. While held, other threads’ getState, setState, and unsetState calls on the same key block until released.

Basic Usage

State is shared across all files processed in parallel within a single step:
Do not rebuild a repo-wide index or rewrite a full-repo setState payload on every file. Each file runs in a fresh QuickJS runtime (module caches reset), and getState clones the entire JSON value. Build once under acquireLock, store a built sentinel plus small per-file shards, then look up. See Performant codemods.
codemod.ts

When to Use Locks

Use acquireLock when you need to read-modify-write shared state from parallel threads. Without it, concurrent getState → setState sequences can overwrite each other:
Always call release() in a finally block. Failing to release a lock will block all other threads waiting on that key.
Simple setState calls that don’t depend on the current value (e.g., setState("status", "done")) don’t need locking — they are individually atomic.

Persisting State Across Workflow Steps

State set with persist: true (the default) is automatically saved after a js-ast-grep step completes. Subsequent steps in the same workflow node can read this state:

Transient State

Pass persist: false to keep state only for the current step execution (useful for in-memory coordination that doesn’t need to survive across steps):

Runtime Hooks

The codemod:runtime module lets a codemod send structured execution signals to the engine without relying on console.log parsing.
Use runtime hooks when you want to:
  • show meaningful progress in workflow task logs
  • warn without failing the task
  • improve watchdog diagnostics by naming the active unit or file
  • fail the current step explicitly instead of returning a generic exception
  • stop cooperatively when the task has been canceled

API Reference

(message: string, meta?: RuntimeMeta) => void
Emits a structured progress event. Progress updates appear in task logs and refresh the step heartbeat so long-running transforms can prove they are still alive.
(message: string, meta?: RuntimeMeta) => void
Emits a non-fatal warning event. Warnings are appended to task logs but do not change task state.
(unitId: string, meta?: RuntimeMeta) => void
Overrides the current logical execution unit for diagnostics. For file-based transforms, this is usually the relative file path.
(message: string, meta?: RuntimeMeta) => never
Fails the current file or unit immediately. The runtime currently treats this as terminal for the running task.
(message: string, meta?: RuntimeMeta) => never
Fails the current step immediately. This is always terminal for the running task.
() => boolean
Returns true if the current task has been canceled. Use it to stop long-running work cooperatively.

Example: Report progress and fail explicitly

codemod.ts

When to use hooks vs exceptions

  • Use runtime.progress(...) and runtime.warn(...) for structured observability.
  • Use runtime.failStep(...) when the codemod has decided the task should stop immediately.
  • Plain thrown errors still fail the task if they escape the codemod, but hooks give better logs and clearer intent.
  • The engine’s idle timeout is only a backstop for silent hangs. Hooks are the preferred way to report semantic failures.
codemod:runtime requires a runtime version that supports runtime hooks. If a codemod must run in mixed-version environments, prefer a dynamic import with a clear upgrade error message when the module is unavailable.