Skip to content

Recover Your Data

This guide walks you through reconstructing your full Stasho project and deployment history using only your wallet's private key. The recovery script does not depend on our backend — it talks directly to the public Aleph network.

The standalone recovery script lives at scripts/recovery/ in the project repository. If you'd rather write your own tool in a different language, the Aleph Storage Schema is a complete, language-agnostic spec.

Alpha note

The project repository is private during the alpha, so the link and git clone below won't work for you yet. Email hello@stasho.xyz and we'll send you the script. The repository goes public no later than the beta — independence is the point of this guide, and we know a script you have to ask us for isn't fully independent yet. The storage schema is published in full today, so you can already build your own recovery tool without us.

When to use this

  • You no longer trust the platform and want to verify your data is portable
  • The platform has gone away (bankrupt, compromised, taken down)
  • You want to migrate your project history to a new tool
  • You want to audit what data exists about your projects on Aleph

What you need

  1. Your wallet's private key. Export it from MetaMask (Settings → Security → Show Private Key) or whatever wallet you use to sign in. The script never transmits this key anywhere; it only uses it locally to decrypt your data.
  2. Node.js 22 or later. Verify with node --version.
  3. The recovery script source. Clone the project repository and run it from scripts/recovery/.
  4. Your wallet address. The 0x-prefixed Ethereum address you used to sign in.
Sequence: you give the recovery script your wallet key, it fetches your project and deployment records from Aleph API nodes, decrypts them locally, and returns your projects and deployments. No Stasho backend is involved.Sequence: you give the recovery script your wallet key, it fetches your project and deployment records from Aleph API nodes, decrypts them locally, and returns your projects and deployments. No Stasho backend is involved.
Recovery talks to Aleph and your key. Nothing else.

Steps

1. Install the script

bash
git clone https://github.com/cpascariello/stasho-app.git
cd stasho-app/scripts/recovery
npm install

2. Run it

The script reads your private key from the USER_PRIVATE_KEY environment variable. Never pass it as a CLI flag — it would leak into your shell history.

bash
export USER_PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE
npm run recover -- --address 0xYOUR_WALLET_ADDRESS --output ./my-recovery.json

You should see output like:

[recover] Wrote 3 projects, 21 deployments, 0 warnings to ./my-recovery.json

3. Inspect the output

Open my-recovery.json. You'll see a JSON document with:

  • wallet — the address you recovered
  • recoveredAt — timestamp of the recovery
  • stats — counts of messages read, projects + deployments recovered
  • projects — your full list of projects, each containing its own list of deployments
  • warnings — any non-fatal issues encountered during recovery

Each project includes its name, source repo, branch, build configuration, and the full deployment history (with status, CID, URL, commit, error, etc.).

