Artifact Store API: schemas
The request and response bodies of the operations in this API.
AddArtifactVersionDto
| Property | Type | Required | Description |
|---|
hash | string | yes | |
pointer | string | yes | |
schemaVersion | string | yes | |
size | number | yes | |
AppendArtifactEntryDto
| Property | Type | Required | Description |
|---|
base64 | string | no | Inline payload bytes (base64-encoded). Mutually exclusive with blobId. Capped at 16 MB; for larger payloads upload to /blobs first and pass blobId. |
blobId | string | no | Reference to an existing Blob row (content-addressed). Mutually exclusive with base64. |
contentType | string | no | MIME type. Falls back to application/octet-stream when omitted. |
filename | string | yes | File name as it should be remembered for this entry. |
metadata | object | no | Producer-defined metadata stamped on the entry. IMAP entries typically carry { uid, messageId, partId } for correlation. |
| Property | Type | Required | Description |
|---|
inputHash | string | no | Content hash at consumption time. Distinguishes "the input moved" from "the input was rewritten identically", which a version alone cannot. |
inputRef | string | yes | Kernel XemaObjectRef of the input. PARSED, not merely stored: a free (kind, id) pair lets two producers spell one input two ways and silently split the reverse index. |
inputVersion | string | no | The input's version AT CONSUMPTION TIME. Omit only when the input's KIND has no version; the store substitutes a sentinel so the uniqueness constraint still holds. |
role | one of "CONTEXT", "DEPENDENCY", "SOURCE" | yes | What the input was to this output. CONTEXT is the assembled-context receipt — what the producing invocation was TOLD. |
ArtifactEntryResponseDto
| Property | Type | Required | Description |
|---|
blobId | string | yes | Reference to the content-addressed Blob holding the bytes. |
entryId | string | yes | |
size | number | yes | Size in bytes. |
ArtifactEntryResponseDtoDataEnvelope
ArtifactEntryScanState
not_scanned means no scanner is armed in this deployment — it is NOT a clean verdict.
Type: one of "not_scanned", "clean", "rejected"
ArtifactEntryUploadState
pending bytes are NOT readable. ready means size, digest and signature all checked out.
Type: one of "pending", "ready", "rejected", "expired"
ArtifactErasureOutcome
erased — the artifact existed in the caller's org + project scope and is
gone. already_absent — nothing with this id is in that scope (already
erased, or never there); the uploaded-object prefix was still swept, so a
retry completes an interrupted erasure.
Type: one of "erased", "already_absent"
ArtifactErasureResponseDto
| Property | Type | Required | Description |
|---|
artifactId | string | yes | |
blobsDeleted | number | yes | Blob rows physically removed — this artifact was their last owner. |
blobsRetainedExternallyClaimed | number | yes | Blob rows KEPT because an external POST /blobs claimant (a workflow snapshot, a Temporal payload spill) holds byte-identical content. |
blobsRetainedShared | number | yes | Blob rows KEPT because another live artifact of the same org references byte-identical content. That content is still that other artifact's; no path from the erased artifact reaches it any more. |
outcome | ArtifactErasureOutcome | yes | erased — the artifact existed in the caller's org + project scope and is gone. already_absent — nothing with this id is in that scope (already erased, or never there); the uploaded-object prefix was still swept, so a retry completes an interrupted erasure. |
uploadedObjectsDeleted | number | yes | Uploaded objects removed from object storage. |
versionsDeleted | number | yes | Versions deleted with the artifact (inline payloads go with them). |
ArtifactErasureResponseDtoDataEnvelope
ArtifactFileDto
| Property | Type | Required | Description |
|---|
contentKind | DeliverableContentKind | yes | How the file content is read. |
path | string | yes | Workspace-relative path of the deliverable file this version is. Relative, no ./.. segment, [a-zA-Z0-9._-/] only. |
ArtifactLinkResponseDto
| Property | Type | Required | Description |
|---|
artifactId | string | yes | |
createdAt | string | yes | |
id | string | yes | |
refId | string | yes | |
refType | string | yes | |
ArtifactLinkResponseDtoDataEnvelope
ArtifactResponseDto
| Property | Type | Required | Description |
|---|
createdAt | string | yes | |
createdBy | string | yes | |
currentVersionId | string or null | no | THE served version. Read this to answer "what does this artifact resolve to?" — never versions[0], and never the highest versions[].version. Those agree until somebody calls POST /artifacts/:id/rollback, after which the highest version is precisely the content that was taken OUT of service. Null means the artifact serves nothing yet: POST /artifacts creates the row and the first version arrives in a follow-up emit. |
id | string | yes | |
latestTitle | string | yes | Denormalized cache of the SERVED version's title — the title of the version named by currentVersionId. Resynced at every emit AND at every rollback. The authoritative per-version title lives on versions[].title. NOTE the field NAME is historical: it caches the served title, not max(version)'s, and after a rollback those are different versions. Renaming it to currentTitle is a coordinated wire change, not a schema edit. |
links | array of ArtifactLinkResponseDto | no | |
orgId | string | yes | |
pipelineRunId | string | no | Pipeline run ID this artifact belongs to |
projectId | string | yes | |
type | string | yes | |
versions | array of ArtifactVersionResponseDto | no | |
ArtifactResponseDtoDataEnvelope
ArtifactResponseDtoPaginatedEnvelope
ArtifactRollbackAuditResponseDto
| Property | Type | Required | Description |
|---|
actorId | string | yes | Who performed the rollback. |
artifactId | string or null | no | The artifact this rollback was performed on. NULL once that artifact has been swept, cleaned up or erased — the audit row deliberately outlives its subject, so the denormalized fields below are what stay readable. |
artifactNaturalKey | string or null | no | The artifact's natural key at rollback time. Null when it carried none. |
artifactType | string | yes | The artifact's type at rollback time. |
correlationId | string | yes | |
createdAt | string | yes | |
fromVersion | number | yes | |
fromVersionId | string | yes | |
id | string | yes | |
orgId | string | yes | |
projectId | string | yes | |
reason | string or null | no | Operator note supplied on the request. Never parsed. |
toVersion | number | yes | |
toVersionId | string | yes | |
ArtifactRollbackAuditResponseDtoDataArrayEnvelope
ArtifactRollbackResponseDto
| Property | Type | Required | Description |
|---|
artifactId | string | yes | |
auditId | string | yes | Id of the durable audit row this rollback wrote, inside the same transaction as the pointer swap. |
fromVersion | number | yes | Number of the version that was being served. |
fromVersionId | string | yes | Id of the version that was being served. |
latestTitle | string | yes | The artifact's title after the flip — resynced to the restored version. When that version predates per-version titles, the previous title is kept (there is nothing to restore and the column is NOT NULL). |
rolledBackAt | string | yes | When the swap committed (ISO-8601). |
toVersion | number | yes | Number of the version now being served. |
toVersionId | string | yes | Id of the version now being served. |
ArtifactRollbackResponseDtoDataEnvelope
ArtifactTypeBiomeSourceDto
| Property | Type | Required | Description |
|---|
biomeId | string | yes | |
installationId | string or null | no | |
kind | one of "biome" | yes | |
origin | one of "distribution", "org_installation" | yes | |
ownerOrgId | string or null | no | |
releaseId | string | yes | |
ArtifactTypeOrgSourceDto
| Property | Type | Required | Description |
|---|
kind | one of "org" | yes | |
orgId | string | yes | |
| Property | Type | Required | Description |
|---|
kind | one of "platform" | yes | |
ArtifactTypeResponseDto
| Property | Type | Required | Description |
|---|
createdAt | string or null | no | ISO timestamp for org rows; null for platform/biome entries. |
description | string or null | no | |
id | string or null | no | Row id for org rows; null for platform/biome entries. |
schemaVersions | array of string | yes | Accepted schemaVersions, or ['*'] for wildcard. |
source | ArtifactTypePlatformSourceDto or ArtifactTypeBiomeSourceDto or ArtifactTypeOrgSourceDto | yes | |
type | string | yes | |
ArtifactTypeResponseDtoDataArrayEnvelope
ArtifactTypeResponseDtoDataEnvelope
ArtifactUploadDownloadUrlResponseDto
| Property | Type | Required | Description |
|---|
contentType | string | yes | |
downloadUrl | string | yes | Presigned URL to GET the bytes from. Unsigned-bearer and short-lived — mint one per request rather than storing it. |
expiresAt | string | yes | |
filename | string | yes | |
method | string | yes | |
ArtifactUploadDownloadUrlResponseDtoDataEnvelope
ArtifactUploadEntryResponseDto
| Property | Type | Required | Description |
|---|
artifactId | string | yes | |
confirmedAt | string | no | When confirmation succeeded. |
contentType | string | yes | The authoritative media type. Once confirmed this is the SNIFFED value, not what the client declared. |
declaredContentType | string | no | What the client claimed, kept for provenance. |
entryId | string | yes | |
filename | string | yes | |
scanState | ArtifactEntryScanState | yes | not_scanned means no scanner is armed in this deployment — it is NOT a clean verdict. |
scannerId | string | no | Which scanner produced scanState. Absent while not scanned. |
sha256 | string | no | Server-computed SHA-256 over the whole stored object. Never accepted from the client. Absent until confirmation succeeds. |
size | number | yes | Size in bytes. |
uploadState | ArtifactEntryUploadState | yes | pending bytes are NOT readable. ready means size, digest and signature all checked out. |
versionId | string | yes | |
ArtifactUploadEntryResponseDtoDataEnvelope
ArtifactUploadIntentResponseDto
| Property | Type | Required | Description |
|---|
artifactId | string | yes | |
entryId | string | yes | Confirm this entry with POST /artifacts/{artifactId}/entries/{entryId}/confirm once the PUT completes. |
expiresAt | string | yes | When BOTH the URL and the intent behind it stop being usable. After this the entry can only be re-created, not confirmed. |
method | string | yes | HTTP method the presigned URL is signed for. |
requiredHeaders | map of string | yes | Headers the client MUST send VERBATIM. The signature covers them — adding, dropping or "tidying" one produces a signature mismatch, not a helpful correction. |
uploadUrl | string | yes | Presigned URL to PUT the bytes to. Short-lived and unsigned-bearer: anyone holding it can write until it expires, so do not log it. |
versionId | string | yes | |
ArtifactUploadIntentResponseDtoDataEnvelope
ArtifactVersionResponseDto
| Property | Type | Required | Description |
|---|
artifactId | string | yes | |
createdAt | string | yes | |
file | ArtifactFileDto or null | no | The deliverable file this version is ({ path, contentKind }), as recorded by the producer at emit. Null when the version is not a recorded file. |
hash | string | yes | |
id | string | yes | |
outputName | string or null | no | Declared output name on the producing activity (the name field of its OUTPUT_DECLARATIONS entry — e.g. response, structuredOutput, deliverables). Null for direct xema/emit-artifact calls that don’t carry a declaration name. Used by the Run Detail "Outputs" panel to group artifact versions by job + output. |
pointer | string | yes | |
pointsOfAttention | array of PointOfAttentionDto or null | no | Generic per-version "points of attention" the producer flagged at emit time ({ label, detail, severity }). Strictly per-version — read this from the specific version, never from the artifact head. Null when the producer supplied none. |
producerJobRunId | string or null | no | Synthetic ${runId}:${jobKey}:${matrixIndex} job-run id of the activity that emitted this version. Pairs with producerRunId for full lineage. |
producerRunId | string or null | no | Workflow run that emitted this specific version. v1 mirrors Artifact.pipelineRunId; v2+ may differ when the revision was produced by a different run. Null on legacy rows. |
schemaVersion | string | yes | |
size | number | yes | |
title | string or null | no | Title at the time this version was emitted. Lets the UI show the producer-supplied title for any prior version, even after a later revision renames the artifact. The parent Artifact.latestTitle is the denormalized cache of the latest version’s title. |
version | number | yes | |
ArtifactVersionResponseDtoDataArrayEnvelope
ArtifactVersionResponseDtoDataEnvelope
ArtifactVersioningMode
How the service should treat a re-emit on the same naturalKey. append (default for approval-gated deliverables) bumps the version; new always creates a fresh artifact row (per-attempt records); replace overwrites v1 in place (ephemeral side-effects). The store enforces the semantics — producers cannot pick the wrong one by forgetting a flag.
Type: one of "append", "new", "replace"
BlobResponseDto
| Property | Type | Required | Description |
|---|
contentType | string | yes | Content-Type recorded at upload time. Returned verbatim on GET; the server never sniffs the body. |
createdAt | string | yes | When the blob row was created. |
sha256 | string | yes | Server-computed SHA-256 of the uploaded bytes (lowercase hex). |
sizeBytes | number | yes | Length of the uploaded body in bytes. |
BlobResponseDtoDataEnvelope
CreateArtifactDto
| Property | Type | Required | Description |
|---|
pipelineRunId | string | no | Pipeline run ID to scope this artifact to |
title | string | yes | |
type | string (38 values) | yes | |
CreateArtifactEntryUploadIntentDto
| Property | Type | Required | Description |
|---|
declaredContentType | string | yes | The media type the client says these bytes are. Checked against the deployment's upload policy at mint time, and PROVEN against the stored bytes' signature at confirmation — a mismatch deletes the object and rejects the entry. |
filename | string | yes | File name to remember for this entry. Recorded verbatim and used as the download filename; never used to build the storage key. |
metadata | object | no | Producer-defined metadata stamped on the entry. Not interpreted by the platform. |
size | number | yes | Exact byte count the client will store. Judged against the per-kind cap now, and against the stored object at confirmation. |
CreateArtifactTypeDto
| Property | Type | Required | Description |
|---|
description | string or null | no | Optional human-readable note about what payloads this type carries. |
schemaVersions | array of string | yes | Closed set of accepted schemaVersion values. Use ['*'] for wildcard (any string). |
type | string | yes | Type id. Lowercase letters, digits, underscores, hyphens. Must start with a letter. |
CreateArtifactUploadIntentDto
| Property | Type | Required | Description |
|---|
classification | DataClassification | no | Retention classification. Drives the artifact-level expiresAt exactly as it does on POST /artifacts/emit. |
declaredContentType | string | yes | The media type the client says these bytes are. Checked against the deployment's upload policy at mint time, and PROVEN against the stored bytes' signature at confirmation — a mismatch deletes the object and rejects the entry. |
filename | string | yes | File name to remember for this entry. Recorded verbatim and used as the download filename; never used to build the storage key. |
metadata | object | no | Producer-defined metadata stamped on the entry. Not interpreted by the platform. |
pipelineRunId | string | no | Workflow run that produced this upload, when there is one. Uploads made by a person normally have none. |
size | number | yes | Exact byte count the client will store. Judged against the per-kind cap now, and against the stored object at confirmation. |
title | string | no | Human title for the artifact. Defaults to filename when omitted. |
type | string | no | Registered artifact type. Defaults to the platform uploaded_file type. An org or biome that has registered its own type may name it here; an unregistered type is refused by the artifact-type registry, not silently accepted. |
CreateEphemeralArchiveDto
| Property | Type | Required | Description |
|---|
metadata | object | no | Free-form producer metadata captured on the v1 inlinePayload. Use to record what kind of scan / fetch produced the archive — surfaces in audit but is not interpreted by the platform. |
pipelineRunId | string | no | Workflow run that owns the archive. Required when the request context does NOT already carry pipelineRunId (e.g. service-to-service mints). Cleanup is keyed on this value. |
title | string | yes | Stable producer-defined slug for the archive. Mostly cosmetic — appears in audit + the latestTitle. |
ttlSeconds | number | no | TTL in seconds. Defaults to 86400 (24h) when omitted. The sweeper deletes rows past expiresAt regardless of run state — fail-safe for lost terminal events. |
DataClassification
Data-classification of this artifact (value-identical to the platform DataClassification set). Drives retention: when present and the deployment maps the class to a non-null TTL, the store derives expiresAt = createdAt + TTL UNLESS the caller supplied an explicit expiresAt (explicit wins). Omit for the unchanged no-auto-expiry behavior.
Type: one of "public", "internal", "confidential", "secret", "regulated"
DeliverableContentKind
How the file content is read.
Type: one of "json", "markdown", "text"
EmitArtifactDto
| Property | Type | Required | Description |
|---|
classification | DataClassification | no | Data-classification of this artifact (value-identical to the platform DataClassification set). Drives retention: when present and the deployment maps the class to a non-null TTL, the store derives expiresAt = createdAt + TTL UNLESS the caller supplied an explicit expiresAt (explicit wins). Omit for the unchanged no-auto-expiry behavior. |
derivedFrom | array of ArtifactDerivationInputDto | no | What this version was produced FROM. Recorded in the derivation ledger in the SAME transaction-scoped call as the emit, so a version can never exist with a silently empty lineage. Absent means "this producer declared no inputs" — never "it had none", which is a different fact and is not one this contract can distinguish. |
encryptAtRest | boolean | no | Explicit opt-in to ENCRYPTION-AT-REST for this version's payload. When omitted/false (default) the payload is stored exactly as before (inline JSON or plaintext blob) — existing behavior is 100% unchanged. When true, the payload is sealed into a per-org AES-256-GCM envelope (per-version content key wrapped by the org data-key) and stored as ciphertext; authorized same-org reads decrypt transparently. The request FAILS FAST (503) if the deployment has no encryption key configured — there is no plaintext fallback for an encryption request. |
expiresAt | string (date-time) | no | Explicit fail-safe expiry instant (ISO-8601). When set it OVERRIDES any retention TTL derived from classification — explicit wins. When omitted, retention falls back to the classification→TTL map (or no expiry when neither is present). |
file | ArtifactFileDto | no | The deliverable file this version is: { path, contentKind }, both required inside it. Recorded on the version as a fact the producer holds, never derived from title or outputName. Omit when the version is not a file. Like title and outputName it is not part of the payload hash, so an idempotent re-emit keeps the first-written value. |
labels | map of string | no | Free-form labels attached to the artifact for downstream queries (e.g. {"source":"agent"}). |
naturalKey | string | no | Stable producer identity for APPEND and REPLACE modes. REQUIRED when versioningMode is append or replace; ignored (stored as null) when new. |
outputName | string | no | Declared output name on the producing activity (the name field of its OUTPUT_DECLARATIONS entry — e.g. response, structuredOutput, deliverables). Set by finalizeOutputs during the unified-outputs promotion path so the Run Detail "Outputs" panel can group artifact versions by job + output name without a scan. Omit for direct xema/emit-artifact calls that don’t carry a declaration name. |
payload | object | yes | JSON-serializable payload for version content. Artifact-store chooses inline vs blob-backed storage by size; callers always use the same endpoint. |
pipelineRunId | string | no | Pipeline run id this artifact belongs to. Inherited from X-Pipeline-Run-Id request context when omitted. |
pointsOfAttention | array of PointOfAttentionDto | no | Generic, domain-agnostic "points of attention" for THIS version — a closed-shape array of { label, detail, severity } (value-identical to the kernel PointOfAttention contract). A producer flags the salient things a reader should notice (an assumption, a gap, a risk) without the artifact schema growing a domain-specific field for each. Strictly per-version metadata (like title) — never denormalized onto the artifact head. Omit for none; the store persists NULL (absent), never a silent default. An explicit empty array is stored as-is. |
producerJobRunId | string | no | Synthetic ${runId}:${jobKey}:${matrixIndex} job-run id of the activity that emitted this version. Recorded on the ArtifactVersion row (producer_job_run_id) for revision lineage. Inherits pipelineRunId separately for the run-level pointer. |
schemaVersion | string | no | Schema version of the payload. Defaults to 1.0.0 when omitted; producers SHOULD declare it explicitly so consumers can validate. |
stageKey | string | no | Phase key, when the artifact is scoped to a particular workflow phase. |
title | string | yes | Human-readable title. |
type | string | yes | Artifact type (a.k.a. kind). Must be registered in the schema-version registry. |
versioningMode | ArtifactVersioningMode | yes | How the service should treat a re-emit on the same naturalKey. append (default for approval-gated deliverables) bumps the version; new always creates a fresh artifact row (per-attempt records); replace overwrites v1 in place (ephemeral side-effects). The store enforces the semantics — producers cannot pick the wrong one by forgetting a flag. |
EphemeralArchiveResponseDto
| Property | Type | Required | Description |
|---|
artifactId | string | yes | |
expiresAt | string | yes | ISO-8601 expiry timestamp (now + ttlSeconds). |
versionId | string | yes | |
EphemeralArchiveResponseDtoDataEnvelope
LinkArtifactDto
| Property | Type | Required | Description |
|---|
refId | string | yes | |
refType | one of "phase_gate", "pull_request", "thread", "backlog_item" | yes | |
| Property | Type | Required | Description |
|---|
hasMore | boolean | no | |
limit | number | no | |
nextCursor | string or null | no | |
page | number | no | |
previousCursor | string or null | no | |
total | number | no | |
totalPages | number | no | |
PointOfAttentionDto
| Property | Type | Required | Description |
|---|
detail | string | yes | Longer human-readable explanation (≤ 2000 chars). |
label | string | yes | Short headline for the point (≤ 200 chars). |
severity | PointOfAttentionSeverity | yes | How much scrutiny this point warrants. Closed set — a consumer renders each value with a fixed badge/colour. |
PointOfAttentionSeverity
How much scrutiny this point warrants. Closed set — a consumer renders each value with a fixed badge/colour.
Type: one of "info", "warning", "critical"
ProblemActionableBy
Who can act on this refusal: user (correct the input, sign in), org-admin (an administrator of the organisation), platform (the operators of this installation), none (nobody — it cannot succeed). ABSENT when not known; never guessed.
Type: one of "user", "org-admin", "platform", "none"
ProblemDetailsDto
RFC 9457 problem document. The declared members are the reserved core; extension members are TOP-LEVEL and OPEN, owned by the refusing plane.
| Property | Type | Required | Description |
|---|
actionableBy | ProblemActionableBy | no | Who can act on this refusal: user (correct the input, sign in), org-admin (an administrator of the organisation), platform (the operators of this installation), none (nobody — it cannot succeed). ABSENT when not known; never guessed. |
code | string | yes | SCREAMING_SNAKE_CASE. The machine-branchable refusal, and the value a policy rule, a retry predicate and a UI branch all name. |
detail | string | no | Human-readable and specific to THIS occurrence. |
errors | array of ProblemFieldIssueDto | no | Field-level issues, when the refusal is about the request body. |
instance | string | no | URI reference identifying the occurrence — a request path, a run, a row. |
params | map of string or number or boolean | no | Safe i18n interpolation values for the message keyed by code — typed and allowlisted per code by its declaration. Never server-authored copy, never internal diagnostics. |
retry | ProblemRetry | no | What a retry can achieve: transient (later, unchanged), after-change (only after someone changes something), never (a defect until a fixed version ships). ABSENT when not known. |
status | number | yes | The HTTP status code, repeated in the body so a logged document is self-contained. |
title | string | yes | Short, human-readable, and STABLE for a given type. Never per-occurrence — that is detail. |
traceId | string | no | W3C trace-context trace-id, present when the caller sent a traceparent. Omitted rather than invented when it did not. |
type | string | yes | Absolute URI identifying the refusal TYPE. Derived one-to-one from code, so a caller may branch on either and can never be told two different things. Never about:blank. |
ProblemFieldIssueDto
| Property | Type | Required | Description |
|---|
code | string | no | SCREAMING_SNAKE_CASE code of THIS issue, for a frontend i18n key. Present when the issue was minted by a declared problem. |
detail | string | yes | Prose for logs and developers. A frontend localises from code + params instead. |
params | map of string or number or boolean | no | Safe i18n interpolation values for this issue's code. |
pointer | string | yes | RFC 6901 JSON Pointer into the request body. Root is "/". |
ProblemRetry
What a retry can achieve: transient (later, unchanged), after-change (only after someone changes something), never (a defect until a fixed version ships). ABSENT when not known.
Type: one of "transient", "after-change", "never"
RollbackArtifactDto
| Property | Type | Required | Description |
|---|
reason | string | no | Free-form operator note recorded on the durable audit row. Never parsed, never interpreted — it exists so the audit trail can answer "why" as well as "who and when". |
targetVersion | number | yes | The version number to serve again. Must be an existing version of this artifact, and must not already be the served one — rolling back to the version already in service is refused rather than treated as a no-op, because reporting success would report a change nobody made. |