Keep the downloaded image immutable and put its descriptive metadata in a neighboring JSON file. Hash the actual bytes with SHA-256, then verify that digest before the asset enters a build. This catches file mix-ups; it does not prove who created an image or that a claimed prompt is authentic.
Define the boundary between evidence and notes
A filename such as final-v3.jpg is not an identifier. Neither is an image URL that might later serve a recompressed version. The two FLUX.2 examples below are useful fixtures: one contains poolside Pro lettering, while the other uses cotton-candy Flex lettering. A sidecar should keep those model labels distinct even if both files are renamed.
These are model examples displayed on Voor, not a matched experiment and not outputs of the sample prompt below. Preserve the original download separately from thumbnails and optimized web copies. Each derivative needs its own hash.
Record one explicit generation contract
The FLUX.2 image workspace exposes Prompt, optional Reference images, Aspect ratio, Resolution and Advanced Settings. On September 6, 2026, the inspected default quote was 11 credits at 1 MP with Public · watermarked visibility. Record the selected model and every setting from your own run; that quote is not a permanent price. Sign-in and account requirements apply before generation.
Concept photograph of a fictional blue ceramic cup on a pale stone shelf.
One soft window light, plain background, no text or logo.
One object, square composition. Reference-free concept, not a product claim.
Write a sidecar using only the Python standard library
Save the following as sidecar.py. It accepts local files and writes one versioned JSON record beside each file. Exclusive creation prevents accidentally overwriting a reviewed record. The script does not upload anything or read embedded private metadata.
import hashlib, json, sys
from pathlib import Path
def digest(path):
h = hashlib.sha256()
with path.open("rb") as stream:
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
h.update(chunk)
return h.hexdigest()
for name in sys.argv[1:]:
path = Path(name)
record = {
"schema_version": 1,
"file": path.name,
"bytes": path.stat().st_size,
"sha256": digest(path),
"model": None,
"prompt": None,
"settings": {},
"source_receipt": None,
}
sidecar = path.with_name(path.name + ".json")
with sidecar.open("x", encoding="utf-8") as output:
json.dump(record, output, indent=2, ensure_ascii=False)
output.write("\n")
assert digest(path) == record["sha256"]
print(sidecar)
Run python3 sidecar.py cup-v1.jpg. Fill the null fields manually from the generation record; do not infer the model or seed from a filename. Keep API keys, private reference images and customer details out of sidecars intended for publication.
Test the checks that can actually fail
First run the script on a copied fixture. Confirm that its stored byte count equals the file size. Rename the image and rerun under a new sidecar name: the hash should stay the same. Change one byte in another copy: the hash must differ. Re-encode the image: expect a new hash even if it looks identical. A missing file should fail rather than silently record an empty digest.
Keep provenance claims modest
This is a content-integrity manifest, not signed provenance, a copyright license or proof of model identity. A person can edit both the image and the JSON. For release review, keep the manifest in version control and retain the original generation receipt in your approved storage. Then create the next image with a recorded brief and treat its downloaded bytes as a new immutable artifact.


Top comments (0)