Name, verify and fetch model weights without depending on any single host.
enspack get qwen--qwen2-5-7b-instruct.mirrors.enspack.eth
# resolves ENS → content-addressed manifest → torrent + webseeds → SHA-256 per file → HF cacheAn ENS name owned by the publisher points at a manifest (IPFS CID in
contenthash). The manifest lists every file with its SHA-256 and how to get
the bytes (BitTorrent with HF / Hugging Bay webseeds, optional OCI and IPFS).
Versions are subnames (v1-0-0.<model>.<publisher>.enspack.eth); a project
pins them in enspack.lock and reproduces its model set with enspack install.
SPEC.md— protocol (frozen atenspack/0.1)MVP.md— work packages, interfaces, service contractsAGENTS.md— rules for agents building this repoBOOTSTRAP.md— how the first models and publishers get onschema/— JSON Schemas forenspack.jsonandenspack.lockexamples/— a real manifest for Qwen2.5-7B-Instruct (real hashes, placeholder infohash)
Hugging Face is upstream, not a competitor: hashes come from HF's LFS
metadata, webseeds point at pinned HF revisions, and enspack publish --from-hf
is the main publishing path. What enspack adds is the layer HF doesn't have:
a publisher-owned name, host-independent verification, and a lockfile.
Requires Node 22+ and pnpm 9.
npm i -g @enspack/cli
# or from this repo:
pnpm --filter @enspack/cli build && node packages/cli/bin/enspack.js --help
enspack get qwen--qwen2-5-7b-instruct.mirrors.enspack.eth
# requires the name to exist on mainnet with a seeded torrent — see Status
# pin a model into a project and reproduce it later
enspack add qwen--qwen2-5-7b-instruct.mirrors.enspack.eth
enspack install
# writes / reads enspack.lock; CID mismatch exits 3 unless --updateensget is an alias for enspack get. Human messages go to stderr; --json
prints one JSON object to stdout. Global --chain mainnet|sepolia defaults to
mainnet. --ens-version v1|v2 (or ENSPACK_ENS_VERSION) selects ENSv1 vs
ENSv2; Sepolia defaults to v2. Flags: enspack <cmd> --help. See
docs/ens-v2.md.
The live get of the Qwen mirror requires Sepolia/mainnet infra that is
not published yet (MVP.md §0.1). Local proof uses Anvil + test/fixtures/tiny-model/
(test/e2e).
| Path | Package | Role |
|---|---|---|
packages/core |
@enspack/core |
labels, schema, ENS read/write, IPFS verified fetch, installer, lockfile |
packages/hf |
@enspack/hf |
Hugging Face tree/license + Hugging Bay client |
packages/torrent |
@enspack/torrent |
metainfo, aria2c downloader, SHA-256 verifier |
packages/cli |
@enspack/cli |
enspack / ensget binaries |
services/seed |
@enspack/seed |
seed node API + qBittorrent + Kubo compose |
services/registrar |
@enspack/registrar |
HF-proof → enspack.eth publisher subnames |
services/indexer |
@enspack/indexer |
Ponder indexer + JSON API |
apps/site |
@enspack/site |
catalog site, read-only view of the indexer API |
bootstrap/ |
@enspack/bootstrap |
models.yaml mirror runner (`enspack-bootstrap plan |
infra/ |
@enspack/infra |
one-box Sepolia deploy (Caddy + compose + scripts) |
test/fixtures |
— | tiny-model folder + torrent for swarm tests |
test/e2e |
@enspack/e2e |
local Anvil swarm (CI) + Sepolia (nightly) |
Docs: docs/publishing.md, docs/registrar.md, docs/seed-node.md,
docs/indexer.md, docs/exit-codes.md, docs/ens-v2.md.
One Docker VM (Caddy + qBittorrent + Kubo + seed + registrar + indexer):
infra/README.md.
pnpm install
pnpm check # build + lint + typecheck + test (includes local e2e)Anvil mainnet-fork tests use ETH_RPC_URL when set, otherwise they rotate
through public endpoints (publicnode, 1rpc, drpc) and pin the fork a few blocks
behind head. anvil (~/.foundry/bin) and aria2c are required for
fork/swarm suites; they skip when missing.
Secrets stay in env (ETH_RPC_URL, SEPOLIA_RPC_URL, ENSPACK_PUBLISHER_KEY,
ENSPACK_OPERATOR_KEY, HF_TOKEN, PINATA_JWT). Never write them to disk or
logs. CLI env vars: packages/cli/src/defaults.ts and enspack --help.
Honest against MVP.md §0. Live path is Sepolia ENSv2; mainnet v1 later. Local CI is the Anvil fork + fixture swarm, not mainnet.
| MVP §0 | Claim | Status |
|---|---|---|
| 1 | enspack get qwen--qwen2-5-7b-instruct.mirrors.enspack.eth on a clean machine |
Blocked on Sepolia enspack.eth / mirrors setup + seedbox (BOOTSTRAP.md). Live path is Sepolia ENSv2; mainnet v1 later. Local equivalent proven in test/e2e (sepolia-fork.e2e.test.ts on an Anvil Sepolia fork, plus mainnet v1 local-swarm.e2e.test.ts). |
| 2 | enspack publish --from-hf ≤ 3 txs |
Sepolia ENSv2: 4 txs new model / 2 new version (plus setup). Proven on Anvil Sepolia fork. V1 mainnet remains 3/2. Live --from-hf requires Sepolia/HF. |
| 3 | HF user claims <user>.enspack.eth with no human |
Blocked on registrar deploy + Sepolia enspack.eth UserRegistry. V2 issuance is 2 txs. Claim HTTP is implemented; live Sepolia E2E is unproven. |
| 4 | enspack.lock + enspack install; refuse if CID changed |
Proven locally (packages/cli lock tests + test/e2e add/install/--frozen + lock-mismatch exit 3). |
| 5 | GET https://index.enspack.dev/v1/names lists mainnet names |
Blocked on indexer deploy + mainnet names. API contract is implemented. |
| 6 | ≥ 25 mirrored models under mirrors.enspack.eth seeded |
Blocked on seedbox + WP-12 live run. bootstrap/models.yaml is the list. |
Nightly (.github/workflows/e2e-nightly.yml, 03:00 UTC) runs @enspack/e2e
with Sepolia secrets when present; the Sepolia suite self-skips without them.