Multi-Frontend Strategy¶
Kairos supports multiple frontends — CLI and Web App (React) — all powered by a single FastAPI backend.
Why a Unified API?¶
All clients go through one HTTP API — no exceptions:
graph TD
CLI["kairos-cli\n(typer)"]
Web["Web App\n(React 19 + Vite+)"]
Client["kairos.client\n(shared HTTP client)"]
API["kairos.api\n(FastAPI server, /api/v1/)"]
CLI --> Client
Web -->|HTTP| API
Client -->|HTTP| API
API --> Core["kairos.core"]
API --> Platform["kairos.platform"]
API --> LLM["kairos.llm"]
API --> DB["kairos.db"]
Benefits¶
| Benefit | Explanation |
|---|---|
| Single source of truth | Business logic lives in one place — the API layer |
| Behavioral consistency | All frontends produce identical results |
| Easier maintenance | Fix a bug once, all clients benefit |
| Auth in one place | API handles authentication; clients just pass tokens |
| Testable | API endpoints can be tested independently of any frontend |
Trade-offs¶
| Concern | Mitigation |
|---|---|
| CLI needs a running server | CLI can auto-spawn a local server if not running |
| Network overhead | Localhost HTTP adds < 1ms; LLM/scraping calls are seconds |
Prior Art¶
This is a well-established pattern:
- Docker CLI → Docker daemon REST API
- GitHub CLI (
gh) → GitHub REST/GraphQL API - Kubernetes
kubectl→ kube-apiserver - Terraform CLI → Terraform Cloud API
Shared Client Library¶
The CLI uses kairos.client — a Python HTTP client library wrapping all API calls:
# kairos.client provides typed API access
client = KairosClient("http://localhost:8880")
jobs = await client.jobs.search(criteria)
analysis = await client.jobs.analyze(job_id)
The Web App (React) calls the same API endpoints directly via fetch. WebSocket is reserved for future streaming work (LLM analysis progress).
Frontend Summary¶
| Frontend | Technology | Connection | Status |
|---|---|---|---|
| CLI | typer + kairos.client | HTTP to API | Shipped |
| Web App | React 19 + Vite+ + TypeScript | HTTP to API (/api/v1/) |
Shipped (search slice) |