Development
Requirements
Section titled “Requirements”- Linux x86_64 (workspace resolution is limited to
sys_platform == 'linux'becausetflite-runtimefor openWakeWord only exists there – see the override inpyproject.toml) - uv ≥ 0.5, Python 3.12 (uv installs it if needed)
- Node 22 for the frontend
- Docker with Compose v2 for the full stack and the E2E tests
- ffmpeg (only for local runs outside Docker)
uv sync --all-packages # backend, SDK, sandbox + dev tools in .venvcd frontend && npm ci # frontend dependenciesModels for local audio tests and local operation without Docker:
uv run python scripts/fetch_models.py ./.modelsexport JUSTAI_TEST_MODELS_DIR=$PWD/.modelsDevelopment mode with Docker (recommended)
Section titled “Development mode with Docker (recommended)”docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build- Backend, SDK and plugins are mounted read-only into the container,
JUSTAI_ENV=developmentenables Uvicorn reload. - Vite dev server on http://localhost:5173 (proxy to the core).
Core locally without Docker
Section titled “Core locally without Docker”Needs a reachable PostgreSQL with pgvector and optionally go2rtc:
docker run -d --name j5-db -e POSTGRES_USER=justai -e POSTGRES_PASSWORD=dev \ -e POSTGRES_DB=justai -p 5433:5432 pgvector/pgvector:0.8.1-pg17export JUSTAI_ENV=development JUSTAI_LOG_JSON=false \ JUSTAI_DATABASE_URL=postgresql+asyncpg://justai:dev@localhost:5433/justai \ JUSTAI_DATA_DIR=$PWD/.data JUSTAI_MODELS_DIR=$PWD/.models \ JUSTAI_BUILTIN_PLUGINS_DIR=$PWD/plugins JUSTAI_STATIC_DIR=$PWD/frontend/dist \ JUSTAI_SECRET_KEY_FILE=$PWD/.data/master_key JUSTAI_DATABASE_PASSWORD_FILE=/nonexistent \ JUSTAI_GO2RTC_URL=http://localhost:1984 JUSTAI_GO2RTC_RTSP_URL=rtsp://localhost:8554uv run python -m justai.mainAll variables: backend/src/justai/config.py (prefix JUSTAI_).
Code quality
Section titled “Code quality”uv run ruff check . # lint (rules in pyproject.toml, line length 120)uv run ruff format --check .(cd backend && uv run mypy src) # strict, with the pydantic plugin(cd sdk/python && uv run mypy src)(cd sandbox && uv run mypy src)cd frontend && npm run lint && npm run typecheckConventions:
- New dependencies only with a reason (the lockfile is committed).
- Write domain logic without I/O where possible (e.g.
ptz/tracking.py,audio/arbitration.py,output/router.py) so it can be tested without infrastructure. - Never start background tasks with a bare
asyncio.create_task, but withjustai.common.tasks.spawnor theSupervisor. - Code, comments, logs, tool descriptions, tool results and error messages are English. The language model answers in the language of the conversation.
- Texts spoken or stored without the model go into
justai/i18n.pywith English, German and Italian versions. - Interface texts go into
frontend/src/shared/i18n/en.tsand are translated inde.tsandit.ts; the build fails if a key is missing. In components useconst t = useT(), outside of componentstg(). - Never log secrets:
justai.common.redactfilters known keys. Plugin secrets are declared by the manifest insecret_fields.
Database migrations
Section titled “Database migrations”cd backenduv run alembic revision -m "description" # file in src/justai/db/migrations/versions/Migrations run automatically at core start. Every migration must work on an existing database (no recreating of data needed).
Adding a new domain module
Section titled “Adding a new domain module”- Package under
backend/src/justai/<module>/with a service (logic) andextension.py(start(),stop(),register_tools(registry)). - Instantiate it in
extensions.py. - API routes in
api/routes/ext_<module>.py, registered inapi/app.py. - Add event types to the catalog (
events/catalog.py). - Unit tests for the pure logic, an E2E test if useful.
A new plugin
Section titled “A new plugin”See PLUGINS.md. In short: a folder under plugins/ with plugin.yaml and
plugin.py, tests with justai_sdk.testing.FakePluginContext.
See TESTING.md.