REVIEW.md: 2 P0 fixed (stale test defaults, sandbox isolation), 8 P1+ flagged for post-hoc review. Verdict: APPROVE_WITH_NOTES. AUDIT.md: 0 critical, 5 warnings. Reconstruction PASS, file discipline PASS, branch hygiene PASS, commit discipline PASS. Verdict: HEALTHY. Doc-drift fixed (REQ statuses → complete). P0 fixes in working tree: 1. lxc-config.bats: aligned stale defaults with production code 2. lxc-deploy.bats: fixed sandbox isolation (HOME redirect) ---ci--- project: praxis phase: 2 milestone: v0.2 status: review ---/ci---
16 KiB
Praxis — Voice-first AI Apprenticeship Platform
Milestone: v0.2 (Proxmox LXC deployment) Status: phase 1 complete — P2 review/ship in-progress Autonomy: full
Vision
Praxis is a voice-first, AI-tutored skill platform for learners in resource-constrained environments. Instead of courses, videos, and quizzes, learners practice real job scenarios through real-time spoken conversation with AI tutors. The platform treats every learner as an apprentice to a master craftsperson — open the app, talk, do the job, get better at it.
One-line pitch: Praxis turns every smartphone into a master craftsperson that talks to you, challenges you, and helps you get good at your job.
Objective
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.2 Scope (Proxmox LXC Deployment)
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.2 in scope:
- Docker image (multi-stage: Node builds
client/dist, Python runsserver+ 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 fordocker 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.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)
- Voice is the primary interface. Text is fallback, not default.
- Doing > Knowing. Every session produces observable action, not passive consumption.
- One skill, one outcome. Each path is a job someone can get.
- Works on a cheap phone, on 2G. Engineering constraints are product features.
- The AI is a master, not a chatbot. Personality, standards, opinions.
- Mastery gates progression. Move on when you can do the thing.
- Failure is the curriculum. AI provokes mistakes, then coaches recovery.
Requirements (summary — see REQUIREMENTS.md for formal REQ-IDs)
- Voice conversation engine: real-time ASR + streaming TTS, <600ms round-trip, interruptible, persona switching
- Scenario engine: branching role-plays with failure-injection and dynamic difficulty (v0.1: one scenario)
- Learner state: progress, session history, mastery accumulation (v0.1: single-learner state, no mastery scoring yet)
- LLM foundation: Ollama-hosted open-weights models
gemma4:cloudanddeepseek-v4-flash:cloud - Low-bandwidth surfaces (later milestones)
- Employer dashboard (later milestones)
Constraints
- C-1 Voice is primary interface; text is fallback only
- C-2 Must work on $100 Android phone over 2G/3G
- C-3 Cost ≤ $3/active learner/month (target markets; v0.1 is Canada launch — relaxed for pilot)
- C-4 Audio-only in v1 (no large video assets)
- C-5 Open-weights LLM via Ollama catalog —
gemma4:cloud+deepseek-v4-flash:cloud - C-6 Domain safety guardrails + human-in-the-loop + disclaimers for safety-sensitive domains
- C-7 Scenarios authored by domain experts + learning designers; AI generates variations only
- C-8 Latency budget < 600ms end-to-end (ASR → LLM → TTS)
Key Decisions
| ID | Decision | Rationale | Confidence | Alternatives |
|---|---|---|---|---|
| D-001 | Launch market = Canada (path: Customer Service) | User-directed; Canada as initial market for v0.1 pilot. PRD named Kenya — overridden. | 0.70 | Kenya + Customer Service (PRD default) |
| D-002 | Milestone = v0.1 foundation (v1.0 reserved for working/tested product) | User-directed; v0.1 is the foundation slice (Phase 0 + Phase 1 minimal voice loop). v1.0 is a future milestone. | 0.90 | v1.0 = Phase 0 + Phase 1 (too ambitious for first milestone) |
| D-003 | LLM foundation = Ollama catalog — gemma4:cloud + deepseek-v4-flash:cloud |
User-directed; open-weights via Ollama, two base models for edge/cloud split. Research phase to verify exact catalog IDs. | 0.75 | Llama-family, Mistral-family, Qwen-family |
| D-004 | Defer monetization model decision to Phase 1 | PRD §11.5 explicitly lists this as a Phase 1 decision (B2C paid, B2B per-seat, donor-funded, government). | 0.85 | Decide now (insufficient data) |
| D-005 | Single-project mode | Fresh repo with one project; no multi-project need. | 1.00 | Multi-project mode |
| D-006 | "One persona" = one voice persona; scenario role-play uses the same TTS voice as mentor (no distinct character voice in v0.1) | Minimizes v0.1 surface area; PRD's full persona-switching (REQ-VOICE-06) is deferred. Same voice avoids a second TTS configuration to validate. | 0.70 | Two voices (mentor + character) — adds TTS config risk |
| D-007 | "Single learner state" = local single hardcoded profile, no auth, no multi-tenant; persisted via SQLite on-device (or local file fallback) | v0.1 is a pilot harness, not a production multi-user system. Auth/multi-tenant is a later-milestone concern. SQLite chosen as the default local store; research phase may refine. | 0.80 | In-memory only (no persistence), server-side Postgres (premature) |
| D-008 | Interruptibility = abort-and-yield (learner speech cuts AI TTS immediately, AI yields the floor, no pause/resume state machine in v0.1) | Matches real-conversation semantics per PRD §6.1; pause/resume adds state-machine complexity inappropriate for v0.1. | 0.75 | Pause/resume state machine |
| D-009 | Failure-injection hook = architecturally present (scenario declares a failure_mode field) but NOT actively provoked in v0.1 sessions |
v0.1 validates the data model and one scenario's success criteria; provoking failures is a coaching-debrief feature tied to mastery (deferred). Hook present so Phase 2+ can activate it without schema change. | 0.70 | Active failure injection in v0.1 (couples to deferred mastery engine) |
| D-010 | v0.1 Canada Customer Service scenario = "Angry customer requesting refund on a damaged product" (retail context, single branch point) | Concrete, universally recognizable, low safety-risk (non-medical/non-electrical). One branch point (customer escalates vs accepts resolution) keeps scenario runtime minimal while exercising branching. | 0.65 | "Customer with wrong booking" (hospitality — less universal for Canada pilot) |
| D-011 | Coaching debrief = included in v0.1 as a single end-of-session text+voice summary (not the full PRD §5.1 multi-moment replay) | The debrief is part of the core daily loop and cheap to include at a basic level. Full replay/multi-moment coaching is tied to mastery (deferred). | 0.70 | Exclude debrief entirely (loses core loop identity), full replay (over-scoped) |
| D-012 | v0.1 cost ceiling = no enforced ceiling (pilot); architecture must not bake in assumptions that would prevent meeting ≤$3/learner/month post-pilot | C-3 is a target-market constraint. Canada pilot is a foundation/tech-validation milestone, not a unit-economics milestone. Logging actual cost per session is a v0.1 NFR to inform later milestones. | 0.85 | Enforce $3 ceiling in v0.1 (premature optimization, wrong market) |
| D-013 | ASR = Deepgram Nova-3 streaming (cloud, WebSocket) | Research-verified: streaming-native, ~200-300ms first partial, accent-robust for Canadian English, first-class Pipecat integration, Canada data-residency available. Fallback: Groq-hosted Whisper. | 0.85 | whisper.cpp (breaks <600ms budget), OpenAI Whisper API (batch) |
| D-014 | TTS = Cartesia Sonic (cloud, ~120ms first audio) primary; Piper (self-hosted, ~80ms) fallback behind interface | Research-verified: Cartesia #1 on Speech Arena; Piper is open-weights post-pilot ≤$3/learner path. R4 risk: all-cloud path ~670ms — Piper local may be required for production v0.1 latency. | 0.80 | ElevenLabs (quality but higher latency/cost), Amazon Polly |
| D-015 | Client = React + WebRTC via Pipecat client SDK | Research-verified: Pipecat ships React/RN/Swift/Kotlin SDKs; web client = fastest v0.1 iteration, no app-store distribution, upgrades to React Native for Android later. | 0.85 | Python CLI harness (dev-integration only), native Android Kotlin (premature) |
| D-016 | Transport = WebRTC (UDP, sub-50ms audio); WebSocket dev fallback | Research-verified: WebRTC is Pipecat's production transport; adaptive bitrate, UDP. SSE/HTTP rejected (unidirectional/high overhead). | 0.85 | WebSocket-only (higher audio latency), custom raw HTTP/2 |
| D-017 | Orchestration = Pipecat (not custom, not Vocode) | Research-verified: 13.8k★, active, integrates Deepgram+Cartesia+Piper+Ollama natively, has VAD/interrupt/Flows for branching. Vocode stale since Nov 2024. Custom orchestration rebuilds solved problems. | 0.85 | Vocode (stale), custom from scratch |
| 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 |
| 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) |
| D-027 | VMID = auto (fresh allocation via pve_nextid) |
CLARIFY auto-decide (full autonomy). Don't reuse coreci's fixed PROXMOX_LXC_VMID — praxis gets its own CT on the same cluster. | 0.95 | Reuse coreci's VMID (collision), hardcode a new fixed VMID (manual allocation) |
| D-028 | Docker installed inside the CT via apt (CT has network via vmbr0 DHCP) | CLARIFY auto-decide. Avoids needing Docker on the PVE host. The debian-12 template + nesting=1 supports Docker-in-LXC. firstboot hook runs pct exec to install docker.io + docker-compose-v2. |
0.90 | Docker on PVE host (extra host dependency), pre-baked template (custom template maintenance) |
| D-029 | Image built inside the CT (clone repo from Gitea, docker build, docker compose up) |
CLARIFY auto-decide. Self-contained — CT fetches its own source + builds. No image transfer needed. Slower first-boot (~3-5 min for build) but simpler and reproducible. | 0.80 | Build on PVE host + pct push tarball (host Docker dependency), pre-built image from registry (external dependency) |
| D-030 | CT network = vmbr0 DHCP only (pilot, no vmbr1, no Traefik proxy) | CLARIFY auto-decide. v0.2 is infrastructure-only pilot. Direct bridge IP access for health-check. Proxy/TLS deferred to a later milestone. | 0.90 | vmbr1 + Traefik proxy (over-scoped for pilot) |
Confidence updates from research
| ID | Before | After | Reason |
|---|---|---|---|
| D-003 | 0.75 | 0.95 | Both Ollama model IDs verified in catalog as real, current, cloud-hosted tags |
| D-007 | 0.80 | 0.90 | SQLite confirmed appropriate for v0.1 single-learner scale; no evidence favors alternatives |
Target Users (v0.1 pilot: Canada)
| Persona | Description | Pain |
|---|---|---|
| Aspiring Adebayo → "Aspiring Alex" | 19–28, Canada. Recent secondary school grad. Smartphone, limited data. Wants a service job. | Can't afford vocational school. Needs to actually do the job. |
| Upskilling Ursula → "Upskilling Uma" | 25–40, Canada. Retail, hospitality, healthcare. Wants promotion/new role. | No time for courses. Learns on the job. |
| Frontline Felix | Customer service / sales / field tech agent, hired recently. | Manager has no time to coach. Wants quick on-shift practice. |
Success Metrics (Year-1 targets, post-v0.1)
| Metric | Target | Why |
|---|---|---|
| Active weekly learners | 100k | Engagement, not downloads |
| Sessions per learner / week | ≥5 | Habit formation |
| Mastery rate per path | ≥40% completion | Real learning |
| Median session length | 6–10 min | On-the-go use |
| Cost / active learner / month | ≤$3 | Sustainable |
| Reported job/promotion outcome | ≥25% | North star |
| NPS (learner) | ≥50 | Word-of-mouth growth |
Open Questions (for research/clarify phases)
- Will learners talk to their phone in public? (earbuds + "no one will know" framing)
- How to certify mastery credibly? (employer/agency recognition)
- Domain safety minimum HITL for health/electrical scenarios
- Voice cloning / impersonation disclosure
- Monetization model (deferred to Phase 1)
- Skills that should remain out of scope
References
- PRD v0.1 (this document's source)
- ARCHITECTURE.md — system architecture
- ROADMAP.md — phase breakdown
- REQUIREMENTS.md — formal requirements with REQ-IDs