Background
CipherStash Stack encrypts individual database columns. @cipherstash/stack-supabase is the Supabase integration: you wrap a Supabase client, and the wrapper encrypts values on the way in and decrypts them on the way out.
The package has two entry points:
| Entry point |
How it learns your columns |
Where it runs |
@cipherstash/stack-supabase |
Introspection — it opens a direct Postgres connection and reads the column types |
Node.js only |
@cipherstash/stack-supabase/wasm-inline |
You declare the tables yourself, in a schemas argument |
Edge runtimes: Deno, Supabase Edge Functions, Cloudflare Workers |
The second entry point exists because a Worker cannot open a raw Postgres socket, and cannot load a native module either. Declaring your tables is what removes the need to introspect; a WASM build of the encryption engine is what removes the native module.
We also ship Agent Skills. These are Markdown guides that travel inside the stash npm package. stash init copies them into the customer's own repository, under .claude/skills/ or .codex/skills/. The customer's coding agent then reads them as instructions. A wrong sentence in a skill becomes wrong guidance inside someone else's codebase.
Problem
The documentation still says the Worker entry point does not exist.
Before #912, there was one entry point, it always introspected, and it genuinely could not run in a Worker. The documentation said so, correctly.
#912 merged on 2026-08-19 and added the second entry point. The documentation was not updated. Three files still tell the reader that a Worker is impossible:
skills/stash-supabase/SKILL.md:269 — "so the factory cannot run in a Worker or the browser."
packages/stack-supabase/README.md:91 — "the factory cannot run in an edge Worker or the browser — construct it in your server-side code."
docs/reference/supabase-sdk.md:33-34 — the same sentence. Line 7 of that file also says "One entry point, EQL v3 only". There are two.
The skill contradicts itself. Line 29 of the same file says the opposite, and is correct:
encryptedSupabase can be constructed inside a Worker, but only from the @cipherstash/stack-supabase/wasm-inline entry and only with declared schemas.
Line 29 is the only mention of the wasm-inline entry in the entire skill. The setup section, which contains line 269, imports the package root and never points anywhere else. A reader who follows the setup steps never learns the second entry exists.
The README is worse: it contains zero occurrences of the word "wasm" in 134 lines. It documents one entry point for a package that ships two.
Who this hurts, and how
The skill ships to customers twice — inside the stash package and inside @cipherstash/wizard — and is then copied into the customer's repository. Their agent reads it as instruction, not as prose.
The population most affected is the one we least want to lose. Managed AI platforms — Lovable, v0, Bolt, Replit — run server code on an edge runtime. That is exactly the case the wasm-inline entry was built for, and exactly the case the skill tells an agent is impossible. We have a separate skill, stash-managed-platforms, whose whole job is to unblock those platforms.
The failure is quiet and total. An agent that reads "cannot run in a Worker" does not file a bug. It concludes the product does not support the platform and stops. Nobody hears about it.
The wrong sentence is already built
The stale line is compiled into the build output on disk:
packages/cli/dist/skills/stash-supabase/SKILL.md:269
packages/wizard/dist/skills/stash-supabase/SKILL.md:269
An npm pack from an un-rebuilt tree ships it.
Why nothing catches this
Nothing checks that the documentation agrees with the export map. Skills are Markdown — no type checker reads them, no test asserts their claims, and CI has no step that compares a runtime claim against package.json. The only signal is a human noticing that two paragraphs in one file disagree.
Proposal
- Fix
skills/stash-supabase/SKILL.md. Scope the sentence at line 269 to the package root entry. Say that introspection and the native module are what need Node, and that the wasm-inline entry has neither. Add the edge entry to the setup section, not only to the callout at line 29.
- Fix
packages/stack-supabase/README.md. Same correction, plus a section documenting the wasm-inline entry, because the README does not mention it at all today. This file renders on the npm package page.
- Fix
docs/reference/supabase-sdk.md, line 7 ("One entry point") and lines 33-34.
- Rebuild so
packages/cli/dist/skills/ and packages/wizard/dist/skills/ no longer carry the stale text.
- Add changesets: a
stash patch, because skills ship inside that package, and a @cipherstash/stack-supabase patch for the README.
- Optional, and cheap: add a test that fails when a shipping document claims a runtime the export map does not offer. This class of drift has now happened once and nothing would catch the second time.
Keep the browser half of every sentence. Only the Worker half is wrong. The browser claim is correct and is tracked by #804 — a workspace client key is required on every authentication path, so a browser build is not constructible today.
Do not edit the CHANGELOG files. packages/stack/CHANGELOG.md and packages/stack-supabase/CHANGELOG.md contain the same sentence, as does docs/superpowers/specs/2026-07-09-supabase-v3-introspection-design.md. They are historical records and were accurate when written. A search-and-replace must not sweep them up.
Verification
All line numbers checked against 0854bda0, the current tip of main.
$ git show origin/main:packages/stack-supabase/README.md | grep -c -i wasm
0
$ git grep -n "cannot run in a Worker" origin/main -- skills/
origin/main:skills/stash-supabase/SKILL.md:269:`DATABASE_URL`), so the factory cannot run in a Worker or the browser.
$ grep -n "cannot run in a Worker" packages/cli/dist/skills/stash-supabase/SKILL.md
269:`DATABASE_URL`), so the factory cannot run in a Worker or the browser.
$ grep -n "cannot run in a Worker" packages/wizard/dist/skills/stash-supabase/SKILL.md
269:`DATABASE_URL`), so the factory cannot run in a Worker or the browser.
The wasm-inline entry's own source comment already states the correct position, and that comment ships compiled into packages/stack-supabase/dist/wasm-inline.d.ts:
packages/stack-supabase/src/wasm-inline.ts:59-68 — "This entry cannot introspect at all, so schemas is required rather than optional. … This entry is ESM-only … and is server-side: it is not browser-safe (#804)."
So the source and the documentation disagree, and the source is right.
Relationship to other work
Background
CipherStash Stack encrypts individual database columns.
@cipherstash/stack-supabaseis the Supabase integration: you wrap a Supabase client, and the wrapper encrypts values on the way in and decrypts them on the way out.The package has two entry points:
@cipherstash/stack-supabase@cipherstash/stack-supabase/wasm-inlineschemasargumentThe second entry point exists because a Worker cannot open a raw Postgres socket, and cannot load a native module either. Declaring your tables is what removes the need to introspect; a WASM build of the encryption engine is what removes the native module.
We also ship Agent Skills. These are Markdown guides that travel inside the
stashnpm package.stash initcopies them into the customer's own repository, under.claude/skills/or.codex/skills/. The customer's coding agent then reads them as instructions. A wrong sentence in a skill becomes wrong guidance inside someone else's codebase.Problem
The documentation still says the Worker entry point does not exist.
Before #912, there was one entry point, it always introspected, and it genuinely could not run in a Worker. The documentation said so, correctly.
#912 merged on 2026-08-19 and added the second entry point. The documentation was not updated. Three files still tell the reader that a Worker is impossible:
skills/stash-supabase/SKILL.md:269— "so the factory cannot run in a Worker or the browser."packages/stack-supabase/README.md:91— "the factory cannot run in an edge Worker or the browser — construct it in your server-side code."docs/reference/supabase-sdk.md:33-34— the same sentence. Line 7 of that file also says "One entry point, EQL v3 only". There are two.The skill contradicts itself. Line 29 of the same file says the opposite, and is correct:
Line 29 is the only mention of the
wasm-inlineentry in the entire skill. The setup section, which contains line 269, imports the package root and never points anywhere else. A reader who follows the setup steps never learns the second entry exists.The README is worse: it contains zero occurrences of the word "wasm" in 134 lines. It documents one entry point for a package that ships two.
Who this hurts, and how
The skill ships to customers twice — inside the
stashpackage and inside@cipherstash/wizard— and is then copied into the customer's repository. Their agent reads it as instruction, not as prose.The population most affected is the one we least want to lose. Managed AI platforms — Lovable, v0, Bolt, Replit — run server code on an edge runtime. That is exactly the case the
wasm-inlineentry was built for, and exactly the case the skill tells an agent is impossible. We have a separate skill,stash-managed-platforms, whose whole job is to unblock those platforms.The failure is quiet and total. An agent that reads "cannot run in a Worker" does not file a bug. It concludes the product does not support the platform and stops. Nobody hears about it.
The wrong sentence is already built
The stale line is compiled into the build output on disk:
packages/cli/dist/skills/stash-supabase/SKILL.md:269packages/wizard/dist/skills/stash-supabase/SKILL.md:269An
npm packfrom an un-rebuilt tree ships it.Why nothing catches this
Nothing checks that the documentation agrees with the export map. Skills are Markdown — no type checker reads them, no test asserts their claims, and CI has no step that compares a runtime claim against
package.json. The only signal is a human noticing that two paragraphs in one file disagree.Proposal
skills/stash-supabase/SKILL.md. Scope the sentence at line 269 to the package root entry. Say that introspection and the native module are what need Node, and that thewasm-inlineentry has neither. Add the edge entry to the setup section, not only to the callout at line 29.packages/stack-supabase/README.md. Same correction, plus a section documenting thewasm-inlineentry, because the README does not mention it at all today. This file renders on the npm package page.docs/reference/supabase-sdk.md, line 7 ("One entry point") and lines 33-34.packages/cli/dist/skills/andpackages/wizard/dist/skills/no longer carry the stale text.stashpatch, because skills ship inside that package, and a@cipherstash/stack-supabasepatch for the README.Keep the browser half of every sentence. Only the Worker half is wrong. The browser claim is correct and is tracked by #804 — a workspace client key is required on every authentication path, so a browser build is not constructible today.
Do not edit the CHANGELOG files.
packages/stack/CHANGELOG.mdandpackages/stack-supabase/CHANGELOG.mdcontain the same sentence, as doesdocs/superpowers/specs/2026-07-09-supabase-v3-introspection-design.md. They are historical records and were accurate when written. A search-and-replace must not sweep them up.Verification
All line numbers checked against
0854bda0, the current tip ofmain.The
wasm-inlineentry's own source comment already states the correct position, and that comment ships compiled intopackages/stack-supabase/dist/wasm-inline.d.ts:So the source and the documentation disagree, and the source is right.
Relationship to other work
.withLockContext()on the WASM entry, which throws today. Any documentation of the edge entry has to say so, because silently dropping an identity claim would write values any keyset holder could decrypt.