Skip to Content
GuidesWrite Custom Workflows

Write custom workflows

Custom workflows are the main way to make nax fit a team’s recurring work. A workflow lives in a directory with one flow.* file and a prompts/ folder. The file describes orchestration; the Markdown prompts describe the work each agent should do.

The most useful workflows usually preserve independent first passes before the agents see each other’s output. Later steps can feed those results forward for cross-review, consensus synthesis, or human approval.

Create the directory

mkdir -p .github/nax-flows/conversion-audit/prompts

Add flow.yml

.github/nax-flows/conversion-audit/flow.yml
id: conversion-audit title: Conversion Audit description: Audit key conversion paths and synthesize one prioritized plan. defaults: transport: auto agents: [claude, gemini, codex] steps: - id: audit title: Audit Conversion Paths prompt: prompts/1_audit.md action: issue submit: new-run agents: [claude, gemini, codex] waitFor: agent-results - id: synthesize title: Synthesize Plan prompt: prompts/2_synthesize.md action: issue submit: new-run agents: [codex] input: - step: audit results: all waitFor: agent-results

Add prompts

.github/nax-flows/conversion-audit/prompts/1_audit.md
# Audit conversion paths Study checkout, pricing, signup, and activation. Report concrete friction with file references, user impact, and a suggested fix.
.github/nax-flows/conversion-audit/prompts/2_synthesize.md
# Synthesize conversion plan Read the prior audit results. Deduplicate findings, reject weak claims, and produce one ranked plan with implementation locations and verification steps.

Verify

nax list --verbose nax run conversion-audit --dry --force

Custom flow roots

nax.config.json
{ "flowsDirs": [ ".github/nax-flows", "tools/nax/flows" ] }

Design guidance

  • Give each step one job.
  • Run independent first-pass steps with submit: new-run before cross-review steps read prior outputs.
  • Use waitFor: agent-results when later steps depend on all prior outputs.
  • Use submit: follow-up when the same agent should continue an earlier runner context.
  • Use results: peers on that first input when every inherited instance should cross-grade the other instances without repeating its own result in Additional Context.
  • Use submit: new-run when a step should start with a clean context plus selected inputs.
  • Use a single synthesis step when you want a concise artifact for human review.
⚠️

JavaScript and TypeScript flow files must contain a single static object export. NAX parses that object as data and rejects dynamic executable code.

Validate your flow

Run nax lint after you add or edit a flow. It checks every discovered flow, or only the ones you name, and prints each problem with a fix:

nax lint # every flow nax lint conversion-audit # one flow nax lint --json # machine-readable report nax lint --strict # also fail on warnings

nax lint exits 0 when every flow is valid, and 1 when any flow has an error. With --strict, warnings also exit 1. The bundled flows are checked this way in CI (npm run check:flows).

How discovery treats broken flows

  • Flows are discovered from each configured flow root in order, then the bundled flows. The first flow with a given id wins, and later flows with the same id are shadowed.
  • A flow that fails to load or validate still claims its id, so it shadows a bundled flow of the same id instead of silently falling back to it. It is listed as invalid and skipped. One broken flow never breaks nax list or the other flows.
  • Disabled flows never shadow anything.
  • nax run, the dashboard, and MCP refuse an invalid flow with invalid_flow (or flow_load_failed when the file could not be parsed). The dashboard and MCP return HTTP 422 with the full diagnostics list, and the dashboard dry-run panel shows each diagnostic.

Plans pin the flow

A run plan (the dashboard’s reviewed plan or MCP workflow_plan) records a digest of the flow and its prompt files. Starting that plan after the flow or a prompt changed fails with flow_changed_since_plan (HTTP 409, recoverable) before anything runs. Create a fresh plan and start that instead. Runs record the same digest, which is how resume detects flow_changed_since_run.

Errors

