# Privacy Policy

**Codescry** — local-first portfolio auditor
Last updated: 2026-09-11 · Applies to all desktop builds (Windows, macOS, Linux)
and to the codescry.app website

## The short version

The Codescry app collects nothing. There is no account, no sign-in, no analytics, no
crash reporting, no phone-home, and no server we operate that your data reaches.
Every project we scan, every finding we produce, every screenshot you attach and
every word of your "About Me" profile stays in a folder on your own disk.

We are not in a position to see your data even if we wanted to. There is nowhere
for it to arrive.

## What we collect

Nothing.

- **No accounts.** Nothing to sign up for, no email required, no license key.
- **No telemetry.** No usage analytics, no event tracking, no crash or error
  reporting, no "anonymous statistics", no A/B experiments — in the app. The
  website counts visits; see [The website](#the-website).
- **No advertising, no profiling, no tracking cookies**, in the app or on the
  site. The only cookie the site can set is the sign-in cookie on `/admin`, the
  private console the operator uses; a visitor never receives it. See
  [The website](#the-website).
- **No code upload.** Your source code is read from disk, analysed on your
  machine, and never transmitted anywhere.

Because we collect no personal data, there is nothing to sell, share, breach, or
hand over in response to a request — and no data-subject request to answer,
since we hold no record that you exist.

## What leaves your machine

Codescry makes exactly two kinds of outbound request, both optional, both
clearly labelled in the app, and both switched off completely by the
**"Go fully offline"** setting (Settings → Data & privacy).

### 1. Registry version checks (Outdated-tech axis)

To tell you a dependency is behind, Codescry asks the public package registry
what the latest published version is:

| Ecosystem | Endpoint contacted |
| --- | --- |
| npm | `https://registry.npmjs.org/<package>/latest` |
| PyPI | `https://pypi.org/pypi/<package>/json` |
| NuGet | `https://api.nuget.org/v3-flatcontainer/<package>/index.json` |

**What is sent:** the package name only, as part of the URL. Nothing else — no
project name, no file path, no machine identifier, no account, no version of
yours. Your *installed* version never leaves the machine: Codescry downloads the
registry's latest version and does the comparison locally.

**What this still reveals:** these are third-party services we do not operate,
and like any web request the call exposes your IP address and the fact that
someone looked up that package, to npm, the Python Software Foundation, or
Microsoft respectively. Their privacy policies govern what they do with it. The
set of package names you look up is itself a weak signal about what you build —
if that matters to you, turn the axis off or go fully offline. Codescry requests
at most 60 packages per project.

Disabled by: **"Go fully offline"**, or by turning the Outdated-tech axis off.
When either is set, the axis reports "offline" and no request is made.

### 2. Update check

Once per launch, Codescry fetches one file — `https://dl.codescry.app/latest.json`
— to see whether a newer version exists. It sends no data about you or your
projects: it is an ordinary, unauthenticated GET of a static file, and what it
reveals is what any web request reveals, namely your IP address and the fact
that a Codescry install checked for updates, to Cloudflare (the download host —
see [the website's processors](#the-websites-processors)).

The manifest is signed, and Codescry verifies that signature before believing a
word of it. Codescry never downloads or installs an update on its own; the
notification links to the download page on codescry.app and you go get it
yourself. There is no second request and no fallback to any other host.

Disabled by: **"Go fully offline"**.

### Not a network request: the local model

Analysis runs against a language model on your own machine, through a local
engine (Ollama) that Codescry talks to at `http://127.0.0.1:11434`. That is
loopback traffic to your own computer — it does not touch the network and does
not leave the device. No prompt, no snippet of your code, and no result is ever
sent to a hosted model.

One exception worth knowing: **downloading a model** is a real download. When
you pull a model from the Models screen, your local Ollama engine fetches it
from its own registry (ollama.com). That transfer is between your machine and
Ollama, initiated by you, and carries none of your data — it only sends what is
needed to fetch the model you asked for.

## Where your data is stored

Everything Codescry produces is written to a single local folder — the results
path, shown to you in **Settings → Data & privacy** and openable from there.

By default it is the app-data directory for the bundle id
`org.helveticlabs.codescry`:

| OS | Exact path |
| --- | --- |
| Windows | `%APPDATA%\org.helveticlabs.codescry` — i.e. `C:\Users\<you>\AppData\Roaming\org.helveticlabs.codescry` |
| macOS | `~/Library/Application Support/org.helveticlabs.codescry` |
| Linux | `$XDG_DATA_HOME/org.helveticlabs.codescry`, defaulting to `~/.local/share/org.helveticlabs.codescry` |

Read the resolved path for your machine off the Settings screen rather than
transcribing the table. A development build (`npm run tauri:dev`) uses the same
bundle id, and therefore the same folder, as an installed one.

That folder holds:

- `codescry.db` — a SQLite database with your scan root, detected projects, scan
  history, findings, health scores, dependency-check results, resolve/snooze
  state, your "About Me" profile, your favourited ideas, and your settings.
- `codescry.db-wal`, `codescry.db-shm` — SQLite write-ahead-log sidecars. Part of
  the database, not scratch files.
- `screenshots/` — copies of any images you attach for the UI axis. Codescry
  copies them in so a result stays self-contained; the original stays where it
  was.
- `logs/` — the local crash log (`codescry.log`, plus up to three rotated
  archives). An app with no telemetry has nowhere to report an uncaught error, so
  it writes one JSON line here instead: the error message, its stack, the screen
  you were on and the app version. It is written for you to read and never sent
  anywhere. Stack traces can contain file paths.

Codescry stores findings *about* your code, never the code itself. File paths and
file names do appear inside findings and project rows.

Nothing is encrypted at rest beyond whatever full-disk encryption your operating
system provides — the store is a plain file in your user profile, protected by
your OS account like any other document. Nothing is synced, backed up, or
uploaded by Codescry.

### Folders the system creates around it

Codescry itself writes only the directory above. The operating system's webview,
which renders the app's UI, keeps a cache of its own under the same bundle id, and
an uninstaller may leave it behind:

| OS | Webview data (may exist) |
| --- | --- |
| Windows | `%LOCALAPPDATA%\org.helveticlabs.codescry\EBWebView` (WebView2) |
| macOS | `~/Library/WebKit/org.helveticlabs.codescry`, `~/Library/Caches/org.helveticlabs.codescry`, `~/Library/Saved Application State/org.helveticlabs.codescry.savedState` |
| Linux | `~/.cache/org.helveticlabs.codescry` (WebKitGTK) |

Codescry keeps nothing of substance there — it writes no `localStorage`, and the
one `sessionStorage` key it uses (`codescry.ideas`, the unsaved idea list) dies
with the window. Delete these folders freely; the app rebuilds them.

Two further things are **not** Codescry's to delete, and survive any reset:

- **The model weights**, which belong to Ollama — `%USERPROFILE%\.ollama` on
  Windows, `~/.ollama` on macOS and Linux (a Linux service install may use
  `/usr/share/ollama/.ollama`). That is where the gigabytes are.
- **Anything you exported yourself** — `codescry-export.json`, report Markdown,
  priority lists — which sit wherever you saved them.

## Your control over it

- **Go fully offline** (Settings → Data & privacy) — stops both outbound
  requests above. The app remains fully functional; the Outdated-tech axis
  reports that latest-version data is unavailable.
- **Export all data** — writes a single JSON file with your settings, scan
  root, every report, your profile and your favourited ideas. It is yours; it
  goes wherever you save it.
- **Clear results & history** — deletes every scan, finding, axis result,
  dependency check and screenshot record from the database, and resets health
  scores. Your detected projects, profile and settings survive. Note that the
  image *files* previously copied into `screenshots/` are left on disk; use the
  full reset below, or delete that folder yourself, if you want them gone.
- **Delete all local data & reset** — empties every table in the database *and*
  deletes the `screenshots/` and `logs/` folders, then `VACUUM`s the database and
  truncates its write-ahead log, so the pages those rows occupied stop holding
  readable content. The app returns to onboarding with default settings, as on a
  first install. It refuses to run while a scan is in progress — cancel the run
  first. There is no undo and no server copy, so use "Export all data" first if
  you want a record. Your project folders themselves are never touched; Codescry
  only ever reads them.
- **Delete everything** — quit Codescry and delete the results folder above.
  That is the whole of it. Uninstalling the app leaves that folder behind by
  design, so your results outlive a reinstall unless you remove it.

### Removing every trace, per OS

```bash
# macOS
rm -rf ~/Library/Application\ Support/org.helveticlabs.codescry
rm -rf ~/Library/WebKit/org.helveticlabs.codescry
rm -rf ~/Library/Caches/org.helveticlabs.codescry
rm -rf ~/Library/Saved\ Application\ State/org.helveticlabs.codescry.savedState

# Linux
rm -rf ~/.local/share/org.helveticlabs.codescry ~/.cache/org.helveticlabs.codescry
```

```powershell
# Windows (PowerShell)
Remove-Item -Recurse -Force "$env:APPDATA\org.helveticlabs.codescry"
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\org.helveticlabs.codescry"
```

Uninstall the app itself the usual way — Windows: Settings → Apps → Installed
apps → Codescry; macOS: drag `Codescry.app` to the Trash; Linux: `sudo apt remove
codescry`, or delete the `.AppImage` — and, if you want the model weights gone
too, `ollama rm <model>` followed by uninstalling Ollama.

Searching your home directory for `org.helveticlabs.codescry` afterwards should
turn up nothing but exports you saved yourself. Step-by-step instructions live in
[docs/USER_GUIDE.md](docs/USER_GUIDE.md#delete-everything).

## The website

Everything above describes the **desktop application**, which collects nothing.
This website — **codescry.app** — is a separate thing, and its home page counts
visitors.

- **What it is.** Plausible Analytics, loaded on the home page only. It records
  a page view and clicks on outbound links — the download buttons — so we can
  tell whether anyone is actually downloading Codescry.
- **No cookies, no identifier.** Nothing is written to your browser: no cookie,
  no localStorage entry, no cross-site ID. Counts are aggregate. We cannot
  single you out, follow you between sites, or connect a visit to anything you
  later do in the app.
- **Opt-out is honoured before the request.** With Do Not Track or Global
  Privacy Control set in your browser, the analytics script is never requested
  at all — that check runs in the site's own code, not on someone else's server.
- **The app is untouched.** Codescry the application loads no analytics on any
  screen, ever. The code lives in the website bundle
  (`frontend/src/landing/analytics.ts`) and is not part of the desktop build.
- **Off unless configured.** The script is only emitted when the site is built
  with `VITE_ANALYTICS_DOMAIN` set. A landing page you build yourself makes no
  analytics request.

Plausible is a third party operating under its own privacy policy. Like any web
request it sees your IP address; it uses that only to derive a daily-rotating
hash for counting unique visits and does not store it. It is listed, with what
reaches it and its data-processing agreement, under [Processors](#processors).

### The admin console (`/admin`)

`codescry.app/admin` is the private console for whoever operates the site. It is
listed here for completeness, because it is the one page that sets a cookie.

- **Only the operator can use it.** Sign-in is HelveticLabs SSO and nothing
  else. Signing in stores an email address, a display name, the HelveticLabs
  account id, and sign-in timestamps — for the operator's own account. Ordinary
  visitors never sign in and never appear in it.
- **One cookie, functional, first-party.** A signed session cookie
  (`HttpOnly`, `Secure`, `SameSite=Lax`), set only after a successful sign-in
  and deleted on sign-out. It is strictly necessary for the sign-in to work,
  carries no tracking value, and is never set for a visitor who does not sign
  in — so it needs no consent banner.
- **It reports on the site, never on the app.** The console shows the same
  aggregate Plausible numbers described above, its own account list, and
  payment records if payments are ever introduced. It cannot see your projects,
  scans, findings or ideas — those exist only on your own machine, and no
  Codescry server ever receives them.

## Processors

A *processor* is a third party that handles data **on our behalf**. This section is
the complete register.

### The desktop app has no processors

**Zero.** The Codescry application engages no processor of any kind — no
analytics vendor, no crash reporter, no hosting provider, no identity provider,
no backend of ours. It cannot, because it holds no data outside your own disk
and never sends any to us: there is no data of yours for anyone to process on
our behalf, and no contract by which they could.

The public package registries described in
[What leaves your machine](#what-leaves-your-machine) are **not** processors.
Your machine contacts them directly, we are not a party to the request, and
nothing of ours transits them — each is an independent controller of its own
server logs. The local model engine (Ollama) is not a processor either: it runs
on your computer over loopback.

The update check is the one exception worth naming: it goes to a host we do
operate, `dl.codescry.app`, so Cloudflare appears in the table below. Even
there, nothing of yours is processed — the app reads a static file and sends
nothing but the request itself.

Everything below therefore concerns **codescry.app, the website, only**.

### The website's processors

| Processor | Role | What reaches it | Where processed | DPA |
| --- | --- | --- | --- | --- |
| Plausible Insights OÜ | Visitor analytics, home page only | Page-view and outbound-click events: URL, referrer, browser/OS/device class, country, and the visitor's IP — discarded after being hashed | EU: company in Estonia, servers in Germany | [plausible.io/dpa](https://plausible.io/dpa) |
| HelveticLabs | SSO identity provider for `/admin` | The operator's HelveticLabs account id, email address and display name, returned to us at sign-in — plus the fact that a sign-in for Codescry occurred | HelveticLabs infrastructure (`helveticlabs.org`, `api.helveticlabs.org`) | First-party — see below |
| Cloudflare, Inc. (Pages + R2) | Static hosting + CDN for `codescry.app`, and the download host `dl.codescry.app` | Every HTTP request for a page, asset or installer: visitor IP, user agent, requested path, timestamp — as host request logs | United States and Cloudflare's global edge, under SCCs for EU/UK transfers | [Cloudflare Data Processing Addendum](https://www.cloudflare.com/cloudflare-customer-dpa/) |

**Plausible.** Loaded only on the site's home page, only when the site is built
with `VITE_ANALYTICS_DOMAIN` set, and never when the visitor has Do Not Track or
Global Privacy Control on — in that case the script is not even requested, so
Plausible receives nothing at all. It sets no cookie and stores no identifier;
the IP address is used to derive a daily-rotating hash for unique-visit counting
and is not retained. Data is stored in the EU, which is why no transfer
mechanism is needed for this one. The DPA must be accepted in the Plausible
account **before** analytics is switched on for a build — see
[docs/RUNBOOK.md](docs/RUNBOOK.md#site-analytics-plausible).

**HelveticLabs.** The sign-in provider for the private admin console, and the
only account system anywhere in this project. It is first-party: HelveticLabs
publishes Codescry, so there is no third-party controller-to-processor transfer
here and no external DPA to link — the same organisation is on both sides. Two
consequences worth stating plainly: a visitor who never signs in never touches
it, and if HelveticLabs SSO is ever operated by a separate legal entity, a DPA
must be executed and linked in this table before that happens.

**Cloudflare.** Two roles, one provider. The site is a folder of static files
served by Cloudflare Pages, and the installers live in a Cloudflare R2 bucket
behind `dl.codescry.app`. Cloudflare sees the same request metadata any web host
or CDN sees, keeps it as operational logs, and gets nothing else — neither the
site nor the download host sends it events, and no user data is stored there.
The Cloudflare DPA applies through its customer terms; EU/UK transfers rely on
its Standard Contractual Clauses.

Downloading an installer, and the app's own once-per-launch update check, both
reach `dl.codescry.app`. That request carries no data about you or your projects
beyond what any HTTP request carries — see
[Update check](#2-update-check) for exactly what the app sends.

The project's source repository is private and hosted on GitHub, but visitors
never touch it: nothing on the website is served from GitHub, and the app
contacts it not at all.

### The admin backend is not a processor

The API behind `/admin` is our own software on our own infrastructure, not a
vendor — it is the controller's system, not a processor of it. It stores the
operator's account row, session records and (if payments are ever introduced)
payment records, in a SQLite file on that server. Its own host, whoever that
ends up being, is a processor for it; when the backend is deployed anywhere
other than the operator's own hardware, that host goes in the table above.

Payments are not wired up. When a provider is chosen it becomes a processor and
must be added here — with what reaches it, where, and its DPA — in the same
change that enables it.

## Children

Codescry is a developer tool with no accounts. The app collects no personal data
at all, and the website's visitor count identifies nobody, of any age.

## Changes to this policy

If this ever changes, it changes here and in the copy shipped with the app, and
the "Last updated" date moves. Since we hold no contact details, there is no
mailing list to notify — the version in the repository is always the current
one.

## Contact

Questions: [support@codescry.app](mailto:support@codescry.app) or open an issue
at [github.com/makr07-sec/codescry/issues](https://github.com/makr07-sec/codescry/issues).