Schema v4 (May 2026 onwards): Each deployment POST references its artifact by storeRef (the STORE message's item_hash). The recovery script fetches each STORE to resolve storeRef → cid, and records the outcome per deployment as storeStatus.

If a project was deleted, its STORE has been FORGOTten: the script reports cid: null, storeStatus: "forgotten" and a STORE_FORGOTTEN warning — the deployment metadata survives but the artifact CID is no longer recoverable.

If Aleph's own garbage collection reclaimed the STORE because the account paying for it ran out of balance or credits, the script reports storeStatus: "removed" with a STORE_REMOVED warning. The artifact is equally unrecoverable, but nobody deleted it — so the remedy is different: fund the account before re-uploading.

A STORE that simply isn't on the node you queried is reported differently, as storeStatus: "absent" with a STORE_ABSENT warning. This is not the same as "forgotten" or "removed" — it means that node had no such message, which can also happen if the node is behind or you queried the wrong one. Try re-running against a different Aleph API node before concluding the artifact is gone.

4. Verify against the audit endpoint (optional)

If our backend is still running, you can compare your recovery output to what the backend claims:

bash
curl https://api.stasho.xyz/api/audit/0xYOUR_WALLET_ADDRESS | jq

The backendView.cachedProjects and backendView.cachedDeployments should match your recovery output's stats.projectsRecovered and stats.deploymentsRecovered. Any discrepancy means either a bug or, in the worst case, backend dishonesty. The recovery script is the ground truth.

Recover an app bundle

If you deployed a project to an App VM rather than IPFS static hosting, your deployment history includes an extra artifact: the encrypted application bundle itself (the built server code your App VM runs). Recovering it uses the exact same cryptographic building blocks as the rest of this page, with one difference: the recovered bundle is a tar archive, not a JSON document, so the final step is not the same.

This path isn't wired into npm run recover as a flag yet. Everything below is a straight walk through building blocks the recovery script already implements in scripts/recovery/src/decrypt.ts, you're assembling the same pieces yourself, in the same order.

  1. Start from your wallet's raw private key. The same key the rest of this page uses.

  2. Derive your encryption key, exactly as described in the Aleph storage schema. Fully offline, no network call needed.

  3. Fetch the bundle's envelope. Resolve the deployment record's storeRef to a STORE message, then fetch its bytes the same way the rest of recovery resolves artifacts. Optionally check sha256(bundle) === bundleHash from the deployment's public block before trusting the bytes.

  4. Unwrap deks.encryption with your derived key (ECIES, same mechanism as every other envelope in this app).

  5. AES-256-GCM decrypt ct with the unwrapped key, iv, and tag.

  6. Write the result to disk as-is, without parsing it. This is the one place bundle recovery diverges from every other decryption in this app: don't JSON.parse the plaintext. A bundle's decrypted contents are bundle.tar.gz's raw bytes, not JSON, and parsing it will throw. Write the buffer directly:

    ts
    writeFileSync("bundle.tar.gz", plaintext); // raw bytes, no JSON.parse
  7. Untar and verify. tar -xzf bundle.tar.gz gives you manifest.json and app.tar.gz. Confirm sha256(app.tar.gz) === manifest.artifactHash to make sure nothing was corrupted in transit or storage.

Don't JSON.parse the plaintext

Every other decryption in this app (projects, deployments) ends with JSON.parse(plaintext). An app bundle's plaintext is a tar archive. Parsing it as JSON will throw immediately, write the raw bytes to a file instead.

Verify your implementation

Before trusting a hand-rolled version of this against real data, check it against the project's own round-trip test. It encrypts random bytes with freshly generated VM and user keypairs, decrypts through both recipients using the exact same calls above, and asserts the result matches the original byte-for-byte:

bash
cd apps/backend && npx vitest run tests/bundle-encrypt-script.test.ts

(This requires the project repository, which is private during the alpha; see the note at the top of this page.)

Troubleshooting

"private key derives to X, not Y" — Your private key doesn't match the address you supplied. Double-check both.

"Aleph API unreachable" — Try a different Aleph API endpoint with --aleph-api https://api2.aleph.im or similar.

Warnings about decryption failures — Some messages couldn't be decrypted. This usually means the encryption envelope is malformed or tampered with. The script skips these and continues, but the warnings tell you which messages had issues.

Empty output — Your wallet has no Stasho data on the current channel. Either you've never used the platform with this wallet, or you're looking at the wrong channel. The channel was renamed twice: ALEPH-CLOUDAPPSTASHO_CHANNEL_V0 on 2026-05-07 (Decision #98), then STASHO_CHANNEL_V0STASHO_CHANNEL_V1 on 2026-05-20 (Decision #117); alpha data on each prior channel was retired at the rename. The recovery script's default targets STASHO_CHANNEL_V1. To inspect an older channel, override with --channel STASHO_CHANNEL_V0 or --channel ALEPH-CLOUDAPP.

Warning codes

The recovery output includes a warnings array. The codes you might see:

CodeWhat it means
STORE_FORGOTTENA deployment's STORE was definitively FORGOTten (project was deleted). Metadata is in the output but cid is null. Together with STORE_REMOVED, one of the two codes that mean the artifact is genuinely gone.
STORE_REMOVEDAleph's own garbage collection reclaimed the STORE because the account paying for it ran out of balance or credits. Nobody issued a delete. cid is null and the artifact is gone from Aleph's index; fund the account before re-uploading.
STORE_ABSENTThe node had no such STORE, or it wasn't usable (not a STORE message, carrying no CID, or rejected / still pending). Not the same as forgotten or removed — the node may be behind, or another node may still have it. Try re-running against a different node with --aleph-api <url>.
STORE_FETCH_FAILEDThe Aleph node didn't respond when the script tried to resolve a storeRef. Try re-running.
LEGACY_SCHEMAA deployment uses the pre-May-2026 schema (inline cid, no storeRef). The script handles it gracefully by reading cid directly.
ALEPH_MESSAGES_TRUNCATEDThe Aleph API capped the response. Re-run with a date filter or paginate.

Independence

The script depends only on:

  • Public Aleph HTTP API (any node — see https://aleph.im for the list)
  • Standard cryptographic primitives (AES-256-GCM, ECIES-secp256k1)
  • Node.js stdlib + two npm packages (eciesjs, ethers)

No part of this recovery flow depends on our infrastructure remaining online. If you have your private key and access to any Aleph node, you can recover your data forever.