Build 1Password

KINDAreplaces $2.99/mosaves $35.88/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A KDBX 4 vault created and driven through KeePassXC and its command line, with a fast search and entry workflow of your own, honest entropy reporting on generated secrets, TOTP codes, and encrypted sync over a cloud drive with conflict detection that does not silently lose an edit.

estimated effort multi-daythe files for this build are in the project pack

Vault formatKDBX 4 with the Argon2id key derivation functionVault engineKeePassXC and keepassxc-cliYour layerPython 3.12 with a small command line and a Textual terminal interfaceSyncAny file-sync drive you already have, holding the encrypted .kdbxAutofillKeePassXC-Browser, the official extension

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why It is the vault engine. Every cryptographic operation in this build happens inside it.

    Get it Download from keepassxc.org, or install with brew install --cask keepassxc, or your Linux package manager. On some distributions the command line tool is a separate keepassxc-cli package. open ↗

    Verify keepassxc-cli --version prints a version

  2. installfree

    Why Runs your search, generation and sync layer.

    Get it Install from python.org or with your package manager, then create a virtual environment in the project folder. open ↗

    Verify python3 --version prints 3.12 or higher

  3. decidefree

    Why It is the only thing standing between a stolen vault file and every account you own, and there is no reset.

    Get it Generate a passphrase of at least five words from a large word list and commit it to memory before you put anything real in the vault. Write it on paper and store that somewhere physical until you are sure.

    Verify You can type it from memory three days running

  4. decidevaries, and free is possible with an external drive you already own

    Why Sync propagates a corrupted or emptied vault as eagerly as a good one. A second, separate copy is what makes recovery possible.

    Get it An external drive, a second cloud account, or an encrypted archive somewhere else. Decide before Phase 5, because sync makes mistakes travel fast.

  5. installfree

    Why Product phase only. Autofill and passkeys both live in the extension, not in the command line.

    Get it Install from your browser's extension store, then enable browser integration in KeePassXC settings for that specific browser. open ↗

    Verify The extension connects and shows the database name

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- The vault itself is a single .kdbx file. It is the only durable state and it is encrypted at rest.
- Groups and entries live inside the vault: title, username, password, url, notes, TOTP seed, tags.
- index.json (local, unencrypted, derived) · title, username, url and tags only, never a secret, rebuilt on unlock to make search instant
- sync_state.json · last known file hash, last sync time, and the path of any conflict copy
- Never write a decrypted secret to disk. The index exists precisely because it holds nothing worth stealing.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
VAULT_PATHrequired~/Sync/vault.kdbxThe .kdbx file. Put it inside the folder your sync tool watches.
VAULT_KEYFILEsecretoptional~/.config/vault/vault.keyOptional second factor for the vault. If you use one, it must never travel in the same sync folder as the vault.
INDEX_PATHrequired~/.cache/vault/index.jsonThe secret-free search index. Safe to delete; it rebuilds on unlock.
CLIPBOARD_CLEAR_SECONDSrequired20How long a copied secret stays on the clipboard. Chosen by you.
BACKUP_DIRrequired/Volumes/Backup/vaultWhere dated vault copies are written. Deliberately not inside the sync folder.

The build, in order

  1. A vault with the right parameters

    A KDBX 4 vault exists, uses Argon2id, and you have proved it does rather than assumed it.

    1. The command line tool ships with the desktop application on macOS and Windows and is often a separate package on Linux. Confirm it before building anything on top of it.

      terminal
      keepassxc-cli --version
    2. Create the database, then set the key derivation function and parameters rather than accepting whatever the version default is. Higher memory costs you a second on unlock and costs an attacker far more.

      Files vault.kdbx

      terminal
      keepassxc-cli db-create vault.kdbx --set-password
      keepassxc-cli db-info vault.kdbx
    3. A short script that runs db-info and asserts the format is KDBX 4 and the KDF is Argon2id, exiting non-zero otherwise. Run it in your test suite so a future migration cannot quietly downgrade you.

      Files scripts/verify_vault.py

    done when · tick each as it passes
    watch out
    • A vault created by an old tool may still be KDBX 3.1 with AES-KDF, which is much cheaper to attack, and nothing in the interface shouts about it. Check the format explicitly rather than trusting the default of whatever created the file.
  2. Entries and instant search

    Finding and copying a credential is faster than opening a browser, and the search index never holds a secret.

    1. One module that shells out for show, add, edit and rm, passing the password on stdin and never as an argument, because arguments are visible in the process list.

      Files vault.py

    2. Enumerate entries and write index.json with title, username, url and tags. Add a test that asserts no field of a seeded entry's password appears anywhere in the file.

      Files index.pytests/test_index.py

    3. Copy the secret, then clear the clipboard after a set number of seconds, but only if the clipboard still holds what you put there. Clearing unconditionally destroys whatever the user copied in between.

      Files clip.py

    done when · tick each as it passes
    watch out
    • Putting the password in the index to make search feel snappier turns a plaintext file into the weakest link in a chain whose whole point was strength. If you catch yourself doing it for performance, measure first: the index without secrets is already fast.
  3. Generation with honest entropy

    Every generated secret comes with a number saying how strong it is, and the number is right.

    1. Python's secrets module, not random. The random module is seeded predictably and is documented as unsuitable for security purposes.

      Files generate.py

    2. Bundle a diceware style list and record its exact length. Entropy is words multiplied by the base two logarithm of the list length.

      Files wordlist.txtgenerate.py

    3. Print bits next to every generated secret, and refuse to generate below a floor you choose, explaining why rather than silently upgrading.

      Files cli.py

    done when · tick each as it passes
    watch out
    • Entropy comes from the process that generated the secret, not from the string itself. A passphrase drawn from a 7776 word list at four words is about 51.7 bits whatever the words turn out to be, and a strength meter that scores the resulting string instead will confidently disagree. Compute from the generator's own parameters.
  4. TOTP

    Six digit codes match what your phone shows, including across a clock that is slightly wrong.

    1. KDBX has a dedicated attribute for this and KeePassXC and its browser extension both read it. Putting the seed in notes works only in your own tool.

      Files vault.py

    2. Extract secret, period, digits and algorithm. Default to thirty seconds and six digits only when the URL does not say otherwise.

      Files totp.py

    3. Use a published test seed and timestamp, assert the expected code, and keep that as a test so a refactor cannot break code generation silently.

      Files tests/test_totp.py

    done when · tick each as it passes
    watch out
    • Not every issuer uses thirty second periods and six digits, and the parameters ride in the otpauth URL rather than in the seed. Parse the URL and honour period, digits and algorithm, or you will produce confidently wrong codes for a minority of services and never work out why.
  5. Sync with conflict detection

    Two machines can edit the vault and you will be told when that happened, instead of losing one side quietly.

    1. Hash the whole file. Store it with a timestamp in sync_state.json immediately after a successful write.

      Files sync.py

    2. Re-hash the file on disk and compare to the recorded hash. A mismatch means a remote write landed and you must not overwrite it.

      Files sync.py

    3. keepassxc-cli merge understands entry history and timestamps. Your own merge would not.

      terminal
      keepassxc-cli merge vault.kdbx vault-conflict.kdbx
    done when · tick each as it passes
    watch out
    • File sync services resolve simultaneous edits by picking one file and, at best, leaving the other beside it with a renamed copy nobody looks at. The whole point of this phase is to notice before that happens. Hash before you write, every time, with no fast path that skips the check.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more security.