diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index e9b200a..812e7c9 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -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" } \ No newline at end of file diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index 8276514..c211cb0 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -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 diff --git a/.ciagent/REQUIREMENTS.md b/.ciagent/REQUIREMENTS.md index 339d55c..67dbbc7 100644 --- a/.ciagent/REQUIREMENTS.md +++ b/.ciagent/REQUIREMENTS.md @@ -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://: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 diff --git a/.ciagent/ROADMAP.md b/.ciagent/ROADMAP.md index 8c50d5a..4849fff 100644 --- a/.ciagent/ROADMAP.md +++ b/.ciagent/ROADMAP.md @@ -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) | \ No newline at end of file +These are indicative and will be refined by ci-roadmapper at the start of each milestone. \ No newline at end of file diff --git a/.ciagent/config.json b/.ciagent/config.json index ebdc4da..bc32585 100644 --- a/.ciagent/config.json +++ b/.ciagent/config.json @@ -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"] } ] },