Privacy
What BashNotes stores, where it lives, who can see it, and how to get it back out. It is short because there is not much of it.
Last updated Terms
What this is
BashNotes is a private library of commands, prompts, paths and URLs — private in what it holds, not in who may arrive: anyone can create an account by signing in with an email address their identity provider has verified.
This page says what the deploy holds about you, because “it’s only us” is not a policy — it is an assumption about who will still be running the deploy in a year, and it stopped being only us the day sign-up opened.
What it holds
Three things, and they are worth keeping apart.
- What you file. Every note you save — its title, the command or prompt or path itself, your description of it, the steps of a recipe, the parts you annotated, your projects, your environments and the values you put in them. It is stored verbatim, exactly as you typed it. It is read to show it back to you and to match your searches, and for nothing else.
- Who you are. An email address, a name if the identity provider gave one, the identifier that provider knows you by, and which library the account holds. That row is written the first time you sign in. No password is set here and none is stored here — signing in happens on the provider’s own page, and what comes back is those few fields.
- What you did. Each row carries when it was created and when it was last changed. A note also carries the time it was last copied — one timestamp, overwritten each time, so the command palette can open on the thing you reached for last. It keeps no history, it is not aggregated, and nothing else is derived from it.
What it does not hold
No analytics. No tracking pixels, no session recording, no advertising, no third-party scripts of any kind. Nothing is sold or shared for marketing, and there is nobody to sell it to.
The pages make no third-party requests at all. Even the fonts are served from this deploy — they are downloaded once at build time and bundled — so reading this page does not tell Google, or anyone else, that you read it.
The single exception is signing in, which is a trip to the identity provider’s own page and back. That is what the provider is for, and it is set out under Where it lives below.
Secrets, and the one rule
BashNotes is built to hold the pointer to a credential — the vault path, the aws secretsmanager get-secret-value line, the name of the environment variable — and never the credential itself. When something you are typing looks like a key, the app tells you so.
That warning does not block the save, on purpose: a check that refuses has to be right every time, and this one cannot be. So the consequence is yours to know about.
Who can see it
You, and nobody else. Your library is not shared with another account, and no other account’s library is reachable from yours. There is nobody to add, nobody to remove and no setting that changes this.
It is enforced twice rather than promised once. Every read and every write is filtered by the library named on your session, which is re-checked against the database on the request rather than trusted from the cookie — so access being withdrawn takes effect on the very next click rather than whenever a cookie expires. Postgres then applies the same rule again underneath, in policies that fail closed: with no library set, nothing matches at all.
One honest note about the future, since the structure for it exists under the surface: if a library is ever shared with somebody, it would be shared whole. A row records who filed it, and that record has never restricted who may read or change it — a shared library where half the entries are invisible is not a shared library. Nothing is shared today and the app offers no way to share it, and this page would say otherwise before that changed.
The operator of the deploy can reach the database directly, as the operator of any system can. Nobody else has been given a way in.
Where it lives
The database is Postgres, hosted by Neon in the United States (Ohio). The application runs on Cloudflare Workers, deliberately placed in the same region so that pages are quick. If you are reading this from outside the United States, that is where your data is.
Signing in is handled by WorkOS, on a page of theirs rather than one of ours. They hold the credential — the password you set with them, or the Google account you used — and this app never sees it. What comes back afterwards is your email address, your name if there is one, and an identifier. If you sign in with Google, then Google knows you signed in somewhere, as it would for any site you use it on.
Those three companies process the data in the course of running the thing. There is no fourth, and nothing is charged for — the day that changes, a payment processor becomes one, and this paragraph is where it gets named, before the first payment rather than after it. Cloudflare also keeps request logs for the deploy — the ordinary sort: the time, the path, the status, and the network the request came from — held for as long as Cloudflare holds them and used for working out why something broke.
One thing is kept in our own database rather than Cloudflare’s, and it is the only network address this app stores itself: when somebody signs in or creates an account, the network the attempt came from is recorded against a counter, so that a single network cannot make unlimited accounts or spend unlimited sign-in attempts. It is stored for the sign-in routes only — no other page records anything about where a request came from — it is never linked to your account or to anything you have filed, and it is deleted within a day. It is the smallest amount of this we could work out how to keep and still refuse a flood.
How long it is kept
What you file stays until you delete it. Deleting a note takes its steps and its annotations with it, and deleting is immediate and final: there is no undo and no recycle bin.
The session cookie expires after 30 days. The sign-in counters described above are deleted within a day of the attempt they counted. Request logs age out on Cloudflare’s own schedule.
Getting it out, and getting it deleted
Export is on the Account settings page, reachable from the nav on every screen, because “can I get my things out?” is a question people ask before they put anything in. It hands back the whole library immediately as JSON, or as Markdown you can actually read. No request, no queue, no waiting.
Deleting is the same in miniature: any note, project or environment can be deleted from the app, and so can the account — on the Account settings page, by you, immediately. No request, no queue, nobody’s approval. The rows go: the account, your library, and every note, project, environment and variable in it, permanently and with nothing kept back in a “deleted” state. It is not reversible, so the page offers you an export first and asks you to type your address.
Two things about that are worth stating plainly. Deleting your account here does not delete your account at the sign-in provider — that is theirs, not ours, and their own settings are where it goes. And what survives on this side is one line in an internal log recording that an account with your address was deleted, when, and how much went with it — that record is the reason the deletion can be accounted for afterwards, and it is not a copy of anything you filed. Anything you would rather ask a person about goes to privacy@bashnotes.com.
Keeping it safe
Everything travels over HTTPS. The session token is signed, so it cannot be edited into a claim about somebody else. Tenant separation is enforced by Postgres itself, in policies the application’s database role has no privilege to switch off; the role that can change the schema is used only when applying migrations and is never given to the running app.
Sign-in is the provider’s job, which is the point of using one: no password reaches this app, so there is none here to leak. Anything you want hardened about how you sign in — multi-factor, password rules — is set with them rather than here. Signing out ends their session as well as ours, so the next person at a shared machine does not land in your library by pressing sign-in.
Two more third parties stand in front of sign-in, and this is the page that should say so. Sign-in attempts and new accounts are rate-limited by network address — the counters described above — and the sign-in page may present a Cloudflare Turnstile challenge, which means Cloudflare processes what such a challenge needs (your IP address, browser characteristics) under its own privacy terms before this deploy hears from you at all. Your email address is also stored in a normalised form — case, dots in some providers’ addresses, and anything after a + removed — used only to keep one inbox to one account, never to send mail.
The honest limit, because a page like this is worth little if it only lists the good parts: everything above bounds how fast abuse happens, not whether it can. An account the provider will authenticate is an account this deploy will create, and what the operator holds against that is the ability to suspend or remove it afterwards, not a way to know in advance.
Changes to this page
The date at the top is the changelog. It is bumped in the same commit as the wording, and the full history of what this document has said is in the project’s git log — which is a firmer record than a line saying we may revise this from time to time.
If a change ever means the deploy starts doing something this page says it does not do, you will be told before it starts, not after.