Tasks: provisioning-api-service
Feature Spec And Setup
- Create feature branch and worktree
- Draft and review
design.md - Reframe feature from
provision-restructuretoprovisioning-api-service - Create
scripts/atomixos_provision/pyproject.tomlwith deps and metadata - Update the design to use Litestar instead of the original Starlette direction
- Compare against Litestar fullstack reference and record applicable patterns
Package Structure
- Create
src/atomixos_provision/package with__init__.py - Create module files: app, auth, config, config_builder, quadlet, quadlet_sync, activation, jobs, provision, bundle, ui, server
- Create
tests/directory withconftest.py
Config Parsing And Generation
- Move
config.tomlparsing and schema validation toconfig.py - Preserve
tomllibusage and validation rules - Keep config generation logic in
config_builder.pyfor tests/future use; no/generateroute is exposed - Add tests covering config parsing and config generation behavior
Authentication
- Move SSH signature verification logic to
auth.py - Implement nonce issuance, TTL, and single-use consumption
- Implement Litestar guards with first-boot bypass
- Preserve
ssh-keygen -Y verifysubprocess verification - Require SSH auth after provisioning for
/api/configand/api/validate - Keep job polling authorized by unguessable job UUID only
- Add tests covering valid signatures, invalid signatures, expired nonces, replay, and unprovisioned bypass
Quadlet Rendering And Sync
- Move container, network, volume, and build rendering to
quadlet.py - Move
quadlet-runtime.jsontracking logic - Move rendered-unit copy logic to
quadlet_sync.py - Add tests covering rendering and sync behavior
Bundle Import
- Move tar.gz/tar.zst extraction and file placement to
bundle.py - Preserve
${CONFIG_DIR}and${FILES_DIR}token substitution behavior - Add tests covering bundle import behavior
Activation And Rollback
- Move activation script execution to
activation.py - Move rootful and rootless service health checks to
activation.py - Move candidate, active, and rollback config swap handling to
activation.py - Add F2FS-safe parent-directory fsync during promotion
- Add tests covering activation and rollback behavior
Async Job API
- Create
jobs.pywith single-flight job execution - Define job states: SUBMITTED, RUNNING, SUCCEEDED, FAILED
- Track rollback status in failed jobs
- Implement mutual exclusion for concurrent submissions
- Bound retained job history to avoid unbounded memory growth
- Add tests for concurrent submission, state transitions, and cleanup
Litestar HTTP Application
- Create
app.pywith Litestar app factory - Wire API routes: GET
/api/nonce, POST/api/config, GET/api/jobs/{id}, GET/api/health, POST/api/validate - Integrate SSH auth guards with first-boot bypass
- Integrate job manager for POST
/api/config
Boot UI Routes
- Create
ui.pywith HTML form endpoints - GET
/— serve Boot UI HTML - GET
/assets/atomixos.png— serve static logo - POST
/apply— multipart form to sync provision to HTML result - Do not expose
/generate; first-boot UI only uploads or pastes a prepared config - Escape user-controlled HTML output
Server Entry Point
- Create
server.pywith click-based CLI - Implement commands:
serve,validate,import,recover,sync-quadlet - Implement sd_listen_fds socket inheritance from systemd
- Preserve systemd unit compatibility
Nix Integration
- Update
modules/first-boot.nixto reference the new Python package - Build Python environment with Litestar, uvicorn, and the new package
- Bind first-boot socket to
0.0.0.0:8080, then rebind to provisioned LAN IP - Preserve PATH dependencies (openssh, gzip, zstd, systemd, util-linux)
- Update
nix/tests/first-boot-provision.nixfor the new package - Update
nix/tests/first-boot-source-discovery.nixfor the new package
Cleanup And Close
- Move provisioning implementation into
scripts/atomixos_provision/while preserving thefirst-boot-provisioncommand interface - Update docs and reference pages for the new package layout
- Update
docs/src/planned-features.mdto mark feature complete - Add
boot-ui-htmxtoplanned-features.mdas a follow-up feature - Run full Nix build and VM tests on aarch64-linux builder
Service Foundation Follow-Up
- Add
settings.pywith a small environment-backedAppSettingsobject - Add
deps.pywith Litestar dependency providers for settings and service facades - Add
exceptions.pyfor consistent domain-error to HTTP-response mapping - Add typed schemas for nonce, validation, submit-config, job, job event, and provision result responses
- Convert job response serialization to use the typed schemas
- Split
/api/healthinto adomain/system/controller.py - Split
/api/nonceinto adomain/auth/controller.py - Split
/api/jobs/{id}into adomain/jobs/controller.py - Split
/api/configand/api/validateinto adomain/config/controller.py - Add a
ConfigServicefacade for apply and validate operations - Keep
create_app()route wiring explicit; do not add domain auto-discovery yet - Add OpenAPI operation IDs, summaries, tags, and typed response metadata for API routes
- Add docs updates for
docs/src/provisioning.md,docs/src/data-flow.md,docs/src/runtime-boundaries.md,docs/src/reference/project-structure.md,docs/src/code-reference/scripts.md, anddocs/src/testing.mdwhen service API behavior changes - Keep Boot UI routes in
ui.pyuntil theboot-ui-htmxfollow-up splits server-rendered partials
Future Dynamic API Direction
- Design
GET /api/config/currentto return normalized current desired state - Design
GET /api/config/exportto export a backup/clone config bundle - Design typed user partial updates such as
PATCH /api/config/users/{name} - Design typed network partial updates such as
PATCH /api/config/network - Design typed container partial updates such as
PATCH /api/config/containers/{name} - Ensure every partial update loads current desired state, applies a typed patch, validates full desired state, renders candidate state, promotes atomically, activates, reports job progress, and rolls back on failure
- Do not allow partial API paths to directly mutate derived files or runtime systemd/Quadlet state
- Define normalized desired-state import and export bookends before implementing partial mutation APIs
- Add import/export round-trip tests so API-managed state can always be backed up or cloned as a config bundle
- Add drift detection/reporting expectations for rendered files under
/data/config/
Validation And Readiness
- Run
uv run --extra dev pytestfor the provisioning package - Run
uv run --extra dev ruff check .for the provisioning package - Run Nix parse checks for touched modules and VM tests
- Run the relevant NixOS VM tests after controller/service refactors
- Verify rootfs closure remains within the 1 GB squashfs budget after dependency changes
- Search docs for stale synchronous
/api/configresponse descriptions after API changes - T999: Reconcile final implementation, feature specs, and docs before close-out
Explicitly Deferred
- Do not add SQLAlchemy, a database, or repository abstractions without a persistent data model that cannot be represented by config state
- Do not add Redis/SAQ unless jobs must survive service restarts or run independently of the provisioning process
- Do not add OAuth/JWT auth unless SSH-signature administration stops meeting operator needs
- Do not add Vite/SPA integration for the bootstrap UI; prefer server-rendered/HTMX follow-up work