A cross-platform, browser-based, locally-deployed psychotherapy documentation platform:
a Docker Compose stack (FastAPI api + FastAPI gateway + SvelteKit web + Postgres) that
runs entirely on hardware you control, with inference and storage local by default. It
re-architects an existing, validated macOS app (ClientNote / Euni™) into a portable,
dramatically easier-to-run product.
Its guiding idea: you don't have to take our word for how it treats your clients' data — there
are receipts, and the code is open. The app runs on your own computer (or a server your practice
controls); if you choose a cloud model, the note is de-identified on your machine first and only the
de-identified version leaves. See the in-app About & Privacy area (/about, readable before you
sign in) for the plain-language explanation and interactive walk-throughs.
- No fabrication. The system never quotes or attributes anything to a client's record unless that text appears verbatim in that specific client's record — anything unverifiable is rendered as unverified, never presented as fact.
- No missed safety-critical content. Safety-critical statements (suicidal/homicidal ideation, self-harm, plans and means, abuse disclosures, risk to others) must never be silently dropped or summarized away — they are detected, preserved verbatim, and forced into the clinician's view for confirmation.
These steps stand the whole stack up on your own machine. They assume you're comfortable running a few terminal commands, but not that you know Docker or Ollama.
- Docker Desktop (macOS/Windows) or Docker Engine + Compose v2 (Linux). This is the only hard requirement — the app itself runs in containers.
- Git, to clone the repository.
- A local AI model (recommended default). Install Ollama on your
computer, then pull the default model once:
On a memory-constrained machine, use the smaller
ollama pull gemma4:12b-mlx
gemma4:e4btag instead. (Prefer not to install Ollama on the host? See Containerized Ollama below.) A local model means nothing ever leaves your machine; a cloud model is optional and configured later in the app's Settings.
git clone <this-repo-url> TherapyNotes
cd TherapyNotes
cp .env.example .envThe defaults in .env work for the host-Ollama setup above — you don't need to edit anything to start.
docker compose up --build -dThis builds and starts postgres, the gateway, the api (which runs its database migrations
automatically on start), the transcription placeholder, and the web app. The first build takes a few
minutes; subsequent starts are fast. (make up is a shortcut for the same command.)
Check that the backend is healthy:
make smoke # or: curl -fsS http://127.0.0.1:8000/health && curl -fsS http://127.0.0.1:8100/healthThe app requires a sign-in (there's no open registration — you provision accounts yourself). Create one:
docker compose exec api python -m app.manage create-user --username youIt will prompt you to set a password. (To add more people later, run it again with a different
--username.)
Visit http://localhost:3000 and sign in with the account you just created.
To stop everything: docker compose down (add -v to also erase the database).
- Write a note: pick a client, paste or type your session notes, choose a format (PIRP/SOAP), and generate. Review the draft — statements the app couldn't verify against your record are flagged — resolve any safety content, then Sign. Change a signed note with Amend (a new version; the original is preserved). Copy a signed note to paste into your system of record.
- See the receipts: open the trust receipt under a note to see where each line came from, and "What the AI saw" on a draft to read exactly what was sent to the model and what came back.
- Diagnosis codes: the "Diagnosis codes" panel in the left sidebar is an offline ICD-10-CM lookup (common mental-health codes) — search by code or keyword and copy the code. It works with no internet; the panel shows when the code set was verified and against what.
- About & Privacy:
/about(reachable before login) explains, in plain language and with interactive diagrams, how your data is protected and what changes if you use a cloud model.
- Host-managed Ollama (default): install Ollama on the host and
ollama pull gemma4:12b-mlx. Thegatewaycontainer reaches it viahost.docker.internal(see.env.example) — no extra compose profile needed. - Containerized Ollama: run
docker compose --profile local-ollama up -d, thendocker compose exec ollama ollama pull gemma4:12b-mlx, and setOLLAMA_BASE_URL=http://ollama:11434in.envso the gateway talks to the containerized instance.
Cloud models are off by default. To use one (e.g. Claude), add your API key in the app's Settings; every note is de-identified through the privacy firewall before anything leaves the equipment you control. If you never add a cloud key, the app runs entirely locally.
The default setup above is loopback-only (just your machine). To host it for a few clinicians on a
trusted local network over HTTPS, use the hardened production profile and follow
docs/product/deploying-on-lan.md.
docs/DEVELOPMENT.md— onboarding: prerequisites, running the stack, running the test suites, and the architecture overview.CONTRIBUTING.md— how changes are proposed and the rules contributors honor.docs/HONEST-STATE.md— the authoritative record of what is actually built versus scaffolded. Read it before building on anything.PRD_Psychotherapy_Note_Platform.md— the canonical product requirements.
Open-source edition: AGPL-3.0-or-later, © 2026 Tucuxi, Inc. AGPL's network-copyleft
means anyone can read, run, and modify this code, but a commercial or hosted product built on it must
either stay open under the AGPL or take a separate commercial license, available from Tucuxi, Inc.
See NOTICE and ADR-0004.
This repository publishes its database schema as a single squashed migration rather than the incremental chain the project develops against. That keeps each release self-contained and easy to install — and it has one consequence worth stating plainly rather than letting you discover it:
A fresh install is unaffected. You get exactly the schema the project runs, verified against the full chain before each release.
An installation created from an EARLIER release of this repository cannot upgrade in place across
a squash boundary. Alembic will not recognise the revision your database is stamped with. If you
are running an older build with data you care about, export it, install fresh, and re-import —
do not run alembic upgrade head and hope.
If in-place upgrades across releases matter to you, please open an issue and say so. It is a solvable problem; whether it is worth solving depends on whether anyone is actually running this.