Pass → Koder migration runbook

active

Pass → Koder migration runbook

Operational plan for retiring Koder Pass as a standalone product and folding its features into the Koder app, per id-app-RFC-001-stack-portal-consolidation.kmd Path B.

Scope

In scope Out of scope
Passtheproduct (mobile + desktop app) Passtheserver (lives on for the 90-day window)
Pass vault data (passwords, documents) Chromium extension migration (own thread — sees #006e)
End-user UX (export + import) Automated migration (RFC explicitly bans silent key movement)
90/180 day cadence Customer comms (forum / Slack — owner-driven)

Timeline

Day Event
*+0*(20260520) RFC-001 ratified, this runbook lands
*+0..D+30* #006a Vault engine surface; #009b Pass last-release modal+export
*+30..D+90* #006b-d Vault UI (passwords, documents, import) ships in Koder app
*+90*(20260818) Pass switches to read-only mode (Go server flag)
*+180*(20261116) Pass removed from app stores; repo stays as historical ref
*+360*(~20270515) services/foundation/pass/ archived

The 90180 cadence is conservative. Owner can compress to 3060 if install base is small (no public analytics; owner has the number).

Per-side checklist

Pass-side (last release)

  • [ ] One-time modal on app open: *"Pass is now part of Koder. Your

    data stays where you put it — to continue, open Koder."*

  • [ ] Settings → *xport to Koder*button.
    • [ ] Asks user to type a transit key (fresh passphrase, vault-only)
    • [ ] Bundles vault data + metadata into a single file
    • [ ] Encrypts the bundle with a key derived from the transit key

      (Argon2id with new salt; same KDF that Koder will use to decrypt)

    • [ ] Saves to platform storage with a clear filename:

      koder-pass-export-<YYYY-MM-DD>.kpex

  • [ ] D+90 read-only flag (Go server feature flag, single boolean):
    • [ ] All write endpoints return `409 Conflict {"error":

      "passreadonlymigrationwindow"}`

    • [ ] Reads continue normally
    • [ ] Modal copy switches to *"Pass is read-only since

      20260818 — finish your migration to Koder."*

  • [ ] D+180 store removal: pull from Play Store + App Store + the

    desktop release feed. Web download links 301 to koder.dev/migrate-from-pass.

Koder-side (this app)

  • [x] Help page reachable at koder://help/migrate-from-pass

    (ships with id-app#009 — lib/sections/help/pass_migration_page.dart)

  • [x] Vault section banner explains Pass absorption (ships with #006)
  • [ ] Import flow in Vault → Import → "From Koder Pass"

    (ships with #006d): picks file + asks for transit key, decrypts ondevice, reencrypts under Koder vault key, persists

  • [ ] Firstlaunch prompt in Vault (post#006): *"Coming from Koder

    Pass? Import your vault here."*

Cross-cutting

  • [x] This runbook
  • [ ] koder.dev/migrate-from-pass landing (cite this runbook, link

    to Help page deep link, show timeline)

  • [ ] Forum / Slack announcement on D+0 ratification
  • [ ] In-app announcement banner in the Pass app's home screen 2

    weeks before D+90

  • [ ] In-app announcement banner 2 weeks before D+180

Encryption / key handoff

*o silent migration of encryption material.*The export file is encrypted under a transit key the user types in Pass. The user types the same transit key in Koder to decrypt. Properties:

  • Transit key never leaves the user's head/notes — not stored by Pass,

    not transmitted, not in the export bundle's plaintext metadata.

  • If the device is taken, the export file alone is insufficient: the

    attacker would need to either bruteforce the Argon2idderived key or coerce the transit key from the user.

  • Different from "we'll just copy the vault key over" — that would be

    silent and would mean a stolen Pass DB grants Koder access too.

  • Different from "user signs in fresh and re-enters every credential"

    — that loses metadata (last-used, notes, document scans).

Argon2id parameters (same on both sides — pinned in #006a engine surface decision):

  • memory: 64 MiB
  • iterations: 3
  • parallelism: 4
  • salt: 16 bytes random per export bundle (in the bundle header)
  • output: 32 bytes (used as the symmetric key for XChaCha20-Poly1305

    vault bundle encryption)

Risk register

Risk Mitigation
Users miss the modal, vault becomes inaccessible at D+180 2week banner reminders preD+90 and preD+180; D+90 readonly mode preserves read access for an extra 90 days
Transit key typo: import fails Standard error UX; user re-exports from Pass with a memorable key
Passserver crashes during readonly window Same server we run today; no new failure mode
Chromium extension breaks at D+90 #006e ships before D+90 — extension switches its API base from pass.koder.dev to `id.koder.devv1me/vault

Source: ../home/koder/dev/koder/meta/docs/stack/runbooks/pass-to-koder-migration.kmd