# Desktop Django Starter

> Minimal reference starter for packaging a Django app inside Electron with a runnable development slice today, a staged packaged-backend slice for bundled-runtime validation, a sign/notarization-aware GitHub packaging slice for desktop artifacts, a minimal Electron connected updater path, plus experimental Tauri and Positron shells for local comparison work. This repository is designed for both human readers and coding agents.

Use this repository when you need the smallest credible architecture for running Django as a local desktop app, or when you need a reusable workflow for wrapping an existing Django project in Electron without importing a product-sized codebase.

Important constraints:

- Keep the example generic, minimal, and server-rendered. The current themed presentation layer ("Flying Stable") is a demo; the underlying architecture is what matters.
- Treat `djdesk` as reference material for packaging and lifecycle patterns only.
- Windows support matters. Electron remains the baseline release lane; Tauri now has a GitHub-hosted Tauri artifact workflow plus a prepared, unverified Windows NSIS path, but it still does not claim release parity. Its Tauri-served shell assets use only a minimal localhost-aware CSP for the local splash/bootstrap surface, not a release-grade hardening claim for the Django UI. The hosted NSIS path still needs a real live Windows install/run test before making a stronger claim, and the current config keeps Tauri's default `downloadBootstrapper` WebView2 installer behavior rather than an offline-ready embedded runtime.
- Electron and Tauri currently bind Django to `127.0.0.1` on a random port, while Positron serves the same Django app from an in-process WSGI server on a random localhost port. Electron uses a per-session shell-to-Django auth token by passing `DESKTOP_DJANGO_AUTH_TOKEN` to Django and injecting `X-Desktop-Django-Token` only for the exact local Django origin. Tauri and Positron pass the same setting to Django and open their web views through a bootstrap URL that validates the token, sets an HttpOnly same-origin cookie, and redirects to the app without the token. The token does not replace CSRF and is not exposed through preload, a shell bridge, or normal page JavaScript.
- Packaged Django keeps SQLite under per-user app data as `app.sqlite3` and now teaches a stronger desktop baseline with `transaction_mode=IMMEDIATE`, a 20-second timeout, WAL, `synchronous=NORMAL`, and modest cache/mmap pragmas.
- The packaged shells now seed a small Flying Stable pony roster only when the per-user `app.sqlite3` does not exist yet; clearing the stable later must leave it empty rather than re-seeding.
- Electron on Windows currently shuts down backend child processes with explicit forced process-tree termination via `taskkill /t /f`, not a graceful drain or broader production orphan-control approach.
- The update story must include air-gapped/manual installs, not only connected environments. Electron has an implemented minimal connected updater path through `electron-updater`, and the repo now records a real signed/notarized macOS packaged update dry run from installed `0.1.2` to published `v0.1.4` that proved detection, download, restart/install, and `app.sqlite3` persistence. It is still not a release-validated updater lane because a real Windows NSIS packaged update dry run is still missing. Tauri now has an experimental connected updater path through `tauri-plugin-updater`, and Positron is manual-only for updates in this repo, with no connected updater or hosted artifact lane.
- Electron lives under `shells/electron/`, the experimental Tauri port lives under `shells/tauri/`, and the experimental Positron port lives under `shells/positron/`, while shared icon source art lives under `assets/brand/`; regenerate the Electron PNG and macOS ICNS with `npm --prefix shells/electron run icons`, the Tauri icon set with `npm --prefix shells/tauri run icons`, and the Positron icons with `just positron-icons`.

## Docs

- [README.md](README.md): Top-level repo intent and available docs.
- [docs/specification.md](docs/specification.md): Main product and technical specification for the starter.
- [docs/architecture.md](docs/architecture.md): Runtime contract, repo shape, startup model, shutdown notes, and release/update direction.
- [docs/decisions.md](docs/decisions.md): Scope and tradeoff decisions captured locally for this repo.
- [docs/release.md](docs/release.md): Packaging secrets, installer artifacts, Electron updater metadata, Tauri updater payloads, checksum files, and connected/offline promotion guidance.
- [docs/backlog.md](docs/backlog.md): Explicit follow-on work structured for implementation handoff.
- [docs/done.md](docs/done.md): Completed backlog entries after they are implemented.
- [docs/agent-use.md](docs/agent-use.md): Guidance for coding agents consuming this repo.

## Wrapping

