Status: accepted and implemented; amended 2026-08-09 for browser-session authorisation, the isolated Pudge Sandbox, and standard CKB confirmation RPCs.
Decision date: 2026-06-23 Current amendment: 2026-08-09
CKB ecosystem discovery spans objects with materially different trust and use contracts: CellScript dependency source, profile libraries, CKB-VM executables, deployed Script Cells, reproducible tooling, and copy-only starters. Treating all of them as “packages” hides whether an object can be installed, executed, deployed, or only copied. Treating publication, build verification, deployment, and availability as one status creates false assurance.
The service also needs a wallet-rooted publisher identity without taking custody of seed material, a static hash-verifiable read path, and an auditable operator boundary.
The production Registry uses:
- one public
/v1/artifactsresource family; - a closed artifact descriptor for kind, verification profile, language, and consumption mode;
- independent verification, deployment, and availability states;
- typed CKB wallet principals that authorise scoped delegated capabilities;
- Postgres as the write authority and immutable static objects as the normal content transport;
- an isolated, profile-aware verification worker;
- signed, live-RPC-verified CKB mainnet deployment evidence;
- an isolated Pudge Testnet Sandbox with separate origins, storage, signing, wallet state, RPC identity, expiry, and evidence;
- fail-closed CellScript dependency resolution that accepts only the
cellscript_source+dependencycontract.
There is no account-style Registry identity, no Git convention as public resolver authority, no testnet option inside the production Registry, and no second public package route. Pudge is a separate environment and cannot create production deployment state.
The accepted contracts are:
| Kinds | Profile | Consumption | Verification boundary |
|---|---|---|---|
| source/profile library | cellscript_source |
dependency | compile authenticated snapshot |
| runtime verifier | ckb_executable |
TCB | source + executable + ABI + optional recipe hashes |
| deployable contract | ckb_executable |
deployment | source + executable + ABI + optional recipe hashes |
| reproducible binary | reproducible_build |
TCB | source + output + recipe hashes and evidence |
| template | copy_material |
copy | authenticated file-map hash |
The coordinate is shared discovery vocabulary, not shared consumption semantics. A caller must select on profile and consumption mode, not infer them from a name or file extension.
Every release records:
verification_status = pending | hash_bound | verified | evidence_required | rejected
deployment_status = not_applicable | undeployed | deployed | chain_verified
availability_status = active | deprecated | yanked | quarantined
The axes are independent. Publication sets initial values only. Verification and deployment claims require accepted evidence. Operator actions modify only availability. Evidence and immutable identities are append-only.
The implementation may retain a derived internal status column while migrating the deployed schema, but public responses and frontend decisions use the three orthogonal fields.
Accepted principals are:
joyid_ckb = normalized JoyID CKB public-key binding
ckb_secp256k1 = normalized compressed secp256k1 public-key binding
Display addresses may be retained for support but are not authority keys. The API verifies scheme, canonical challenge, public-key recovery/binding, and principal identity before storing a capability.
The wallet root authorises a P-256 capability scoped to a namespace/artifact, with expiry and revocation. Daily publish and deployment requests use the delegated key. Seed phrases and private wallet keys never cross the wallet boundary.
For interactive first publish, cellc publish --authorise creates the key as a
pending keychain entry and opens a 15-minute exact-coordinate browser session.
The browser holds only a fragment token and signs a server-built challenge.
Session completion atomically consumes the nonce, registers the public key,
claims or reviews the namespace, records the terminal session state, and writes
audit events. The polling CLI activates only the matching returned key ID and
then resumes the original publish. The explicit capability and namespace
commands remain the manual/CI path.
Capabilities do not claim namespaces implicitly. The namespace must be active and owned by the capability principal. Reserved names may require attributed operator review.
The website exposes one CKB wallet entry that opens a compact chooser. The chooser contains the supported CKB wallet directory; CCC-discovered signers can connect directly, and unavailable connectors link to the official wallet or use the external signature handoff.
The Registry does not pretend that catalog presence means runtime support. Backend signature verification is identical for browser and external handoff flows. Recovery phrases are never accepted by the frontend or API.
The production network is fixed to CKB mainnet and is not shown as a selectable control. The Pudge site is a separate testnet-only origin with separate wallet state, not a selector value.
Release admission verifies the active capability, scope, namespace ownership, route/payload equality, closed artifact descriptor, immutable coordinate, manifest/source hashes, signature, nonce, idempotency record, snapshot/bundle, and initial state claims.
Immutable bundle and static release writes happen before database admission. The release, verifier job, capability use, audit event, nonce, and completed idempotency response commit transactionally. Admission reports verification as queued; it is not verification evidence.
Non-CellScript artifacts use an explicit Artifact.toml and JSON bundle. The
closed cellscript-registry-profile-contract-v1 binds build, declared security,
CKB/ABI, verifier IPC, reproducibility, or copy semantics to the immutable
objects. The bundle is bounded to 5 MiB. Unknown fields and unknown or duplicate
roles fail closed in admission, publisher CLI, and isolated verifier.
Deployable Lock Scripts may attach
cellscript-registry-ls-idl-interface-v1. It binds SHA-256 of the exact ABI
object bytes to the executable's final 32 bytes. The read API resolves those
bytes only from active chain-verified deployment evidence and preserves them
without JSON reserialisation. This is interface identity evidence, not proof of
implementation correctness or a security audit.
The worker leases jobs with FOR UPDATE SKIP LOCKED, bounded retry, dead-letter
handling, and crash recovery. The verifier runs under resource and filesystem
bounds.
For CellScript source it authenticates and compiles the real snapshot. For
other profiles it validates bundle identity, required roles, and published
hashes. Reproducible output remains evidence_required until appropriate
evidence exists. A copied template is never promoted into dependency or TCB
semantics.
Evidence insertion and the worker publishing checkpoint commit together. Static-object refresh happens afterward; reclaiming a crashed publishing job repeats only the static write.
A CKB executable begins as undeployed. Deployment evidence uses a separate
signed protocol and requires prior verified-build evidence.
The production API accepts only network = mainnet. It calls get_live_cell
for the declared OutPoint and requires a live Cell whose data hash equals the published
executable hash. For Type-hash references it computes the returned Type Script
hash from canonical Molecule serialization; for data-hash references it
requires code hash and data hash equality.
Confirmation depth comes from the standard creation-transaction path:
get_transaction.tx_status must report committed and supplies the block hash
used with the current tip. The service does not rely on a proxy-specific
get_live_cell.block_hash extension.
For DepGroups, the API decodes the live container data as canonical Molecule
OutPointVec, loads the members, and verifies the matching live code Cell. The
container hash is not substituted for the member executable identity.
Success appends hash-addressed evidence and sets deployment_status to
chain_verified. It does not alter verification or availability.
The Registry may additionally commit the release/deployment tuple in a live
mainnet Cell. Canonical cellscript-registry-commitment-v1 JSON is CKB
Blake2b-hashed into CSREGv1 || hash Cell data. Acceptance checks that exact
data, the commitment custody Lock hash, a Registry Type Script hash used for
chain indexing, minimum confirmation depth, and the live Type/Lock code
CellDeps. A public commitment-proof route returns the preimage, expected Cell
data, and accepted commitment evidence. The full source, ABI, build recipe,
compiler metadata, audit corpus, and publisher history remain off-chain and
content-addressed.
The canonical Registry Type Script binds its 32-byte args to the complete custody Lock Script hash, requires every group Cell to use that Lock, and requires every creation, replacement, or destruction transaction to consume a Cell under that Lock. This closes the CKB creation-authority gap: sending a new Cell to the Registry Lock is not sufficient to manufacture an official commitment without exercising the Registry signer. Production API readiness also pins the Type code data hash and standard mainnet secp Lock/DepGroup.
Production domains:
api.registry.cellscript.dev -> authenticated writes and dynamic artifact reads
registry.cellscript.dev -> immutable bundles and static release JSON
cellscript.dev/registry -> static Astro discovery and publishing UI
The testnet sandbox uses api.testnet.registry.cellscript.dev and
testnet.registry.cellscript.dev with independent storage and signing state.
Its records leave discovery after 72 hours and source objects are deleted after
a 24-hour grace period; this does not erase Pudge chain history.
Static release objects use:
https://registry.cellscript.dev/artifacts/:namespace/:name/releases/:release.json
LS-IDL adds a dynamic, chain-identity read at
/v1/ckb/scripts/:code_hash/interfaces/ls-idl and the upstream-compatible
/idl/:code_hash alias. hash_type=type requires a data hash, and ambiguity
fails closed rather than selecting one deployment.
The static origin does not require Postgres. Objects include immutable bundle identity, artifact descriptor, all state axes, and accepted evidence. Consumers verify object, file, source, build, and deployment hashes independently.
Public list/detail/evidence routes suppress quarantined releases. The API list supports explicit kind, verification, deployment, availability, namespace, query, and pagination filters.
Generic consumers use explicit cellc artifact operations. Fetch/verify check
the receipt and all immutable identities; pin records TCB/deployment inputs;
copy safely materializes only an authenticated file map; record-deployment
submits evidence to the network fixed by the selected Registry environment;
CellDep generation requires attached RPC evidence;
commitment generation produces the canonical chain payload. Generic artifacts
never flow through dependency installation.
cellc install resolves through the public artifact API and rejects profiles
other than cellscript_source or consumption modes other than dependency.
The resolver downloads the immutable source snapshot, verifies its object and
file identities, and only then materializes it.
Unverified releases require an explicit --allow-unverified; quarantined
releases are absent from public reads and require operator remediation rather
than accidental fallback. Resolver failure never falls back to a conventional
Git URL. Path and explicit Git dependencies remain independent user-selected
dependency sources.
The service enforces bounded bodies, per-IP/ASN/principal/capability/artifact quota hooks, namespace claim cooldown, reserved-name policy, signed one-use nonces, and idempotency conflict detection. Successful and rejected sensitive actions are attributable through the audit log.
Admin availability changes accept only active, deprecated, yanked, and
quarantined. Generic admin mutation cannot manufacture build or deployment
assurance. Evidence-specific recovery paths validate identity and predecessor
evidence.
API and static responses use HSTS, no-sniff, anti-framing, no-referrer, restrictive browser permissions, and deny-all JSON CSP. Postgres is internal; static serving is read-only.
The live self-hosted slice uses Postgres 17, Node 22, an isolated verifier, persistent object storage, and read-only nginx behind the production TLS proxy. Cloudflare Worker, Hyperdrive, Neon, and R2 remain a supported equivalent deployment shape.
Migrations are additive after the frozen 0001 baseline. The artifact-model
migration intentionally refuses to transform non-empty legacy release data
because no released public contract exists that would justify a lossy mapping.
Migration 0010_ls_idl_interfaces.sql adds only a partial functional index for
eligible deployment evidence; exact release, bundle, ABI, digest, and suffix
checks still run on every response.
Readiness covers database/object access, admin configuration, and the verifier heartbeat. Backups contain a Postgres custom dump, object archive, image identity, and checksum manifest; restores are rehearsed into empty volumes before traffic cut-over.
Benefits:
- broad CKB discovery without weakening CellScript dependency safety;
- deployed and undeployed executables are distinguishable;
- publication cannot masquerade as verification;
- mainnet deployment claims are independently checked against live Cells;
- static content survives write-database incidents;
- wallet authority stays outside the Registry.
Costs:
- publishers of generic artifacts must construct an explicit bundle;
- reproducibility needs evidence beyond uploaded bytes;
- deployment recording requires live mainnet RPC availability;
- internal storage still carries derived compatibility fields during the additive migration.
- One
statusfield: conflates assurance, deployment, and availability. - Infer artifact type from content: ambiguous and unsafe for resolution.
- Treat every entry as installable: permits executable/template confusion.
- Git convention as resolver authority: conflates naming with ownership and availability.
- Store the full evidence corpus on chain: expensive and unnecessary; the chain should carry runtime commitments while full evidence remains content-addressed off chain.
- Accept testnet deployment records in production: creates a misleading production state whose deployed status is used for mainnet discovery. Pudge is instead isolated by origin, storage, signer, wallet state, RPC identity, expiry policy, and build.