Contributing
The long-form documentation lives in docs/. This file is the short
version: what you need to get a change landed.
- docs/development.md: setup, working without hardware, adding an integration (a plugin)
CLAUDE.md: every convention, each one a hard rule, for people and AI agents alikeTODO.md: the backlog
#Requirements
- mise, which pins Bun, prek, Go and Python with their linters, and the mobile app's JDK, Android SDK tools and xcodegen. Or Bun alone for the web app.
- Docker, to build the image.
- ffmpeg and Python 3 (
mise run doctorchecks them). - For the iOS app, a Mac with Xcode and an iOS simulator runtime.
#Setup
mise run bootstrap # bun install, .env, the Android SDK and emulator, the doctors
mise run dev # dev server on :5173, worker included#The mobile app
mise run mobile:emulator # boot the emulator mobile:setup made
mise run mobile:run:android # build and launch on it, localhost:5173 reaching the dev server
mise run mobile:run:ios # build and launch on a simulator
mise run mobile:test # the shared code's tests, as CI runs themWithout mise: bun install, copy .env.example to .env and set AUTH_SECRET
(openssl rand -base64 32).
The dev server migrates ./data/localassistant.sqlite and starts the worker
under watch. Delete the file to start over from a fresh instance; the setup code
is in the dev server's output.
Installing dependencies wires the git hooks through prek: pre-commit runs the
fixers and checks, commit-msg enforces Conventional Commits, pre-push runs
the type check, the import-cycle check and the unit tests.
#The commands
bun run dev # Vite dev server on :5173, with the worker
bun run build # build/server and build/worker
bun run start # run the compiled server, which spawns the worker
bun run check # svelte-check (fails on warnings) and bun check
bunx prek run --all-files # every hook over every file, bun lint included
bun run format # bun fmt, Markdown included
bun run circular # fails on an import cycle
bun run test # unit tests
mise run sdk:test # Go and Python SDKs
mise run test # unit tests of the app, the SDKs and the mobile app
bun run test:integration # HTTP flows against the built server
bun run test:e2e # Playwright against the built server
bun run db:generate # a migration from the schema
mise run verify # every hook at the commit and push stages, as CI runs themThe package manager is bun. Never npx or npm.
#The container
compose.yaml builds the image from your checkout and runs it on port 3000,
with AUTH_SECRET and ORIGIN from .env:
docker compose up --buildIt is for checking the real container before a PR. Self-hosters copy the
compose.yaml block in README.md and docs/install.md, which pulls the
published image, the same as compose.prod.yaml; keep all of them in step.
#Screenshots
mise run screenshots # every screen into docs/images/
mise run showcase # the README hero, docs/images/feature.webpDesktop shots are dark theme at 1440 by 900, phone shots light theme at 390 by 844. Rerun them when a change moves a screen, and commit the images with it.
#Before you open a PR
bun run check,bunx prek run --all-filesandbun run testpass on the whole repo, with zero warnings.- A schema change comes with its generated migration. Committed migrations are append-only: fix a bad one with a new one.
- A new environment variable is declared in
src/env.tswith a schema and a description, and documented in docs/configuration.md. - A user-facing change updates the page of
docs/that describes it. - Every screen still works at 375px wide.
- Conventional Commit title. Squash merges turn it into the commit releaser
reads, and
fix,featand the rest all ship in the next canary.
This guide lives in the project repo: edit it there, and this page follows with the next release.