Skip to content

Artifact Component

Available since SDK 1.10.0

The Artifact component requires cereal-sdk 1.10.0 or later. Set your manifest's sdk_version to 1.10.0 (or higher) to use it.

The Artifact component is your script's channel for output the user keeps: named blobs of binary data — a CSV export, a JSON report, a generated image — that the Cereal application persists against the current task and that the user can download from the app after the run finishes.

This is distinct from the other output channels:

  • Logger and the statusUpdate callback — transient text for progress and diagnostics.
  • Notification — out-of-band alerts to the user or external services.
  • Preference — small key/value state that the script itself reads back on a later run.

The emit method is a suspend function and must be called from a coroutine context (e.g., inside onStart, execute, or onFinish).

Usage

suspend fun execute(provider: ComponentProvider) {
    val artifact = provider.artifact()

    val csv = buildString {
        appendLine("sku,price")
        appendLine("ABC-1,19.99")
    }.toByteArray()

    artifact.emit(
        name = "results.csv",
        bytes = csv,
        mimeType = "text/csv", // optional; inferred from the name's extension when omitted
    )
}

Parameters

Parameter Type Description
name String Display name for the artifact, also used as the default filename when the user downloads it. Include the extension you want (e.g. "results.csv").
bytes ByteArray The artifact content. Held in memory, so keep it reasonably sized.
mimeType String? Optional MIME type (e.g. "text/csv", "application/json"). When omitted, the host infers it from the name's extension where possible.

Semantics

  • Append-only. Every call to emit produces a new, distinct artifact scoped to the current task. Emitting the same name twice yields two artifacts — it never replaces a previous one.
  • Persisted. Emitted artifacts outlive the run and the application session; they remain available for download until the user deletes the owning task.
  • In-memory payload. The content is passed as a ByteArray held in memory, so this is suited to small, bounded outputs. Avoid emitting payloads large enough to exhaust the heap.
  • Throws on failure. emit returns once the artifact has been durably persisted by the host. If persistence fails the call throws, surfacing the failure to your script — the artifact is not stored.

Handling optional artifacts

An uncaught failure from emit terminates the run with an error, like any other thrown exception. If an artifact is optional and should not fail the run, wrap the call yourself:

try {
    provider.artifact().emit(name = "report.json", bytes = report)
} catch (e: Exception) {
    provider.logger().info("Could not persist report artifact: ${e.message}")
}

Best Practices

  • Give artifacts descriptive names with the correct extension so the user gets a sensible download filename.
  • Keep payloads small and bounded — the content is held in memory.
  • Use artifacts for results the user wants to keep; use the Logger for progress and diagnostics.

Testing

When testing with TestComponentProviderFactory, the artifact channel is backed by an in-memory RecordingArtifactComponent. Every emission is recorded in its emitted list (in emission order) as EmittedArtifact(name, mimeType, bytes), so logged messages, stored preferences, sent notifications, and emitted artifacts are all accessible after a run for assertions. See Testing for the full test setup.