Implementation Roadmap¶
Status (2026-06-02): Phases 1–5 and the Settings slice have shipped. On top of the job-search vertical (Adzuna primary + Seek + LinkedIn adapters, the FastAPI server at
/api/v1/, the CLI), the LLM layer is live —kairos.llmcovers the LiteLLM client, JD analyzer + match scoring, skill extractor, resume tailor, and WebSocket streaming, with pandoc-based resume rendering inkairos.renderand a keyring-backed secret store inkairos.secrets. The React frontend ships theJobSearch,ResumeForm, andSettingsviews (Sidebar/Topbar nav, LLM key + settings UI). Remaining work, in flight onfeat/audit-followups: the Phase 6 apply/track backend and the matching Job Detail / JD-analysis / Applications frontend views (Phase 8c–e), plus a CI test gate. Phase 6 Indeed stays deferred (Cloudflare ban risk — Adzuna API covers the same listings); Phase 7 polish is ongoing.
Phase Overview¶
gantt
title Kairos Implementation Phases
dateFormat YYYY-MM-DD
axisFormat %b %d
section Phase 1 Skeleton + API
Project setup + Docker Compose :done, p1a, 2026-04-01, 2d
Domain entities + interfaces (core) :done, p1b, after p1a, 2d
PostgreSQL models + migrations :done, p1c, after p1b, 1d
FastAPI server + core routes :done, p1d, after p1b, 2d
kairos.client library :done, p1e, after p1d, 1d
section Phase 2 Seek Search
SeekClient + parser :done, p2a, after p1e, 3d
PostgreSQL job repository :done, p2b, after p1c, 1d
Job search + list API endpoints :done, p2c, after p2a, 1d
section Phase 3 LLM Analysis
LiteLLM client setup :done, p3a, after p2c, 2d
JD analysis + match scoring :done, p3b, after p3a, 2d
Analysis API endpoints :done, p3c, after p3b, 1d
section Phase 4 Resume Tailoring
Resume parser + import :done, p4a, after p3c, 2d
Tailoring prompts + validation :done, p4b, after p4a, 3d
Resume API endpoints + WebSocket :done, p4c, after p4b, 1d
section Phase 5 CLI
Typer commands + kairos.client :done, p5a, after p1e, 3d
Rich output formatting :done, p5b, after p5a, 1d
section Settings + Secrets
Keyring secret store :done, psa, after p4c, 1d
LLM key + settings API :done, psb, after psa, 1d
Settings + Resume form UI :done, psc, after psb, 2d
section Phase 6 Apply + Track
Apply workflow + browser open :active, p6a, after psc, 1d
Application tracking :active, p6b, after p6a, 2d
Indeed adapter (deferred) :p6c, after p6a, 3d
section Phase 7 Polish
Error handling + edge cases :p7a, after p6c, 2d
CLI UX polish :p7b, after p7a, 2d
section Phase 8 Web Frontend
React project setup :done, p8a, after p1e, 2d
Core views (search + resume + settings) :done, p8b, after p8a, 5d
Job detail + JD analysis + tracker UI :active, p8c, after p8b, 3d
Phase Details¶
Phase 1: Skeleton + API ✅ Shipped¶
Goal: Working project with a running FastAPI server, PostgreSQL, and shared client library.
- Init Python project with
uv init, configurepyproject.toml - Docker Compose: PostgreSQL 18 + FastAPI (hot reload)
- Define all entities in
kairos.core(Pydantic models) - Define all interfaces (ABCs for Repository + Service)
- Define exception hierarchy per module
- Config loading via
pydantic-settings(TOML + env vars) - PostgreSQL setup + Alembic migrations (001 initial, 002 cursor index, 003 owner_id)
- FastAPI server with health check, RFC 9457 problem+json errors (no envelope), middleware stack
kairos.clientlibrary with typed async methods
Verify: docker compose up -d succeeds. curl localhost:8880/api/v1/health/ returns 200.
Phase 2: Job Search ✅ Shipped¶
Goal: Search jobs across multiple platforms via API.
- AdzunaSearchService (HTTP API, primary source — free, structured JSON, no scraping)
- SeekClient + LinkedInClient with httpx + beautifulsoup4 (fallback)
- Rate limiter with randomized delays for scrapers
- PostgreSQL job repository (SQLAlchemy, owner-scoped)
- API endpoints:
POST /api/v1/jobs/search,GET /api/v1/jobs(cursor-paginated),GET /api/v1/jobs/{id},POST /api/v1/jobs/{id}/fetch-details,DELETE /api/v1/jobs/{id} - Backend pytest suite locks the contract (270 cases overall, +12 DB-gated)
Verify: curl -X POST localhost:8880/api/v1/jobs/search -d '{"keywords":"rust","country":"AU","location":"Perth"}' returns results.
Phase 3: LLM Analysis ✅ Shipped¶
Goal: Analyze JDs with an LLM via API.
- LiteLLM async client (
LiteLlmClient, multi-provider) with mapped error hierarchy - JD analysis + skill-extraction prompt templates
Analyzer+SkillExtractorwith Pydantic structured output and match scoring- API endpoints:
POST /api/v1/jobs/{id}/analyze,GET /api/v1/jobs/{id}/analysis, plus the/api/v1/skillsSkill Profile CRUD JdAnalysispersisted (migration 006)
Verify: POST /api/v1/jobs/{id}/analyze returns analysis with match score.
Phase 4: Resume Tailoring ✅ Shipped¶
Goal: Import resume, tailor per JD via API, with WebSocket streaming.
- Resume section parser + import flow, PostgreSQL resume repository (migration 004)
Tailorwith anti-hallucination prompts + a validation pass (validation.py)- API endpoints: resume CRUD under
/api/v1/resumes(incl.set-baseand per-section patch),POST /api/v1/jobs/{id}/tailor,GET /api/v1/jobs/{id}/tailored-resume,POST /api/v1/tailored-resumes/{id}/approve,POST /api/v1/tailored-resumes/{id}/export - WebSocket streaming of
TailorEvents atWS /api/v1/jobs/{id}/tailor/stream(kairos.llm.streaming+kairos.api.ws.tailor) - Pandoc-based rendering in
kairos.render(migration 007 stores tailored resumes)
Verify: Full resume flow works via API: import → tailor → approve → export.
Phase 5: CLI ✅ Shipped¶
Goal: Lightweight command-line client for scripting and daily use.
- Typer-based command structure, talks to the API over HTTP
- Commands:
jobs search/list/view,resumes import/list/delete/tailor/export,skills extract/list, plusconfigandinit - Rich output formatting (tables)
applicationscommands deferred to Phase 6
Verify: kairos jobs search "rust" --location perth returns results.
Settings + Secrets ✅ Shipped¶
Goal: Manage LLM provider keys and settings safely, from the API and the web UI.
- Keyring-backed secret store (
kairos.secrets.secret_store) + env injection on startup - LLM key + settings API:
GET/PATCH /api/v1/config/llm,GET /api/v1/config/llm/models,POST /api/v1/config/llm/key,DELETE /api/v1/config/llm/key/{env_var} - Frontend
Settingsview (LLM key + model UI) andResumeFormview, wired via theuseSettings/useResumeFormhooks, with Sidebar/Topbar nav
Verify: Set an LLM key in the Settings view → POST /api/v1/jobs/{id}/analyze succeeds.
Phase 6: Apply + Track ◐ In flight (feat/audit-followups)¶
Goal: Complete semi-automatic workflow.
- Apply action (open browser with application URL)
- Application tracking API endpoints (this branch adds the backend slice)
- ~~Indeed adapter (playwright)~~ — deferred, Cloudflare ban risk
- ~~LinkedIn adapter~~ ✅ shipped in Phase 2 (public guest API, httpx + bs4)
Verify: Full flow: search → analyze → tailor → apply → track.
Phase 7: Polish¶
Goal: Production-quality UX.
- Graceful error handling across API and CLI
- CLI: colorized output, progress spinners, help text
- Resume export (PDF/LaTeX)
- API rate limits, retries, and edge case handling
Phase 8: Web Frontend (React) ◐ Search + resume + settings shipped¶
Goal: Browser-based access to all Kairos features.
- ✅ React 19 + Vite+ + TypeScript scaffold with token-based design system (Phase 8a)
- ✅ Core search view: filter panel matching all CLI flags, cursor pagination, per-platform error surfacing (Phase 8b)
- ✅
ResumeFormandSettingsviews (resume import/edit + LLM key/model), Sidebar/Topbar nav - Job detail view + JD analysis surface (in flight on
feat/audit-followups, Phase 8c) - Resume tailor diff viewer (planned, Phase 8d)
- LLM streaming consumed via the existing
WS /api/v1/jobs/{id}/tailor/streamendpoint (frontend wiring planned) - Application tracker board (in flight on
feat/audit-followups, Phase 8e) - Responsive design polish for mobile access (planned)
Verify: Open browser → search → analyze → tailor → track — full workflow.
Definition of Done¶
- All tests pass with
pytest ruff checkandruff formatpass with no issues- Core workflow works end-to-end (search → analyze → tailor → apply → track)
- At least Seek adapter is fully functional
- Resume tailoring produces valid LaTeX output
- API server handles all core operations via REST + WebSocket
- CLI can perform the full workflow via API
- All frontends produce consistent behavior through the unified API
- API keys and JWT secrets handled securely (env var or config, never logged)
docker compose up -dbrings up the full stack