Kaspa Forge
Safe uses vaultctl; Escrow and Deposit use the public dealctl recovery kit. Both work from source against a Kaspa node without a Kaspa Forge API.
Got a "withdrawal started" alert and it wasn't you? You have the entire cancel window from the moment it started (you chose its length at creation; the timer is visible in "My vault"). Any computer or borrowed phone works: use your alarm card in separate-storage mode, or import the full encrypted .age copy exported from the creation device if you chose shared storage. Forge Sync alone does not transfer alarm keys.
Your vaults, deals and listings all live in one encrypted master key file โ your Desk profile. On any device, open your Desk, choose Import / restore and load your master key file (.age) with its password โ the profile comes back at once. Working keys for things created after an earlier export are derived from the master seed, and the Desk re-discovers their public records from the server. Alarm keys are the exception described below: after choosing shared storage for a Safe, export a fresh full copy from that device.
Alarm-key storage follows the choice you made when creating each vault. In the safer separate-storage mode, the key lives only on the alarm card and the Desk marks the vault "alarm: card"; cancelling a theft or migrating asks for the key from that card. If you chose the more convenient shared-storage mode, the alarm key is inside the full encrypted master key file exported from the creation device. Forge Sync deliberately omits every alarm key, so a synced second device can show the vault but cannot cancel a withdrawal until that full .age copy is imported.
Need the raw keys out of the file โ even if this site is gone? Download the offline key-file decryptor (a single HTML file, ~3 MB): open it from disk with your internet off, load the .age file and its password โ it shows every private key stored inside without any network requests. Alarm keys from separate-storage vaults are absent because they exist only on their cards. The file is standard age, so the CLI works too: age -d keyfile.age. Also mirrored in the open-source repo: github.com/Kaspaforge/kaspaforge.
Someone left you a Kaspa Safe vault. The owner set a period: as long as they kept checking in ("I'm alive"), the vault was theirs alone. If the check-ins stopped โ after the period, the vault opens to you. Before that you can't see or take anything; that's how the contract is designed.
How long is left โ visible in the panel (the "Timer" row) or via vaultctl status. No permission from us is needed: the blockchain enforces the rules. Site down โ vaultctl inherit does the same (block below).
Kaspa Safe doesn't depend on us: the vault is an on-chain contract, and it checks only your keys and time. The open-source vaultctl tool does everything the site does, from a terminal, against any Kaspa v2+ node (running with --utxoindex). The code is published: github.com/Kaspaforge/kaspaforge โ keep a copy (Code โ Download ZIP) and you won't depend even on GitHub.
# once: build it (needs Rust from rustup.rs, protobuf-compiler, clang) git clone https://github.com/Kaspaforge/kaspaforge cd kaspaforge/vaultctl && cargo build --release # decrypt with web/keyfile-decrypt.html offline, or use standard age: # decrypt it once, then pull out the vault you need โ vaultctl reads JSON too: age -d kaspa-office-profile.age > profile.json # asks your Desk password jq '.vaults[0]' profile.json > vault.json # pick the vault you need # vault state: balance, age, inheritance timer vaultctl status --recovery vault.json # start a withdrawal to your address (needs the hot key from the profile) vaultctl initiate --recovery vault.json --to kaspa:q... # cancel an in-flight withdrawal (alarm key; --dest = the address the # withdrawal is going TO โ yours you know, a thief's is in the TG alert / panel) vaultctl cancel --recovery vault.json --dest kaspa:q... # deliver a matured withdrawal to its destination (no key needed) vaultctl complete --recovery vault.json --dest kaspa:q... # "I'm alive" check-in ยท deliver the inheritance after the period vaultctl checkin --recovery vault.json vaultctl inherit --recovery vault.json # "automatic": no key vaultctl inherit --recovery vault.json --heir-sk KEY # "manual": heir's key # migrate โ BOTH keys (hot + alarm) = instant full authority: move the whole vault # anywhere with no delay (rotate a leaked key, upgrade the contract version, escape). # --dest rescues a mid-withdrawal UTXO from the unvault address. vaultctl migrate --recovery vault.json --to kaspa:q... [--dest kaspa:q...]
Alarm-key storage: if you kept the alarm key in the encrypted profile, it is present only when profile.json came from a full .age export that contains it โ never from Forge Sync. For a separate-storage vault, add the key from your alarm card as an "alarm_sk" field before cancel or migrate.
Useful flags: --node grpc://your-node:16110 โ any Kaspa v2+ node with --utxoindex (defaults to the public OfficeForge node grpc://node.kaspaforge.org:16110 โ or run your own); --dry-run โ build and sign the transaction, print its txid, but do NOT broadcast (try this first). To verify the contract itself: vaultctl selftest โ 25 checks of every path and attack inside the node VM.
The public recovery-kit/ contains the shared Rust transaction core, dealctl, escrow.sil, versioned schemas, deterministic vectors, EN/RU guides, the offline .age decryptor and a checksum manifest. It deliberately contains no hosted server, chat/media layer, moderation, Telegram or operator/admin API.
# verify and build the published source git clone https://github.com/Kaspaforge/kaspaforge cd kaspaforge/recovery-kit sha256sum -c RECOVERY-SHA256SUMS cargo build --release --locked -p dealctl # OFFLINE: decrypt the Desk backup, extract and verify one deal age --decrypt -o profile.json your-backup.age ./target/release/dealctl extract --profile profile.json --deal ID --output deal.recovery.json ./target/release/dealctl verify --recovery deal.recovery.json # OFFLINE: make a PUBLIC watch file โ it contains no private key ./target/release/dealctl watch --recovery deal.recovery.json --output watch.json # ONLINE: query any Kaspa v2+ node with --utxoindex dealctl prepare --watch watch.json --node grpc://YOUR_NODE:16110 --output lines.json # OFFLINE: sign an allowed path; the line package is bound to this deal dealctl escrow release --recovery deal.recovery.json --line lines.json --output release.tx.json # ONLINE: submit the already-signed transaction; no key is needed here dealctl submit --tx release.tx.json --node grpc://YOUR_NODE:16110
The private recovery record stays offline. Only watch.json, lines.json and the signed transaction cross to the online machine; none contains a private key. dealctl also supports refund, dispute, mutual settlement, keyless auto-release/timeout and the matching Deposit aliases. Read the complete guide before moving funds.
If anyone asks you to send a private key, a seed phrase, your Desk password, your master key file or your alarm card โ it's a scammer.
The alarm card deserves special care: together with the key file it gives instant full control of the vault (the migrate path). Nobody legitimate will ever ask to "check" or "verify" it.
Your master key file does not give OfficeForge access to your coins โ it's encrypted with your password and exists for you alone, to sign actions with your own keys. We don't store private keys or your password and can't recover them for you. And we will never ask for them โ not in chat, not by email, not "for verification". Support (kaspa@officeforge.co) can explain the steps, but physically has no access to keys or coins.