Expand description
Card storage — immutable run-result snapshots.
A Card is a frozen record of a strategy run: identity, parameters,
model, scenario, aggregate stats, and (optionally) per-case detail.
Cards are immutable — once written they are never modified, only
annotated via additive append. Mutable aliases point to a
Card and can be rebound freely.
§Design principles
- Minimal REQUIRED, maximal OPTIONAL — v0 needs only 4 fields; lightweight “ran this pkg” records and heavy optimize snapshots share the same schema.
- Immutable append-only — no overwrite, no delete. New data is
added via
append(new top-level keys only) or by creating a new Card with a freshcard_id. - Two-tier storage — TOML for human-readable aggregate, JSONL sidecar for machine-parseable per-case detail.
- File-primary — files are the source of truth; in-memory state is cache. Cards can be copied, diffed, and version-controlled.
§Storage layout (two-tier)
| Tier | File | Content |
|---|---|---|
| Tier 1 | ~/.algocline/cards/{pkg}/{card_id}.toml | Aggregate scalars, decisions, identity, params |
| Tier 2 | ~/.algocline/cards/{pkg}/{card_id}.samples.jsonl | Per-case raw data (JSONL, write-once) |
Tier 1 holds a shareable summary (a few KB). Tier 2 holds per-case detail ��� the engine does not interpret its columns; packages define their own schema.
Alias table: ~/.algocline/cards/_aliases.toml (global).
§card_id naming
{pkg}_{model_short}_{compact_ts}_{hash6}
compact_ts:YYYYMMDDTHHMMSSin UTChash6: first 6 hex chars of DJB2 param fingerprint- Example:
cot_opus46_20260412T061500_a3f9c1
§v0 schema (frozen)
§REQUIRED (minimum valid Card)
| Field | Type | Example |
|---|---|---|
schema_version | string | "card/v0" |
card_id | string | "cot_opus46_20260412T061500_a3f9c1" |
created_at | string (RFC 3339) | "2026-04-12T06:15:00Z" |
[pkg].name | string | "cot" |
§OPTIONAL (auto-injected where possible)
| Section | Fields |
|---|---|
[pkg] | version, category, source, source_ref, source_sha |
[runtime] | alc_version, lua_version, host_os, git_sha |
[model] | provider, id, id_short, cutoff |
[params] | Free-form ctx snapshot; param_fingerprint for DJB2 hash |
[strategy_params] | Strategy-tunable parameters surfaced for sweeps / optimizers (e.g. alpha, temperature, depth). Free-form, but where-queryable as a first-class section |
[scenario] | name, source, case_count, grader |
[stats] | pass_rate, mean_score, std, median, min, max, n |
[stats.by_bucket] | Disaggregated sub-bucket stats (array of tables) |
[cost] | llm_calls, input_tokens, output_tokens, elapsed_ms, usd_estimate |
[optimize] | target, search, rounds_used, top_k (for optimize Cards) |
[metadata] | Free-form escape hatch. Recognized lineage conventions: prior_card_id (parent Card id), prior_relation (relation kind, e.g. "sweep_variant", "reflection_of", "derived_from") |
§Lua API (alc.card.*)
| Function | Description |
|---|---|
create(table) | Write new Card (Tier 1). Returns { card_id, path } |
get(card_id) | Read Card by id. Returns table or nil |
list(filter?) | List Cards as summaries (newest first) |
find(query?) | Prisma-style where DSL + dotted-path order_by + offset/limit |
append(card_id, fields) | Additive-only annotation (new keys only) |
alias_set(name, card_id, opts?) | Pin mutable alias |
alias_list(filter?) | List aliases |
get_by_alias(name) | Resolve alias → full Card |
write_samples(card_id, samples) | Write Tier 2 sidecar (write-once) |
read_samples(card_id, opts?) | Read Tier 2 with where filtering + offset/limit paging |
lineage(query) | Walk ancestry/descendants via metadata.prior_card_id |
Structs§
- Alias
- Card
Event Bus - Process-wide fan-out bus. Subscribers are registered once at startup
(from
ALC_CARD_SINKS) and stored behind aMutexso that tests can swap them out viareplace_subscribers_for_testwithout losing the singleton identity. - Comparison
- One parsed comparison:
pathpoints at a nested field,op+valuedescribe how to compare it. - File
Card Store - File-backed implementation of
CardStore. - File
Card Subscriber - A subscriber that mirrors events to a local directory using the
same two-tier layout as
FileCardStore: - Find
Query - Query parameters for
find. - Last
Error - Most recent delivery failure for a single subscriber. Exposed via
SubscriberHealthRow.last_errorin thealc_statsJSON snapshot. - Lineage
Edge - One edge in the lineage result (child → parent, always).
- Lineage
Node - One node in the lineage result.
- Lineage
Query - Query parameters for
lineage. - Lineage
Result - Full lineage walk result.
- Order
Key - Parsed sort key: path with optional descending flag.
- PerSubscriber
- Per-subscriber counter state. Held inside
SubscriberStatsunder aMutex;snapshotclones the fields into an ownedSubscriberHealthRowwhile the lock is held, so the lock window stays short. - Samples
Query - Query parameters for
read_samples. - Sink
Backfill Report - Result of a [
card_sink_backfill] run. One row per card the tool touched (classified as pushed / skipped / failed / pushed_samples). Thefailedentries carry the error message so an operator can triage read-only mounts etc. - Subscriber
Health Row - Snapshot row for a single subscriber, serialized directly into the
alc_statsJSON output as one element of thecard_sinksarray. - Subscriber
Stats - Process-wide per-subscriber statistics, keyed by subscriber URI
(the value returned by
CardSubscriber::describe). - Summary
- Summary row for
alc.card.list().
Enums§
- Card
Event - A Card-level event emitted from the write path.
- Card
Event Kind - Lightweight discriminant for
CardEvent. Used as aHashMapkey inSubscriberStatsso that ok/err counters can be tracked per event kind without holding the full payload. - CmpOp
- Single comparison operator.
- Lineage
Direction - Walk direction for
lineage. - Predicate
- Parsed predicate tree.
Constants§
Traits§
- Card
Store - Storage backend for Cards.
- Card
Subscriber - A downstream backend that receives
CardEvents in best-effort, serial fan-out order.
Functions§
- alias_
list_ with_ store - List aliases from
store, optionally filtered by pkg. - alias_
set_ with_ store - Bind (or rebind) an alias to a Card in
store. - aliases_
to_ json - append_
with_ store - Append new top-level fields to an existing Card.
- card_
sink_ backfill_ with_ store - Backfill one subscriber (
sinkURI) from the primary store. - create_
with_ store - Create a new Card backed by
store. - eval_
predicate - Evaluate a predicate tree against a full Card JSON.
- event_
bus - Return the process-wide
CardEventBussingleton, initializing it on the first call from theALC_CARD_SINKSenvironment variable. - find_
with_ store - Filter/sort Cards across the store using the
whereDSL. - get_
by_ alias_ with_ store - Resolve an alias name to its bound Card and return the full Card JSON.
- get_
with_ store - Read a Card from
storeby id. Returns None if not found. - import_
from_ dir_ with_ store - Import Card files into
storefromsource_dirunderpkg. - init_
event_ bus - Eagerly initialize the bus. Idempotent and safe to call multiple
times; intended for startup hooks (
main.rs) so that subscriber registrationtracing::info!lines are emitted at boot rather than on the first Card write. - lineage_
to_ json - Render a LineageResult as JSON for the service layer.
- lineage_
with_ store - Walk the lineage tree from
q.card_idinstore. - list_
with_ store - List cards from
store.pkg_filter = Some("name")restricts to that pkg subdir. - parse_
order_ by - Parse an order_by JSON value. Accepts:
- parse_
where - Parse a
whereJSON value into aPredicate. - publish
- Convenience wrapper: publish through the singleton.
- read_
samples_ with_ store - Read per-case samples from
{card_id}.samples.jsonl. - subscriber_
stats_ snapshot - Public entry point: snapshot of all process-wide subscriber stats.
Wrapper around
event_bus().stats().snapshot()so that downstream crates (notablyalgocline-app) do not need a handle to theCardEventBussingleton. - summaries_
to_ json - write_
samples_ with_ store - Write per-case samples to
{card_id}.samples.jsonl(write-once).