Contributing to CipherStash Stack
August 11, 2026 · View on GitHub
Thank you for your interest in contributing to the CipherStash Stack for TypeScript! This document walks you through the repository's structure, how to build and run the project locally, and how to make contributions effectively.
I want to report a bug, or make a feature request
Please use the GitHub issue tracker to report bugs, suggest features, or documentation improvements.
When filing an issue, please check existing open or recently closed issues to make sure somebody else hasn't already reported it. Please include as much information as you can.
Repository Structure
This is a Turborepo monorepo managed with pnpm workspaces:
.
├── packages/
│ ├── stack/ <-- Main package (@cipherstash/stack)
│ ├── cli/ <-- The `stash` CLI
│ └── ... <-- stack-drizzle, stack-supabase, stack-prisma, nextjs, migrate, wizard, ...
├── examples/ <-- Runnable example apps
├── e2e/ <-- Cross-package end-to-end tests
├── skills/ <-- Agent skills
├── .changeset/
└── package.json
See AGENTS.md for a detailed layout, key APIs, environment variables, and gotchas — it's written for coding agents but is the most complete developer reference in the repo.
packages/stack
@cipherstash/stack is the main package published to npm. It contains the encryption client and all integrations (Drizzle, Supabase, DynamoDB, secrets, identity). This is likely where you'll spend most of your time.
examples/ Directory
The examples/ directory contains applications demonstrating how to use @cipherstash/stack. They reference the local workspace packages, so you can verify your changes in a real application scenario.
Setup Instructions
Prerequisites
- Node.js >= 22
- pnpm (the version pinned in
package.json'spackageManagerfield) - CipherStash credentials if you want to run integration tests or examples (see AGENTS.md for the required environment variables)
1. Clone the Repo
git clone https://github.com/cipherstash/stack.git
cd stack
2. Install Dependencies
pnpm install
3. Build the Packages
pnpm run build
This triggers Turborepo's build pipeline, compiling each package in packages/* and linking them locally so the examples can reference them.
4. Run an Example App
Start the dev script, which watches for changes to the packages and is picked up by the example apps:
pnpm run dev
Then navigate to one of the examples in examples/ and follow its README.
Making Changes
-
Create a new branch from
main:git checkout -b feat/my-new-feature -
Implement your changes in the relevant package.
-
Write tests to cover any new functionality or bug fixes:
pnpm --filter <package-name> test -
Format and lint with Biome before pushing:
pnpm run code:fix -
Add a changeset if your change affects a published package's public behaviour (see below).
-
Sign your commits — every commit in a pull request must be signed (see below).
Signing Your Commits
All commits must be cryptographically signed. This is a hard requirement: pull requests containing unsigned commits will not be merged. Signing ties each commit to a verified identity, which matters for a repository whose packages ship as dependencies into other people's applications — an unsigned commit is an unattributable change in a supply chain.
GitHub shows a Verified badge next to signed commits. If a commit in your PR doesn't have one, it needs to be re-signed.
Set up signing
You can sign with SSH (simplest if you already push over SSH) or GPG.
SSH signing (Git >= 2.34):
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
Then add the same public key to your GitHub account as a Signing Key (Settings → SSH and GPG keys → New SSH key → key type "Signing Key"). A key registered only as an authentication key will not produce a Verified badge.
GPG signing:
gpg --full-generate-key # if you don't already have a key
gpg --list-secret-keys --keyid-format=long # copy the key ID
git config --global user.signingkey <KEY_ID>
git config --global commit.gpgsign true
Then export the public key (gpg --armor --export <KEY_ID>) and add it to GitHub
under Settings → SSH and GPG keys → New GPG key.
The email on your signing key must match the email in your Git config and be a verified email on your GitHub account, or GitHub will mark the commit Unverified rather than Verified.
Full instructions: GitHub — signing commits.
Fixing unsigned commits
If you've already pushed unsigned commits, sign them retroactively and force-push to your branch:
# Sign the last N commits (replace N with the number of commits in your PR)
git rebase --exec 'git commit --amend --no-edit -S' -i HEAD~N
# Or sign every commit on your branch relative to main
git rebase --exec 'git commit --amend --no-edit -S' main
git push --force-with-lease
Force-pushing rewrites history on your branch. Only do this on your own PR branch,
never on main, and check with the maintainers first if anyone else has based work
on your branch.
Publish Process (via Changesets)
We use Changesets to manage versioning and publication to npm.
- When you've completed a feature or bug fix, add a changeset using
pnpm changeset. - Follow the prompts to indicate the type of version bump (patch, minor, major).
- The GitHub Actions workflows handle the publish step to npm once your PR is merged and the changeset is committed to
main.
Releases are stable — Changesets is not in pre mode. Merging a changeset to
main opens (or updates) a "Version Packages" PR with plain semver versions, and
merging that PR publishes to npm under the latest dist-tag.
The stash / @cipherstash/stack / @cipherstash/stack-drizzle /
@cipherstash/stack-supabase / @cipherstash/stack-prisma / @cipherstash/wizard
packages are a fixed group in .changeset/config.json:
they always version together, so a bump to any one of them bumps all six.
Pre-release process
The 1.0 line published its 1.0.0-rc.* series through
changesets pre mode.
That mode is exited — do not re-enter it for ordinary work; a stable release
is the default.
If a future line genuinely needs a prerelease series:
- Run
pnpm changeset pre enter rc(this writes.changeset/pre.json) - Commit that file — from then on, every "Version Packages" PR produces
x.y.z-rc.Nversions and publishes under thercdist-tag - When the line is ready to go stable, run
pnpm changeset pre exitand commit the change. The nextchangeset versiongraduates every package to its final version, consumes the accumulated changesets intoCHANGELOG.md, and deletes.changeset/pre.json
Important
Pre mode retains every consumed changeset until exit, so its markdown is what
lands in the stable changelog — an entry that a later change made wrong stays
wrong until someone edits it. Review .changeset/*.md as a set before exiting.
This process can be dangerous, so please be careful when using it as it's difficult to undo mistakes. If you are unfamiliar with the process, please reach out to the maintainers for help.
Supply-Chain Rules
This repo applies supply-chain controls that CI enforces (see SECURITY.md). When contributing, keep in mind:
- CI uses
pnpm install --frozen-lockfile— don't drop the flag. - Adding to
pnpm.onlyBuiltDependenciesis an audit decision — vet the package and explain the addition in the PR. - Never commit auth tokens in
.npmrc— tokens belong in your user-level~/.npmrcor environment variables.
Additional Resources
- AGENTS.md — detailed developer/agent reference for this repo
- CipherStash documentation
- Turborepo Documentation
- Changesets Documentation
Security issue notifications
If you discover a potential security issue in this project, we ask that you contact us at security@cipherstash.com.
Please do not create a public GitHub issue. See SECURITY.md for our full security policy.
Code of Conduct
This project has adopted the Contributor Covenant. For more information see the Code of Conduct FAQ or contact support@cipherstash.com with any questions or comments.
Licensing
See the LICENSE file for our project's licensing.