docs: refresh root README around the three Stack pillars - #526
Conversation
🦋 Changeset detectedLatest commit: 9d5d891 The changes in this PR will be included in the next version bump. This PR includes changesets to release 12 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📝 WalkthroughWalkthroughThe README is substantially rewritten with expanded product documentation, examples, setup guidance, and links. Two planning documents add go-live verification criteria and specifications for architecture, type-safety, performance, and social-preview assets. ChangesREADME refresh
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
20e13ae to
88c9aec
Compare
* docs(stack-drizzle): conversion-focused README rewrite The package README documented mechanics without ever making the case. Rewritten along the lines of the root-README refresh in #526: a bold searchable-encryption lead, the zero-knowledge trust line up front, a ciphertext-queries example before any setup, a query-type table mapping the ops.* surface to the docs, an account-first quick start, a How-it-works section on EQL payloads and searchable terms, and reference-style links with UTM attribution (stack_drizzle_readme). The quickstart, indexing, and v2-legacy sections are retained. All API claims match the shipped surface (ops.matches/contains, not the doc-driven ilike forms from #526's root draft). No code changes. Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R * docs(stack-drizzle): open with the Why — threat model, searchable indexes, bounded trade-off Replaces the trust blockquote with the team's threat-model-first framing: who normally sees everything, per-value identity-derived keys with audited decryption, how queries still work (deterministic encryption / ORE / bloom filters over native Postgres indexes), and the explicit leakage boundary — equality and order relationships, nothing else; not FHE. Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
freshtonic
left a comment
There was a problem hiding this comment.
Request changes — direction and design are great; a few code-example claims are factually wrong against the current v3 API and should be corrected before this clears the go-live checklist.
I appreciate that this is deliberately doc-driven and gated behind docs/plans/readme-go-live-checklist.md with the in-file TODO before merge markers (relative image paths → restore absolute prefixes; placeholder doc links). This isn't a challenge to that staging approach — just flagging concrete inaccuracies I verified against source so they get folded into the checklist rather than shipping to the npm page:
- Node version. "Requirements: Node.js ≥ 18" contradicts
engines("node": ">=22"in both root andpackages/stack/package.json). Should be ≥ 22. types.Int4Ord. The v3 factory istypes.IntegerOrd(packages/stack/src/eql/v3/types.ts:119) — there is noInt4Ord. The SQL type name in the code path ispublic.eql_v3_integer_ord, noteql_v3.int4_ord; please verify the wholeeql_v3.text_match/text_eq/int4_ord/jsonSQL block against the actual EQL v3 domain names.- Prisma authoring type.
email cipherstash.EncryptedString()—EncryptedStringis an internal runtime envelope class, not aschema.prismaauthoring type. The authoring catalog iscipherstash.TextSearch()/text()/bigIntOrd()(packages/prisma-next/src/contract-authoring.ts). Looks like it should becipherstash.TextSearch(). config.strategy. The documented field isconfig.authStrategy;strategyis the deprecated alias (packages/stack/src/types.ts:164-171). PreferauthStrategyin the example.
Confirmed correct, for what it's worth: the Supabase encryptedSupabase({ ... }) usage is right for v3 (encryptedSupabase is now the v3 function; encryptedSupabaseV3 is the deprecated alias).
The architecture SVGs and overall structure look great.
@freshtonic FYI I've been holding off on finalising the readme until the changes settle. I'll re-request a review once that happens. |
- Lead with a searchable-encryption value prop and zero-knowledge trust line - Account-first quick start; show encrypt + search-without-decrypt + decrypt - Cover all three pillars early: searchable encryption, ORM integrations (Supabase/Drizzle/Prisma Next/DynamoDB), identity-aware encryption - Add a 'How it works' section linking the security architecture docs - Use reference-style links with all URLs centralised at the bottom (CipherStash links carry README UTM params) - Mark @cipherstash/protect (Protect.js) as legacy in its README - Spec the architecture diagram + type-safety GIF in docs/plans
Reflects the auth changes in #497: replace the deprecated LockContext.identify() ceremony with client-level OidcFederationStrategy + .withLockContext({ identityClaim }), which makes every OIDC provider (Clerk, Supabase, Auth0, Okta) first-class.
Add the four architecture SVG variants (desktop/mobile x light/dark) and embed them in the How it works section via a single <picture> element. Sources select on both prefers-color-scheme and max-width:600px; the desktop-light <img> is the universal fallback for npm and older renderers.
Temporary: switch the architecture <picture> srcset/src to relative paths so they render on the PR branch. Must be restored to absolute raw.githubusercontent.com/.../main/ URLs before merge (relative paths break on the npm package page). TODO noted inline and in the visual-assets spec.
- Lead with three short searchable-encryption examples (Supabase, Prisma Next, Drizzle) and a Quick starts table - EQL v3 framing: CREATE TABLE with domain types replaces per-column SEM config; auth gains device auth; keysets replace BYOK under Advanced features - Add performance table (benches-attributed), FAQ from the Supabase listing, and a Start free CTA; drop the Protect.js migration section - Spec a purpose-built flat-latency chart as Asset 3 in the visual assets plan
- Drizzle example uses the types namespace (types.TextMatch) instead of the SEM-style options object, matching the v3 authoring surface - Add docs/plans/readme-go-live-checklist.md consolidating every doc-driven claim to confirm before merging to main, referenced from a comment at the top of the README
Make the "only raw pg needs a client-side schema" claim concrete with an encryptedTable + types example mirroring the CREATE TABLE domain types above it; sharpen the matching go-live checklist item.
og:image via repo Settings → Social preview (1280×640 dark-brand card, export kept in-repo), About description doubling as og:description; add the upload/verify step to the go-live checklist.
Tighten the hero to a one-line tagline and open with a value-prop
section ("encryption-level security without the pain") backed by a
capability list. Move the ORM code samples below the advanced features
so the top of the page sells before it demonstrates, and relocate the
zero-knowledge callout next to the key-management section it supports.
Split the quick starts into the wizard path and the per-ORM guides.
Restore the raw.githubusercontent.com prefix on the architecture diagram sources, as the TODO required: relative paths render on GitHub but break on the npm package page, which has no repo context to resolve them against. The four SVGs land on main with this PR, so these URLs 404 until it merges — including in the PR preview. Also qualify the key-management bullet as "up to 14x faster", matching the claim already made in the Key management section.
The README was written doc-driven, ahead of the code. EQL v3 has since shipped with different names than the draft guessed, so every code example is now corrected against main: - SQL column domains live in public as eql_v3_text_match / eql_v3_text_eq / eql_v3_integer_ord / eql_v3_json_search (the eql_v3 schema holds only the query_* domains and functions) - types.IntegerOrd, not types.Int4Ord; client schema imports from @cipherstash/stack/v3 - config.authStrategy (config.strategy is deprecated) - Supabase: await encryptedSupabase(url, key) introspects the database; the sizzle filters with .eq() since matches() is unavailable through PostgREST on EQL 3.0.2 - Prisma Next: cipherstash.TextSearch() + db.orm.public.User with eqlMatch (package renamed to @cipherstash/stack-prisma) - Drizzle: types.TextSearch + ops.matches — no like/ilike on the v3 surface, by design - Keysets: scoped-operations framing from stash-zerokms; dropped the unshipped per-keyset region pinning and 'permanently unreadable' claims - Node.js >= 22 (matches engines); wasm-inline pointer in the install note The go-live checklist is updated to record what was verified, and its Linear issue references are removed (public repo). The packages/protect README banner was dropped during rebase — the package itself was removed from main.
0edbbd9 to
dddfb5b
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/plans/readme-visual-assets.md`:
- Line 38: Update the fenced ASCII diagram in the documentation to specify the
text language identifier, using a text-labeled fenced block instead of an
unlabeled one. Preserve the diagram content unchanged.
In `@README.md`:
- Line 46: Update the “ORM/database specific guides” heading to
“ORM/database-specific guides” by adding the hyphen between “database” and
“specific.”
- Around line 128-143: Update the “Built-in key management” claims in README.md,
including the repeated security callout, so automatic key rotation and universal
decryption audit logging are not presented as unconditional guarantees while
they remain unverified. Verify these capabilities against the go-live checklist
before retaining them; otherwise qualify or remove the affected bullets and
wording.
- Around line 377-381: Resolve the placeholder references query-equality,
query-match, query-range, and query-json in the README by verifying they point
to existing EQL v3 documentation pages and anchors; if those pages are
unavailable, remove the links and associated placeholder TODO rather than
leaving broken references.
- Around line 233-241: Update the Performance section in README.md and the
corresponding FAQ figures to avoid presenting unrefreshed EQL 2.3 benchmark
results as current: either rerun the benchmarks with EQL v3 and replace the
values, or explicitly label the existing figures as historical.
- Around line 164-167: Update the keyset guidance in the README so revoking a
keyset is described as temporarily making the tenant’s data inaccessible, not
permanently undecryptable. Preserve the reversible revocation behavior and
distinguish it from irreversible key deletion if deletion is mentioned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e9a83e06-510f-4e67-bb7a-00b5e170b079
⛔ Files ignored due to path filters (4)
docs/images/architecture-dark.svgis excluded by!**/*.svgdocs/images/architecture-light.svgis excluded by!**/*.svgdocs/images/architecture-stacked-dark.svgis excluded by!**/*.svgdocs/images/architecture-stacked-light.svgis excluded by!**/*.svg
📒 Files selected for processing (3)
README.mddocs/plans/readme-go-live-checklist.mddocs/plans/readme-visual-assets.md
The go-live checklist said the performance numbers came from the EQL 2.3 run and needed a v3 refresh — that was stale: cipherstash/benches' main report is now the EQL v3 run, and its per-family medians match the README table (equality ~0.12-0.14ms, ORE range ~0.5ms, JSON field eq ~0.1ms, flat 10k -> 10M). Label the README table as measured on EQL v3 and close the checklist item.
All docs-site URLs were checked against the published docs. The one correction: there is no standalone authentication page, so the [auth] reference now points at /docs/stack/cipherstash/encryption/identity. Drop the placeholder-links TODO and close the checklist item.
The @cipherstash/stack package README had drifted badly from the root README. A symlink was the obvious fix but npm cannot publish symlinks (npm-packlist drops them — verified: the tarball loses its README entirely), and GitHub doesn't render symlinked READMEs either. So: - packages/stack/README.md is a committed copy of the root README - the prebuild script re-copies it before every build, so any root README edit that goes through a stack build lands in the package - a unit test (readme-sync.test.ts) fails CI if the two files drift Root README relative links (examples, CONTRIBUTE, SECURITY, LICENSE) became absolute GitHub URLs: package.json's repository.directory makes npm resolve relative links against packages/stack/, where they 404.
- keysets: 'undecryptable' implied permanent destruction — grant revocation is reversible, so say unreadable until the grant is restored - hyphenate 'ORM/database-specific guides' - language tag on the ASCII-diagram fence in readme-visual-assets - re-sync packages/stack/README.md
…ma READMEs These ship on each package's npm page. stack-supabase was a 44-line stub; it's now a full README in the stack-drizzle style: the introspecting encryptedSupabase(url, key) factory, the encrypted filter surface, the EQL 3.0.2 PostgREST limitations, quick start, and how-it-works. stack-drizzle's hero example called ops.contains on a text column — contains is encrypted-JSONB containment (types.Json / ste_vec only, split from matches in #617) and would throw at runtime; the free-text operator is ops.matches. The operator table listed contains under free-text match too; fixed. stack-prisma claimed 'six encrypted column types' — the catalog is domain-named factories across text/integer/smallint/bigint/numeric/ real/double/date/timestamp/boolean/JSON. Also fixed the authentication docs URL (missing the /cipherstash/ segment) and replaced relative links, which 404 on npm because repository.directory scopes them to the package folder. All three gain the root README's badge header and the theme/viewport- responsive architecture diagram (absolute raw.githubusercontent URLs — they 404 until this PR's SVGs merge to main, same as the root README).
The v2 wrapper is long gone; the README doesn't need to re-litigate it. The encryptedSupabaseV3 deprecated-alias note moves into the wrapper section since it's current API surface, not v2 history.
freshtonic
left a comment
There was a problem hiding this comment.
Re-reviewed at head 9d5d891d (branch rebased onto current main since freshtonic's review), checking every prior thread against the current head and verifying each technical claim against the actual v3 code.
Approving. All of freshtonic's CHANGES_REQUESTED points and all of CodeRabbit's inline findings are resolved, and the refreshed examples are accurate.
freshtonic's 4 items — all resolved
- Node version → now "Node.js ≥ 22" (no "≥ 18" remains).
- SQL domains / factory → client schema uses the real
types.IntegerOrd; SQL block uses real storage domains (eql_v3_text_match/eql_v3_text_eq/eql_v3_integer_ord/eql_v3_json_search); noint4_ord/eql_v3.mis-qualification. - Prisma authoring type →
schema.prismanow usescipherstash.TextSearch();EncryptedStringappears only in its correct runtime-envelope use (EncryptedString.from(...)). config.strategy→ example usesconfig: { authStrategy: OidcFederationStrategy.create(...) }.
CodeRabbit inline threads — all addressed/withdrawn: benchmark now labelled "Measured on EQL v3" (verified against cipherstash/benches), key-management guarantees human-verified, keyset-revocation reworded to "unreadable until the grant is restored", placeholder query links resolved to real anchors, hyphenation + fenced-code-language fixes. FAQ perf figures are internally consistent with the Performance table.
Also verified: adapter READMEs are clean of removed v2 surface (.equality(), protectOps, createEncryptionOperatorsV3, encryptedColumn); the drizzle README fixes a real bug (ops.contains → ops.matches for free-text); supabase README uses encryptedSupabase(url, key) and correctly notes encryptedSupabaseV3 as a deprecated alias; all referenced prisma subpath exports and stash CLI commands resolve. The npm README-sync invariant holds (packages/stack/README.md byte-identical to root, guarded by readme-sync.test.ts). Changesets present for stack/stack-drizzle/stack-prisma/stack-supabase (patch) — appropriate since these READMEs ship in tarballs.
Non-blocking
- Nit: a
<!-- TODO: embed a purpose-built latency chart -->HTML comment still ships in the npm README (README.md:243and the mirror). Invisible when rendered and tracked as Asset 3 in the go-live checklist, but ideally stripped before publish. - Minor: the four query-reference links now point at real doc anchors, but I couldn't confirm those fragment anchors exist on the live site from here — worth a final click-through.
- Minor: the architecture-diagram
<img>URLs are absoluteraw.githubusercontent.com/.../main/...paths, so they only resolve after merge tomain(intentional/documented, but the branch can't fully preview the diagram).
Aside (not a blocker for this PR): the README correctly constructs the v3 client with Encryption({ schemas }) from @cipherstash/stack/v3 — on this branch that subpath re-exports Encryption as the v3 constructor and there is no exported EncryptionV3. So AGENTS.md's EncryptionV3 naming is the stale reference, not the README; worth fixing AGENTS.md separately.
Note: freshtonic's CHANGES_REQUESTED is stale (submitted against old commit 0edbbd9c) and will keep counting against the PR until they re-review or dismiss — my approve doesn't clear their block.
What
A conversion-focused rewrite of the root
README.md, benchmarked against 8 company-backed, high-star OSS READMEs (Supabase, Clerk, Infisical, Vault, Trigger.dev, Prisma, Drizzle, React Email).The README now:
npx stash initwizard first, then per-integration guides (Supabase / Prisma Next / Drizzle / rawpg/ DynamoDB).<picture>, four SVG variants underdocs/images/) and a link to the security architecture docs.?utm_source=github&utm_medium=stack_readme.Rebased onto current
main— examples re-verified (2026-07-30)The branch was originally doc-driven, written slightly ahead of the code. EQL v3 has since shipped with different names than the draft guessed, so every code example was re-verified against
main:eql_v3_text_match/eql_v3_text_eq/eql_v3_integer_ord/eql_v3_json_search(column domains live inpublic; theeql_v3schema holds thequery_*domains).types.IntegerOrd(noInt4Ord), imported from@cipherstash/stack/v3.config.authStrategywithOidcFederationStrategy.create(crn, () => getJwt())—config.strategyis deprecated.await encryptedSupabase(url, key)(introspects the database at connect time); the example filters with.eq()becausematches()is unavailable through PostgREST on EQL 3.0.2.cipherstash.TextSearch()+db.orm.public.User.where((u) => u.email.eqlMatch(...))— package renamed to@cipherstash/stack-prisma.types.TextSearch+ops.matches— nolike/ilikeon the v3 surface, by design.skills/stash-zerokms; dropped the unshipped per-keyset region-pinning claim.engines); install note points edge/serverless users at@cipherstash/stack/wasm-inline.Dropped during rebase: the
packages/protect/README.mdlegacy banner — the package itself was removed frommain(#772), so there is nothing to banner.docs/plans/readme-go-live-checklist.mdrecords exactly what was verified and what remains.Remaining before merge (tracked in the go-live checklist)
Verify the docs-site URLs— all links checked against the published docs;[auth]now points at the identity page (there is no standalone authentication page).Refresh the performance numbers on an EQL v3 benches run— verified: the benches main report is the EQL v3 run and its medians match the README table (labelled "Measured on EQL v3"). Still open: embed the flat-latency chart (Asset 3).raw.githubusercontent.com/.../main/...), so they 404 on this branch and resolve on merge — check the rendered branch README for everything except the diagram.Also in this PR: adapter README refresh + npm README sync
packages/stack/README.mdis now a synced copy of the root README (npm can't publish symlinks): theprebuildscript re-copies it and a unit test fails CI on drift.stack-supabaseREADME: full rewrite (was a 44-line stub) — introspecting factory, encrypted filter surface, EQL 3.0.2 PostgREST limitations, quick start.stack-drizzleREADME: fixed a real bug — the hero example usedops.containson a text column (JSON-only containment; would throw). Free-text isops.matches.stack-prismaREADME: corrected the column-type catalog, the auth docs URL, and relative links that 404 on npm.Notes for reviewers
cipherstash.comlinks) matches what analytics expects — they're all in one block.