Artifacts
Every nax run writes a durable local record under .nax/. The artifact tree is the handoff surface between workflow steps, the dashboard, follow-up prompts, and later debugging sessions.
For multi-agent workflows, artifacts are the evidence trail. They let you inspect the workflow config, prompts, per-agent responses, cross-review notes, consensus summaries, generated patches, and token or cost metadata when available.
Resolved request intent is stored on each agent run as agent, optional
model, optional effort, instanceId, and resolution provenance. The
backend-observed session configuration is stored separately:
{
"agent": "opencode",
"instanceId": "opencode:z-ai/glm-5.2:max",
"model": "z-ai/glm-5.2",
"effort": "max",
"resolvedFrom": "pinned",
"agent_config": {
"agent": "opencode",
"model": "z-ai/glm-5.2",
"effort": "xhigh"
}
}If requested and observed values differ, session JSON includes
configurationMismatch diagnostics instead of overwriting the request.
Historical artifacts without model or effort mean that backend defaults were
used. Friendly Markdown renders the catalog effort label. Request intent keeps
the catalog id (max), while backend-observed agent_config retains its wire
value (xhigh).
Known backend limitation: on a completed follow-up session, the Agent
Runner backend currently returns agent_config with agent and model but
without effort, even when the follow-up request pinned an effort. This is a
backend response-persistence gap, not a NAX omission — NAX sends the requested
effort on the follow-up, stores it as run intent, and replays it exactly on
retry and resume. Until the backend echoes follow-up effort, read the run’s
requested effort as the source of truth for a follow-up’s configured effort;
the observed session agent_config may under-report it. Initial runs echo all
three fields correctly.
Artifact layout
- state.json
- workflow.json
- events.jsonl
- blob-refs.jsonl
latest symlinks are created when the filesystem supports them. The most common handoff file is:
.nax/workflows/latest/artifacts/summary.mdPer-instance result paths
NAX 2.1 keys saved runs and results by instance id. When a step has multiple instances from one provider, each result gets a distinct sanitized basename:
artifacts/steps/01-review/agent-runners/claude__claude-opus-5__low.md
artifacts/steps/01-review/agent-runners/claude__claude-opus-5__high.mdFor backward compatibility, a step with only one instance of a provider keeps
the provider basename, such as agent-runners/claude.md. New consumers should
read step.json or the instance fields in each JSON artifact instead of
constructing a provider-only path. Historical artifacts without instanceId
are interpreted as provider:auto:auto.
Local state and git ignore
The first time nax writes durable artifacts in a project, it also makes sure local artifacts are ignored by Git. If the project .gitignore does not already contain a .nax rule, nax adds:
.nax/This check is intentionally one-time. After the first check, nax records it in .nax/state.json:
{
"schemaVersion": 1,
"generatedBy": {
"name": "netlify-agent-executor",
"version": "<installed-version>"
},
"version": 1,
"gitignore": {
"checkedAt": "<timestamp>",
"status": "created",
"path": "/path/to/project/.gitignore"
}
}On later runs, nax sees gitignore.checkedAt and does not touch .gitignore again. If you remove .nax/ from .gitignore, nax will respect that choice and will not re-add it unless you delete .nax/state.json or remove the gitignore entry from that file.
nax treats existing .nax, .nax/, /.nax/, .nax/**, and /.nax/** entries as already configured.
Artifact metadata
New JSON artifacts include both a schema version and the package version that generated them:
{
"schemaVersion": 1,
"generatedBy": {
"name": "netlify-agent-executor",
"version": "<installed-version>"
}
}Older artifacts may not have generatedBy. Dashboard and tooling should treat that field as optional and use schemaVersion as the primary compatibility signal.
Handoff paths
nax handoff
nax handoff -c
nax handoff --session <id> --copy
nax handoff --workflow <id> --flow review
nax handoff --runner <id> --agent codexThe dashboard exposes the same idea through Run details and Send to next agent.
Do not delete .nax before handing off results. It is the durable local record for workflow summaries, runner summaries, session summaries, event streams, and prompt blob mirrors.
Prompt blob artifacts
For netlify-api runs, the serialized SDK handle and agent artifact record safe
delivery metadata: delivery kind, byte counts, and—when used—the blob
store/key/tenant/expiry plus sentinel. They never record NETLIFY_AUTH_TOKEN or
the runner fetch command. SDK-owned blobs are removed after success,
cancellation, or timeout and retained after failure until logical expiry so a
safe retry can reuse the exact reference. That expiry is enforced by the SDK;
Netlify Blobs does not automatically delete the stored object, so consumers
that can abandon failed handles must sweep expired SDK entries separately.
The GitHub issue/comment compatibility transport still mirrors its offloaded
payloads locally under .nax/workflows/<run-id>/blobs/ and tracks those legacy
remote refs in .nax/blob-refs.jsonl.
Clean stale refs with:
nax admin clean blobs
nax admin clean blobs --forceCommon mistakes
- Treating
.naxas disposable cache before the run has been handed off. - Looking only at terminal output after a failed synthesis. Inspect the SDK delivery metadata and saved workflow inputs; failed-run blob refs remain reusable until logical expiry.
- Assuming SDK cleanup and
nax admin clean blobsmanage the same refs. The SDK ownsnetlify-apirefs; the admin command sweeps the legacy local registry.
See also
- Transports for how runs are submitted.
- Run workflows for the commands that produce workflow artifacts.
- Council pattern for the review, cross-check, and synthesis loop these artifacts preserve.
- Troubleshooting for recovery commands.