# How Artifact Stores Work in aisuite for Persisting Generated Outputs

> Learn how aisuite artifact stores persist generated outputs like command line output or model text. Prevent trace bloat and retrieve data efficiently with this lightweight abstraction.

- Repository: [Andrew Ng/aisuite](https://github.com/andrewyng/aisuite)
- Tags: internals
- Published: 2026-08-03

---

**aisuite uses a lightweight artifact store abstraction to store large data payloads—such as command-line output, file contents, or model-generated text—outside of trace messages, preventing trace bloat while enabling efficient retrieval.**

The `aisuite` framework implements a clean separation between trace metadata and bulky generated outputs. This article explains how artifact stores work, drawing directly from the source code in `andrewyng/aisuite`.

## Core Concepts and Data Structures

Three foundational classes define the artifact system in [`aisuite/agents/artifact_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifact_store.py):

### ArtifactRef: The Lightweight Pointer

An `ArtifactRef` is a JSON-serializable reference that gets embedded directly in trace messages. According to the source at [lines 14-21](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifact_store.py#L14-L21), it stores:

- `artifact_id`: Unique identifier for retrieval
- `uri`: Location hint for the stored data
- `media_type`: MIME type describing the content
- `size`: Byte length of the payload
- `metadata`: Optional dictionary for additional context

### Artifact: The Payload Container

The `Artifact` class ([lines 44-50](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifact_store.py#L44-L50)) wraps the actual binary data with its reference and creation timestamp. It provides convenient access methods:

- `.data`: Raw bytes payload
- `.text()`: Decoded string representation

### ArtifactStore Protocol

Any artifact store must implement three operations defined at [lines 54-66](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifact_store.py#L54-L66):

- `put(data, media_type, metadata=None) → ArtifactRef`: Store payload, return reference
- `get(ref: ArtifactRef) → Artifact`: Retrieve payload by reference
- `delete(ref: ArtifactRef) → None`: Remove stored artifact

## Built-in Artifact Store Implementations

### InMemoryArtifactStore: Ephemeral Storage

The `InMemoryArtifactStore` ([`put` implementation at lines 72-93](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifact_store.py#L72-L93)) keeps artifacts in a Python dictionary keyed by `artifact_id`. This store is ideal for:

- Unit tests requiring fast cleanup
- Short-lived runs where persistence isn't needed
- CI/CD environments without filesystem access

Artifacts evaporate when the process terminates—no cleanup required.

### FileArtifactStore: Durable Persistence

The `FileArtifactStore` ([`put` implementation at lines 15-35](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifact_store.py#L15-L35)) provides production-grade persistence:

- Each artifact gets its own directory under a configurable root (default: `.aisuite/artifacts/`)
- Raw payload written to a `data` file
- Reference and timestamp saved to [`metadata.json`](https://github.com/andrewyng/aisuite/blob/main/metadata.json)

This structure enables external tools to inspect artifacts without loading the full aisuite runtime.

## The Artifact Lifecycle: Creation and Retrieval

### How Artifacts Are Created

The dehydration process in [`aisuite/agents/artifacts.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifacts.py) converts large values into artifact references:

1. **Threshold detection**: During message dehydration, values exceeding a configurable size limit trigger artifact creation
2. **Store invocation**: The `Context`-supplied `artifact_store` receives the payload via `artifactize_value`, which calls `artifact_store.put(data, media_type=…, metadata=…)`
3. **Reference insertion**: The returned `ArtifactRef` replaces the original value in the trace JSON, appearing as `{"type":"artifact_ref","artifact_ref":{…}}`

### How Artifacts Are Retrieved

Hydration reverses the process:

1. `hydrate_value` detects dictionaries with `type=="artifact_ref"`
2. It calls `artifact_store.get(ref)` to fetch the full `Artifact`
3. The caller accesses `.text()` or `.data` to recover the original content

This design keeps traces compact while preserving access to complete outputs.

## Integration with aisuite Components

### Runner: Orchestration Layer

[`aisuite/agents/runner.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/runner.py) manages de-/hydration around every tool execution. It ensures the same `artifact_store` instance handles both sides of the transformation, maintaining consistency across the execution boundary.

### CLI and Viewer: User-Facing Access

The CLI ([`aisuite/cli/py/aisuite-code-cli/aisuite_code_cli/app.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/cli/py/aisuite-code-cli/aisuite_code_cli/app.py)) instantiates a `FileArtifactStore` from the `--artifact-root` argument. The viewer ([`aisuite/tracing/viewer.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/tracing/viewer.py)) serves stored artifacts via an HTTP endpoint at `/api/artifacts/<id>`, enabling browser-based inspection of generated outputs.

## Key Files Reference

| File | Purpose |
|------|---------|
| [`aisuite/agents/artifact_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifact_store.py) | Core abstractions: `ArtifactRef`, `Artifact`, `ArtifactStore` protocol, and concrete implementations |
| [`aisuite/agents/artifacts.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifacts.py) | De-/hydration logic: `artifactize_value`, `hydrate_value` |
| [`aisuite/agents/runner.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/runner.py) | Execution wrapper applying artifact transformations |
| [`aisuite/cli/py/aisuite-code-cli/aisuite_code_cli/app.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/cli/py/aisuite-code-cli/aisuite_code_cli/app.py) | CLI wiring for `FileArtifactStore` instantiation |
| [`aisuite/tracing/viewer.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/tracing/viewer.py) | HTTP server exposing artifacts to the web viewer |

## Summary

- **ArtifactRef** provides a JSON-serializable pointer that keeps traces small
- **ArtifactStore protocol** defines three required operations: `put()`, `get()`, `delete()`
- **Two implementations** ship with aisuite: `InMemoryArtifactStore` for ephemeral use, `FileArtifactStore` for durable persistence
- **Automatic threshold-based dehydration** in [`aisuite/agents/artifacts.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifacts.py) converts large values to references without manual intervention
- **CLI and viewer integration** enables seamless artifact inspection via filesystem or HTTP

## Frequently Asked Questions

### What triggers artifact creation in aisuite?

Values larger than a configurable threshold during message dehydration are automatically converted to artifacts. The `artifactize_value` function in [`aisuite/agents/artifacts.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifacts.py) performs this detection and delegates to the context's `artifact_store.put()` method.

### Can I implement a custom artifact store for cloud storage?

Yes. The `ArtifactStore` protocol at [lines 54-66](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/artifact_store.py#L54-L66) requires only three methods. Implement `put()`, `get()`, and `delete()` with your preferred backend—S3, GCS, Azure Blob, or any object storage—and inject your store into the `Context`.

### How does FileArtifactStore organize files on disk?

Each artifact receives a dedicated directory under the configured root. The raw bytes go to a `data` file; the `ArtifactRef` plus timestamp serialize to [`metadata.json`](https://github.com/andrewyng/aisuite/blob/main/metadata.json). This human-readable structure supports external tooling and manual inspection.

### Are artifacts automatically cleaned up?

The `InMemoryArtifactStore` loses all data on process exit. For `FileArtifactStore`, persistence is intentional—artifacts remain until explicitly deleted via `store.delete(ref)` or manual filesystem removal. The viewer's HTTP endpoint allows on-demand retrieval without loading the full trace.