peregrine/docs/plans/2026-02-24-generalization-handoff.md
pyr0ball c368c7a977 chore: seed Peregrine from personal job-seeker (pre-generalization)
App: Peregrine
Company: Circuit Forge LLC
Source: github.com/pyr0ball/job-seeker (personal fork, not linked)
2026-02-24 18:25:39 -08:00

4.8 KiB

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