Skip to content

Docs / Artifact storage

Artifact storage

Agents store files (screenshots, reports, builds) in your own S3 bucket or the platform bucket. Presigned URLs; expiry by policy.

Agents produce files: screenshots, test reports, build outputs, generated code. developerz.ai stores these as artifacts, objects in an S3-compatible bucket with presigned URLs for upload and download. Bucket credentials stay server-side; you only ever see short-lived presigned URLs.

Storage options

Option Setup Default expiry Max expiry
Platform bucket Zero config. Available on all tiers. 7 days 7 days (fixed)
BYO S3 Connect any S3-compatible bucket in Settings → Storage. 7 days "never", or any TTL up to 10 years

To lift the 7-day cap or keep artifacts longer than a week, connect your own bucket. The artifact.put MCP verb surfaces expiry_capped: true (with an explanatory note) if you request a longer expiry on the platform bucket.

Connecting a BYO bucket

  1. Go to Settings → Storage in the dashboard.
  2. Enter your bucket name, endpoint, region, access key, and secret.
  3. Click Test connection, the platform writes and reads a sentinel object.
  4. Save.

Supported: Amazon S3, Cloudflare R2, Backblaze B2, MinIO, and any s3:// endpoint that implements PutObject, GetObject, HeadObject, and DeleteObject.

Uploading an artifact

# MCP, register the artifact and get a presigned PUT url
artifact put \
  --content-type "image/png" \
  --filename "screenshot.png" \
  --size 204800 \
  --expires-in 604800
# → { id: "art_…", upload_url: "https://…", upload_expires_in_seconds: 3600 }

# Upload the bytes (from the agent or your machine)
curl -X PUT -H "Content-Type: image/png" \
  --data-binary @screenshot.png \
  "<upload_url>"

The upload_url is a presigned PUT that expires in 1 hour, the same window a download URL gets. Upload before then; the artifact row is created immediately (so artifact list sees it even if bytes haven't landed yet, with has_bytes: false).

Downloading / sharing

# Get a presigned download URL
artifact get --artifact-id art_…
# → { url: "https://…", expires_in_seconds: 3600 }

# Mint a fresh URL for an existing artifact (e.g. to share with a user)
artifact share --artifact-id art_…

Presigned download URLs expire in 1 hour by default. Refresh with artifact share.

Expiry model

Field Accepted values Default
expires_in a whole number of seconds (3600, 604800, …), or the literal "never" 604800, 7 days

Seconds, not a duration string: "7d" is a validation error, not seven days. The ceiling on a number is 10 years; "never" means the artifact lives until you delete it, and needs a BYO bucket (the platform bucket caps everything at 7 days).

Expiry is from artifact creation, not first access. A reaper janitor sweeps hourly and deletes the stored object and its metadata row together, so neither outlives the other. There is no grace window and nothing is soft-deleted: once expires_at has passed, the next pass removes both. A "never" artifact is never touched.

Listing artifacts

# All artifacts for the account
artifact list

# Narrow to one task
artifact list --task-id <task_id>

# Narrow to one fleet run
artifact list --run-id <run_id>

# Narrow to one repo
artifact list --repo-id <repo_id>

Visibility

Artifacts are always account-scoped, only the account that created them can access or share them. There is no public artifact URL; sharing always requires a presigned URL from an authenticated call.

Audit trail

Every artifact operation (put, get, share, delete) is written to the append-only audit log with the token ID, timestamp, and artifact ID.

Full verb reference: MCP verb reference → artifact.