Development setup
This guide is for humans working on the Toposync repository. It covers the local workflow used for core backend work, frontend work, first-party extensions, documentation, tests, and distribution checks.
Toposync is a mixed Python and Node monorepo:
- Python backend and runtime live under
src/toposync. - The frontend host lives under
frontend. - First-party extensions live under
extensions/*. - Extension frontend bundles live under
extensions/*/ui. - The public documentation site lives under
docs-site.
Prerequisites
Install:
- Python 3.12 recommended.
uv.- Node 20 or newer.
- npm. The repository uses
package-lock.jsonand npm workspaces.
Install uv if needed:
curl -LsSf https://astral.sh/uv/install.sh | sh
Install Node through your preferred version manager. The repository currently uses npm workspaces, not Yarn or pnpm.
First setup
From the repository root:
uv sync
npm install
uv sync installs the Python core, development dependencies, and first-party extensions in editable mode through the extensions dependency group.
npm install installs the frontend host, the plugin API package, extension UI workspaces, the docs site, and test tooling.
Build the extension frontend bundles once:
npm run build:extensions
Extension UI builds generate static assets such as remoteEntry.js that are served by the Python extension packages.
Running the local app
For day-to-day development, run the backend and frontend together:
TOPOSYNC_AUTH_MODE=bypass npm run dev
Then open:
http://127.0.0.1:5173/
This starts:
- the Python backend through
uv run --group extensions python -m toposync serve; - the frontend host through
npm --workspace @toposync/frontend run dev; - a local data directory at
.toposync-dataunless overridden.
Use TOPOSYNC_AUTH_MODE=bypass for local development and visual validation. Without it, the UI enters the normal authentication flow and API calls may return 401 until setup or login is completed.
Running backend and frontend separately
Run the backend:
TOPOSYNC_AUTH_MODE=bypass uv run --group extensions python -m toposync serve --data-dir .toposync-data
Run the frontend host:
npm --workspace @toposync/frontend run dev
Use the separated workflow when you want to restart only one side.
Typical behavior:
- Python backend changes usually require restarting the backend process.
- Host frontend changes are handled by webpack dev server and hot reload.
- Extension frontend changes require rebuilding that extension UI bundle, then refreshing the browser.
Local ports and environment
Default development ports:
| Service | Default port |
|---|---|
| Backend | 8000 |
| Frontend dev server | 5173 |
| Processing server | 49321 |
| Docs site | 18763 |
Useful environment variables:
| Variable | Use |
|---|---|
TOPOSYNC_BACKEND_PORT | Override the backend port used by toposync serve |
TOPOSYNC_FRONTEND_PORT | Override the frontend dev server port |
TOPOSYNC_PROCESSING_PORT | Override the processing server port |
TOPOSYNC_DATA_DIR | Choose the runtime data directory |
TOPOSYNC_AUTH_MODE | Use bypass for local development, default is enforced auth |
TOPOSYNC_ENV_FILE | Load a different env file in npm run dev |
Example second local instance:
TOPOSYNC_BACKEND_PORT=8100 \
TOPOSYNC_FRONTEND_PORT=5174 \
TOPOSYNC_DATA_DIR=.toposync-data-2 \
TOPOSYNC_AUTH_MODE=bypass \
npm run dev
Then open:
http://127.0.0.1:5174/
You can also copy the sample env file:
cp .env.example .env
npm run dev
Working with extensions
Backend extension code is installed by uv sync in editable mode. Restart the backend after changing Python extension code.
Frontend extension code is built from each extensions/*/ui workspace. Build all extension UIs:
npm run build:extensions
Build one extension UI:
npm --workspace @toposync/extension-cameras-ui run build
Most extension UI packages currently expose a build script only. If you change extension UI code while the app is running, rebuild the relevant extension and refresh the browser.
Extensions are discovered from Python entry points and surfaced to the frontend through /api/extensions. The frontend loads extension remotes with Module Federation from /extensions/<extension_id>/....
Processing server development
Run a local processing server when working on distributed pipelines or remote execution:
TOPOSYNC_AUTH_MODE=bypass uv run --group extensions toposync processing-serve --data-dir .toposync-processing-data --host 0.0.0.0 --port 49321
Check status:
curl http://127.0.0.1:49321/api/processing/status
Then register it from the Toposync UI or through the origin API. Use a separate data directory for the processing server so it does not share origin runtime state.
Documentation site
Run the docs site in English:
npm run docs:start
Run the Portuguese locale:
npm run docs:start:pt-BR
Build all locales:
npm run docs:build
The local docs site uses:
http://127.0.0.1:18763/
Docusaurus serves one locale at a time in development mode. Use npm run docs:serve after a full build when you want to browse both English and Portuguese static output at the same time.
Checks and tests
Use the smallest check that covers your change.
Python unit tests:
uv run pytest
Specific Python test file:
uv run pytest tests/test_extension_manager_compatibility.py
Frontend host typecheck:
npm --workspace @toposync/frontend run typecheck
Plugin API typecheck and package dry-run:
npm run typecheck:plugin-api
npm run pack:plugin-api
Extension UI builds:
npm run build:extensions
End-to-end tests:
npx playwright install chromium
npm run test:e2e
Distribution smoke test:
python scripts/test_distribution_install.py
ARM64 distribution check:
python scripts/check_arm64_distribution.py
Docker/runtime contracts:
uv run pytest tests/test_dockerfile_runtime_contract.py
Docs build:
npm run docs:build
Common workflows
Backend API or runtime change
- Update Python code.
- Run the focused
uv run pytest ...test. - Restart the backend.
- Validate with
TOPOSYNC_AUTH_MODE=bypass npm run devif UI behavior is involved.
Frontend host change
- Update
frontend. - Run
npm --workspace @toposync/frontend run typecheck. - Use the running dev server at
http://127.0.0.1:5173/. - If routes, links, API calls, events, WebSockets, or asset URLs are involved, verify they preserve the Toposync base path used by Home Assistant ingress.
Extension change
- Update the extension Python code or extension UI.
- For Python changes, restart the backend.
- For UI changes, rebuild the extension UI.
- Confirm the extension appears in
/api/extensionsand loads in the host.
Packaging or installation change
- Build the relevant wheels.
- Run
python scripts/test_distribution_install.py. - Validate a clean install in a fresh virtual environment when changing dependencies, entry points, frontend packaging, or package data.
Local data and config
The default development data directory is .toposync-data.
Manual edits to .toposync-data/config.json are supported while Toposync is running: the runtime reloads the file when its size or modification time changes. Prefer the UI or API when possible because they validate and normalize data before writing.
If you edit config manually:
- keep the JSON valid;
- keep pipeline graph schema fields valid;
- avoid concurrent edits from the UI and your editor;
- expect invalid config files to be moved aside as corrupt and replaced with defaults.
Use a separate TOPOSYNC_DATA_DIR for each local instance.