CodeMeaningFix
invalid_flowThe flow has at least one error below.Fix every listed diagnostic.
flow_load_failedThe flow file could not be read or parsed.Fix the YAML/JSON/TOML syntax, or make a JS/TS flow a single static object export.
duplicate_step_idTwo steps share an id.Give each step a unique id.
invalid_agent_config_wrapperagentConfig is used on defaults or a step.Use first-class models and efforts maps.
invalid_default_transportdefaults.transport is not a known transport.Use auto, github, or netlify-api (or a listed alias).
missing_promptA step has no prompt.Set prompt to a file relative to the flow directory.
missing_prompt_fileThe prompt file does not exist.Create the file or fix the path.
invalid_actionaction is not issue or comment.Use a supported action.
invalid_submitsubmit is not new-run or follow-up.Use a supported submit mode.
invalid_wait_forwaitFor is unsupported.Use agent-results (or human-review for review steps).
invalid_inputinput is not an array.Use entries like { step: previous-step, results: all }.
missing_input_stepAn input entry has no step.Set input[].step to an earlier step id.
unknown_input_stepAn input names a step that does not exist.Use an existing step id.
self_input_stepA step uses itself as input.Reference an earlier step.
future_input_stepAn input names a later step.Inputs can only reference earlier steps.
invalid_input_resultsAn input’s results mode is unsupported.Use a supported mode such as all or peers.
followup_without_inputA follow-up step has no input to continue from.Add an input from an earlier agent step, or use submit: new-run.
followup_source_not_agent_stepA follow-up step’s first input runs no agents (for example, a human-review step).Point the first input at an agent step, or use submit: new-run.
invalid_findings_sourcefindings.step is missing, is a human-review step, or findings.adapter is not registered.Point findings at an agent step and use a registered adapter such as review-consensus.
invalid_lineupagents is not a list of entries.Make agents an array.
invalid_lineup_entryAn agents entry has the wrong shape.Use a provider name or { agent, model(s), effort(s) }.
invalid_instance_specAn instance string is empty or malformed.Use provider[:model[:effort]].
unsupported_agentAn unknown agent provider is named.Use a supported provider such as claude, gemini, codex, or opencode.
duplicate_instanceThe same provider, model, and effort appear twice in one step.Vary the model or effort, or remove the duplicate.
step_instance_limitA step resolves to more agent instances than allowed.Reduce the fan-out or split the work into another step.
ambiguous_provider_mapA provider appears more than once, so its models/efforts map entry is ambiguous.Put the model and effort inline on each entry.
model_provider_mismatchA model belongs to a different provider.Use a model owned by that provider.
unsupported_model_effortA model does not support the requested effort.Use one of the model’s efforts, or auto.
effort_requires_modelAn effort is set while the model is Auto.Pin a model, or set the effort to auto.
invalid_agent_configurationAnother model or effort configuration problem.Use a model owned by the provider and a supported effort, or set both to auto.
github_transport_unsupportedThe lineup needs features the GitHub transport lacks (pinned models, efforts, or several instances of one provider).Use the netlify-api transport for this flow.
transport_lineup_conflictThe flow is pinned to the GitHub transport but a step’s lineup needs netlify-api.Switch defaults.transport to netlify-api or auto, or simplify the lineup.

Warnings

Warnings do not stop a run. --strict turns them into failures.

CodeMeaningFix
deprecated_followup_lineupA follow-up step declares agents in a flow pinned to netlify-api, where follow-ups inherit the source step’s lineup.Remove the declaration, or keep it only if the flow also runs on the GitHub transport.
empty_prompt_fileA prompt file is empty.Write the step’s instructions.
unused_prompt_fileA file in prompts/ is not used by any step.Reference it from a step, or delete it.
flow_id_mismatchThe flow’s id differs from its directory name.Rename the directory or remove the id field.
catalog_passthroughA model id is not in the known catalog and is passed through unchanged.Check the spelling; the Agent Runner rejects unsupported models when the run is submitted.
effort_clampedThe requested effort is unsupported, so the nearest supported effort is used.Choose an effort the model supports.
effort_unavailableThe model has no reasoning effort, so Auto is used.Remove the effort for this model.
lineup_warningAnother lineup note from the agent catalog.Review the step’s model and effort configuration.

When starting a run

CodeMeaningFix
flow_changed_since_planThe flow or a prompt changed after the plan was made.Create a fresh plan and start it.

See also

Last updated on