Skip to content

client.artifacts

client.artifacts — the artifacts operations.

On AsyncKindgi every method is the same, awaited.

list(
*,
limit: int | None = None,
cursor: str | None = None,
owner_run_id: str | None = None,
content_type: str | None = None,
timeout: float | None = None,
) -> ArtifactCollectionPage

List artifact metadata. GET /v1/artifacts

Cursor-paginated. Metadata rows only (no bytes). Filters: ?ownerRunId=, ?contentType=, ?tag.<key>=<value> (repeatable — every provided tag must match as AND). Sort order is binding-defined (typically createdAt desc, blobId desc).

upload(
*,
idempotency_key: str | None = None,
data: Mapping[str, Any] | None = None,
timeout: float | None = None,
) -> BlobMeta

Upload an artifact. POST /v1/artifacts

Multipart upload. file part carries the bytes; other form fields carry metadata (name, contentType, tags (JSON), ownerRunId, expectedHash). Framework computes sha256 and returns it in BlobMeta.hash. If expectedHash was supplied and diverges, response is 400 blob-hash-mismatch. Content-type sniffing is NOT performed server-side — the framework trusts the caller.

download(*, timeout: float | None = None) -> bytes

Download an artifact (stream). GET /v1/artifacts/{blobId}

Streams raw bytes. Response headers: Content-Type (as declared at upload), Content-Length, X-Kindgi-Blob-Hash (sha256 hex), X-Kindgi-Blob-Name (URI-encoded caller name).

delete(
*,
idempotency_key: str | None = None,
timeout: float | None = None,
) -> DeleteArtifactResult

Delete an artifact. DELETE /v1/artifacts/{blobId}

Idempotent: first call returns { deleted: true }, subsequent calls return { deleted: false } (already gone). The route responds 200 either way — 404 only when the id was never known (structurally impossible after list returned it).