The Problem
CAAL is a local voice assistant that extends its capabilities through auto-discovered n8n workflows exposed as tools via MCP. The codebase has accumulated technical debt that directly impacts engineer productivity: a circular import dependency in the setup wizard blocks straightforward changes, 240 duplicated six-line API blocks across 43 files create maintenance risk, and four files exceed 1,300 lines each making localized changes risky. Compounding these issues, the development Docker compose runs in host networking mode with privileged escalation, and the pinned Next.js version carries a published high-severity CVE.
What This Does
CAAL functions as a local voice assistant built on LiveKit Agents, supporting multiple LLM/STT/TTS provider combinations (Ollama + Kokoro/Groq + Piper). The repository contains two primary projects: frontend (144 files, Next.js/React) and src (21 files, Python/CAAL core).
The core workflow executes as follows: the frontend app.tsx renders the setup wizard, which collects user configuration written to .env. On subsequent runs, the setup-wizard.tsx/integrations-step.tsx/provider-step.tsx modules validate connectivity. The src/caal/llm/ modules (llm_node.py, ollama_node.py, providers/__init__.py) handle LLM inference, while src/caal/integrations/mcp_loader.py and src/caal/integrations/n8n.py discover and load n8n workflows as callable tools. The frontend/components/tools/ panel routes tool invocations through frontend/hooks/useToolRegistry.ts to the API routes under frontend/app/api/tools/. The mobile app (mobile/lib/main.dart, Flutter) provides a companion client for Android and iOS.
How It Is Wired
Execution starts at frontend/components/app/app.tsx, which renders the setup wizard and livekit agent interface. User configuration flows through frontend/hooks/useWakeWordState.ts and frontend/hooks/useToolStatus.ts into frontend/components/tools/tools-panel.tsx, which queries frontend/hooks/useToolRegistry.ts for available n8n-discovered tools. Tool invocations hit frontend/app/api/tools/registry/route.ts, which delegates to src/caal/integrations/mcp_loader.py. That module scans n8n workflow definitions and exposes them as MCP tools; src/caal/llm/llm_node.py processes the tool calls via Ollama or Groq. The src/caal/integrations/n8n.py module contains the n8n discovery logic but participates in a circular import with src/caal/llm/providers/__init__.py — four files are cycle members. The frontend/app/api/setup/ route handlers (test-groq/route.ts, test-hass/route.ts, test-n8n/route.ts, etc.) contain 240 duplicated six-line blocks that validate provider connectivity and should be extracted into a shared helper. The Docker compose development file (docker-compose.dev.yml) uses network_mode: host and privileged mode, which removes the network boundary and grants container-every host capability.
Code Health & Issues
The static analysis identified 39 findings across 7 categories:
- [HIGH/soundness] Import cycle member x4:
frontend/components/setup/setup-wizard.tsx,frontend/components/setup/integrations-step.tsx,frontend/components/setup/provider-step.tsx— mutually reachable modules requiring extraction or inversion to break. - [HIGH/cognitive_load] Deep nesting x22:
src/caal/integrations/n8n.py,src/caal/llm/llm_node.py,src/caal/llm/ollama_node.py— max indentation depth 6; guard clauses recommended. - [HIGH/clarity] Duplicated code blocks x240: 43 files including
frontend/app/api/greetings/route.ts,frontend/app/api/prompt/route.ts,frontend/app/api/settings/route.ts— 6-line patterns repeated across the codebase. - [HIGH/cognitive_load] Oversized file x4:
mobile/lib/screens/settings_screen.dart(1393 lines),frontend/components/settings/settings-panel.tsx,voice_agent.py— changes ripple widely; split by responsibility. - [MEDIUM/resilience] Broad exception handling x2:
src/caal/integrations/mcp_loader.py,src/caal/llm/llm_node.py— bareexceptswallows errors indiscriminately. - [MEDIUM/cognitive_load] High branching density x5:
src/caal/utils/formatting.py,frontend/components/livekit/agent-control-bar/tool-status-indicator.tsx,frontend/components/livekit/agent-control-bar/wake-word-toggle.tsx— 47 branch points over 157 lines. - [MEDIUM/resilience] Empty catch block:
frontend/app/layout.tsx— silently discards errors.
Additional SDLC observations from the hygiene audit:
- Pinned
next@15.5.7carries CVE-2026-44575 (high) and 27 other advisories - No CI configuration exists despite 130 source files
- Docker compose dev uses
privileged+hostnetworking - Base image
python:3.11-slim-bookwormis not pinned by digest - Dependabot/Renovate not configured; 2 manifest files unmanaged
- Test suite: 1 file against 160 source files (ratio 0.006)
How To Use It
Setup:
git clone https://github.com/CoreWorxLab/caal.git
cd caal
cp .env.example .env
nano .env # Set CAAL_HOST_IP to your server's LAN IP
GPU mode (Ollama + Kokoro):
docker compose up -d
CPU-only mode (Groq + Piper):
docker compose -f docker-compose.cpu.yaml up -d
Apple Silicon:
./start-apple.sh
Open http://YOUR_SERVER_IP:3000 and complete the First-Start Wizard. Required environment variables are defined in frontend/.env.example and .env.example at root. API keys for Groq, Ollama, or Piper must be configured during wizard setup.
Running the build/test: No CI workflow currently exists. To build the frontend: cd frontend && pnpm build. Python tests reside in frontend/lib/__tests__/workflow-sanitizer.test.ts.
Real-World Use
A user enables "Hey Cal" wake word detection via OpenWakeWord. The voice stream routes through LiveKit to the backend, where src/caal/llm/llm_node.py processes speech-to-text and determines intent. If the user asks "What's the weather in Boston?", CAAL routes to the n8n-discovered hass_control tool (MCP-integrated Home Assistant support). The tool executes against the user's Home Assistant instance and returns a response spoken via TTS (Kokoro or Piper). The setup wizard's provider-step (frontend/components/setup/provider-step.tsx) lets the user select Ollama (local) or Groq (cloud) for the LLM, and Kokoro or Piper for TTS — this choice writes the selection to .env and configures the corresponding node module.
The Bottom Line
The repository has a solid architecture for a local voice assistant with extensible n8n tooling, but the import cycle in setup modules, 240 duplicated API blocks, and four oversized files create real friction for changes. The privileged Docker compose configuration and unpatched Next.js CVE are immediate security concerns. This is suitable for teams wanting a self-hosted voice assistant with n8n extensibility who can tolerate addressing the outlined code health items. Teams requiring out-of-the-box security hygiene and maintainable code should plan the upgrade and refactor sprints before production deployment.