# Session Handoff — Generalization Implementation **Date:** 2026-02-24 **For:** Next Claude session implementing the public fork --- ## Current State The personal version (`/devl/job-seeker/`) is **complete and working** on `main`. ### What was completed in the 2026-02-24 session - Survey Assistant page (`app/pages/7_Survey.py`) — text paste + screenshot via moondream2 - Vision Service (`scripts/vision_service/`) — FastAPI on port 8002, `job-seeker-vision` conda env - LLM Router `images=` parameter — vision-aware routing - `survey_responses` table + `survey_at` column in SQLite - Kanban consolidation — applied+survey as pre-kanban section; offer+hired merged column - `survey_received` email classifier label - Forgejo remote: https://git.opensourcesolarpunk.com/pyr0ball/job-seeker.git ### Remote repo ``` git remote: https://git.opensourcesolarpunk.com/pyr0ball/job-seeker.git branch: main (up to date as of 2026-02-24) ``` --- ## What to Implement Next Follow the plan at `docs/plans/2026-02-24-job-seeker-app-generalize.md`. The design doc is at `docs/plans/2026-02-24-generalize-design.md`. **Target directory:** `/Library/Development/devl/job-seeker-app/` (new repo, no shared history) **CRITICAL:** Do NOT start implementing the public fork until explicitly asked. The user confirmed this. --- ## Complete List of Hardcoded Personal References Everything that must be extracted into `config/user.yaml` via a `UserProfile` class: | File | Hardcoded value | Generalized as | |------|----------------|----------------| | `company_research.py` | `"Meghan McCann"` in prompts | `profile.name` | | `company_research.py` | `_NDA_COMPANIES = {"upguard"}` | `profile.nda_companies` | | `company_research.py` | `_SCRAPER_DIR = Path("/Library/...")` | bundled in Docker image | | `generate_cover_letter.py` | `SYSTEM_CONTEXT` with Meghan's bio | `profile.career_summary` | | `generate_cover_letter.py` | `LETTERS_DIR = Path("/Library/...")` | `profile.docs_dir` | | `4_Apply.py` | contact block (name/email/phone) | `profile.*` | | `4_Apply.py` | `DOCS_DIR = Path("/Library/...")` | `profile.docs_dir` | | `5_Interviews.py` | email assistant persona "Meghan McCann is a Customer Success..." | `profile.name + profile.career_summary` | | `6_Interview_Prep.py` | `"Meghan"` in interviewer prompts | `profile.name` | | `7_Survey.py` | `_SURVEY_SYSTEM` — "The candidate values collaborative teamwork..." | `profile.career_summary` or survey persona field | | `scripts/vision_service/main.py` | `model_id = "vikhyatk/moondream2"`, `revision = "2025-01-09"` | `config/llm.yaml` vision_service block | | `match.py` | `RESUME_PATH = Path("/Library/...Meghan_McCann_Resume...")` | configurable in Settings | | `Home.py` | `"Meghan's Job Search"` | `f"{profile.name}'s Job Search"` | | `finetune_local.py` | all `/Library/` paths + `"meghan-cover-writer"` | `profile.*` | | `2_Settings.py` | `PFP_DIR`, host service paths (manage-services.sh etc.) | removed / compose-driven | | `config/llm.yaml` | hard-coded `base_url` values | auto-generated from `user.yaml` | --- ## New Components to Dockerize ### Vision Service - Currently: `job-seeker-vision` conda env, port 8002, `manage-vision.sh` - In public fork: separate container in `single-gpu` / `dual-gpu` profiles only - In `remote` / `cpu` profiles: vision falls back to cloud backends - Model configurable via env var in container (default: moondream2) ### CompanyScraper - Currently: `/Library/Development/scrapers/companyScraper.py` (external path) - In public fork: bundled directly in the app image at a fixed internal path --- ## Key Architectural Decisions (from design doc) 1. **`UserProfile` class** wraps `config/user.yaml` — imported everywhere personal data is used 2. **Four Docker Compose profiles:** `remote`, `cpu`, `single-gpu`, `dual-gpu` 3. **First-run wizard** gates the app until `config/user.yaml` exists (5-step flow) 4. **No shared git history** with personal repo — fresh `git init` in target dir 5. **`.env` file** generated by wizard (never hand-edited), gitignored, contains resolved paths 6. **`config/llm.yaml` base URLs** are derived values auto-generated from `user.yaml` services block 7. **Claude Code Wrapper + Copilot Wrapper** removed from Services tab entirely --- ## Files/Paths in Personal Repo to Reference - Entry point: `app/app.py` - All pages: `app/pages/` - DB helpers: `scripts/db.py` (single source of truth for schema) - LLM router: `scripts/llm_router.py` - Config: `config/llm.yaml`, `config/search_profiles.yaml` - Vision service: `scripts/vision_service/` (FastAPI + environment.yml) - Test suite: `tests/` --- ## Skill to Use When starting the generalization session: 1. Load `superpowers:executing-plans` skill 2. Reference `docs/plans/2026-02-24-job-seeker-app-generalize.md` as the plan 3. Work task-by-task with review checkpoints