Add Backend
ahpxex/open-dashboard
Everything about the data layer — pick one of six ready-to-run backend templates (TanStack Start + Drizzle + better-auth, Hono + Drizzle + better-auth, Hono + Prisma + better-auth, Hono + Drizzle +…
The ZeroKMS key model — keysets, clients, client keys, and the grant/revoke lifecycle.
$ npx skills add cipherstash/stack --skill stash-zerokms -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install cipherstash/stack stash-zerokms --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/cipherstash/stack.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/stash-zerokms .claude/skills/stash-zerokms && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "stash-zerokms" agent skill from https://github.com/cipherstash/stack/tree/main/skills/stash-zerokms into .claude/skills/stash-zerokms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "stash-zerokms", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/cipherstash/stack/tree/main/skills/stash-zerokmsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add cipherstash/stack --skill stash-zerokms -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install cipherstash/stack stash-zerokms --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/cipherstash/stack.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/stash-zerokms .agents/skills/stash-zerokms && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "stash-zerokms" agent skill from https://github.com/cipherstash/stack/tree/main/skills/stash-zerokms into .agents/skills/stash-zerokms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "stash-zerokms", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add cipherstash/stack --skill stash-zerokms -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install cipherstash/stack stash-zerokms --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/cipherstash/stack.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/stash-zerokms .cursor/skills/stash-zerokms && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "stash-zerokms" agent skill from https://github.com/cipherstash/stack/tree/main/skills/stash-zerokms into .cursor/skills/stash-zerokms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "stash-zerokms", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/cipherstash/stack.git --path skills/stash-zerokms--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add cipherstash/stack --skill stash-zerokms -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install cipherstash/stack stash-zerokms --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/cipherstash/stack.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/stash-zerokms .gemini/skills/stash-zerokms && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "stash-zerokms" agent skill from https://github.com/cipherstash/stack/tree/main/skills/stash-zerokms into .gemini/skills/stash-zerokms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "stash-zerokms", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install cipherstash/stack stash-zerokmsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add cipherstash/stack --skill stash-zerokms -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/cipherstash/stack.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/stash-zerokms .github/skills/stash-zerokms && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "stash-zerokms" agent skill from https://github.com/cipherstash/stack/tree/main/skills/stash-zerokms into .github/skills/stash-zerokms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "stash-zerokms", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add cipherstash/stack --skill stash-zerokms -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install cipherstash/stack stash-zerokms --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/cipherstash/stack.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/stash-zerokms .opencode/skills/stash-zerokms && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "stash-zerokms" agent skill from https://github.com/cipherstash/stack/tree/main/skills/stash-zerokms into .opencode/skills/stash-zerokms/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "stash-zerokms", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
stash-zerokmsThe ZeroKMS key model — keysets, clients, client keys, and the grant/revoke lifecycle.
Stash Zerokms is an agent skill from cipherstash/stack. The ZeroKMS key model — keysets, clients, client keys, and the grant/revoke lifecycle. Covers the four-level key hierarchy, why every encrypt/decrypt/query is scoped to a keyset, the exact failure surface when a client lacks keyset access (unreachable keysets fail loudly; the one silent case is a reader granted the writer's keyset but bound to a different one — decrypt works, encrypted search returns zero rows), the workspace default keyset, multi-tenant isolation via config.keyset, and the ZeroKMS API for…
Its SKILL.md is about 4.4k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Backend & APIs, covering Multi-tenancy. It works with PostgreSQL, Prisma and Supabase. The repository describes itself as: Searchable, application-level encryption for building privacy-first apps. The licence is MIT.
2 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 3eb459b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).
From the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
dashboard.cipherstash.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
CS_CLIENT_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Stash Zerokms loads about 4.4k tokens when it runs. Until then it costs about 238 tokens; SKILL.md has 2,379 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from cipherstash/stack at commit 3eb459b, republished under its MIT licence (© cipherstash). 2,379 words, ~4,374 tokens.
.claude/skills/stash-zerokms/SKILL.md (or your agent's skills folder).ZeroKMS is the key service behind every CipherStash Stack operation. This
skill is the canonical description of its access model. Other skills
(stash-edge, stash-deployment, stash-cli, stash-postgres,
stash-supabase) touch credentials and keysets in passing; where their
wording and this skill disagree, this skill wins.
stash-auth)ZeroKMS accepts exactly one credential: a CipherStash service token — a
short-lived signed JWT minted by CTS, the CipherStash token service. Access
keys and IdP JWTs are never sent to ZeroKMS directly; they are exchanged at
CTS for a service token first. The auth strategies do this for you —
stash-auth is the canonical skill for that whole surface (strategies,
CS_* variables, token contents, failure codes).
ZeroKMS runs in a number of regions (the current list: stash auth regions,
or the table in stash-auth). Your workspace's region is part of its CRN
(crn:<region>.<provider>:<workspace-id>), and CTS resolves the matching
ZeroKMS endpoint and stamps it into the service token — the client discovers
where ZeroKMS is from the token itself. You never configure a ZeroKMS URL,
which is also why the CS_*_HOST override variables are debug-only and must
not appear in CI or examples.
Every value is encrypted under a keyset. A client (an application
credential with its own client key) is bound to one keyset — the one
named in its config (config.keyset) or, when omitted, its default keyset,
the one it was created against — and can additionally be granted access
to others. The routing is asymmetric, and everything below follows from it:
Two corollaries that follow directly, and that agents get wrong most often:
config.keyset), it's that keyset; when it doesn't, ZeroKMS
uses that client's default keyset — the keyset the client was bound to
when it was created. So two clients that both omit config.keyset only
interoperate if their default keysets are the same keyset.stash-indexing), the operand cast / predicate form
(stash-postgres). What can not cause it is the credential string —
every client bound to the same keyset derives the same index key. The
same-keyset rule therefore binds writers and query readers;
decrypt-only readers need just a grant.Four levels, each narrowing scope; no single component holds enough material to derive a data key alone.
| Level | Key | Held by | Purpose |
|---|---|---|---|
| 1 | Root key | HSM / hardware root of trust | Protects all downstream key material. Never exported. |
| 2 | Authority key (per keyset) | ZeroKMS | Derives key seeds for a keyset. Materialized per client grant, so every granted client resolves the same keyspace. |
| 3 | Client key (per client / device) | Application runtime only | Never transmitted to ZeroKMS. Multiple clients can share a keyset, each with its own key. |
| 4 | Data key (per value) | Derived in-process, ephemeral | Derived from client key + key seed during encrypt/decrypt. Never stored or transmitted. |
ZeroKMS uses proxy symmetric re-encryption: it sends key seeds, never usable keys, and the client combines a seed with its own client key to derive each per-value data key. Because the data key requires both halves:
A keyset is the isolation unit: data encrypted under one keyset can never be decrypted or queried with another keyset's keys. Every operation runs under the data's own keyset, and only clients granted that keyset can perform it. Keysets belong to a workspace.
_, -, /. The
name default is reserved (case-insensitively) for the workspace default
keyset. Descriptions are 1–256 characters.default, created automatically the first time it's needed. It cannot be
renamed or disabled. A client created without naming a keyset is bound to
it.default unless another was named). An operation that
doesn't specify a keyset resolves to the client's default keyset — not
automatically the workspace's. The two coincide when the client was
created without naming a keyset — as with the profile credentials in a
dev environment — which is why single-tenant apps that never mention
keysets still work. But a client created against tenant-a defaults to
tenant-a, and a client with no default at all (possible via the API)
gets 404 — "Client (…) has no default keyset" on any keyset-less
operation.403 — "Keyset disabled: request could not be processed because the keyset has been disabled". Re-enabling restores
access; no data is touched.A client is a credential identity in ZeroKMS: it has an id, a client key (generated at creation, returned once, held only by the application), and a set of keyset grants.
The device client is a special case worth knowing about: after
stash auth login, the CLI generates a device identity (a device
identifier and name, stored in the profile), provisions a client in ZeroKMS
named after the device — bound to the workspace default keyset, at most one
device client per device per workspace — and persists the resulting key to
~/.cipherstash/secretkey.json. That key is a standard client key; only
its encapsulation differs (a JSON profile file holding the client id and key
material, rather than the hex CS_CLIENT_KEY form a deployed app uses). It
is what makes local dev work with no environment variables: everything this
skill says about clients — the default keyset, grants, revocation — applies
to the device client like any other. The profile files are read only by the
CLI and the auth strategies; agents never read them directly (see
stash-auth).
Manage all of this in the
dashboard (the _
resolves to your selected workspace). The underlying ZeroKMS API, for
automation:
| Endpoint (POST) | Effect | Required scope |
|---|---|---|
/create-keyset | Create a keyset (optionally with a client in one call) | keyset:create (+ client:create if bundling a client) |
/list-keysets | List the workspace's keysets | keyset:list |
/modify-keyset, /enable-keyset, /disable-keyset | Rename/describe, re-enable, kill-switch | keyset:modify / keyset:enable / keyset:disable |
/create-client | Create a client bound to a keyset (default if unnamed) | client:create (+ keyset:grant when naming a keyset) |
/list-clients | List clients and their keyset grants (filterable by keyset) | client:list |
/grant-keyset | Grant an existing client access to a keyset (by name or UUID) | keyset:grant |
/revoke-keyset | Remove one client's access to one keyset | keyset:revoke |
/delete-client | Delete a client and all its grants | client:delete |
/list-clients is the check an agent can run to answer "does this client
have a grant for that keyset?" — it returns each client with the keyset ids
it can reach.
Scope strings in existing tokens may use the legacy dataset: prefix
(dataset:create, dataset:grant, …) — it is the same permission family as
keyset:; ZeroKMS accepts both spellings. Scopes are assigned by CTS when
the service token is minted, based on the credential's role — see
stash-auth.
const client = await Encryption({
schemas: [users],
config: {
keyset: { name: "tenant-a" }, // or { id: "<uuid>" }
},
})config.keyset → the client's default keyset (the keyset the
ZeroKMS client behind your CS_CLIENT_* credentials was created against —
the workspace default keyset if using the profile credentials in a dev
environment).@cipherstash/stack — the underlying Rust SDK accepts a per-call
keyset on decrypt, but the FFI does not expose it. Multi-tenant
applications create one Encryption() client per tenant.authStrategy and lock context: a keyset
isolates a whole keyspace (coarse, fixed per client); lock context binds
retrieval of an individual value's data key to a claim from the caller's
service token (fine-grained, per operation — see stash-auth). They
compose.stash login binds your device to the workspace's default keyset, which is
why CLI operations (stash encrypt backfill, dev-time tooling) work
without any keyset configuration.Keyset access and lock context are independent gates, and their failures look different. Do not diagnose one as the other.
Gate 1 — keyset access (client-level, wholesale). Checked first, on every request. No grant for the requested keyset means ZeroKMS cannot even locate key material for the client:
| Cause | ZeroKMS response | What the application sees |
|---|---|---|
| Client has no grant for the keyset (or keyset name/id doesn't exist in this workspace) | 404 — "Not Found: no record found with id=…" | Encryption() init fails (the per-keyset index key cannot be loaded); if a payload names an unreachable keyset, encrypt/decrypt return { failure } (EncryptionError / DecryptionError) |
| Keyset disabled | 403 — "Keyset disabled: …" | Same surface — init or operation failure, for every client of that keyset |
| Token missing scopes | 403 — "Not permitted" | Operation failure; fix the credential's scopes, not the grants |
Gate 2 — lock context / decryption policy (value-level, per identity).
Only reached when gate 1 passes. A value encrypted under a lock context has
its data key bound to a claim from the encrypting caller's service token; a
caller whose token doesn't carry the same claim is refused that value's
data key (403, surfaced as a { failure } on decrypt). Encrypting and
other values are unaffected, and every denial is recorded in the access
log. See stash-auth for the lock-context model and usage.
The practical tell: gate-1 failures are total (the client can do nothing under that keyset — encrypt, decrypt, and query all fail), gate-2 failures are selective (specific values, specific callers).
Encrypted operations failing with a ZeroKMS error? Check in this order — each step's failure explains everything after it:
CS_CLIENT_* / CS_WORKSPACE_CRN variables (see stash-edge for the
list). A keyset name resolves within a workspace — the same name in
another workspace is a different keyset./list-keysets. Typos in
config.keyset.name surface as the 404 above, not as a helpful "no such
keyset"./list-clients filtered by the
keyset, or the dashboard's keyset page. If no keyset is being specified,
check which keyset each client defaults to — a writer and a reader that
both omit config.keyset can still be on different keysets if their
clients were created against different ones.stash-indexing (is the extractor index there and used?) and
stash-postgres (is the operand cast/predicate form right?).stash-deployment covers where each environment's
credentials come from.config.keyset is the
safe form; if both sides omit it, each resolves to its own client's
default keyset, so verify the two clients were created against the same
keyset — same workspace is necessary but not sufficient. The credential
string itself may differ.© cipherstash, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/stash-zerokms of cipherstash/stack.
Open the folder on GitHubat commit 3eb459b
Stash Zerokms next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Stash Zerokms this skillcipherstash/stack | 157 | — | ~4.4k | Automated safety check: Pass | MIT | |
| Add Backendahpxex/open-dashboard | 146 | — | ~3.6k | Automated safety check: Pass | MIT | |
| Prisma 8 Contract-First ORMprisma/orm | 48k | — | ~3.8k | Automated safety check: Notes | Apache-2.0 | |
| Database Schema Designerborghei/Claude-Skills | 881 | — | ~1.7k | Automated safety check: Pass | MIT | |
| Database Schema DesignerOneWave-AI/claude-skills | 323 | — | ~1.6k | Automated safety check: Pass | MIT | |
| Supabase Development and Debuggingsupabase/agent-skills | 2.7k | 3 repos | ~3.6k | Automated safety check: Pass | MIT |
ahpxex/open-dashboard
Everything about the data layer — pick one of six ready-to-run backend templates (TanStack Start + Drizzle + better-auth, Hono + Drizzle + better-auth, Hono + Prisma + better-auth, Hono + Drizzle +…
prisma/orm
Routes Prisma 8 tasks such as contracts, migrations, queries and upgrades to the right reference files for projects on the contract-first @prisma/orm packages.
borghei/Claude-Skills
Design relational schemas from requirements with normalization, migrations, ERDs, RLS policies, and indexes for PostgreSQL, MySQL, and SQLite.
OneWave-AI/claude-skills
Designs relational and document database schemas from requirements or an existing app - tables and collections, keys, relationships, constraints, indexes driven by real query patterns, ERDs, and…
supabase/agent-skills
General Supabase skill for database, auth, Edge Functions, Realtime and storage work, plus client libraries, migrations, security audits, debugging and reading logs.
curvenote/curvenote
A skill your agent uses when doing ANY task involving Supabase.
cipherstash/stack
How an agent files a GitHub issue on cipherstash repos — required structure (Background / Problem / Proposal), dumbed-down wording rules, and pre-filing checks.
cipherstash/stack
How an agent authors branches, commits, and pull requests on cipherstash/stack — naming, signed commits, the changeset/skills/meta-file checklist, and PR body structure with dumbed-down wording.
cipherstash/stack
Deploy a CipherStash encryption rollout to a live environment without losing data — the multi-deploy ladder (schema-add + dual-write → backfill → read cutover → stop dual-writes → drop plaintext)…
cipherstash/stack
Supply-chain security controls for the @cipherstash/stack monorepo.
cipherstash/stack
Integrate CipherStash encryption with Drizzle ORM using @cipherstash/stack-drizzle (EQL v3).
cipherstash/stack
Run CipherStash encryption on edge and non-Node runtimes with the @cipherstash/stack/wasm-inline entry — Deno, Supabase Edge Functions, Cloudflare Workers, and Bun.
Works with
Categories
The ZeroKMS key model — keysets, clients, client keys, and the grant/revoke lifecycle. Stash Zerokms is an agent skill from cipherstash/stack. The ZeroKMS key model — keysets, clients, client keys, and the grant/revoke lifecycle.
Stash Zerokms fits situations like: query fails with a ZeroKMS error; planning multi-tenant key isolation; deciding which credentials a backfill job; edge function should use.
Run `npx skills add cipherstash/stack --skill stash-zerokms -a claude-code`. Or copy the skill folder (skills/stash-zerokms in cipherstash/stack) into .claude/skills/stash-zerokms in your project. Claude Code loads it when a task matches its description.
Run `npx skills add cipherstash/stack --skill stash-zerokms -a codex`. Or copy the skill folder (skills/stash-zerokms in cipherstash/stack) into .agents/skills/stash-zerokms in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add cipherstash/stack --skill stash-zerokms -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/stash-zerokms, .gemini/skills/stash-zerokms, .github/skills/stash-zerokms and .opencode/skills/stash-zerokms in your project.
Going by SKILL.md and its folder, Stash Zerokms needs credentials named CS_CLIENT_KEY. Our summary lists: A credential in CS_CLIENT_KEY.
SKILL.md names 1 domain. As links in the text: dashboard.cipherstash.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Stash Zerokms is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.4k tokens (SKILL.md is roughly 17k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Stash Zerokms: Add Backend (ahpxex/open-dashboard, 146 stars), Prisma 8 Contract-First ORM (prisma/orm, 48k stars), Database Schema Designer (borghei/Claude-Skills, 881 stars) and Database Schema Designer (OneWave-AI/claude-skills, 323 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
cipherstash (a GitHub organization) maintains it in cipherstash/stack, which has 157 GitHub stars. The repository holds 14 skills in this directory. The repository was last updated on October 8, 2026.
Source: cipherstash/stack on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.