Skip to main content
The artifact tools family contains a single tool — get_artifact — that fetches artifact metadata and a download URI by artifact_id. Artifacts are the durable outputs of runs: every backtest produces an 8-file bundle, and every skill run produces its own artifacts. Each file is content-hashed with SHA-256 so reproducibility can be verified independently.

get_artifact

Fetch artifact metadata and a download URI by artifact_id. The URI is a short-lived, signed URL — it expires after a few minutes. Fetch the content promptly after calling get_artifact.

Arguments

ArgumentTypeRequiredDescription
artifact_idstringYesThe artifact identifier.

Return value

FieldTypeDescription
artifact_idstringThe artifact identifier.
run_idstringThe run that produced this artifact.
filenamestringThe file name within the bundle (e.g. metrics.json).
content_typestringMIME type (e.g. application/json, text/html).
content_hashstringSHA-256 hash of the file content.
size_bytesintegerFile size in bytes.
uristringShort-lived signed download URL.
expires_atstring (ISO 8601)When the signed URL expires.

Example call

{ "artifact_id": "art_01HQKX2J3K4M5N6P7R8S9T0V2B" }

Example response

{
  "artifact_id": "art_01HQKX2J3K4M5N6P7R8S9T0V2B",
  "run_id": "run_01HQKX2J3K4M5N6P7R8S9T0V2A",
  "filename": "metrics.json",
  "content_type": "application/json",
  "content_hash": "sha256:d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5",
  "size_bytes": 1843,
  "uri": "https://artifacts.doomberg.me/run_01.../metrics.json?sig=...",
  "expires_at": "2025-01-15T14:45:00.000Z"
}

The 8-file backtest artifact bundle

Every backtest_run produces a bundle of exactly 8 files. Together they form a complete, reproducible record of the backtest. The bundle is stored as a group; the artifact_bundle returned by backtest_run points to all 8.
FileContent typeDescription
summary.jsonapplication/jsonTop-level summary: run ID, strategy ID, range, engine version, final stats, and pointers to the other 7 files.
metrics.jsonapplication/jsonFull statistics block: Sharpe, Sortino, CAGR, max drawdown, win rate, turnover, VaR, CVaR, and per-period returns.
equity_curve.jsonapplication/jsonThe complete equity curve as an array of { date, equity } points.
positions.jsonapplication/jsonThe position history: per-date weights for every symbol in the universe, including cash.
data_manifest.jsonapplication/jsonManifest of every data input: symbol, date range, interval, provider, and content hash for each OHLCV series used.
environment_lock.jsonapplication/jsonThe execution environment: numpy version, engine version, Python version, and OS platform.
run_trace.jsonapplication/jsonThe chronological event log from the run: state transitions, job starts/ends, and timing.
report.htmltext/htmlA human-readable HTML report with charts (equity curve, drawdown), the stats table, and the risk attestation.

Why 8 files

The bundle is designed so that a third party with no access to Ithaca can reproduce the backtest. Give them the bundle and they have everything: the strategy (in summary.json), the data (in data_manifest.json), the environment (in environment_lock.json), and the expected output (in metrics.json and equity_curve.json).
The split serves three purposes:
  1. Machine readability. The 7 JSON files are structured and parseable. Tools can diff two bundles field-by-field.
  2. Human readability. report.html renders the same information as a styled report with charts — no JSON parsing required.
  3. Selective access. A reviewer can grab just metrics.json and report.html without downloading the full equity curve or position history.

SHA-256 content hashing

Every file in the bundle has a SHA-256 content hash. The hash is computed over the exact bytes stored in the bundle, not a normalized form. This means:
  • Reproducibility check. If you re-run a backtest with the same spec, range, engine version, and data hashes, the output file hashes will match. If they don’t, something changed — and the data_manifest.json and environment_lock.json tell you what.
  • Tamper detection. The hashes are stored on the artifact record in the database, separate from the file storage. If a file is modified in storage, the hash won’t match the record.
  • Bundle integrity. The artifact_bundle.content_hash returned by backtest_run is a hash over the concatenation of all 8 file hashes. This single hash verifies the entire bundle.
When comparing two backtests, start by comparing their artifact_bundle.content_hash values. If they match, the runs are identical — no need to diff the individual files.

Fetching the full bundle

To fetch all 8 files, call get_run first to get the artifacts array, then call get_artifact for each:
run = get_run(run_id="run_01HQKX2J3K4M5N6P7R8S9T0V2A")
for artifact in run["artifacts"]:
    meta = get_artifact(artifact_id=artifact["artifact_id"])
    # fetch meta["uri"] within the expiry window
The signed URIs returned by get_artifact expire after a few minutes. If you need long-term access, download the content and store it yourself. The content_hash lets you verify that your stored copy hasn’t drifted.