Run multi-step Netlify Agent workflows across Claude, Codex, Gemini, and OpenCode from your Netlify project.
Note
This project is in early alpha and subject to change.
nax uses the netlify-cli and GitHub CLI. Make sure you have those on your machine for nax to operate.
npm install -g netlify-agent-executor
# Connect to your Netlify project or create and connect a new site
nax init
# Start using Netlify agentic workflows
nax runTo control NAX workflows from Claude Code, see the canonical NAX MCP guide.
You want the best possible coding outcome from the world's leading agentic coding models, not just whichever one you happen to subscribe to. Claude Code, Gemini, and Codex each catch different classes of issues; the real value shows up when they review the same work, cross-check each other's findings, and synthesize one consensus. Doing that manually means:
- Opening N issues per model with the same prompt
- Waiting for each agent run to finish before kicking off the next round
- Copy-pasting prior-round results into follow-up prompts
- Re-running the bottom half when one model times out
nax makes the orchestration the artifact. A workflow is a static YAML, JSON, or TOML flow.* config file plus Markdown prompts. You run nax run, pick a flow, pick where to run it, and the steps execute in order — fanning out to agent instances, waiting for terminal results, and feeding surviving prior-round output into the next step.
| Feature | What it gets you |
|---|---|
| Workflow-first | Steps and prompts live in config files + Markdown — diffable, reviewable, repeatable. |
| Multi-instance fan-out per step | Run any provider/model/effort lineup, including several models or effort levels from one provider. |
| Step gating | Round N+1 starts after every instance is terminal; mixed-success rounds continue with survivors. |
| Follow-up sessions | A step can reuse a runner from a prior step so its agent sees its own context. |
| Two transports, one CLI | Run on GitHub Actions or directly via the Netlify Agent Runner API. |
| Single-agent runs | Start Claude, Codex, Gemini, or OpenCode directly without creating a full workflow. |
| Model and effort controls | Pin real provider-specific model IDs and reasoning effort, or leave both on Auto. |
| Failure isolation | Survivors continue after a partial failure; an all-failed step halts the workflow. |
| Project-aware Netlify selection | Multi-project repos prompt for the Netlify project/config to run against. |
| Durable artifacts | Every workflow, runner, and session lands under .nax/ with latest symlinks. |
| Resume | A killed Netlify API run picks up at the first not-yet-completed step. |
| Agent-only CI hooks | nax ci '<command>' runs commands inside Netlify Agent Runner and no-ops elsewhere. |
| Auto-injected review context | Pinned SHA + open-PR ledger appended to every prompt unless you opt out. |
| Hand-off in one flag | nax handoff -c copies the latest consensus summary to your clipboard. |
The bundled review flow runs three rounds against the current branch:
# Preview without creating issues, runners, or .nax files
nax run review --dry --force
# Run for real, choose transport interactively
nax run review
# Run one agent without a workflow
nax run agent gemini "Check this branch for broken links"
# Specific branch / PR, non-interactively
nax run review --branch fix/auth --transport github-actions --force
nax run review --branch '#123' --transport netlify-api --force
# Re-run just one step (or skip ahead)
nax run review --step cross-review
nax run review --from-step synthesizeThe review workflow looks like this:
╭────────────────────────────────────────────────────────────────────────────╮
│ Multi step agent workflow: "Review" │
├────────────────────────────────────────────────────────────────────────────┤
│ Review, cross-review, and synthesize findings with multiple Netlify │
│ agents. │
│ │
│ Orchestrated via: Netlify API │
│ Branch: master │
│ │
│ ╭──────────────────────────────────────────────────────────────────────╮ │
│ │ 1. Review new agent run │ │
│ ├──────────────────────────────────────────────────────────────────────┤ │
│ │ Explore, review, and improve the current setup with three │ │
│ │ independent agents. │ │
│ │ ╭────────╮ ╭────────╮ ╭───────╮ │ │
│ │ │ Claude │ │ Gemini │ │ Codex │ │ │
│ │ ╰────────╯ ╰────────╯ ╰───────╯ │ │
│ ╰──────────────────────────────────────────────────────────────────────╯ │
│ │ │
│ ▼ │
│ ╭──────────────────────────────────────────────────────────────────────╮ │
│ │ 2. Cross Review follow-up session │ │
│ ├──────────────────────────────────────────────────────────────────────┤ │
│ │ Cross-check the first-round Claude/Gemini/Codex review findings │ │
│ │ against each other. │ │
│ │ ╭────────╮ ╭────────╮ ╭───────╮ │ │
│ │ │ Claude │ │ Gemini │ │ Codex │ │ │
│ │ ╰────────╯ ╰────────╯ ╰───────╯ │ │
│ ╰──────────────────────────────────────────────────────────────────────╯ │
│ │ │
│ ▼ │
│ ╭──────────────────────────────────────────────────────────────────────╮ │
│ │ 3. Summarize Consensus new agent run │ │
│ ├──────────────────────────────────────────────────────────────────────┤ │
│ │ Summarize the first-round reviews and second-round cross-review │ │
│ │ outputs into one ranked consensus plan. │ │
│ │ ╭───────╮ │ │
│ │ │ Codex │ │ │
│ │ ╰───────╯ │ │
│ ╰──────────────────────────────────────────────────────────────────────╯ │
╰────────────────────────────────────────────────────────────────────────────╯What that produces:
- review — Claude, Gemini, Codex each open a GitHub issue with the review prompt.
- cross-review — each agent comments on the other agents' issues, via follow-up sessions on the same runner.
- synthesize — Codex reads both rounds and posts one consensus issue.
After the review is complete, you can use the nax handoff command to pass the results on to downstream AI tooling.
nax handoff
╭───────────────────────────────────────────────────────────────────────────────────────────╮
│ Latest result from Claude agent runner │
├───────────────────────────────────────────────────────────────────────────────────────────┤
│ Date: May 20, 2026, 7:39 PM (14 days ago) │
│ Summary: .nax/agent-runners/6a0e6eedd90fa5ba6cbb2f6a/summary.md │
│ Preview: │
│ - Agent: Claude │
╰───────────────────────────────────────────────────────────────────────────────────────────╯
│
◆ Hand off previous results
│ ● Copy latest results markdown to clipboard (from claude .nax/agent-runners/6a0e6eedd90fa5ba6cbb2f6a/summary.md)
│ ○ Copy latest results filePath to clipboard (.nax/agent-runners/6a0e6eedd90fa5ba6cbb2f6a/summary.md)
│ ○ Open latest results in code editor (.nax/agent-runners/6a0e6eedd90fa5ba6cbb2f6a/summary.md)
│ ○ Run followup prompt with previous results (claude .nax/agent-runners/6a0e6eedd90fa5ba6cbb2f6a/summary.md)
Copied .nax/agent-runners/6a0e6eedd90fa5ba6cbb2f6a/summary.md to clipboardThis is handy for passing remote Netlify agent runner results into local Claude Code or Codex sessions to continue work on your machine.
- The flow file is the program. Flows are not a DSL bolted onto code — they are the unit of execution. Anyone can read a workflow's
flow.yml(orflow.json,flow.js,flow.ts,flow.toml) and tell you exactly whatnax run reviewwill do. - Steps gate on results, not time. A step's
waitFor: agent-resultsmakes the next step wait for every instance in the fan-out to become terminal, not a wall-clock timeout. Long thinkers don't poison fast ones. - Same flow, two transports. A flow runs identically on
github-actions(workflow_dispatch intonetlify-labs/agent-runner-action) andnetlify-api(this machine orchestrates the runner directly). You don't rewrite the flow to move it. - Artifacts are first-class. Every run, runner, and agent session writes a summary into
.nax/withlatestsymlinks, so the next prompt or the next operator can pick up the trail. - Resume over re-run. If your laptop sleeps mid-
netlify-apirun,naxfinds the unfinished workflow on next launch and continues from the first incomplete step.
nax |
Manual issue/comment loops | One-shot agent CLI | Custom orchestrator scripts | |
|---|---|---|---|---|
| Multi-agent fan-out per step | ✅ | ❌ | ||
| Waits for every instance before next step | ✅ | ❌ | ||
| Follow-up sessions reuse runner context | ✅ | ❌ | ❌ | |
| GitHub Actions + Netlify API from one CLI | ✅ | ❌ | ❌ | ❌ |
| Durable per-step artifacts | ✅ | ❌ | ❌ | |
| Resume after process kill | ✅ (netlify-api) | ❌ | ❌ | |
| Auto-injected pinned SHA / PR ledger | ✅ | ❌ | ❌ | ❌ |
From npm:
npm install -g netlify-agent-executorWithout installing globally:
npx netlify-agent-executor run review
npx netlify-agent-executor run agent codex "Review this change"
npx netlify-agent-executor ci 'npm test'Or from source:
git clone https://github.com/netlify-labs/nax.git
cd nax
npm install
npm link # exposes `nax` globallyPrerequisites:
- Node 18+ for the published CLI. Developing or rebuilding the dashboard UI requires Node 20.19+ or 22.12+.
- Netlify CLI — authenticated (
netlify login) - GitHub CLI — authenticated (
gh auth login)
Verify:
nax --help
nax list-
Authenticate the prereq CLIs in any repo you want to run flows against:
gh auth login netlify login
-
Wire the repo for
nax. This links a Netlify site, writes the GitHub Actions workflow, and sets the repo secretsNETLIFY_SITE_ID+NETLIFY_AUTH_TOKEN:nax init
Variations:
nax init --create --site-name my-app # create a fresh Netlify site instead of linking nax init --dry # preview without writing
-
Run a flow (interactive picker if you omit the flow id):
nax run # pick single-agent run or workflow nax run review # multi-agent review of current branch nax run agent codex "Check the nav links"
The interactive picker separates built-in NAX workflows from project-local workflows:
◆ What do you want to run? │ ● Start a single Netlify agent with a custom prompt │ ○ NAX Workflow - Review (Review, cross-review, synthesize) │ ○ NAX Workflow - Performance Audit (Find bottlenecks and measurement gaps) │ ○ Workflow - Local Smoke Test (Minimal project-local workflow for verifying nax...) -
Run from anywhere in the repo.
naxresolves the Git root before transport and Netlify project detection, so subdirectories work:cd frontend nax run agent gemini "Check for broken links"
-
Hand off the result to your IDE / the next session:
nax handoff -c # copy latest workflow summary to clipboard nax handoff --workflow <id> --flow review # chain a follow-up flow
| Flow | Use it for |
|---|---|
review |
Broad multi-agent code review with cross-review and consensus synthesis. |
human-review-example |
Example flow that pauses for human approval before continuing. |
ideas |
Multi-agent idea generation, adversarial scoring, reactions, and ranked synthesis. |
do-next |
Choosing the single most logical next development task. |
security-audit |
Auth, billing, webhook, tenant isolation, secrets, and attack-surface audits. |
performance-audit |
Bottleneck discovery and measurement-first optimization planning. |
analytics-audit |
Missing funnel, conversion, feature usage, and product telemetry plans. |
seo-audit |
Metadata, crawlability, structured data, links, alt text, content, page-speed checks. |
accessibility-audit |
WCAG 2.1 AA audit, synthesized fix plan, focused Codex implementation. |
mobile-responsiveness |
Small-viewport audit and focused responsive layout fixes. |
e2e-tests |
Critical-flow discovery, Playwright test planning, first test implementation. |
unit-tests |
High-value unit test gap discovery and focused test implementation. |
documentation |
README, setup, architecture, contributing docs grounded in the codebase. |
error-handling |
Error boundaries, logging, retries, validation, user-friendly failure states. |
ux-copy-polish |
Loading/empty/error states, visual polish, CTA hierarchy, product copy. |
Run nax list to print the live set.
nax run [flow] Start a workflow, or open the interactive picker
nax run agent <name> Run one Netlify agent with a custom prompt
nax run --retry <run-id> Retry one failed Netlify API agent run, then continue
nax init Wire this repo to Netlify + GitHub Actions
nax handoff Copy or continue from prior workflow/session results
nax dashboard [flow] Open the local workflow dashboard
nax list List available flows
nax admin sync last Pull remote updates for the latest local Agent Runner
nax admin clean blobs Preview or delete stale prompt blob refs
nax admin skills install Install bundled agent skills into detected harness dirs
nax dashboard review
nax dashboard --run <workflow-run-id>
nax dashboard --no-open
nax dashboard --no-open --no-tail
nax dashboard --project-root ../my-site --flows-dir .github/nax-flowsnax dashboard starts a localhost workbench for browsing workflows and renders the selected flow as a React Flow graph. Pass --run <workflow-run-id> to open a saved workflow directly in Run details. Browsing and graph rendering are read-only. Dry-run and run controls are explicit actions inside the workbench.
The workbench includes:
| Surface | Behavior |
|---|---|
| Workflow list | Reads the same project and bundled flow definitions as nax list. |
| Graph canvas | Renders workflow steps as React Flow nodes with per-instance configuration/status, inputs, and submit mode. |
| Dry Run | Calls the local API to run nax run <flow> --dry --force; it previews the command and output without writing .nax artifacts. |
| Run | Requires a browser confirmation, then starts the workflow through the local nax command and streams stdout/stderr plus structured run events into the UI. |
| Recent runs | Reads durable .nax/workflows state, highlights resumable runs, and overlays run status on the graph. |
| Run details actions | Opens saved workflow, step, and agent results; switches between Results and Prompt when prompt markdown is available; copies or opens the active markdown source; and can send selected artifacts to a follow-up agent. |
The browser talks only to the local dashboard server. Mutating endpoints require a per-process token embedded in the opened URL, and the server binds to 127.0.0.1 by default. Real runs still use the same transport setup as the CLI, so GitHub Actions and Netlify API prerequisites are unchanged.
Run details resolve the original step prompt from the workflow definition when possible. The center pane switches between rendered Results and Prompt, while the table of contents, copy button, open-file actions, and markdown source links follow the active view.
From a completed run details modal, Send to next agent opens a follow-up composer. The composer requires fresh user instructions, defaults to the last meaningful result artifact, and lets you choose which workflow, step, runner, session, or result artifacts to include. In Follow up prompt on previous Agent Run mode, the selected agent continues its matching prior Netlify Agent Runner when one exists; extra selected agents start fresh runner threads seeded with the selected artifacts. Start fresh agent runner always starts new runner threads.
Workflow step cards show one chip per agent instance. Existing bare-provider
chips load as Auto. Each chip can be edited or removed independently, and
Add agent creates model bake-offs, effort sweeps, or a flagship council
from the server-owned catalog. Follow-up step lineups are inherited and
read-only. Requested values remain distinct from the backend-observed
session.agent_config shown in run history.
Dashboard follow-up submission returns after Netlify accepts the runner/session, not after the remote agent finishes. The notification includes remote links and any local artifact path the server could persist. Fresh runner submissions are saved as one-step pseudo-workflow runs so they can be opened from Recent runs. If Netlify accepts work but local artifact persistence fails, the API still returns success with warnings[] so the remote link is not lost.
Live graph status is event-driven. When the dashboard starts a real run, the child nax run process writes JSONL lifecycle events on file descriptor 3 while stdout/stderr are captured for the UI. The dashboard server relays those structured events to the browser with Server-Sent Events at /api/runs/<id>/events, and the UI reducer updates step cards, agent pills, edges, output, and diagnostics from those events. Child workflow stdout/stderr also streams to the nax dashboard terminal by default; pass --no-tail to keep that terminal quiet.
Each durable run also stores the same structured stream at:
.nax/workflows/<run-id>/events.jsonl
Browser reconnects replay from that log with since=<seq>, and developers can inspect the raw stream as JSON at:
/api/runs/<run-id>/events.json?since=<seq>
The Output panel diagnostics button shows the latest raw events and parser errors. Remote model status is best effort: nax emits every Netlify API or GitHub Actions transition it can prove, but it may show submitted or waiting when the remote service does not expose a more precise live state yet. Cancellation stops local orchestration and marks submitted remote work as abandoned; cancelling remote Agent Runner jobs is a separate transport feature.
The published command serves built UI assets from the package. Developing or rebuilding the UI uses Vite 8, which requires Node 20.19+ or 22.12+:
npm run dashboard:dev
npm run dashboard:build
npm run dashboard:smokeBy default, npm run dashboard:dev serves read-only workflow data from Vite so the UI can boot without a running backend. To iterate against the real local API runner, start the dashboard server in one terminal:
node src/cli/nax.js dashboard --no-open --port 53734To keep runs started from the browser out of the dashboard terminal:
node src/cli/nax.js dashboard --no-open --no-tail --port 53734Copy the token value from the printed URL, then start Vite in another terminal:
NAX_DASHBOARD_API_URL=http://127.0.0.1:53734 npm run dashboard:devOpen the Vite URL with the same token:
http://127.0.0.1:5173/?token=<token>&workflow=do-next
You can also inject the token from the proxy process and omit it from the Vite URL:
NAX_DASHBOARD_API_URL=http://127.0.0.1:53734 NAX_DASHBOARD_TOKEN=<token> npm run dashboard:devNAX_DASHBOARD_API_URL may point at either the backend origin or its /api path. For the common fixed-port loop, npm run dashboard:dev:real defaults the backend to http://127.0.0.1:53734.
nax ci 'npm test && npm run build'nax ci no-ops outside Netlify Agent Runner environments, including normal local shells and Netlify build CI. Inside Agent Runner it executes the command through the shell and exits with the command's status.
This is useful in prompts when you want an agent to run project checks only in the runner environment:
nax ci 'npm run typecheck'
nax ci 'npm test -- --runInBand'nax run agent codex "Review this branch for regressions"
nax run agent gemini --prompt "Check for broken links"
nax run agent claude --model claude-opus-4-8 --effort high --transport netlify-apiIf you omit --prompt in a TTY, nax opens a multiline prompt. Single-agent runs still use the same transport detection, Netlify project picker, artifacts, and handoff support as workflows.
The unit of execution is an instance tuple: provider, optional model, and
optional effort. Its stable id is provider:model:effort, with auto for an
omitted field. Repeating a provider is supported:
# Model bake-off
nax run review \
--agents claude:claude-opus-5:auto \
--agents claude:claude-opus-4-8:auto
# Effort sweep
nax run review \
--agents claude:claude-fable-5:low \
--agents claude:claude-fable-5:medium \
--agents claude:claude-fable-5:high
# Flagship of each provider
nax run review \
--agents claude:latest:high \
--agents gemini:latest:high \
--agents codex:latest:highBare providers such as --agents claude,gemini,codex remain Auto and omit
model and effort on the wire. latest and default resolve at launch to the
catalog default and are recorded concretely for retry and resume. Exact
duplicate tuples are rejected.
Pinned or repeated-provider lineups select netlify-api under transport Auto.
Local runs execute in waves of at most four non-terminal runners. A step is
capped at four resolved agent instances; --force does not bypass this limit.
nax admin sync last
nax admin sync https://github.com/OWNER/REPO/actions/runs/123456789
nax admin sync 123456789 --repo OWNER/REPOnax admin sync last reconciles the latest local .nax/agent-runners/<id> artifact with remote Netlify Agent Runner sessions. Use it when a follow-up happened out of band in the Netlify UI or another process and the local .nax cache is missing the newer session.
The command fetches remote sessions through nax-agent-runner-sdk, writes missing or changed sessions under .nax/agent-sessions/, and rebuilds the runner rollup under .nax/agent-runners/.
When the target is a GitHub Actions run URL or run ID, nax admin sync downloads the uploaded nax-<flow>-<run_id> artifact with gh, merges its workflow, runner, and session artifacts into local .nax/, localizes the workflow metadata for this checkout, and rebuilds the latest symlinks. This is the handoff path for workflows run through .github/workflows/run-nax.yml.
nax admin clean blobs
nax admin clean blobs --ttl-hours 1 --forcenax admin clean blobs sweeps stale or pending Netlify Blob prompt refs recorded in .nax/blob-refs.jsonl. It is a dry run by default. Add --force to delete eligible remote refs after interrupted runs or cleanup retries. Local debug mirrors under .nax/workflows/<run-id>/blobs/ are workflow artifacts and are not removed by this command.
| Flag | What it does |
|---|---|
--dry |
Preview the workflow plan without creating issues, comments, Agent Runner jobs, or .nax artifacts. |
--force |
Skip confirmation prompts. |
--branch <name> |
Branch to review. Accepts a PR selector like #123. |
--transport <kind> |
auto (default), netlify-api, or GitHub Actions aliases (github, github-actions). |
--agents <instances> |
Select comma-separated or repeated provider[:model[:effort]] tuples. |
--models <agent=model> |
Assign a real model ID; repeat for more providers. |
--efforts <agent=effort> |
Assign reasoning effort; repeat for more providers. |
--step-agents <step=agents> |
Select providers for one step, e.g. --step-agents review=claude,codex. Repeat as needed. |
--step-models <step:agent=model> |
Assign a real model for one step and provider. |
--step-efforts <step:agent=effort> |
Assign effort for one step and provider. |
--label <name> / --labels <list> |
Add labels to GitHub issue/comment based submissions. |
--date <yyyy-mm-dd> |
Pin date-sensitive prompt context. |
--archive |
With netlify-api, archive completed intermediate agent runs after their results are captured; final-step runs stay visible. |
--step <id> |
Run only that step. |
--from-step <id> |
Run from that step through the end. |
--context <text> |
Extra context appended to every step's prompt. |
--context-file <path> |
Same, read from disk. |
--sha <rev> |
Pin auto-injected context to a specific git revision. |
--pr-limit <n> |
Cap open-PR ledger entries (default 10). |
--timeout-minutes <n> |
Per-step wait (default 25). |
--runner <mention> |
Agent runner mention prefix (default @netlify). |
--notify |
macOS desktop notification when the flow finishes. |
--no-auto-context |
Skip pinned SHA + PR ledger injection. |
--no-fetch-results |
Skip prior-round result fetching. |
--output-budget |
Opt into response-size guidance for chained workflow prompts. Off by default because blob offload can carry large downstream context. |
--output-budget-bytes <n> |
Target response size when --output-budget is enabled (default 64000). |
--issue <list> |
Recovery: comma-separated issue numbers for comment steps. |
--from-issues <list> |
Recovery: source issue numbers to embed for comment steps. |
--filter <app> |
Explicit Netlify JavaScript workspace filter for local Agent Runner API runs. |
nax admin skills install # auto-detect .claude / .codex / .cursor / .gemini / .agents
nax admin skills install --provider codex # explicit provider; repeatable
nax admin skills install --all-providers # install into every supported provider
nax admin skills install --skill review # install one named skill
nax admin skills install --all-skills # install the full bundled matrix
nax admin skills check # compare installed versions vs. nax package version
nax admin skills update # reinstall latestgithub-actions |
netlify-api |
|
|---|---|---|
| Where agents run | Netlify's hosted runner via a workflow in your repo | Netlify Agent Runner API, orchestrated by this machine |
| Requires | .github/workflows/netlify-agents.yml + repo secrets |
Logged-in Netlify CLI with a linked site |
| Visibility | GitHub Actions logs + issues | Local console + issues |
| Desktop notifications | n/a | macOS only (--notify) |
| Resume after interruption | Re-run the issue | nax offers to resume the unfinished run |
| Provider-specific model/effort | Not supported | Supported |
--transport auto keeps the usual transport preference while every model and
effort is Auto. Pinning either setting or repeating a provider makes Auto
select netlify-api.
Explicit GitHub transport rejects pinned settings before dispatch because the
GitHub Action supports provider selection only.
Repos with multiple netlify.toml files prompt before local Agent Runner submission:
Multiple Netlify projects detected. Choose where to run Agent Runner.
frontend
sanity-legacy
sanity
The picker is ordered by the directory you ran nax from, so cd frontend && nax puts frontend first while still using the Git repo root for transport detection and artifacts.
If a project directory has its own .netlify/state.json, the option includes the linked site ID:
frontend (1963fff0-bb0c-4f91-8601-f7acd91cd76e)
For JavaScript workspaces, nax uses @netlify/build-info to decide whether a Netlify CLI --filter is required. Non-workspace multi-project repos can choose a project without inventing a workspace filter; workspace repos still need one clear filter in the build command or an explicit --filter <app>.
This is a temporary workaround for a Netlify platform limitation: hosted Agent Runner currently receives prompts through a constrained argv path, so large fan-in prompts can fail before the agent starts.
For netlify-api prompt delivery, nax-agent-runner-sdk owns the decision. It measures the final request-marker-decorated UTF-8 prompt and sends it inline when safe. When the prompt is oversized and site-scoped blob storage is available, NAX preserves the complete prompt in a Netlify Blob and submits a small wrapper that tells the runner how to fetch it. Deterministic compaction is reserved for environments where blob delivery is disabled or unavailable. The SDK persists the effective prompt or safe blob reference in its handle, reuses that exact reference for capacity retry, and never stores the caller token or fetch command in artifacts. prompt-too-large means no configured path fits; prompt-ref-expired requires a fresh run so the SDK can upload a new reference.
SDK-owned blobs are deleted after success, cancellation, or timeout. Failed-run blobs are retained until their reference expiry for diagnosis and safe retry. GitHub Actions issue/comment workflow delivery remains a compatibility path: its refs are recorded in .nax/blob-refs.jsonl, and payloads are mirrored under .nax/workflows/<run-id>/blobs/<blob-key>.md with adjacent metadata JSON. Its interrupted cleanup leaves refs for the legacy sweep:
nax admin clean blobs # dry-run stale/pending blob cleanup
nax admin clean blobs --force # delete stale/pending blob refsRelevant environment knobs:
| Name | Default | Meaning |
|---|---|---|
NAX_SAFE_PROMPT_BYTES |
16384 |
Maximum final decorated UTF-8 bytes submitted by the SDK. |
NAX_PROMPT_BLOB_DISABLE |
unset | Disable SDK and compatibility-path blob offload; SDK delivery becomes inline/compact only. |
NAX_BLOB_RETRY_ATTEMPTS |
3 |
Attempts for compatibility-path blob set/get/delete operations. |
NAX_BLOB_CLEANUP_TTL_HOURS |
24 |
Age after which legacy registry refs are eligible for nax admin clean blobs. |
NAX_OUTPUT_BUDGET |
unset | Set to 1/true to append optional response-size guidance to chained prompts. |
NAX_OUTPUT_BUDGET_BYTES |
64000 |
Target response size when output-budget guidance is enabled. |
Context fetch verification is intentionally conservative. nax records contextFetchStatus as confirmed, probable, suspect, or failed; it does not automatically rerun an expensive synthesis just because an agent forgot to echo a marker.
flowchart LR
branch[Branch or PR] --> r1
subgraph r1[Step 1: review]
direction TB
c1[Claude]
g1[Gemini]
x1[Codex]
end
r1 --> r2
subgraph r2[Step 2: cross-review]
direction TB
c2[Claude]
g2[Gemini]
x2[Codex]
end
r2 --> syn[Step 3: synthesize<br/>Codex posts consensus]
Each step waits for every instance to become terminal before the next step starts. Round 2 reuses each surviving runner via follow-up sessions so the cross-review sees its own prior context. Round 3 reads both rounds and posts one consensus issue.
src/cli/nax.js # CLI entrypoint
src/ # CLI, dashboard, workflow engine, storage, integrations, contracts
workflows/<id>/ # bundled workflow definitions and prompts
workflows/<id>/flow.* # one workflow file per built-in workflow
workflows/<id>/prompts/ # one Markdown prompt per step
.github/nax-flows/ # optional committed project-local workflows
src/templates/ # bundled GitHub Actions workflow and skill templates
src/dashboard/web/src/ # React dashboard source
src/dashboard/web/dist/ # packaged dashboard assets served by `nax dashboard`
tests/ # unit, integration, and e2e suites
Key modules:
src/transports.js:1— transport resolution and dispatch.src/local-runner.js:1— Netlify Agent Runner API orchestration.src/run-state.js:1—.nax/workflows/<id>/workflow.jsondurable state.src/workflow-artifacts.js:1— summary rollups.src/round-results.js:1— prior-round result fetching for follow-up steps.src/dashboard/server.js:1— local dashboard API, SSE, and mutation auth.src/dashboard/shared/run-details.js:1— run-details data assembly for workflow, step, runner, session, result, and prompt markdown.src/followup-plan.js:1— dashboard follow-up target, artifact, model, and mode planning.src/followup-delivery.js:1— prompt/context delivery policy for dashboard follow-ups.src/followup-persistence.js:1— submitted follow-up and fresh-run artifact projection.src/runner-event-log.js:1— structured event JSONL append/replay support.
A flow is <flow-root>/<id>/flow.* plus a prompts/ directory beside it. Built-in workflows ship inside the package under workflows/; project-local flows default to .github/nax-flows/ and are shown before bundled workflows in the picker.
Flow files can be YAML, JSON, JavaScript, TypeScript, or TOML. The examples use YAML because it is compact and easy to skim, but the filename can match your preferred format: flow.yml, flow.json, flow.js, flow.ts, or flow.toml.
JavaScript and TypeScript flow/config files are data-only. NAX accepts a static object through module.exports = { ... } or export default { ... }, including TypeScript as const and satisfies suffixes, and rejects dynamic executable code.
Project-local example:
.github/nax-flows/conversion-audit/flow.yml
.github/nax-flows/conversion-audit/prompts/1_audit.md
Configure one or more project flow roots with nax.config.json (or the same style of YAML, TOML, JavaScript, or TypeScript config file if you prefer):
{
"flowsDirs": [
".github/nax-flows",
"tools/nax/flows"
]
}You can also pass --flows-dir <path> more than once or set NAX_FLOWS_DIR / NAX_FLOWS_DIRS. Relative paths resolve from the project root. If a project flow uses the same id as a bundled flow, the project flow wins.
Example (workflows/review/flow.yml):
id: review
title: Review
description: Review, cross-review, and synthesize findings.
defaults:
transport: auto
agents: [claude, gemini, codex]
steps:
- id: review
title: Review
prompt: prompts/1_review.md
action: issue # `issue` opens a new issue, `comment` replies on an existing one
submit: new-run # `new-run` spawns a fresh runner, `follow-up` reuses the runner from `input`
agents:
- { agent: claude, models: [claude-opus-5, claude-opus-4-8] }
- gemini
- codex
waitFor: agent-results
- id: cross-review
title: Cross Review
prompt: prompts/2_cross-review.md
action: comment
submit: follow-up
input:
- step: review
results: all
waitFor: agent-results
- id: synthesize
title: Summarize Consensus
prompt: prompts/3_summarize-consensus.md
action: issue
submit: new-run
agents: [codex]
input:
- step: review
results: all
- step: cross-review
results: all
waitFor: agent-resultsPrompt files are plain Markdown. The runner appends auto-injected review context (pinned SHA, open-PR ledger) and prior-round results before submission unless you pass --no-auto-context / --no-fetch-results.
| Key | Values | What it does |
|---|---|---|
action |
issue, comment |
Open a new issue per agent, or comment on the source issue. |
submit |
new-run, follow-up |
Spawn a fresh runner, or reuse the runner from a prior step. |
agents |
bare providers or instance objects | Ordered lineup; plural models/efforts expand to a cartesian fan-out. |
input |
[{ step, results }] |
Prior step(s) whose results are passed into this prompt. |
waitFor |
agent-results |
Block on every agent completing before the next step. |
isArchivable |
true, false |
Opt a step in or out of --archive cleanup. Defaults to true; final-step runs are still kept unless autoArchive: true is set explicitly. |
autoArchive |
true, false |
Explicit per-step override. Use sparingly; --archive is the normal cleanup switch. |
Follow-up steps inherit surviving instances from the first input step and do
not declare agents. Each tuple continues its own runner session by
(sourceStepId, instanceId). Legacy provider-keyed models and efforts maps
remain valid only when that provider occurs once; instance objects are the
unambiguous form for repeated providers.
Every completed workflow writes durable artifacts under .nax/:
.nax/workflows/<workflow-run-id>/workflow.json
.nax/workflows/<workflow-run-id>/artifacts/summary.md
.nax/workflows/<workflow-run-id>/artifacts/steps/01-review/agent-runners/claude__claude-opus-5__high.md
.nax/workflows/<workflow-run-id>/blobs/<blob-key>.md
.nax/agent-runners/<runner-id>/summary.md
.nax/agent-sessions/<session-id>/summary.md
.nax/workflows/— full multi-step workflow record and rollup..nax/workflows/<id>/blobs/— local debug mirrors of prompt blob payloads..nax/agent-runners/— one Netlify Agent Runner thread/conversation rollup..nax/agent-sessions/— one concrete agent result with output, usage, links, metadata.
When a step has multiple instances of one provider, its step artifacts use an
instance-scoped basename such as claude__claude-opus-5__high.md. A provider
with only one instance keeps the legacy claude.md basename. Read step.json
or artifact instanceId fields instead of constructing provider-only paths.
Each directory has a latest symlink (when the filesystem supports symlinks). The most common handoff file is:
.nax/workflows/latest/artifacts/summary.md
nax handoff # interactive picker (latest/workflow/session/runner)
nax handoff -c # copy latest summary to clipboard
nax handoff --session <id> -c
nax handoff --runner <id> --agent codex
nax handoff --workflow <id> --flow review # chain a follow-up flownax dashboard --run <workflow-run-id> opens a browser-based handoff path from Run details: choose Send to next agent to submit a Netlify Agent Runner follow-up or a fresh seeded runner from selected artifacts. The CLI nax handoff command remains the terminal path for copying or chaining saved results.
If a netlify-api run is interrupted (process killed, machine slept, network died) the workflow state is in .nax/workflows/<workflow-run-id>/workflow.json. Next time you start nax run, it detects the unfinished workflow and offers to resume — it polls the in-flight runner sessions and continues from the first not-yet-completed step.
Failed and timed-out runs are terminal; resume only polls in-flight runs. To retry a failed step:
nax run --retry <run-id>
nax run review --retry <run-id> --step cross-review --agent gemini
nax run review --step <step-id> # re-run one step from scratch| Error | Fix |
|---|---|
gh: command not found or netlify: command not found |
Install and authenticate both CLIs (gh auth login, netlify login). |
Could not resolve NETLIFY_SITE_ID |
nax init couldn't find a linked site. Run netlify link or pass --site-id / --site-name / --create. |
No runnable transport detected from a subdirectory |
Upgrade nax; current versions resolve the Git root before checking .github/workflows and .netlify/state.json. |
| Multiple Netlify projects detected | Pick the directory/project you want. If it is a JavaScript workspace and no filter can be inferred, pass --filter <app> or add one clear package-manager filter to the Netlify build command. |
Branch has uncommitted changes |
nax warns before submitting. Commit/stash, or accept the warning if you want agents to review WIP. |
| Agent run times out | Bump --timeout-minutes. Default 25; long-running flows often want 45+. |
Pinned SHA not on remote |
Auto-injected context pins to a SHA. Push first, or pass --no-auto-context. |
| Resume keeps offering an old run | Decline the prompt; the run state is moved out of "unfinished" once you do. |
A Netlify UI follow-up is missing from .nax |
Run nax admin sync last to refresh the latest local runner from remote sessions. |
nax dashboard shows the fallback HTML page |
Build the packaged UI with npm run dashboard:build, or reinstall a package that includes src/dashboard/web/dist. |
nax dashboard --port <n> fails with address in use |
Omit --port to let the server choose an available port, or pass a different port. |
Dashboard API returns unauthorized |
Reopen the full URL printed by nax dashboard; mutating API calls require that session's token query value or x-nax-token header. |
| Run details has no Prompt tab | The selected entry only shows Prompt when its workflow definition and prompt file can still be resolved. Verify the flow root, prompt path, or open the prompt from the graph node. |
| Dashboard follow-up is unavailable | The browser follow-up composer currently submits through the Netlify API transport. Use CLI handoff/workflow commands for GitHub Actions transport. |
| Dashboard reports an unknown workflow | Run nax list and use the displayed flow id. For project flows, also verify --project-root and --flows-dir. |
| Dashboard Run fails before submission | Fix the same GitHub/Netlify transport prerequisites you would fix for nax run: authenticated CLIs, linked Netlify site, or initialized GitHub Actions workflow. |
Dashboard agent pills stay on submitted or waiting |
The UI only shows states nax can prove from the active transport. Open Output diagnostics or inspect .nax/workflows/<run-id>/events.jsonl to see the raw event stream. |
| Dashboard diagnostics show malformed runner events | stdout/stderr are still valid, but the structured status stream had invalid JSON or a bad envelope. Save the raw diagnostic event and rerun with the same workflow if you need to report it. |
- Authenticated CLIs only. Requires logged-in
netlifyandgh. No web auth flow. - macOS-only desktop notifications.
--notifyshells out toosascript. - GitHub-only. No GitLab/Bitbucket transport.
netlify-apitransport assumes outbound network. Your machine must reach Netlify's API.- Local site slugs are best-effort.
naxcan read exact site IDs from.netlify/state.json; if a multi-project repo is only linked at the root, per-project options show directories/configs instead of guessed site names. - Sync starts with known local runners.
nax admin sync lastrefreshes the latest local runner. It does not yet discover every remote Agent Runner for a site. - Four supported providers. Claude, Gemini, Codex, and opt-in OpenCode are supported. Bundled council workflows keep their existing three-provider defaults unless you select OpenCode.
- No automatic rollback. Partial failures are retained as evidence while surviving instances continue; NAX does not revert work produced by a failed or mixed workflow.
Q: Why not just use Claude Code (or another single-CLI agent) and call it a day?
A: Single-CLI agents can't cheaply give you three independent perspectives on the same diff, then have them critique each other. nax is the gluing layer that turns "ask one model" into "run a fan-out + synthesis workflow." If you only ever want one model, you don't need nax.
Q: Does nax upload my code anywhere?
A: nax itself is a local CLI. The agents run on Netlify Agent Runner (either via your repo's GitHub Actions or via the Netlify Agent Runner API). What ends up on Netlify is whatever the runner action sends — typically the repo checkout and your prompt.
Q: Can I write a custom flow?
A: Yes — .github/nax-flows/<id>/flow.* plus a prompts/ dir is the whole contract. Use YAML, JSON, JavaScript, TypeScript, or TOML for the flow file. Use nax.config.json with flowsDirs if you want project workflows somewhere else.
Q: Can I run only one agent for a step?
A: Set the step's agents: list to one entry (e.g. agents: [codex]). The synthesize step in the bundled flows does this.
Q: Can I inspect the prompt that produced a result?
A: Yes. In nax dashboard, open Run details and switch from Results to Prompt. Copy and open-file actions follow the active view, so copying from the Prompt tab copies prompt markdown instead of result markdown.
Q: What happens if one agent fails mid-step?
A: After retry is exhausted, a step with at least one survivor becomes completed_with_failures; downstream follow-ups inherit only surviving instances. If every instance fails, the step fails and the workflow halts. Use nax run --retry <run-id> --instance <provider:model:effort> to target one failed tuple.
Q: Do flows have to be YAML? A: No. YAML is the default in the bundled examples because it is diffable, reviewable, and trivially generatable, but custom flows can be JSON, JavaScript, TypeScript, or TOML too. Use whichever format your team will actually read.
Q: Can I run this without GitHub Actions?
A: Yes. Pass --transport netlify-api. The trade-off is that your machine has to stay alive for the duration of the run, or you will need to use the resume path.
Q: Can I use it from npx?
A: Yes. Use npx netlify-agent-executor .... For shell commands, quote the command passed to nax ci, e.g. npx netlify-agent-executor ci 'npm test'.
Q: Why does the Netlify project picker show directories instead of site names?
A: Site IDs are only local when that directory has .netlify/state.json or NETLIFY_SITE_ID is set. nax avoids guessing remote site slugs from config paths; if it cannot prove the site ID, it shows the directory/config.
MIT