Skip to main content

Eval directory layout

A typical layout keeps the eval directory and adapter code in the app repo while storing recordings outside the repo:
You can also keep videos next to the case file and reference them with a local filename such as video: task-01.mp4. Local paths are the simplest setup. The video: path in the case file is resolved relative to that file. If recordings are too large to keep locally or share through Git, use a cloud video store as described below. The adapter config file is optional and must be named adapter.yaml for automatic discovery. The eval config file is also optional and supports eval-level thresholds and named video_stores; it must be named config.yaml. Case files must live directly under cases/ and use the .yaml suffix. Supported video suffixes are .mp4, .mov, .m4v, .webm, and .mkv. Timestamps in case files are seconds from the start of the decoded clip.

Cloud-stored videos

GlassKit supports AWS S3, Cloudflare R2, and other S3-compatible object stores. This keeps large recordings out of your app repository and makes them easier to share with a team. Eval commands download videos when needed and reuse cached copies on later runs. Define a named store in <eval-dir>/config.yaml. For a private Cloudflare R2 store, configure credentials through environment variables:
Keep the credential values in an ignored .env file or your team’s secret manager:
Upload a recording from the directory containing your eval setup:
The command prints a video: block to copy into the case file:
The store, key, and sha256 values identify the uploaded video. Copy them as printed rather than writing them by hand. Ordinary run, seed, validate, export-frames, and review commands download cloud videos automatically. For AWS S3, omit endpoint_url and use the bucket’s AWS region. You can also omit the custom credential variable names to use the standard AWS credential configuration:
access_key_id_env and secret_access_key_env must be set together, and temporary credentials can add session_token_env. Only bucket is required: type defaults to s3 and region defaults to us-east-1. Omit --key when uploading to let GlassKit use <sha256><extension> as the object key. Uploading is idempotent: when the destination object already exists with a matching size and SHA-256, the command reports that and prints the same video: block; any other existing object at the key is refused rather than overwritten. Use pull when you want to download selected videos ahead of time:
list-samples validates cloud references without downloading videos. Downloads are stored in a per-user cache outside the eval directory — ~/Library/Caches/glasskit/eval/videos on macOS, $XDG_CACHE_HOME/glasskit/eval/videos on Linux when XDG_CACHE_HOME is set (otherwise ~/.cache/glasskit/eval/videos), and %LOCALAPPDATA%\GlassKit\Cache\eval\videos on Windows — and shared by all of that user’s eval directories. Set GLASSKIT_EVAL_CACHE_DIR to override the location. To clear downloaded videos, run glasskit eval video-store prune-cache --all; they will be downloaded again when needed.

Public downloads

For a public repository, you may want anyone to run the eval without storage credentials while allowing only maintainers to upload. Expose the bucket through a public HTTP URL and add it to the store:
Downloads then use public_base_url without credentials. Uploads still require the configured credentials.

Case file reference

Here is a representative case file:
Case fields: Target fields: Most evals should put adapter metadata directly under targets.<id>.config. workflow.targets is useful when an eval is generated from or synchronized with an app workflow manifest and workflow-owned metadata should stay separate from eval-owned samples, expectations, and per-case overrides. Each workflow target needs an id; label and extra metadata keys are allowed. Entries are matched by id, and their metadata keys other than id and label are merged into the adapter target config before targets.<id>.config is applied. A workflow label is used as the target’s display label when the target does not define one, and entries whose id matches no target are ignored:
Sample block fields: Sample times must be finite and nonnegative. Ranges must have end greater than start. Overlapping or duplicate samples for the same target are invalid; overlap is checked on the declared at times and range intervals, so two blocks with overlapping ranges are rejected even when their expanded samples would not collide. Expansion is capped at 10,000 samples across all targets in one case; pathological ranges are rejected before their samples are materialized. Unknown keys anywhere in a case file are validation errors, so a misspelled field name fails fast instead of being silently ignored; only workflow.targets entries accept extra metadata keys. Use ignore for a known exceptional sample that should remain documented without affecting a run. An ignored at list or range ignores every expanded sample in that block; use a single at timestamp when only one sample is exceptional. Sample settings use the precedence sample block > target sample_defaults > case sample_defaults > built-in behavior. compare is inherited or replaced as one complete value rather than merged key by key, so an override never retains an unrelated tolerance from a broader scope. Only field and compare can be defaulted; expectations, locations, comments, and ignore reasons remain explicit sample-block properties. For example, these defaults apply a structured result envelope and subset comparison to every target in the case, while the confidence target replaces both settings:

Comparison reference

The adapter observation and the sample expect value must both be JSON-like. For simple checks, return only the value you want compared and omit field. Use field when the adapter naturally returns a structured result but only one nested value should determine correctness. For example, an adapter can return its result alongside diagnostic metadata; selecting the result with field makes it the seeded and compared value while preserving the complete adapter response in machine-readable reports and saved failure artifacts. Field paths are dot-separated. Mapping keys are matched by name, and list indexes can be addressed with nonnegative numeric path parts such as detections.0.label. Missing fields fail the sample with an adapter observation is missing configured field: ... reason. Supported comparison modes: Default comparison modes are inferred from expect: booleans, strings, and null use exact; numbers use numeric; arrays and objects use exact. Example: