docs(init): validate specification — v0.2 Proxmox LXC deployment

---ci---
project: praxis
phase: 0
milestone: v0.2
status: specify
---/ci---
This commit is contained in:
Praxis CI
2026-08-01 13:51:29 +00:00
parent 7fe52f34bc
commit 70994e18ad
5 changed files with 104 additions and 93 deletions
+5 -9
View File
@@ -1,12 +1,8 @@
{
"phase": 2,
"stage": "complete",
"milestone": "v0.1",
"phase_role": "final",
"phase": 0,
"stage": "specify",
"milestone": "v0.2",
"phase_role": "pre_execution",
"attempts": 0,
"updated_at": "2026-08-01T00:07:00Z",
"release_status": "created",
"release_url": "https://git.cloudinit.dev/coreci/praxis/releases/tag/v0.0.2",
"milestone_complete": true,
"next_milestone": "v0.2"
"updated_at": "2026-08-01T14:00:00Z"
}
+23 -18
View File
@@ -1,7 +1,7 @@
# Praxis — Voice-first AI Apprenticeship Platform
**Milestone:** v0.1 (foundation)
**Status:** complete
**Milestone:** v0.2 (Proxmox LXC deployment)
**Status:** in-progress
**Autonomy:** full
## Vision
@@ -14,25 +14,24 @@ Praxis is a voice-first, AI-tutored skill platform for learners in resource-cons
Build a voice-first AI apprenticeship platform where learners engage in spoken role-play scenarios with AI tutors, receive coaching debriefs, and progress via mastery gates — working on low-cost phones over constrained bandwidth.
## v0.1 Scope (Foundation)
## v0.2 Scope (Proxmox LXC Deployment)
v0.1 establishes the minimal viable voice loop on which all later capabilities build. v1.0 is reserved for a working, tested product; v0.1 is the foundation milestone.
v0.2 deploys praxis into a Proxmox LXC container, reusing and adapting the battle-tested deployment toolkit from `~/coreci/scripts/proxmox/`. The v0.1 voice loop becomes deployable infrastructure — a Docker image runs the Python/Pipecat server (serving the React client as static files) inside an LXC container on the operator's Proxmox cluster.
**v0.1 in scope:**
- Phase 0: pre-execution (specify, clarify, research, plan, grill)
- Phase 1: minimal viable voice loop — one persona, one branching scenario, ASR + TTS round-trip (<600ms target), single learner state, Ollama-hosted LLM foundation
**v0.2 in scope:**
- Docker image (multi-stage: Node builds `client/dist`, Python runs `server` + serves dist via FastAPI StaticFiles)
- `scripts/proxmox/` adapted from coreci (api.sh, lxc-deploy, lxc-clone, lxc-config, lxc-start, health-check, rollback, stage-snippet, firstboot-hook, timing)
- `scripts/install-service.sh` (systemd unit for `docker compose up`)
- Secret wiring: PROXMOX_* sourced from coreci's `.env.secrets`; GITEA_TOKEN + DEEPGRAM_API_KEY from praxis's secrets
- Health-check adapted for `/health` :8789 (praxis's endpoint, not coreci's `/healthz` :18080)
- E2E deploy verification against the live Proxmox cluster
**v0.1 out of scope (deferred to later milestones):**
- Mastery scoring, competency rubrics, verifiable credentials
- Multi-language support (launch: Canadian English; French-Canadian noted for later)
- Employer / program dashboard
- Live Assist on-the-job companion mode
- WhatsApp / SMS bot, USSD fallback
- Drill Mode, Review Mode
- Open scenario authoring marketplace
- B2B SaaS
- Voice cloning of real individuals
- Early childhood education, medical procedures (permanently out of scope per PRD §11.6)
**v0.2 out of scope (deferred):**
- Mastery scoring, competency rubrics (deferred to v0.3)
- CARTESIA_API_KEY / OLLAMA_API_KEY provisioning (infrastructure-only; server degrades gracefully per v0.1 design)
- Traefik proxy / public TLS (pilot = direct bridge IP access)
- Multi-environment (dev/staging/prod) — single pilot CT
- vmbr1 private network (pilot uses vmbr0 DHCP)
## Product Principles (non-negotiable)
@@ -88,6 +87,12 @@ v0.1 establishes the minimal viable voice loop on which all later capabilities b
| D-018 | Scenario format = **YAML DSL → Pydantic → Pipecat Flows** | Research-verified: YAML is human-authorable + diffable + supports comments (critical for learning-designer rationale per C-7); Pydantic gives typed runtime; Pipecat Flows consumes the schema for branching. JSON is wire format only. | 0.85 | JSON DSL (no comments), code-authored (couples authoring to engineering) |
| D-019 | v0.1 guardrail layer = **pluggable interface** with Customer Service ruleset implementation | Research: v0.1 is low-risk (Customer Service) but architecture must support pluggable guardrails for later high-risk domains (health/electrical). Ruleset: no legal/financial/medical advice, no real-company employee impersonation, stay-in-role, session-start disclaimer audio, no PII beyond hardcoded profile. | 0.80 | No guardrails (violates C-6), hardcoded non-pluggable rules (blocks future domains) |
| D-020 | LLM access = **Ollama Cloud direct API** (`https://ollama.com/api/chat` + `OLLAMA_API_KEY`) — no local daemon | Research-verified: `:cloud` tags are real Ollama hosted-inference on NVIDIA cloud partners. Direct API eliminates local-daemon deployment dependency. `gemma4:cloud` (256K ctx) → role-play fast path; `deepseek-v4-flash:cloud` (1M ctx, no-think mode) → debrief. Self-host `gemma4:e4b` is the post-pilot cost-reduction path. | 0.85 | Local Ollama daemon proxy mode (adds deployment dependency) |
| D-021 | v0.2 scope = **Proxmox LXC deployment** (replaces roadmap's mastery-scoring v0.2) | User-directed: deploy praxis into an LXC container hosted on Proxmox, reusing `~/coreci/scripts/proxmox/` methods. Mastery scoring deferred to v0.3. | 0.95 | v0.2 = mastery scoring (original roadmap), v0.2 = LXC deploy + mastery (too large) |
| D-022 | Artifact = **Docker image in LXC** (nesting=1) | User-directed. Isolates Python/Pipecat deps; coreci's clone script already sets `features=nesting=1`. Avoids venv/pip first-boot fragility (Pipecat has many native deps). Multi-stage build: Node stage produces `client/dist`, Python stage runs the server. | 0.85 | Clone repo + venv + pip (fragile first-boot), sdist tarball (needs build/release step) |
| D-023 | Client serving = **FastAPI serves `client/dist` as StaticFiles** | User-directed. Single port (8789), simplest pilot — no nginx/caddy. The Docker image bundles the pre-built dist. | 0.90 | Separate static server (nginx/caddy — more moving parts), client out of scope |
| D-024 | Voice-service keys = **infrastructure-only** for v0.2 | User-directed. Server starts and `/health` passes even without CARTESIA/OLLAMA keys (v0.1 graceful degradation). Keys provisioned in a later milestone. Only GITEA_TOKEN + DEEPGRAM_API_KEY are in `.env.secrets`. | 0.90 | Provision all keys in v0.2 (premature — deploy infra first) |
| D-025 | Image distribution = **host-build → `pct push` tarball** (research decision, see RESEARCH.md) | The LXC CT may not route to the internet (coreci pattern: host-fetch → pct push). Build the Docker image on the PVE host (Docker available on Proxmox host) and `docker save | pct exec -- docker load`, or `pct push` a tarball. Avoids needing a container registry. | 0.75 | Gitea container registry (requires registry setup), Docker Hub (external dependency) |
| D-026 | Proxmox secrets sourced from **`~/coreci/.ciagent/.env.secrets`** | Same Proxmox cluster, same operator. PROXMOX_API_URL/TOKEN/NODE/STORAGE/TEMPLATE_VOLID already provisioned there. Praxis's `.env.secrets` adds GITEA_TOKEN + DEEPGRAM_API_KEY. The deploy script sources both. | 0.90 | Duplicate proxmox secrets in praxis (drift risk) |
### Confidence updates from research
+33 -3
View File
@@ -1,9 +1,9 @@
# Praxis — Requirements
**Milestone:** v0.1 (foundation)
**Status:** complete
**Milestone:** v0.2 (Proxmox LXC deployment)
**Status:** in-progress
Formal requirements with REQ-IDs. Scoped to v0.1 unless noted. Later-milestone requirements are marked `deferred`.
Formal requirements with REQ-IDs. Scoped to the active milestone unless noted. Later-milestone requirements are marked `deferred`. v0.1 requirements (complete) are retained for reference.
## Functional Requirements
@@ -121,6 +121,36 @@ Formal requirements with REQ-IDs. Scoped to v0.1 unless noted. Later-milestone r
- C-7 Scenarios authored by domain experts + learning designers; AI generates variations only
- C-8 Latency budget < 600ms end-to-end
## Deployment (v0.2 — Proxmox LXC)
| REQ-ID | Requirement | Priority | Phase | Status |
|--------|-------------|----------|-------|--------|
| REQ-DEPLOY-01 | Multi-stage Dockerfile: Node stage builds `client/dist` via `npm run build`, Python stage runs the Pipecat server and serves `client/dist` via FastAPI StaticFiles (D-022, D-023) | must | P1 | pending |
| REQ-DEPLOY-02 | `docker-compose.yml` defining the praxis service with volume for SQLite DB (`praxis.db`), env injection, port mapping (8789), restart policy | must | P1 | pending |
| REQ-DEPLOY-03 | Port `scripts/proxmox/api.sh` from coreci verbatim (PVE REST helpers: pve_curl, pve_poll, pve_nextid, pve_get, pve_env, pve_lxc_env_args) | must | P1 | pending |
| REQ-DEPLOY-04 | Port `scripts/proxmox/lxc-clone.sh` adapted for praxis (hostname=praxis, port 8789, features=nesting=1 for Docker-in-LXC) | must | P1 | pending |
| REQ-DEPLOY-05 | Port `scripts/proxmox/lxc-config.sh` adapted: hookscript snippet, lxc.environment injects GITEA_TOKEN + DEEPGRAM_API_KEY + voice-service env vars (empty if unprovisioned), PRAXIS_PORT=8789 | must | P1 | pending |
| REQ-DEPLOY-06 | Port `scripts/proxmox/firstboot-hook.sh` adapted: host-builds Docker image (or loads pre-built), `pct exec` runs `docker compose up -d` inside the CT, health-checks `/health` :8789 | must | P1 | pending |
| REQ-DEPLOY-07 | Port `scripts/proxmox/health-check.sh` adapted for praxis: polls `http://<bridge-ip>:8789/health` (not coreci's `/healthz` :18080) | must | P1 | pending |
| REQ-DEPLOY-08 | Port `scripts/proxmox/{lxc-start,rollback,stage-snippet,timing}.sh` from coreci (adapted for praxis snippet name) | must | P1 | pending |
| REQ-DEPLOY-09 | Port `scripts/proxmox/lxc-deploy.sh` orchestrator: clone → config → start → health-check → rollback-on-failure, with idempotency (--recreate/--reconfigure) | must | P1 | pending |
| REQ-DEPLOY-10 | `scripts/install-service.sh` adapted: creates praxis user, data/log dirs, env file, systemd unit (`praxis.service`) that runs `docker compose up -d`, health-checks `/health` :8789 | must | P1 | pending |
| REQ-DEPLOY-11 | `scripts/proxmox/praxis.service` systemd unit running `docker compose up -d` with `Restart=on-failure` | must | P1 | pending |
| REQ-DEPLOY-12 | Secret wiring: extend `config.json` secrets.scopes with proxmox + voice scopes; source PROXMOX_* from `~/coreci/.ciagent/.env.secrets` | must | P1 | pending |
| REQ-DEPLOY-13 | FastAPI `server/__main__.py` mounts `client/dist` as StaticFiles at `/` (serving the React client from the same port as the API) | must | P1 | pending |
| REQ-DEPLOY-14 | `.env.example` updated with PROXMOX_* + deployment env vars (documented, not secret) | must | P1 | pending |
| REQ-DEPLOY-15 | E2E deploy verification: `scripts/proxmox/test/` bats tests (mirroring coreci's test structure) + health-check + smoke against live CT | must | P1 | pending |
| REQ-DEPLOY-16 | `.dockerignore` excluding `node_modules`, `.git`, `__pycache__`, `.pytest_cache`, `client/dist` (rebuilt in image), `.ciagent/.env*` (secrets) | must | P1 | pending |
## Non-Functional Requirements (v0.2)
| REQ-ID | Requirement | Target | Phase | Status |
|--------|-------------|--------|-------|--------|
| REQ-NFR-DEPLOY-01 | Deploy idempotency — re-running `lxc-deploy.sh` against a healthy CT is a no-op; unhealthy CT requires explicit `--recreate`/`--reconfigure` | must | P1 | pending |
| REQ-NFR-DEPLOY-02 | Deploy rollback — any stage failure (clone/config/start/health) triggers `rollback.sh` (stop + destroy the partial CT) | must | P1 | pending |
| REQ-NFR-DEPLOY-03 | First-boot install time | < 5 min (Docker image load + compose up + health) | P1 | pending |
| REQ-NFR-DEPLOY-04 | Secrets never committed to git (`.ciagent/.env*` in `.gitignore`, secrets injected via `lxc.environment` at runtime) | must | P1 | pending |
## Out of Scope (v0.1)
- Mastery scoring, competency rubrics, verifiable credentials
+34 -62
View File
@@ -1,90 +1,62 @@
# Praxis — Roadmap
**Milestone:** v0.1 (foundation)
**Status:** complete
**Milestone:** v0.2 (Proxmox LXC deployment)
**Status:** in-progress
## Milestone Philosophy
v0.1 is the **foundation milestone** — it establishes the minimal viable voice loop (one persona, one scenario, ASR+TTS+LLM round-trip, single learner state). v1.0 is reserved for a working, tested product and is a future milestone.
v0.2 deploys praxis into a Proxmox LXC container, reusing and adapting the battle-tested deployment toolkit from `~/coreci/scripts/proxmox/`. The v0.1 voice loop becomes deployable infrastructure. v1.0 is reserved for a working, tested product and is a future milestone.
## v0.1 Phases (2 phases)
## v0.2 Phases (2 phases)
### Phase 0 — Pre-Execution (complete)
### Phase 0 — Pre-Execution (in-progress)
**Branch:** `phase/00-pre-execution` → merged to `milestone/v0.1-praxis`
**Ship target:** `v0.0.0` (patch release, NFR milestone type — docs-only)
**Status:** ✓ complete (tagged v0.0.0; release pending — Gitea repo not yet created)
**Branch:** `phase/00-pre-execution` → merged to `milestone/v0.2-lxc-deploy`
**Ship target:** `v0.1.0` (patch release, NFR milestone type — docs/planning only)
**Status:** in-progress
Pipeline stages: SPECIFY → CLARIFY → RESEARCH → PLAN → GRILL
**Goal:** Produce all `.ciagent/` planning artifacts, validated requirements, research-grounded architecture, and persona-assigned vertical-slice plans for Phase 1.
**Goal:** Produce all `.ciagent/` planning artifacts for v0.2: validated requirements (REQ-DEPLOY-01..16), research-grounded Docker-in-LXC architecture, persona-assigned vertical-slice plans for Phase 1.
**Deliverables:**
- PROJECT.md (validated)
- REQUIREMENTS.md (formal REQ-IDs)
- ARCHITECTURE.md (research-refined)
- PERSONAS.md (persona roster + territory)
- PROJECT.md (v0.2 scope validated)
- REQUIREMENTS.md (16 REQ-DEPLOY IDs + 4 NFR-DEPLOY IDs)
- ARCHITECTURE.md (deployment topology: Docker-in-LXC, image distribution, secret injection)
- PERSONAS.md (updated roster for deploy-heavy milestone)
- Phase 1 plan (vertical slices with wave ordering)
### Phase 1 — Minimal Viable Voice Loop (complete)
### Phase 1 — LXC Deploy Implementation (pending)
**Branch:** `phase/01-minimal-voice-loop` → merged to `milestone/v0.1-praxis`
**Ship target:** `v0.0.1` (patch release, feature milestone type)
**Status:** ✓ complete (tagged v0.0.1; release pending — Gitea repo not yet created)
**Branch:** `phase/01-lxc-deploy` → merged to `milestone/v0.2-lxc-deploy`
**Ship target:** `v0.1.1` (patch release, feature milestone type)
**Status:** pending
**Goal:** A single learner can open the client, speak to an AI tutor playing a Customer Service role-play scenario, hear the tutor respond with <600ms round-trip latency, and have the session logged to learner state.
**Goal:** A working `lxc-deploy.sh` orchestrator that clones a Debian template from the Proxmox cluster, configures the CT with Docker + nesting, builds/loads the praxis Docker image on first boot, starts the service via systemd, and health-checks `/health` :8789 — all idempotent with rollback on failure.
**Implemented (5 slices, 3 waves, 26 tasks, 22 commits):**
1. SLICE-01 — Latency spike probes (R1-R4) + report
2. SLICE-02 — Thin vertical voice loop (walking skeleton: Pipecat + Deepgram + Cartesia/Piper + Ollama Cloud + React/WebRTC)
3. SLICE-03 — Branching scenario (YAML→Pydantic→Pipecat Flows) + guardrails + interruptibility
4. SLICE-04 — SQLite learner state + per-session cost logging
5. SLICE-05 — Coaching debrief (deepseek-v4-flash no-think) + full React client UX + e2e smoke
### Final Phase (P2) — Review + Ship (pending)
**Verification:** 73 tests pass, 9 skipped (pending live API keys), 0 failed. 15/15 P1 REQ-IDs covered. 2 P0 fixes applied. 6 P1+ flagged for post-hoc review.
### Final Phase (P2) — Review + Ship (complete)
**Branch:** `phase/02-final-review-ship` → merged to `milestone/v0.1-praxis` → merged to `main`
**Ship target:** final patch = v0.1 milestone release
**Status:** ✓ complete (review APPROVE_WITH_NOTES, audit HEALTHY)
**Branch:** `phase/02-final-review-ship` → merged to `milestone/v0.2-lxc-deploy` → merged to `main`
**Ship target:** final patch = v0.2 milestone release
**Status:** pending
**Goal:** Multi-persona code review, project audit, milestone merge to main, milestone release.
**Outcome:** 0 P0 issues (2 from VERIFY confirmed in place), 9 P1+ flagged for post-hoc review, 0 escalations. Audit HEALTHY (0 critical, 3 cosmetic warnings fixed). 15/15 REQ-IDs verified.
## v0.1 Milestone (complete — reference)
## Future Milestones (post-v0.1, indicative)
v0.1 was the **foundation milestone** — minimal viable voice loop (one persona, one scenario, ASR+TTS+LLM round-trip, single learner state). Shipped as `v0.0.0` (phase 0) → `v0.0.1` (phase 1) → `v0.0.2` (final/milestone release).
## Future Milestones (post-v0.2, indicative)
| Milestone | Scope (indicative) |
|-----------|-------------------|
| v0.2 | Mastery scoring + competency rubrics for the Customer Service path |
| v0.3 | Second scenario + second persona; Drill Mode |
| v0.4 | Live Assist on-the-job companion |
| v0.5 | Low-bandwidth surfaces (WhatsApp, offline cache) |
| v0.6 | Multi-language (French-Canadian, then PRD's 10-language list) |
| v0.7 | Employer / program dashboard |
| v0.8 | Credentialing (verifiable, shareable) |
| v0.9 | USSD fallback, feature-phone support |
| v0.3 | Mastery scoring + competency rubrics for the Customer Service path (deferred from original v0.2) |
| v0.4 | Second scenario + second persona; Drill Mode |
| v0.5 | Live Assist on-the-job companion |
| v0.6 | Low-bandwidth surfaces (WhatsApp, offline cache) |
| v0.7 | Multi-language (French-Canadian, then PRD's 10-language list) |
| v0.8 | Employer / program dashboard |
| v0.9 | Credentialing (verifiable, shareable) |
| v1.0 | Working, tested product — multiple paths, multi-market, production-ready |
These are indicative and will be refined by ci-roadmapper at the start of each milestone.
## Requirement Coverage (v0.1 final — verified)
| REQ-ID | Phase | Status |
|--------|-------|--------|
| REQ-VOICE-01 | P1 | ✓ covered |
| REQ-VOICE-02 | P1 | ✓ covered |
| REQ-VOICE-03 | P1 | ✓ covered (probe built; live number pending keys) |
| REQ-VOICE-04 | P1 | ✓ covered |
| REQ-SCEN-01 | P1 | ✓ covered |
| REQ-STATE-01 | P1 | ✓ covered |
| REQ-LLM-01 | P1 | ✓ covered (live call pending keys) |
| REQ-LLM-02 | P1 | ✓ covered (live call pending keys) |
| REQ-DEBRIEF-01 | P1 | ✓ covered |
| REQ-ORCH-01 | P1 | ✓ covered |
| REQ-ORCH-02 | P1 | ✓ covered |
| REQ-SCEN-FMT-01 | P1 | ✓ covered |
| REQ-NFR-LAT-01 | P1 | ✓ covered (probe built; live number pending keys) |
| REQ-NFR-COST-01 | P1 | ✓ covered (logging) |
| REQ-NFR-SAFE-01 | P1 | ✓ covered (baseline) |
These are indicative and will be refined by ci-roadmapper at the start of each milestone.
+9 -1
View File
@@ -3,7 +3,7 @@
{
"slug": "praxis",
"name": "Praxis",
"milestone": "v0.1",
"milestone": "v0.2",
"status": "specify"
}
],
@@ -91,6 +91,14 @@
{
"name": "release",
"env_vars": ["GITEA_TOKEN"]
},
{
"name": "proxmox",
"env_vars": ["PROXMOX_API_URL", "PROXMOX_API_TOKEN", "PROXMOX_NODE", "PROXMOX_STORAGE", "PROXMOX_TEMPLATE_VOLID", "PROXMOX_LXC_VMID", "PROXMOX_TLS_SKIP_VERIFY"]
},
{
"name": "voice",
"env_vars": ["DEEPGRAM_API_KEY", "CARTESIA_API_KEY", "OLLAMA_API_KEY"]
}
]
},