- [scripts/wrap](scripts/wrap): Front-door command for wrapping a target Django project. Run from inside the target repo; requires an existing checkout of this starter. Runs preflight checks by default; `--run` invokes the agent.
- [scripts/bench-wrap-local-models](scripts/bench-wrap-local-models): Benchmarks local Ollama models against the resolved wrap prompt plus a compact target-repo snapshot, and reports prompt plus generation throughput.
- Packaged CLI: `uvx desktop-django-starter init` saves a user-level default harness and optional model under `~/.config/dds/config.toml` on Unix-like systems. `uvx desktop-django-starter wrap --run` then resolves the harness in this order: explicit CLI flags, saved config, then auto-detect when exactly one supported harness is installed. If no config exists yet and stdin is a TTY, `wrap --run` launches the same setup flow inline; non-interactive runs fail clearly instead of prompting. Current `dds` builds stream concise Claude progress when you choose the `claude` harness. Use `--harness` and `--model` to override the saved defaults, for example `--harness pi --model openai-codex/gpt-5.4`; `--agent` remains available as a backward-compatible alias.
- [skills/wrap-existing-django-in-electron/SKILL.md](skills/wrap-existing-django-in-electron/SKILL.md): Reusable workflow for adapting an existing Django project to run inside an Electron shell.
- [skills/wrap-existing-django-in-electron/prompt.md](skills/wrap-existing-django-in-electron/prompt.md): Prompt template for unattended agent-driven wrapping — used by `scripts/wrap` or piped manually to an agent CLI.
- [skills/wrap-existing-django-in-electron/run-log.md](skills/wrap-existing-django-in-electron/run-log.md): Run results from agent wrapping iterations, with git refs to the skill/prompt version used.
- [skills/wrap-existing-django-in-electron-staged/SKILL.md](skills/wrap-existing-django-in-electron-staged/SKILL.md): Experimental staged alternative for smaller local models that drift on the one-shot wrap prompt.
- [skills/wrap-existing-django-in-electron-staged/scripts/scaffold-target.sh](skills/wrap-existing-django-in-electron-staged/scripts/scaffold-target.sh): Deterministic scaffold helper that copies the Electron baseline and pre-adapts brittle Electron identity/path boilerplate, wrapped-target manage/settings assumptions, packaged manage path, packaged-backend copy paths, a generic splash asset, a default native Home/Back/Forward navigation menu, the common Django desktop baseline for Stage 3, known wrapped-template back-to-list navigation affordances, default desktop auto-login behavior for the wrapped Electron runtime, target-side `just` desktop shortcuts, and `electron/wrap-target.json` before any model edits begin. The Django-side scaffold now handles both flat settings modules and common `settings/` package layouts, including targets that need desktop middleware inserted into a shared base settings file and targets with no committed seed SQLite database. It still assumes a recognizable `urlpatterns = [` layout rather than arbitrary project structure.
- [skills/wrap-existing-django-in-electron-staged/prompt-stage-2-electron.md](skills/wrap-existing-django-in-electron-staged/prompt-stage-2-electron.md): Focused Electron-only stage prompt template; verification-first and stop-early once the required Electron checks pass.
- [skills/wrap-existing-django-in-electron-staged/prompt-stage-3-django.md](skills/wrap-existing-django-in-electron-staged/prompt-stage-3-django.md): Focused Django-only stage prompt template; verification-first and stop-early once the required Django checks pass.
- [skills/wrap-existing-django-in-electron-staged/prompt-stage-4-fix-from-failures.md](skills/wrap-existing-django-in-electron-staged/prompt-stage-4-fix-from-failures.md): Exact-failure repair prompt template.

## Optional

- [.github/workflows/ci.yml](.github/workflows/ci.yml): Current cross-platform CI scaffold using GitHub-hosted runners.
- [.github/workflows/desktop-packages.yml](.github/workflows/desktop-packages.yml): On-demand GitHub Actions packaging workflow for macOS, Windows, and Linux artifacts, Electron updater metadata, checksum manifests, optional signing inputs, and optional draft GitHub Release publication.
- [.github/workflows/tauri-packages.yml](.github/workflows/tauri-packages.yml): Experimental GitHub-hosted Tauri packaging workflow using `tauri-action` in build-only mode with installer artifacts, updater payloads, `.sig` files, and checksum manifests.
- [tests/test_docs.py](tests/test_docs.py): Minimal smoke tests for the documentation scaffold.
- [tests/test_example_app.py](tests/test_example_app.py): Backend behavior checks for the demo CRUD slice ("My Ponies").
- [tests/test_tasks_demo.py](tests/test_tasks_demo.py): Backend tests for the real async task demo ("Stable Routines"), including enqueueing, reconciliation, and status transitions.
- [tests/test_health.py](tests/test_health.py): Readiness endpoint coverage.
- [src/tasks_demo/](src/tasks_demo/): Background task visualization demo ("Stable Routines") with animated pulse-ring indicators, polling-based live updates, and a SQLite-backed `django_tasks` plus `django_tasks_db` worker flow (optional post-v1 extension).
