| 1 | # Product |
| 2 | |
| 3 | <!-- impeccable:product-schema 1 --> |
| 4 | |
| 5 | π€ Product record for CONTRA. Confirmed with Paul, 2026-09-03. Everything |
| 6 | here is product truth, not visual direction β `AGENTS.md` holds the settled |
| 7 | decisions, `PROTOCOL.md` the cryptographic protocol, `DESIGN.md` the visual |
| 8 | system, `PLAN.md` what is built. |
| 9 | |
| 10 | ## Platform |
| 11 | |
| 12 | adaptive |
| 13 | |
| 14 | The web console is what exists today. `AGENTS.md` decision 6 fixes the build |
| 15 | order: rastrillo instance and client-shape web console first, then a native |
| 16 | Mac app as the *second* implementation of a settled contract, then the macOS |
| 17 | AutoFill Credential Provider extension, then iOS. Recorded as `adaptive` |
| 18 | because those native surfaces are the product, not ports of it β and because |
| 19 | the trust story differs by platform in a way design must not blur: the |
| 20 | at-rest promise holds everywhere, but "compromise the running server and |
| 21 | still get nothing" is only fully true where the code is signed and not |
| 22 | fetched per visit. |
| 23 | |
| 24 | ## Users |
| 25 | |
| 26 | Two primaries, weighted equally. Neither may be traded off for the other. |
| 27 | |
| 28 | - **A small team moving off a shared password manager.** Eleven is the first, |
| 29 | and its secrets move in as soon as CONTRA is ready β with shared vaults |
| 30 | working on day one, not as a later capability. Their situation: credentials |
| 31 | that several people genuinely need, on infrastructure they control, without |
| 32 | a multi-tenant operator holding anything that opens them. |
| 33 | - **A person leaving 1Password with their own vault.** Their job is getting |
| 34 | everything across without a support article, and then trusting a thing whose |
| 35 | recovery story is stricter than what they left. The `.1pux` file is opened, |
| 36 | parsed and sealed in their browser; it never reaches the server. |
| 37 | |
| 38 | An AI agent is a third, narrow actor rather than an audience: it may list a |
| 39 | vault, use a secret without receiving it, and add new secrets. It may not read |
| 40 | a value into its own context, and there is no setting that turns that on |
| 41 | (`AGENTS.md` decision 5). |
| 42 | |
| 43 | ## Product Purpose |
| 44 | |
| 45 | A password manager where the server knows nothing about you. Not "we promise |
| 46 | not to look" and not "we encrypt at rest": the instance holding a vault cannot |
| 47 | open it, cannot tell one account from another by content, and does not know |
| 48 | the account's email address. |
| 49 | |
| 50 | Success is that a stolen instance yields a pile of ciphertext and the times of |
| 51 | day somebody connected β and that a person who reads the trade-offs first |
| 52 | still chooses it. |
| 53 | |
| 54 | ## Positioning |
| 55 | |
| 56 | Built to **CARLOS A1, host-blind** β the strictest class the family |
| 57 | publishes. What a neighbouring product cannot truthfully copy without |
| 58 | rebuilding on the same terms: |
| 59 | |
| 60 | - **No content-derived identifiers at rest.** Item names, URLs, usernames, |
| 61 | folder structure and vault names seal exactly like passwords, because a name |
| 62 | is a secret too. All object identifiers are random, never content hashes: |
| 63 | a content-derived identifier is both an A1 violation and an equality oracle. |
| 64 | - **There is no way back in that we control.** No reset link, no support |
| 65 | override, no identity verification that restores a vault β because a server |
| 66 | that could give your vault back could give it to someone else. Every |
| 67 | competitor that can email you a way in has, by definition, a way in. |
| 68 | - **Sign-in is a signature, not a stored verifier.** The server holds only a |
| 69 | public key and authenticates by signed challenge, so a fully compromised |
| 70 | server holds something that cannot decrypt and cannot be replayed. |
| 71 | - **The honest trade-offs are on the front page**, not in a support article β |
| 72 | including the ones competitors omit: that removing somebody from a shared |
| 73 | vault cannot un-download what they already have, that the server learns |
| 74 | transport shape, and that a browser trusts the server to send honest code. |
| 75 | |
| 76 | ## Operating Context |
| 77 | |
| 78 | - **One instance per account**, on the owner's own deployment. A shared vault |
| 79 | lives on its owner's instance and other members are identities there. That |
| 80 | is what keeps membership an access-control list β transport shape β rather |
| 81 | than a content-derived identifier, and the distinction is load-bearing. |
| 82 | - **The Emergency Kit is paper.** Two printed documents, generated in the |
| 83 | browser at signup and never sent to the server: an **Account Key card** (a |
| 84 | new device asks for it once; useless without the passphrase) and a |
| 85 | **Recovery sheet** (the way back if the passphrase is forgotten; opens the |
| 86 | vault on its own, and nobody can reissue it). They are stored differently on |
| 87 | purpose β a drawer versus a safe β and the copy must keep saying so. |
| 88 | - **Getting onto a new device** is a three-rung ladder that must never |
| 89 | dead-end: a handoff from an already-enrolled device, scanning the card's QR, |
| 90 | or typing its code. Once a device holds the Account Key, the passphrase |
| 91 | alone unlocks it β the everyday case. |
| 92 | - **Migration is a file, not an integration.** 1Password `.1pux`, opened |
| 93 | client-side. Passkeys stored in 1Password cannot be exported by anyone, so |
| 94 | those are re-created by hand and the product must show which ones. |
| 95 | |
| 96 | ## Capabilities and Constraints |
| 97 | |
| 98 | - **Crypto is byte-identical across implementations**, pinned by shared golden |
| 99 | vectors generated by neither of them. Changing a pinned value is changing |
| 100 | the protocol. |
| 101 | - **Sealing happens where the keys are**, which makes a server-rendered vault |
| 102 | impossible rather than merely discouraged: the server has never seen a title |
| 103 | and could not render one. |
| 104 | - **A new storage surface lands with its canary or it does not land.** Canary |
| 105 | strings are pushed through every write path and the raw database bytes |
| 106 | searched for them. |
| 107 | - **Recovery, stated plainly:** lose the kit *and* the passphrase and the data |
| 108 | is gone. Lose the kit while a device is still enrolled and it reprints β the |
| 109 | Account Key card exactly, the recovery sheet only by regenerating, which |
| 110 | invalidates the old one. |
| 111 | - **Accepted residue**, published rather than hidden: the sharing graph (which |
| 112 | accounts share a vault, never what is in it), item count, per-item write |
| 113 | timing, and sign-in timing. |
| 114 | - **Money:** a genuine free rung, then β¬5/year. Cheap on purpose β a password |
| 115 | manager people cannot afford to keep is one that loses their data. Integer |
| 116 | cents; a float never touches an amount. |
| 117 | - **Terminology that must stay stable:** Account Key, recovery code, Emergency |
| 118 | Kit, vault, item, member, drop box, instance, handoff. |
| 119 | - **Explicitly undecided / not built:** Bitwarden and Apple Passwords |
| 120 | importers, passkey migration out of 1Password, cross-instance sharing |
| 121 | (federation β never in v1), breach monitoring, one-off sharing links, agent |
| 122 | mutation of an existing item. Each has a written trigger in `AGENTS.md`. |
| 123 | |
| 124 | ## Brand Commitments |
| 125 | |
| 126 | - **Name:** CONTRA. A CARLOS app. |
| 127 | - **Voice:** plain, specific, and unapologetic about consequences. It states |
| 128 | the cost of a decision in the same breath as the decision, and does not |
| 129 | soften a limitation into a feature. "That is the product, not a gap in it." |
| 130 | - **AI authorship is disclosed.** Machine-authored text carries π€ where it |
| 131 | surfaces; a person marker (π¨/π€/π§) certifies human text an LLM must not |
| 132 | rewrite, rephrase, condense or delete. AI features are opt-in, always |
| 133 | disclosed, and every path works with AI switched off. |
| 134 | - **No dark patterns around loss.** The product nags toward a second device |
| 135 | and a reprinted kit because both are real protection β never to manufacture |
| 136 | urgency. |
| 137 | |
| 138 | ## Evidence on Hand |
| 139 | |
| 140 | - **Pre-alpha. Nothing to sign up for yet.** There are no customers, no |
| 141 | testimonials, no press, no benchmarks and no pricing page in market. None |
| 142 | may be invented. |
| 143 | - Real artefacts that do exist: the deployed canary |
| 144 | (https://contra.bdj.oncarlos.com), the golden vectors |
| 145 | (`vectors/contra-v1.json`), `README.md`'s trade-offs section, `AGENTS.md`'s |
| 146 | nine settled decisions, `PROTOCOL.md`'s protocol and compromise matrix, and |
| 147 | `PLAN.md`'s built/not-built state with a trigger per deferral. |
| 148 | - The two kit documents are generated by the product itself |
| 149 | (`internal/contra/static/crypto/kit.js`) and are the only real "assets". |
| 150 | |
| 151 | ## Product Principles |
| 152 | |
| 153 | 1. **Say the cost where the promise is made.** Trade-offs belong on the front |
| 154 | page and beside the button, not in a support article. The recovery rule, |
| 155 | the sharing residue and the browser-trust boundary are stated in the copy |
| 156 | that precedes the action. |
| 157 | 2. **Never dead-end a person who still has a way through.** Every screen that |
| 158 | needs a key offers every rung that can work, and the last one always can. |
| 159 | 3. **The server is a hostile witness.** Design as though the instance is |
| 160 | already stolen: nothing it holds may name, rank, group or identify content. |
| 161 | 4. **Sealed by default, everywhere a name could hide.** If a person typed it, |
| 162 | it is a secret β titles, URLs, usernames, vault names included. |
| 163 | 5. **Paper is a feature, and it is asked for honestly.** The kit exists so |
| 164 | that a chosen passphrase cannot cap how safe a vault can be; the product |
| 165 | explains that rather than assuming compliance. |
| 166 | |
| 167 | ## Accessibility & Inclusion |
| 168 | |
| 169 | **WCAG 2.2 AA**, binding. |
| 170 | |
| 171 | Two places where that is more than a checklist and design must treat it as a |
| 172 | product constraint: |
| 173 | |
| 174 | - **The printed kit is an accessibility surface.** Contrast, type size and the |
| 175 | QR's quiet zone have to survive real paper and a phone camera, at the worst |
| 176 | moment somebody will ever use this product. |
| 177 | - **Recovery paths must not assume a mouse, a camera, or a steady hand.** The |
| 178 | device ladder's typing rung is the one that always works, and it self-heals |
| 179 | a single mistyped character rather than only rejecting it. |
| 180 | |