Soup Cans
A .can is a portable, verifiable recipe bundle — tar.gz of a manifest, the soup.yaml, and a data_ref. v0.26.0 ships soup can pack / inspect / verify / fork for sharing and forking fine-tunes without shipping checkpoints or training data directly.
Pack
soup can pack \
--entry-id chat-llama:v1 \
--out chat-llama-v1.can--entry-id takes a registry entry id, a unique id prefix or name:tag; the tag is separated by a colon, as in the registry, not by @. --author and --description fill those manifest fields (the author defaults to unknown), and --attest <statement.json> embeds an in-toto Statement in the manifest and can be repeated. soup can fork takes --author too.
The pack includes:
manifest.json— name, tag, parent, created-at, schema versionsoup.yaml— exact training configdata_ref.json— a hash + URI pointing at the dataset (not the dataset itself)
Inspect
soup can inspect chat-llama-v1.canPrints manifest + config without extracting the archive.
Verify
soup can verify chat-llama-v1.canChecks schema version, manifest integrity, and whether the embedded soup.yaml still parses against the current Pydantic schema.
Fork and modify
soup can fork chat-llama-v1.can \
--out chat-llama-v2.can \
--modify training.lr=3e-4 \
--modify training.lora.r=32Fork re-packs the archive with your overrides and a fresh manifest (new id, parent = original).
Safety
Tar extraction is the classic attack surface. Soup Cans neutralize it:
- Rejects absolute paths and
..traversal - Rejects symlinks that point outside the extraction root
- 100 MB cap on archive size, and since v0.75.1 the reads inside it are bounded too: manifest and config members are size-capped rather than read whole, extraction is bounded in both member count and total bytes, and an attestation's YAML is refused above an expanded-node limit before it is deserialised. Until then, reading an untrusted can through
inspect,verify,fork,publishorrunwithout--yescould exhaust memory, because the alias expansion was counted after the size cap rather than before it (0.26.0 to 0.75.0) - Manifest fields are escaped for terminal control sequences, not only for Rich markup. Before v0.75.1 a crafted manifest could rewrite the
soup can runconfirmation panel, which is the one screen whose whole job is telling you what you are about to allow - Format version was locked to
1when this shipped. It is 3 at v0.74.0, and versions 1, 2 and 3 are all accepted on read; anything else is refused dunderkeys (__class__,__import__, etc.) and null bytes are rejected infork --modify- Path containment uses shared
os.path.realpath + commonpathso Windows short-name / junction tricks don't escape
See also
- Model registry — the source of truth that Cans export from
- Configuration — what lives inside a
.can
Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.