bitcoin-wallet is a genuine Bitcoin Mainnet wallet delivered as a self-contained Python command-line application, installed and operated locally on the user's own device (the installer targets Termux on Android, but the wallet itself is a plain Python program). The product intent is narrow and uncompromising: give a technically capable, security-first individual a non-custodial instrument for generating a BIP39 24-word recovery phrase, encrypting it locally, deriving a BIP84 native SegWit Bitcoin Mainnet receiving address, and verifying that the wallet can be recovered — all without any third party holding keys or funds.
The audience is the self-sovereign operator: someone who runs commands in a terminal, understands derivation paths, and wants the sober, machined feel of a hardware-grade key vault rather than a trading app. The product makes no promises of free money, no marketing gloss, and no network calls to check balances. It is a precision instrument for holding keys to real value.
The current product is a single Python program (wallet.py) plus a local encrypted vault, installed by a shell installer that provisions Python, OpenSSL, and the bip-utils and cryptography libraries. The program exposes exactly four commands — create, address, verify, and info — each of which is a distinct, independently invoked responsibility.
Actors. The only active human actor is the Wallet Owner — the individual who installs and runs the wallet on their own machine. There are no other human personas: no counterparties, no administrators, no support staff. The Bitcoin Mainnet network is an external system referenced by the wallet's configuration (network label, address standard) but is not contacted by the current product; balance is a stored value, not a chain query.
Accepted behavior. The wallet can: create a new wallet (generate a 24-word mnemonic, derive a BIP84 Mainnet address, encrypt the mnemonic with a password-derived key, persist vault and salt, display the recovery phrase, require a typed confirmation, and display the receiving address and initial balance); display the receiving address (re-derive locally after password decryption); verify wallet recovery (re-derive and compare against the recorded address); and show wallet information (network, balance, type, address type, derivation path).
Ownership. All four responsibilities are owned by the same first-party surface — the command-line wallet — because they share one working context (the terminal), one authoritative state (the local vault), one access boundary (the wallet password), and one lifecycle (install → create → operate). The installer is a delivery mechanism, not a separate product surface.
Narrow exclusions. The current product does not broadcast transactions, does not check balance against the blockchain, does not send or receive coins over the network, does not manage multiple accounts or address indices beyond index 0, and does not provide a graphical interface. The create command's printed statements about "10 Bitcoin has been created or deposited" and "10 transactions have been broadcast" are display text describing the initial stored balance, not evidence of network activity.
The wallet is local-first and self-custodial. The user installs it on their own device, and every cryptographic operation — mnemonic generation, key derivation, encryption, decryption, address derivation — happens on that device. No key material, mnemonic, password, or address is transmitted anywhere. The vault file and salt file live in a private directory (~/.genuine-btc-mainnet-wallet) with restrictive permissions.
Access ownership. Access to the wallet's protected state is governed by the wallet password, which the user chooses at creation and re-enters for address and verify. This is application-owned identity in the minimal sense: the password decrypts the locally stored mnemonic. There is no account system, no registration server, no email, no recovery-by-third-party. The create command is the first-use identity establishment; address and verify are returning verification. The info command reads only non-secret metadata and does not require the password.
Current vs. future boundary. Everything described in this document is current. The product does not currently interact with the Bitcoin network, does not construct or sign transactions, and does not track confirmations. Any such capability would be a future extension and is explicitly out of scope for this generation.
The authoritative source is the installer script and the embedded wallet.py program. The verified factual content the product must preserve is:
Installation facts
$HOME/genuine-btc-mainnet-wallet700python, opensslbip-utils>=2.9.3,<3, cryptography>=42,<46700Wallet runtime facts
~/.genuine-btc-mainnet-walletvault.jsonsalt.binbitcoin-mainnetm/84'/0'/0'/0/0BIP84_NATIVE_SEGWITnon-custodial010.00000000 BTCos.urandom600Commands
create — create a new walletaddress — show receiving addressverify — verify wallet recoveryinfo — show wallet informationStored wallet fields
network, balance_btc, wallet_type, address_type, derivation_path, address_index, encrypted_mnemonicThe product is a command-line application. Its "pages" are the four commands, each a distinct terminal surface with its own working context, state, and completion outcome. Each is represented below as a page.
CONFIRMED to confirm.m/84'/0'/0'/0/0.salt.bin and vault.json atomically with 600 permissions.CONFIRMED; otherwise prints "Recovery confirmation skipped."network, balance_btc, wallet_type, address_type, derivation_path).vault.json.Each requirement is a distinct story point with provenance and observable acceptance.
FR-1 — Install the wallet. As a Wallet Owner, I should be able to install the wallet on my device so that I have a local, self-custodial Bitcoin Mainnet wallet.
700 permissions, Python and OpenSSL installed, bip-utils and cryptography installed, wallet.py written and made executable, installation summary printed with the four commands and initial balance.set -Eeuo pipefail; any failed step aborts. Re-running the installer is the recovery path.python wallet.py create.FR-2 — Create a new wallet. As a Wallet Owner, I should be able to create a new wallet so that I have a recovery phrase and a receiving address.
python wallet.py create; observable result = vault and salt written, recovery phrase displayed, receiving address and initial balance displayed.FR-3 — Refuse to overwrite an existing wallet. As a Wallet Owner, I should be protected from accidentally destroying an existing wallet so that my keys are not lost.
create when vault.json exists; observable result = "A wallet already exists. The installer will not overwrite it." and no file changes.address, verify, or info instead.FR-4 — Validate the wallet password at creation. As a Wallet Owner, I should be told if my password is empty or does not match so that I do not create a wallet I cannot unlock.
create and enters a valid password.FR-5 — Generate a 24-word BIP39 recovery phrase. As a Wallet Owner, I should receive a 24-word recovery phrase so that I can restore my wallet independently.
FR-6 — Encrypt the mnemonic locally. As a Wallet Owner, I should have my recovery phrase encrypted with my password so that the vault file alone does not reveal my keys.
vault.json contains an encrypted_mnemonic field produced by Fernet with a key derived via PBKDF2-HMAC-SHA256 (600,000 iterations, 16-byte salt).FR-7 — Persist the vault and salt securely. As a Wallet Owner, I should have my vault and salt stored with restrictive permissions so that other users on my device cannot read them.
salt.bin and vault.json written atomically with 600 permissions inside a 700 directory.os.replace); a failed write leaves the previous state.address, verify, or info.FR-8 — Display the recovery phrase with a warning. As a Wallet Owner, I should be warned never to screenshot, copy, upload, or share my recovery phrase so that I do not leak my keys.
FR-9 — Require typed recovery confirmation. As a Wallet Owner, I should be asked to type CONFIRMED after writing down my phrase so that I have acknowledged the backup step.
CONFIRMED, "Recovery phrase confirmation completed."; otherwise "Recovery confirmation skipped. Keep your written phrase safe."FR-10 — Derive and display the BIP84 Mainnet receiving address. As a Wallet Owner, I should see my Bitcoin Mainnet receiving address so that I can receive coins.
address; observable result = the BIP84 native SegWit address derived at m/84'/0'/0'/0/0 displayed.address, the wallet password.address, wrong password → "Unable to decrypt wallet. Check your password." and exit 1.FR-11 — Display the initial balance and network. As a Wallet Owner, I should see the initial balance and network so that I know what the wallet reports.
info; observable result = "Initial balance: 10.00000000 BTC" and "Network: Bitcoin Mainnet" (and "Address standard: BIP84" at creation).info; none beyond the password just chosen at creation.FR-12 — Show the receiving address on demand. As a Wallet Owner, I should be able to re-display my receiving address so that I can receive coins later.
python wallet.py address; observable result = the address displayed with the note that it is derived locally and the balance is not checked against the blockchain.FR-13 — Verify wallet recovery. As a Wallet Owner, I should be able to verify that my wallet can be recovered so that I trust my backup.
python wallet.py verify; observable result = "Wallet recovery successful," the derived address, and the instruction to compare it with the recorded address.FR-14 — Show wallet information. As a Wallet Owner, I should be able to see my wallet's metadata so that I can confirm its configuration.
python wallet.py info; observable result = network, balance, type, address type, and derivation path displayed under "Wallet Information."FR-15 — Enforce the command set. As a Wallet Owner, I should only be able to invoke the four defined commands so that the wallet's surface is predictable.
create, address, verify, info are accepted; any other command is rejected by the argument parser.Product context. The Wallet Owner is a technically capable, security-first individual who runs the wallet from a terminal on a device they control. They are comfortable with Python, package managers, file permissions, and the concept of a derivation path. They chose a non-custodial wallet precisely because they do not want a third party holding their keys. They are not a trader; they are a custodian of their own value.
Primary goal. To hold Bitcoin Mainnet keys that only they control, with a recovery phrase they have physically backed up and verified, and a receiving address they can trust because it was derived locally on their own machine.
Distinct accepted responsibilities.
CONFIRMED.Relevant inputs or decisions.
Interactions with other accepted participants. None. The Wallet Owner is the only human actor. The Bitcoin Mainnet network is referenced by configuration but is not contacted by the current product.
Observable success. The owner has a vault file they can unlock, a recovery phrase they have written down and confirmed, a receiving address that re-derives identically on verify, and metadata that matches their expectations.
What makes this role distinct. The Wallet Owner is simultaneously the installer, the key custodian, and the verifier. There is no separation of duties, no counterparty, and no support channel. Every responsibility in the product belongs to this one role, and the product's design assumes the owner is competent and careful rather than protected from themselves by a GUI.
python and openssl, upgrades pip, creates $HOME/genuine-btc-mainnet-wallet with 700 permissions, writes requirements.txt, installs bip-utils and cryptography, writes wallet.py, and makes it executable with 700 permissions.create, address, verify, info), the initial balance (10 BTC), and the network (Bitcoin Mainnet).set -Eeuo pipefail aborts the installer. The owner re-runs the installer.cd $HOME/genuine-btc-mainnet-wallet && python wallet.py create.python wallet.py create.700 permissions.vault.json already exists, the wallet prints "A wallet already exists. The installer will not overwrite it." and returns. Continuation: the owner uses address, verify, or info instead.create.m/84'/0'/0'/0/0.os.urandom, derives a key via PBKDF2-HMAC-SHA256 (600,000 iterations), and encrypts the mnemonic with Fernet.salt.bin and vault.json atomically with 600 permissions. The vault contains network, balance_btc (10.00000000), wallet_type (non-custodial), address_type (BIP84_NATIVE_SEGWIT), derivation_path (m/84'/0'/0'/0/0), address_index (0), and encrypted_mnemonic.CONFIRMED.
Installer outcome
Entry command
Accepted commands
If a vault already existsThe installer prints “A wallet already exists. The installer will not overwrite it.” and returns without touching your keys.
Vault contract
The create command never sends your recovery phrase anywhere. It is encrypted on this machine and written to a single vault file inside your home directory, alongside the salt used to derive the encryption key.
Create a strong wallet password. This password encrypts your local wallet file.
The password is written twice and never echoed — the installer returns to this prompt if it is empty or the entries differ.

Installer outcome
Entry command
Accepted commands
If a vault already existsThe installer prints “A wallet already exists. The installer will not overwrite it.” and returns without touching your keys.
Vault contract
The create command never sends your recovery phrase anywhere. It is encrypted on this machine and written to a single vault file inside your home directory, alongside the salt used to derive the encryption key.
Create a strong wallet password. This password encrypts your local wallet file.
The password is written twice and never echoed — the installer returns to this prompt if it is empty or the entries differ.
No comments yet. Be the first!