Fingerprints and reuse
A fingerprint says what an Artifact’s reviews depend on. An eval’s earlier result is reused when the eval is unchanged and the fingerprints of the Artifacts it depends on are unchanged, so review cost follows the size of a change.
Fingerprints
Folder and file Artifacts use artifactsum by default. Omit fingerprint to
hash their own files, or choose a script. The root graph Artifact always uses the
structural graph fingerprint; it cannot declare fingerprint
to override or disable that value. For folder and file Artifacts, the configurable
forms below add no tool declarations or other Artifact’s value; dependencies enter
through the reuse key.
- Omission uses artifactsum:
artifactsum:plus SHA-256 over the Artifact’s own input paths and bytes.fingerprint = {}also works for folders. A folder hashes its own files; a file Artifact hashes its one target file. fingerprint = { script = { command = "hash", args = [] } }uses the command’s output as the fingerprint. It hashes nothing on its own, so the command must reflect every input and script change that should re-review.fingerprint = falsedisables reuse.fingerprint = trueis rejected.
Artifactsum
An Artifact is reviewed again when its own files change or when an Artifact its eval depends on changes its fingerprint. To narrow a folder’s inputs:
fingerprint = { files = ["src"], ignore = ["*.log"] }
files: 1–64 unique owner-relative paths, default["."](the owner’s own files). Each must exist and stay inside the Artifact: paths into child Artifacts are rejected. Directory walks skip child Artifact folders and every*.artfdeclaration. Explicit.artffile inputs failconfig check; they are not silently skipped. A directory whose name ends in.artfis an invalid declaration and fails discovery. A neighboring file Artifact’s target remains in the folder’s hash; it creates no automatic child relation.ignore: up to 64.gitignore-style globs relative to the owner, without negation. They always exclude, like the built-in ignores.git,__pycache__/,*.pyc,target/andnode_modules/..gitignorefiles exclude more, with git semantics: every one from the repository root (--repo) down through the Artifact and walked directories applies. A pattern is relative to its own file’s folder; negation works, and deeper files override shallower ones. Explicitly named non-declarationfilesare never ignored.
File Artifacts hash only their target filename. An explicit artifactsum form
must name just that file, for example fingerprint = { files = ["hero.png"] }.
fingerprint = {}, files = ["."] and ignore (even []) are rejected for a
file Artifact. Omit the field for its default; use a script if the fingerprint
needs to cover more than the file.
The old dependencies fingerprint option is rejected: a fingerprint covers only its own
Artifact. Walk limits and manifests are in the reference; the script form is under
fingerprint scripts.
The reuse key
An eval depends on its target Artifact and on what the target directly connects:
- the target’s child Artifacts;
- the Artifacts the eval names in its instruction or runtime args.
artifactize does not follow connections further than that. Whether a change two connections away matters is up to how you define fingerprints: a fingerprint script can read a file of any Artifact it names in its args. The key is
hash(Eval definition hash, sorted (Artifact name, kind, fingerprint) of each covered Artifact)
Artifact names and kinds (folder, file or graph) are part of the key, for the
target and every covered dependency. A change from folder to file never reuses
the former result, even if a script emits the same fingerprint. Physical paths
are never key inputs, so copies with matching names, kinds and fingerprints reuse.
Changing a covered Artifact’s name changes the key. Differently named targets can
still share a result when their evaluation criteria and complete covered Artifact
maps match: the key does not separately identify which covered Artifact is the target.
For example, two Artifacts whose identical evals reference each other can share results.
The Eval definition hash is lowercase SHA-256 of canonical JSON with recursively
sorted keys over the evaluation criteria:
- the eval kind (runtime, agent or human);
payload, including the instruction;pass_schemaandfail_schema;- for runtime evals, the command and args.
Evaluation execution options are not part of the key: an Agent’s backend, model, reasoning,
timeout_ms, max_tool_calls and max_tokens, a runtime timeout_ms, and the selected
profile variant. Neither are the eval id and title, tags, repository paths, unused
profile variants, or tool declarations (views): a tool is a way of viewing an
Artifact, so changing only a tool’s description or schema does not review again. To
make a tool change matter, include the relevant files in the fingerprint.
An executable eval has a key only when its target and every Artifact it depends on
have a fingerprint. Omission supplies artifactsum for folder and file Artifacts,
including basis Artifacts of those kinds; graph Artifacts always supply their
structural graph fingerprint. If a folder or file Artifact declares
fingerprint = false, the eval has no reuse: every verify reviews it
again. For an unforced READY Runtime/Agent eval, status names the disabled target
or dependency in its execution reason. A READY Human eval instead gives the
request-awaiting-claim-and-submission reason; forced, blocked and waiting evals
use their respective execution, gate or wait reasons.
Completed result reuse
A successful end-of-review recheck adds the GREEN or RED result to its key’s
history: its self-contained executions row gets its completion time, size and last
use (State). Errors and cancellation are
never recorded there. When a key holds more than one record,
the most recent by completion time is reused, GREEN or RED. Results from different
profiles therefore reuse each other: a review that --profile fast produced
satisfies the declared profile, and the other way around.
Records retain their producing profile and provenance; the Run result reference owns the audit-field and source-kind inventory.
Before accepting reuse, artifactize validates admitted file targets again:
they must exist as regular files without symlink traversal. fingerprint = false
disables reuse, not these file-target safety checks. Targets are checked during
fingerprint preparation/recheck, at eval start/end and on every tool call too.
A hit returns the original result without running the eval or re-validating it against the requested profile or schema. The producing profile remains distinct from the requested one, and a reused request spends no new usage. A reused RED remains RED for gates and final obligations. Dependencies outside execution selection can supply cached evidence without running. Results remain readable after the source repository is deleted; external paths embedded in result text are not made portable.
With a team review store,
verify also asks the store for every key and reuses whichever record completed
last, the local latest or the store’s latest; a store that cannot be reached leaves
the local latest.
No key means no cache lookup or publication. --force re-executes explicitly
selected executable evals without reading or joining earlier results, local or in
the store, and its completed GREEN or RED is appended as a newer record (and
published to a configured store), which later runs then reuse. Forced and unkeyed
results still satisfy their own Run and keep their execution.
Upgrading to 0.9
For declaration, state-directory and terminal changes, see
Install: Upgrading to 0.9.
Reuse-key v2 matches no pre-0.9 result, including script fingerprints and team
review store records. The first full verify therefore reviews every executable
eval once, Human sign-offs included; later Runs reuse normally.
Graph fingerprint
The root .artf graph Artifact
uses graph:<sha256>, computed from one canonical, name-based extraction of the
whole project’s current declarations. Objects and relations are sorted; child
folder locations and repository paths are not identities. Extraction includes:
- Artifact names and kinds,
basis, and fingerprint coverage: artifactsumfilesandignore; scriptcommand,argsandfiles; orfingerprint = false. The graph Artifact has a graph-coverage marker, not its own recursively embedded digest. - Input → consumer relations: child ownership (names, not child folder paths), instruction references, runtime argv references (including eval ID, argv index and logical suffix), and their input targets.
- Qualified eval IDs, owning Artifact, titles, optional
gateand evaluation criteria: default profile kind, the fullpayloadincluding instruction and owner context,pass_schema,fail_schema, and runtimecommand/args.
Excluded are evaluation execution options (backend, model, reasoning, all
timeout_ms values including fingerprint-script timeouts, max_tool_calls,
max_tokens, profile_variants, eval mutex tags), all tool views and sessions, Artifact tags, repository
paths and source file contents. Declared coverage paths and scoped argument
suffixes remain meaningful; a relocation that preserves those logical declarations
and ownership does not change the graph fingerprint. Execution options are still
saved in ordinary state records.
This is only a fingerprint algorithm. Existing reuse keys, Runs, status and review
flows decide whether to reuse or review again. The graph is evaluated against
current state, never a stored diff or structural history. A graph eval title
change invalidates its graph fingerprint even though titles are excluded from the
ordinary Eval definition hash. Both built-in graph tools use this same extraction.