Repository navigation
Scaffold contextmem Move package (Move.toml, module stubs) + CI build/test + testnet publish #8
Description
Context
ContextMEM has zero Move code today — find for Move.toml/*.move returns nothing, and every "on-chain" touch is a read-only Sui query (packages/walrus/src/proof.ts uses SuiGrpcClient.getObject against Mysten's Walrus Sites package) or a third-party-signed write (Tatum, MemWal). This is the literal "where is my smart contract?" gap. Per roadmap §2, the answer is one minimal contextmem Move package (registry + receipt). This issue stands up the package skeleton and its CI so the two real modules (separate issues) have somewhere to live and a repeatable publish path.
Goal / user story
As a contributor, I can run sui move build / sui move test locally and in CI, and publish the package to Sui testnet with a single workflow run that records the resulting packageId, so downstream modules and the TS client have a stable on-chain address to target.
Acceptance criteria
- New top-level
move/contextmem/package (sibling topackages/andapps/) withMove.toml(edition2024.beta, named addresscontextmem = "0x0", Sui framework dep pinned to a testnet rev) and asources/dir. - Compiling stub modules
sources/registry.moveandsources/receipt.move(emptymodule contextmem::registry {}/::receipt {}is enough) plus atests/dir wired sosui move testruns green. - New CI workflow
.github/workflows/move.ymlthat installs the Sui CLI and runssui move build+sui move teston every PR touchingmove/**(the existingbun-check.ymlis JS-only and must NOT be overloaded). - A
workflow_dispatch(manual) job in the same workflow publishes to testnet using aSUI_TESTNET_PRIVATE_KEYrepo secret + testnet faucet gas, and writes the publishedpackageIdtomove/contextmem/published.testnet.json(uploaded as an artifact). -
move/contextmem/README.mddocuments local build, the named-address/upgrade-cap conventions, and the signer/network decision (see notes). - Root
package.jsongains amove:buildscript (sui move build --path move/contextmem) so the toolchain is discoverable from the monorepo.
Implementation notes
- Toolchain: pin a Sui CLI version in CI (download a
MystenLabs/suitestnet release binary, orsuiup); do NOT usecargo install(too slow). Cache the binary. - Network: publish to testnet to match what's already there —
WALRUS_NETWORKS.testnet.sitePackageinpackages/walrus/src/constants.tsand Harbor's testnet alpha. Roadmap decision docs: add product roadmap (Harbor storage + Talus on-chain direction) #4 (one network for the launch surface) means receipts and the blobs they cite must be co-located; testnet is the choice for the demo. - Publish gas: publish needs real testnet SUI from the faucet (Enoki sponsorship covers runtime txs, not the one-time publish). Have the workflow request faucet gas for the publish address before
sui client publish --json. - Upgrade cap: capture the
UpgradeCapobject id alongsidepackageIdinpublished.testnet.jsonso future module changes can be upgraded, not re-published to a new address. - DECISION to record in README (affects all sibling issues): signer + ownership. Runtime mints will be Enoki-sponsored (no SUI balance needed, mirroring Harbor's reserve→sign→finalize), but the sender/signer is the open question — recommended for alpha: a single backend service key (
suiprivkey1..., decoded viaEd25519Keypair/decodeSuiPrivateKey) signs, Enoki sponsors gas, and the service key is therefore the on-chain owner ofNamespace/Receiptobjects (user wallet / zkLogin ownership deferred). Document this so the registry/receipt modules don't assume user-owned objects.
Sui Overflow angle
This is the foundation of the "real Sui-native contract" story — it turns ContextMEM from a consumer of Mysten packages into a publisher of its own on-chain logic, and gives judges a concrete packageId on a testnet explorer. Reproducible CI publish is what lets the team iterate the contract during the hackathon without manual key juggling.
Dependencies
None (this is the gating issue; registry, receipt, and the on-chain TS client all build on it).
Part of the ContextMEM roadmap (#4) • Sui Overflow build.
Activity
harrymove-ctrl commentedon Jun 19, 2026
Implementation Plan
Approach
Stand up a single top-level
move/contextmem/package (sibling toapps//packages/) containingMove.toml(edition2024.beta,contextmem = "0x0", explicit Sui framework dep pinned to a testnet tag), two empty-but-compiling module stubs (registry,receipt), and a trivialtests/module sosui move testis green. Add a dedicated.github/workflows/move.ymlthat is path-scoped tomove/**(never touching the JS-onlybun-check.yml): a PR/push job that installs a pinned, cached prebuilt Sui CLI binary (nocargo install) and runssui move build+sui move test, plus a separateworkflow_dispatchpublish job that importsSUI_TESTNET_PRIVATE_KEY, faucets gas, runssui client publish --json, and emitspublished.testnet.json(packageId + UpgradeCap + tx digest) as an artifact. Key design decision: keep this purely a scaffold — empty modules, no business logic — so theregistry/receipt/TS-client issues have a stable on-chain address and a reproducible publish path to build on, and record the signer/network DECISION (testnet + service-key-signed, Enoki-sponsored runtime) in the README so sibling modules don't assume user-owned objects.Prerequisites & dependencies
registry,receipt, on-chain TS client all depend on it).WALRUS_NETWORKS.testnetinpackages/walrus/src/constants.ts:13and Harbor testnet alpha); Spike: run @mysten/seal encrypt+decrypt inside a Cloudflare Worker #5 signer/ownership → single backend service key signs, Enoki sponsors runtime gas, service key owns objects (documented in README, not implemented here); Build HarborClient: reserve→sign→finalize bucket, multipart upload, status poll, download #6 service-key custody → noted as shared-vs-per-owner deferred.SUI_TESTNET_PRIVATE_KEYin bech32suiprivkey1...form (consumed bysui keytool import).sui client faucet/https://faucet.testnet.sui.io/v2/gas). Publish needs real testnet SUI — Enoki sponsorship covers runtime txs only, not the one-time publish.MOVE_PUBLISH_ENABLEDto gate the publish job (mirrorsdeploy.yml'sDEPLOY_ENABLEDpattern so forks stay green).@mysten/sealinvolvement in this issue.testnet-v1.51.x) and use the same tag for both the CLI binary and theMove.tomlframeworkrevto avoid framework/CLI mismatch warnings.Step-by-step
Create
move/contextmem/Move.toml(new). Contents:Pin
revto the chosen testnet tag (keep it equal to the CI CLI version). Note: recent CLIs treat Sui as an implicit system dep and may warn the explicit dep is unnecessary — the issue explicitly requires it pinned, so keep it; if the CLI errors on the duplicate-system-dep, fall back torev = "framework/testnet"or drop the block and rely on the implicit dep (document whichever in the README).Create stub modules (new):
move/contextmem/sources/registry.move→module contextmem::registry { }move/contextmem/sources/receipt.move→module contextmem::receipt { }An empty module compiles under
2024.beta. Add a one-line//!-style comment in each pointing to its dedicated issue so the next engineer knows where the realNamespace/AttributionReceiptstructs land.Wire
tests/(new) —move/contextmem/tests/contextmem_tests.move:This makes
sui move testexit 0 with a passing test (proving the test harness is wired, not just "0 tests found"). Also addmove/contextmem/.gitignorewithbuild/so compiled artifacts aren't committed.Create
.github/workflows/move.yml(new) — build/test job:pull_requestandpush(branchesmain,staging) filtered topaths: ['move/**', '.github/workflows/move.yml'], plusworkflow_dispatch. This keeps it independent ofbun-check.yml(.github/workflows/bun-check.ymlstays JS-only) — a JS-only PR showsmove.ymlas skipped, not run.https://github.com/MystenLabs/sui/releases/download/<tag>/sui-<tag>-ubuntu-x86_64.tgz, extract thesuibinary to~/.sui/bin, add to$GITHUB_PATH. Cache it withactions/cachekeyed on the tag (key: sui-cli-<tag>). Do notcargo install(per issue note). Alsoactions/cachethe Move dep cache (~/.move) keyed onhashFiles('move/contextmem/Move.toml')so the framework git-clone is reused.actions/checkout@v4→ restore CLI cache / install →sui move build --path move/contextmem→sui move test --path move/contextmem.Add the publish job to
move.yml—publish-testnet:if: github.event_name == 'workflow_dispatch'(and optionally&& vars.MOVE_PUBLISH_ENABLED == 'true'). Add a guard step that fails with a clear message ifsecrets.SUI_TESTNET_PRIVATE_KEY == ''.~/.sui/sui_config/client.yamlfor the testnet env (rpc: https://fullnode.testnet.sui.io:443), thensui keytool import "$SUI_TESTNET_PRIVATE_KEY" ed25519, resolve the imported address viasui keytool list --json,sui client switch --address <addr>and--env testnet. (First-runsui clientis interactive — pre-writing config or pipingyesavoids the prompt; document the exact incantation.)sui client faucet(falls back tocurl -X POST https://faucet.testnet.sui.io/v2/gas -d '{"FixedAmountRequest":{"recipient":"<addr>"}}'); pollsui client gas --jsonuntil a coin appears.sui client publish --path move/contextmem --json --gas-budget 200000000 --skip-dependency-verification > publish.json.move/contextmem/published.testnet.jsonwithjq:packageId = .objectChanges[] | select(.type=="published") | .packageIdupgradeCap = .objectChanges[] | select(.objectType? and (.objectType|test("::package::UpgradeCap$"))) | .objectIdtxDigest = .digest; also recordnetwork: "testnet",sender,publishedAt.actions/upload-artifact@v4forpublished.testnet.json. (Recommend committing it back to the repo via a follow-up PR — avoid CIcontents: writefor alpha — so downstream issues read a stable address from the repo.)Create
move/contextmem/README.md(new) documenting: local build (sui move build --path move/contextmem,sui move test,bun run move:build); the named-address convention (contextmem = "0x0"placeholder → publish assigns the real id; downstream builds can override with--named-addresses contextmem=<packageId>); the UpgradeCap convention (future changes usesui client upgradewith the captured cap, never republish to a new address); and the DECISION (per issue notes + roadmap docs: add product roadmap (Harbor storage + Talus on-chain direction) #4/Spike: run @mysten/seal encrypt+decrypt inside a Cloudflare Worker #5): testnet launch surface; runtime mints Enoki-sponsored; thesuiprivkey1...service key (decoded viaEd25519Keypair/decodeSuiPrivateKey) is the sender/signer and on-chain owner ofNamespace/Receiptobjects; user-wallet/zkLogin ownership deferred — soregistry/receiptmust not assume user-owned objects.Edit root
package.json(/Users/harryphan/Documents/contextMeM/package.json, scripts block ~line 16-27): add"move:build": "sui move build --path move/contextmem"(optionally"move:test": "sui move test --path move/contextmem"). Keep it out of thecheck/buildaggregates so the JS CI/dev flow doesn't require the Sui CLI.New / changed files
move/contextmem/Move.toml(new)move/contextmem/sources/registry.move(new)move/contextmem/sources/receipt.move(new)move/contextmem/tests/contextmem_tests.move(new)move/contextmem/.gitignore(new —build/)move/contextmem/README.md(new)move/contextmem/published.testnet.json(produced by the publish job as an artifact; committed back via follow-up PR after first successful publish).github/workflows/move.yml(new)package.json(edit — addmove:buildscript)Test plan
sui move build --path move/contextmemcompiles all three sources;sui move test --path move/contextmemreports1 passing(thescaffold_buildstest);bun run move:buildsucceeds from repo root. Proves AC Walrus storage + Memory via Tatum, plus CI deploy #1, Memory knowledge graph: 3D neural constellation + grounded entity panel #2, Build HarborClient: reserve→sign→finalize bucket, multipart upload, status poll, download #6.move/**→move.ymlbuild+test job runs green; open a JS-only PR →move.ymlis skipped whilebun-check.ymlstill runs (proves the two are decoupled, AC fix(ci): force bun + pin wrangler in Deploy workflow #3).workflow_dispatchwithSUI_TESTNET_PRIVATE_KEYset → faucet funds the address →sui client publish --jsonreturns a real testnet packageId + UpgradeCap + tx digest; download thepublished.testnet.jsonartifact and confirm thepackageId/upgradeCapresolve on a testnet explorer (suiscan/suivision testnet). The on-chain tx digest is the acceptance proof (AC docs: add product roadmap (Harbor storage + Talus on-chain direction) #4).sui move build --path move/contextmem --named-addresses contextmem=<publishedPackageId>and confirm it still compiles (validates the named-address override path the TS client andsui client upgradewill use).Risks & gotchas
cargo installis too slow — must use the prebuilt release tarball +actions/cache. Asset naming has shifted across releases (e.g.sui-<tag>-ubuntu-x86_64.tgz); confirm the exact asset name for the chosen tag, or usesuiupas an alternative installer.Move.tomlrevand the CI CLI tag diverge, builds emit framework-version warnings or fail. Keep them equal; pin a concretetestnet-vX.Y.Ztag rather than the movingframework/testnetbranch for reproducibility.sui clientis interactive (prompts to create config/key). Pre-write~/.sui/sui_config/client.yamlor pipe answers; otherwise the publish job hangs.--gas-budgetexplicitly (~0.2 SUI) so a dry-run estimate failure doesn't block.published.testnet.jsonwrite-back: committing from CI needscontents: write+ a bot commit; default to artifact-only + manual follow-up PR to avoid granting CI write perms.2024.betais required for the empty-module + label syntax; verify the pinned CLI supports it (recent testnet releases do).Acceptance-criteria mapping
move/contextmem/+Move.tomledition/named-address/framework rev +sources/) → Step 1 (+ dir from Steps 2).registry.move/receipt.movestubs +tests/sosui move testgreen) → Steps 2, 3; verified by local test plan.move.ymlinstalls Sui CLI, runs build+test on PRs touchingmove/**, not overloadingbun-check.yml) → Step 4.workflow_dispatchpublish job usingSUI_TESTNET_PRIVATE_KEY+ faucet, writespublished.testnet.jsonas artifact) → Step 5.README.mddocuments local build + named-address/upgrade-cap conventions + signer/network decision) → Step 6.package.jsonmove:buildscript) → Step 7.Effort: S–M, ~1–1.5 person-days. The Move scaffold + README + package.json edit is ~2 hours; the bulk is the
move.ymlpublish job (cached pinned CLI install, non-interactive client config, faucet, JSON parsing) and one real end-to-end testnet publish to validate the digest.Implementation plan generated for execution (planning phase). Part of the roadmap (#4).