Artifacts
An artifact is a file a run produces and keeps: a generated report, a rendered image, a diff, a CSV, a build output. The run's working directory is scratch and disappears when the run ends, so anything you want to hand back to a person or a downstream system becomes an artifact, stored durably and attached to the run.
What an artifact is
It belongs to the run that wrote it and, through it, to your org; like everything else, it is tenant-isolated. Each artifact record carries:
| Field | What it is |
|---|---|
| Name | The file name, e.g. weekly-report.md. |
| Content type | A MIME type, e.g. text/markdown. |
| Size | The size of the stored bytes. |
| Metadata | Optional key/value data you attach, yours to read back later. |
| Expiry | When the artifact expires. |
Writing one
From the program, call artifacts.write. Pass text or raw bytes; it stores the file and resolves to a reference with a download URL:
import { artifacts, agent } from "@boardwalk-labs/workflow";
export default async function run() {
const report = await agent("Write the weekly metrics report as Markdown: ...");
const ref = await artifacts.write(
"weekly-report.md",
"text/markdown",
report,
{ week: "2026-W24" }, // optional metadata, yours to read back later
);
return { report: ref.url }; // ref = { id, name, url }
}Binary is the same call with a Uint8Array body, so a generated PNG or a zipped bundle works exactly like text.
From an agent
The artifacts built-in tool is on by default, so an agent can persist its own output without you wiring anything: ask it to save its work and it writes the artifact, then you read the reference back. The program around it stays in control of what counts as a deliverable.
// The artifacts built-in tool is on by default: just ask.
await agent("Write the weekly metrics report as Markdown and save it as an artifact.");Retrieving artifacts
List a run's artifacts, then fetch one:
| Surface | How |
|---|---|
| Dashboard | The run page lists every artifact with a download link. |
| CLI | The run's output and artifacts show up alongside its logs. |
| REST API | GET /v1/orgs/:slug/runs/:id/artifacts to list, then GET /v1/artifacts/:id/download (a 302 to a signed URL) or /download-url(the signed URL as JSON, for clients that can't attach a bearer token across a redirect). |
| MCP | list_artifacts then get_artifact_download_url. |
Signed URLs & lifetime
Downloads go through short-lived signed URLs, so the bytes are served by the CDN without exposing the storage bucket, and a link you mint is only good for a window. Request a custom window with ttlSeconds when you mint one (up to a day). The artifact record itself persists with the run; the URL is the thing that expires, so mint a fresh one when you need it rather than storing it.
Artifacts vs. output
Reach for an artifact when the thing is a file: something to download, large, or binary. Reach for the run's output, the value your runfunction returns, when the thing is the run's result: a JSON value a person reads on the run page, a notification carries, or a calling workflow consumes. They compose well: return a small JSON summary that points at the heavier artifacts by URL.