A notes app by Oxy. Write a note, or put the phone on the table and let it take the note for you — the recording is transcribed and structured on the device.
- Notes and labels — colour, pin, archive, trash, search, and a masonry grid that packs cards by height.
- Local-first — every note is written to a per-account SQLite database first and synchronised afterwards, so the app works with no network and survives a process that dies mid-edit.
- Recording — started from any list of notes; it keeps running across screens and into the background, and the indicator follows it.
- Transcription on the device — whisper.cpp on a phone, transcribing while the meeting runs; an ONNX build of the same model in the browser. Nothing leaves the device.
- A note, not a transcript — a downloaded language model on the device reads the transcript and writes the note: a title, the points worth keeping, what was decided, and what was left open.
- Reminders — with push notifications on native and Web Push in the browser.
- Markdown export, attachments, and an in-app feedback inbox.
packages/
frontend/ # @noted/frontend — Expo app (iOS, Android, web)
backend/ # @noted/backend — Express API
shared-types/ # @noted/shared-types — the DTOs both sides agree on
- Frontend — Expo SDK 56 (React Native 0.85), expo-router, NativeWind 5, Reanimated, Zustand, TanStack Query, expo-sqlite
- Backend — Express, PostgreSQL (drizzle over postgres.js, via
@oxy.so/db), Socket.IO, Redis - Auth — Oxy (
@oxy.so/core,@oxy.so/services); no app-local session handling - UI — Bloom (
@oxy.so/bloom) for dialogs, toasts and theming
bun install # bun only — never npm or yarn
bun run dev # frontend and backend together
bun run dev:frontend # Expo
bun run dev:backend # Express
bun run web # Expo on the web
bun run ios # native build, iOS
bun run android # native build, AndroidTests are bun run test inside packages/frontend; bun run lint at the root.
PostgreSQL, database noted on the shared oxy-postgres instance. Connection in packages/backend/src/db/postgres.ts, schema in src/db/schema/, migrations in drizzle/.
Two rules that are not obvious from the code:
- Every generated migration needs a
-- oxy:deploy-phase=pre|postmarker.db:migraterefuses to apply an unmarked one, before any DDL runs. - Postgres has no TTL index. A table that would have carried one needs an entry in
src/db/expiry.ts, or it grows forever with no error and no failing test.
Speech transcription and transcript enhancement run on the user's device; they
do not fall back to a hosted provider. If Noted later adds hosted point
inference, its route is Noted -> Oxy -> Kaana. Agent, chat, tool or memory
features route Noted -> Alia -> Oxy -> Kaana.
Kaana is Oxy's only hosted inference data plane and its only canonical signed
origin is https://kaana.ai. AI provider credentials live only encrypted in
Kaana PostgreSQL/KMS, never in Noted environment variables or source. An Oxy
service application credential identifies Noted; it is not a provider key.
Both halves ship from GitHub Actions:
| workflow | what it does |
|---|---|
ci.yml |
lint, tests and both builds |
deploy-aws.yml |
builds the linux/arm64 backend image, pushes it to ECR, and rolls the ECS service on oxy-cluster |
deploy-cloudflare.yml |
exports the Expo web build and deploys it as the Cloudflare Worker noted, serving noted.oxy.so |
The frontend deploy is gated on backend CI, so the web app cannot ship ahead of the API it talks to.
Architecture and product contracts live in docs/index.mdx.
AGENTS.md contains only the hard rules, commands and documentation pointers
needed while changing the repository. CLAUDE.md only imports it.