skills: document the managed AI platform path (Lovable, v0, Bolt, Replit) - #909
skills: document the managed AI platform path (Lovable, v0, Bolt, Replit)#909coderdan wants to merge 1 commit into
Conversation
Lovable, v0, Bolt and Replit share a shape -- no shell the developer controls, an edge/Workers runtime, a database role that is not `postgres`, and schema changes only through the platform's own migration tool -- and each of those changes the setup. Nothing covered it. The costly fact goes first, because it decides whether anyone gets further: use `@cipherstash/stack` with the `wasm-inline` entry. `@cipherstash/protect` is the deprecated predecessor, and reasoning from its `-ffi` dependency to "CipherStash cannot run on an edge runtime" is a wrong conclusion drawn from the wrong package -- it cost an agent a full turn on a real project before it found `stash`. The same correction now sits in `stash-edge`'s entry table, where an agent comparing runtimes will hit it. The rest: headless `auth login --json` in an ephemeral sandbox (the CLI can authenticate there, which the reporter did not know and worked around by fetching a raw .sql release asset), minting `CS_*` with `stash env`, installing EQL as a non-`postgres` role or generating a migration instead, which predicates survive PostgREST, and why `encryptedSupabase` cannot be constructed in a Worker. Two things lifted above the fold in `stash-supabase`: a pointer to the new skill, and a one-line PostgREST summary. The full treatment was correct but ~500 lines down, which is not where a time-pressured agent finds it. Registered for `supabase` and `postgresql` in both the CLI and wizard skill maps, in SKILL_PURPOSES, and in the AGENTS.md inventory and routing table. Claude-Session: https://claude.ai/code/session_01AwM5Cm5ddasXozb6stxPR1
🦋 Changeset detectedLatest commit: 4a4b7bd The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 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 |
freshtonic
left a comment
There was a problem hiding this comment.
Approve. The skill earns its place: the four-property platform shape is a real category the existing skills didn't cover as a combination, and leading with the @cipherstash/protect correction — the inference that cost an agent a full turn — is the right editorial call. CI green.
What I verified:
- Every CLI fact the skill states resolves against the registry on this branch:
stash impl --target lovable(the target list includeslovable),stash auth regions --json,stash eql verify, theauthorization_requiredfirst-event andregion_requirednon-TTY exit forauth login --json, andSTASH_REGIONas the flag fallback — all present and matching the tests that pin them. That matters more than usual here because this file ships into customer repos and describes behaviour, not code the reader can check. - All four registration sites are in the diff (CLI
SKILL_MAPsupabase + postgresql, wizard's mirrored map,SKILL_PURPOSES, and both AGENTS.md tables), and the existing SKILL_MAP resolution test now covers the new entry on both integrations, so a rename that misses a map fails CI. - The skill is a single self-sufficient
SKILL.mdwith no sibling files — correct for thereadBundledSkillinlining path, where split content is silently dropped. - Content is consistent with the stack it sits on: the "Optional SQL — requires postgres" framing and heal-on-rerun match #902's final shape, the
ORE operator class: not creatable → types.*Ordguidance matches #907, the capability-matrix pointer matches #908, and the PostgREST table agrees with thestash-supabaseabove-the-fold summary added in the same PR. Thepg_has_roleguard claim about generated migrations is accurate. - Changeset present (
stashpatch); the AGENTS.md skills inventory and routing table are updated per the repo's keep-the-meta-files-honest rule.
On the flagged-not-fixed item — stash-dynamodb and stash-supply-chain-security sitting in no SKILL_MAP with no test noticing — I agree with flagging rather than guessing. For what it's worth, both look deliberate (stash-dynamodb's integration isn't an init path, and supply-chain is a repo-internal guide), so if a guard is added later it probably wants an explicit allowlist of unmapped skills rather than a blanket converse rule.
Fixes #893. Stacked on #908 (→ #907 → #906) — this PR's diff is the last commit only.
The gap
A Lovable agent implemented CipherStash end-to-end and reported what it had to work out for itself. Most of it applies to every managed AI app platform — Lovable, v0, Bolt, Replit — because they share a shape: no shell the developer controls, an edge/Workers runtime, a database role that is not
postgres, and schema changes only through the platform's own migration tool. Each of those changes the setup, and nothing in the skills covered the combination.Its most expensive discovery, in its own words:
It found
@cipherstash/protect, inferred "native Rust addon, won't run on Workers" from the-ffidependency name, and concluded the product was unusable. That is a wrong conclusion drawn from the wrong package — and a near-miss we should not rely on the next agent surviving.New skill:
stash-managed-platformsThat correction is the first thing on the page, before any setup content, because it decides whether anyone gets further: use
@cipherstash/stackwith the@cipherstash/stack/wasm-inlineentry;@cipherstash/protectis the deprecated predecessor and its native module will not load there.The rest, in the order an implementer needs it:
stash auth login --json --region <slug>runs the device flow with the verification URL as the first NDJSON event, opens no browser, and writes to~/.cipherstash— which exists fine in an ephemeral sandbox. The reporter did not know this and reached for a raw EQL.sqlrelease asset on the assumption the CLI could not authenticate; once it confirmed--jsonworked, the CLI was the better path throughout. Written with the three things that actually bite:--regionis required in a non-TTY, the command blocks while polling (~900 s — run it backgrounded, it is not hung), and you must authenticate beforestash init.stash env --name <x> --write—--namerequired non-interactively, mode 0600, existing file refused rather than overwritten, secrets shown once. The reporter called this part "flawless and worth codifying"; recording it matters because we had it flagged internally as a suspected blocker and it is not one.postgres. The install completes; only three optional owner-scoped statements are skipped.stash eql preflight --jsonbefore touching anything, and two of its answers change what you write next —ORE operator class: not creatablemeanstypes.*Ordnot*OrdOre(eql: detect the ORE-unavailable case at install time, and name a remedy that exists #907), and a relocatedpgcryptoaborts the bundle for any role.stash eql migration --supabase/--drizzle, which on a Supabase-backed platform is the only durable option sincesupabase db resetdiscards a direct install. The generated migration'spg_has_roleguard is what makes it apply cleanly under whatever role the platform's runner uses.encryptedSupabasecannot be constructed in a Worker (Supabase v3: encryptedSupabaseV3 requires a Postgres connection, so it cannot run in Workers or the browser #708) — it introspects the database, so it needs a Postgres connection. Stated as a property of the wrapper, with the two supported shapes, so nobody debugs it as a config mistake.Plus an "order of operations" list, since the constraint that actually hurts on these platforms is sequencing rather than any individual step.
Changes to existing skills
stash-edgegains the@cipherstash/protectcorrection directly under its runtime-entry table — that table is where an agent goes to decide "what do I import here", so it is where the wrong inference gets made. (Agent-verified: the deprecated-predecessor language existed only instash-drizzle, about a different package.)stash-supabasegains two above-the-fold callouts: a pointer to the new skill, and a one-line summary of what does and does not survive PostgREST. The existing treatment is correct but ~500 lines down, which is not where a time-pressured agent finds it — the issue's point 5.Registration
A new skill directory ships automatically (
tsupcopiesskills/recursively) but is not installed anywhere until it is named in the maps. All four sites:packages/cli/src/commands/init/lib/install-skills.ts—SKILL_MAP.supabaseand.postgresqlpackages/wizard/src/lib/install-skills.ts— the mirrored map (supabase,generic)packages/cli/src/commands/init/lib/setup-prompt.ts—SKILL_PURPOSES, else it renders as "(no description)"AGENTS.md— theskills/*inventory and the package→skill routing tableThose two integrations because the hosted AI builders are either Supabase-backed (Lovable) or reach a plain Postgres (v0, Bolt, Replit); Drizzle and Prisma Next projects are not built this way.
Worth knowing while reviewing: nothing enforces the converse —
stash-dynamodbandstash-supply-chain-securitysit inskills/registered in noSKILL_MAPat all, and no test notices. I have not added a guard, because I would be encoding a guess about whether those two are deliberate. Flagging it rather than fixing it silently.Verification
stash(1334),@cipherstash/wizard(366) and@cipherstash/stack(1050) suites green; Biome clean. Built the CLI and confirmeddist/skills/stash-managed-platforms/SKILL.mdships — and the existingSKILL_MAPtest (every listed skill must resolve to a bundledSKILL.md) now covers the new entry on both integrations, so a rename that missed the maps fails.https://claude.ai/code/session_01AwM5Cm5ddasXozb6stxPR1