A relapse tracker that runs on your own machine and keeps your record to itself.
Tip
Check out the LIVE demo here: https://backslsh.github.io/anchor/
If it shows streak as 0, open the Dev Console with F12 and paste this: anchor.demo({force:true}) to reset it
Habits with colors, a master calendar, goals, daily quotes, urge support, and a permanent record you can amend but never erase.
No account. No subscription. No servers. No telemetry. No build step, and not a single dependency — clone it, run one command, and it works offline forever.
Most habit and recovery trackers want an email address, a monthly fee, and a copy of the most private thing about you on someone else's database. Anchor is the other option: it is private by architecture, because there is no backend that could leak. When you set a passphrase, your entries are encrypted on your own device with AES-256-GCM, and the key never leaves your browser.
It is also honest about its limits — see SECURITY.md for the full threat model, in plain language, including the things it cannot protect you from.
Important
Not medical software. Anchor is a self-tracking tool, not treatment. If what you are tracking involves alcohol, drugs, self-harm, or anything where a relapse could be dangerous, please keep a real person in the loop too and consider ways to get assistance.
Note
This software is provided as-is, with NO WARRANTY, to the extent of applicable law.
You can find more information and screenshots by scrolling down. ↓↓
- Download
- Run with npx
- Quick Start
- Server Options
- Using Anchor on a mobile device
- Permanence Rule
- Password Protection
- Streak Pet
- What's Included
- Things to Find
- Files
- Building the executables
- Contributing
- License
- IMPORTANT NOTE
- Full Feature List
Grab the file for your system from the latest release:
| System | File |
|---|---|
| Windows | Anchor-windows.exe |
| macOS | Anchor-macos |
| Linux | Anchor-linux |
Double-click it and Anchor opens in your browser.
Note
This is not an installer. It is the whole application in one file. It copies nothing into Program Files, writes nothing to the registry, and needs no admin rights. Anchor runs while the window is open and stops when you close it, so keep the file somewhere handy and double-click it whenever you want it.
Your data lives in a folder called .anchor in your home directory, not next
to the file — so moving the app, renaming it, or downloading a newer version
never loses your history. Pass --portable if you would rather keep everything
together on a USB stick.
Important
The downloads are not code-signed, because certificates cost money a free tool
does not have. Windows SmartScreen will say "Windows protected your PC" —
click More info → Run anyway. macOS will refuse the first launch —
right-click → Open, then confirm. On Linux, chmod +x Anchor-linux first.
If you already have Node:
npx anchor-trackerNothing is installed permanently — npx fetches it, runs it, and Anchor opens
in your browser. Your data goes to a .anchor folder in your home directory, so
it survives updates and cache clears.
To keep it around:
npm install -g anchor-tracker
anchor-trackerFor Mac users, open 'Terminal' and enter:
git clone https://github.com/YOUR-USERNAME/anchor.git
cd anchor
node serve.js --openTip
Node 18+ is the only requirement. There is nothing to install — no npm install, no bundler, no framework.
Install Node 18+
Be sure to select the correct operating system you are using, eg., Windows
On first run you get a blank slate: no habits, no entries, no passphrase. Set one in Settings → Privacy & lock and it encrypts everything from then on.
It serves at http://127.0.0.1:4321/ and binds to loopback only, so nothing else on your network can reach it.
| Flag | Meaning |
|---|---|
--lan |
HTTPS + sync, reachable from your phone (see below) |
--port 5000 |
Use a different port |
--open |
Open your browser automatically |
--portable |
Keep data beside the executable instead of in your home folder |
--no-sync |
Disable the on-disk sync store (it is on by default) |
Why a server at all? The app uses ES modules, which browsers refuse to load over
file://. Openingindex.htmldirectly will show a blank page.
Sync is on by default, including for local-only use. Once you set a
passphrase, your vault is written to .anchor-data/vault.json as ciphertext as
well as living in the browser — so your history survives clearing site data, and
any other device you point at this server shares the same record. Nothing syncs
before a passphrase exists, because the store refuses unencrypted data.
Load a sample vault — fourteen months of invented history with a real improvement arc, a 54-day run in progress against a 62-day record:
[https://backslsh.github.pages
Or from the browser console: anchor.demo() in your local instance.
The demo shows the theme ladder honestly: six unlocked by the sample streak,
three still locked, and the off-ladder secret hidden. Add ?demo=unlocked if
you want to look at every palette.
The passphrase is switched off in the demo. There is no recovery from losing one, so a public sample vault should not let a passing visitor lock a record they never meant to own.
It only fills an empty vault. If you already have a habit or a single entry, it refuses, so it can never overwrite a real record. Clear it afterward with Settings → Erase everything.
node serve.js --lanOr double-click start-phone.bat. Leave the window open while you use it.
It prints the addresses to type into your phone, e.g. https://192.168.1.24:4443/.
Pick the one on your actual Wi-Fi adapter — virtual adapters (VMware, VirtualBox,
Hyper-V) get listed too and won't work.
Your phone must be on the same network as the PC.
A certificate warning. The cert is self-signed and generated on first run,
in-process — Anchor builds the X.509 itself, so nothing needs to be installed
and OpenSSL is not required. It covers localhost and every local IP, and is
issued for under 825 days so iOS accepts it. Tap Advanced → Continue. You must
accept it — see below.
It will ask for your passphrase, then pull your history down. No export or import needed. The phone fetches the PC's KDF salt, you type the same passphrase, and it decrypts your real data in place.
Browsers only expose crypto.subtle — the API the entire passphrase and
encryption layer is built on — in a secure context: HTTPS, or localhost.
Over plain http://192.168.x.x it is simply undefined, and encryption cannot
work at all. --lan exists to satisfy that requirement. If Anchor ever detects
it is running without it, it says so rather than failing quietly.
Your PC holds the master copy in .anchor-data/vault.json. That file contains
one AES-GCM blob and nothing else — the server process cannot read a single
entry, because the key never leaves the browser.
- Writes are authenticated by a token derived from your passphrase. It is the second half of the same PBKDF2 output the key comes from, so it proves you know the passphrase without being reversible into the key.
- The store refuses to accept anything that isn't an encrypted envelope.
- Every write is revision-checked. A stale write gets the current copy back and merges instead of clobbering.
- The last 40 revisions are kept in
.anchor-data/backups/.
Merges never drop a relapse. The merged set is the union by id — the same promise the rest of the app makes. If the same entry exists on both devices, the copy with more amendments wins. Log on your phone and your PC on the same afternoon, and you end up with both.
Turn it off per device in Settings → Sync with this PC.
.anchor-data/holds your encrypted vault and your TLS private key. Don't commit it or copy it anywhere public.
A logged relapse cannot be deleted. There is no delete button, no context
menu item, and no store method that removes one — store.js deliberately has no
removeRelapse().
What you can do is amend it: change the habit it belongs to, the date, the
time, the intensity, the triggers, the notes. Every amendment is timestamped and
appended to that entry's history, which is shown at the bottom of the amend
dialog.

The single escape hatch is Settings → Erase everything, which wipes the
entire vault at once and requires typing ERASE. That is a decision, not an
edit.
Anchor's lock screen is not a JavaScript if (password === …) check that a
determined person could step around in devtools.

When you set a passphrase in Settings → Privacy & lock:

- The passphrase is stretched with PBKDF2-SHA256, 600,000 iterations
- That yields an AES-256-GCM key
- Your whole vault is encrypted with it before being written to
localStorage - The passphrase itself is never stored — only a random salt and a small verifier blob, so a wrong passphrase simply fails to decrypt
Without the passphrase, the stored data is ciphertext. Not hidden — unreadable.
There is no recovery. If you forget it, the data is gone. That is the tradeoff that makes it real. Export a backup somewhere safe.
Also available once protection is on:
- Auto-lock after 5 / 15 / 60 minutes idle
- Ctrl + L to lock immediately
- An optional lock-screen hint
What this does not cover — browser extensions, malware on your device, and anyone at your unlocked screen can all still reach your data. Read SECURITY.md before trusting it with anything you could not bear to have exposed.
(Terminology: Anchor uses a passphrase, not a WebAuthn "passkey". Longer is
better than cleverer — a short memorable sentence beats Xk7$q.)
The object on the dashboard is not decoration. It is your streak:
- Height is your current clean run measured against your personal best
- The hollow ghost standing over it is that record — the gap between the two tips is how many days you still need
- Each satellite crystal at the base is a milestone this run has cleared (1, 3, 7, 10, 14, 21, 30 …)
- Log a relapse and it shatters, then regrows from a chip
Hover over any piece to see what it represents. Drag to spin it.
Dashboard — current clean run, a WebGL solid that gets calmer and brighter
the longer you go, the day's quote, per-habit streaks with sparklines, active
goals, next milestone, and an estimate of money and time reclaimed.

Calendar — month grid with a color bar per habit on each day, plus a year
view of twelve mini heatmaps and per-year totals. Click the legend to filter.

Habits — one color per behavior, an optional written reason you will read
back on a bad night, a 30-day heat strip, and optional cost/minutes per slip.

Goals — three kinds:
- Clean run — reach N days; completes itself
- Budget — at most N slips per week/month/year
- Milestone — free-form, with an optional deadline
Insights — by month, by weekday, by hour on a 24-hour clock, split by habit,
every clean run in order, your named triggers weighted by frequency, and
intensity distribution.

Urge support — a 4-7-8 breathing overlay that also shows your current run,
what is riding on it, and the notes you wrote to yourself after previous slips.

Some of it is meant to be discovered, so this list is partial.
Ctrl + K |
Command palette — everything is in there |
? |
Full keyboard map |
1–6 |
Jump between views |
L / P / N / G |
Log · Urge · New habit · New goal |
← → T |
Move around the calendar |
| Click the big streak number | Switches to a live second counter |
| Drag the 3D solid | It has momentum; clicking makes it pulse |
| Shift-click a calendar day | Logs straight to that date |
| Right-click a calendar day | Same thing |
Type calm anywhere |
Breathing exercise |
Type why anywhere |
Your own reasons, back at you |
| The Konami code | — |
The dashboard also drips out a tip every few minutes until you have seen them all. Settings → Show the tips again resets that.
index.html markup + overlay containers
serve.js zero-dep server: static files + encrypted sync store
start.bat Windows launcher (local only)
start-phone.bat Windows launcher (HTTPS + sync, for phone access)
.anchor-data/ created on first --lan run: vault, backups, TLS cert
assets/css/app.css the whole design system
assets/js/
app.js boot, routing, lock flow, keyboard, easter eggs
store.js state, mutators, selectors ← permanence enforced here
vault.js localStorage + encryption at rest
sync.js pull/push, conflict resolution, union merge
crypto.js PBKDF2 → AES-GCM key + sync auth token
crystal.js procedural crystal geometry for the dashboard
scene.js WebGL renderer + lock-screen particle field
ui.js modals, toasts, tooltips, confetti, palette, breathing
forms.js the shared dialogs
quotes.js ~120 lines in rotation
util.js DOM builder + date helpers
views/ dashboard · calendar · habits · goals · insights · settings
node build.jsProduces dist/Anchor-<platform> using Node's built-in Single Executable
Application support: serve.js and every web asset are embedded into a copy of
the Node binary. The result is ~80 MB, because it contains a whole JavaScript
runtime, and depends on nothing at all.
The only build-time dependency is postject, fetched on demand via npx, which
performs the injection. Nothing from it ends up in the output.
Single Executable Applications cannot cross-compile — a Windows .exe has to be
built on Windows. .github/workflows/release.yml builds all three platforms on
a tag push, smoke tests each from an empty directory, and attaches them to a
draft release.
Warning
Only install and run Anchor from repositories you trust; @backslsh is the original author. Other dependencies may have maliciously modified code; use at your own risk.
Issues and pull requests are welcome. A few ground rules that keep the project what it is:
- No dependencies. No npm packages, no CDN links, no build step. If it cannot be done with the platform, it probably should not be done here.
- No network calls. The app must work with the network cable pulled. The only permitted request is to Anchor's own sync endpoint.
- Relapses stay permanent. No pull request adds a delete button. Amend and audit, never erase — this is the point of the project, not a limitation.
- Be honest in the docs. If a change weakens a security property, say so in SECURITY.md in the same PR.
.anchor-data/ is gitignored and holds your vault, your backups, and the TLS
private key generated for LAN mode. Never force-add it. To double-check what you
are about to publish:
git status --ignored --shortIf you have ever run the app from your clone, confirm no vault.json, no
*.pem, and no anchor-backup-*.json appear in git status.
MIT. Fork it, rename it, make it yours.
This is a tracker, not treatment. If what you are tracking involves alcohol, drugs, self-harm, or anything else where a relapse could be dangerous, please also have a real person in the loop — a doctor, a therapist, or a helpline. A calendar is a good mirror and a poor safety net.
