Skip to content

Repository files navigation

JSCC — Job Search Command Center

ci

A pipeline tracker for a real job search. Ingests job descriptions, scores fit against a profile, drafts follow-ups for routine cases only, and surfaces stale opportunities. The eval-gated LLM stages ship in Phase B.

Part of the ai-portfolio index. Phase A (foundations) is complete; Phase B (evals + first LLM stage) is next. See CHANGELOG.md for the slice-by-slice arc.

Why this project

Three ideas being demonstrated at once:

  1. Eval-driven agent design. Every LLM stage is behind an eval suite. The extract / score split (D9) exists so extraction facts and scoring judgment can regress independently.
  2. Structural safety for dual-use data. The tool runs against real personal data and against a synthetic fixture. Safety is enforced by construction, not by user discipline — two isolated DBs stamped with a mode marker, and two egress points that share one definition of "personal": a pre-commit scanner guarding git, and an authenticated, redacting sanitizer guarding every LLM call (D7, D8). Redaction is unconditional and runs before the payload is authenticated, so no caller can opt out of it — including the ones that forget to. The guarantee's scope is stated narrowly and honestly in D8: structured identifiers and known names, not free-text NER.
  3. Knowing when not to automate. The drafter routes to a briefing card, not a prose draft, for anything non-routine (D10).

Quick start

uv sync
uv run python -m jscc validate-config
uv run python -m jscc db init
uv run python -m jscc seed --random-seed 42 --now 2026-08-28T12:00:00+00:00
uv run python -m jscc report

Default mode is synthetic. Switch by env: JSCC_DATA=real. The real DB (data/real.db) is gitignored; the synthetic one is tracked as a portfolio-visible fixture.

Sample output

uv run python -m jscc report after the seed above:

[mode: synthetic]
Funnel
------
  identified           6
  applied              8
  recruiter_screen     3
  hm_screen            3
  technical_loop       2
  onsite               1
  offer                0
  closed               2
  (total)             25

Stale alerts (13)
----------------
  hm_screen         Yield Model Co     Director of Engineering, ML  overdue by 25d (last interaction 32d ago, threshold 7d)
  applied           Rift Cloud         Director of Engineering, ML  overdue by 19d (last interaction 33d ago, threshold 14d)
  identified        Timber Motors      Director of Engineering, ML  overdue by 13d (last interaction 20d ago, threshold 7d)
  applied           Pinnacle Search    Director of Engineering, ML  overdue by 7d (last interaction 21d ago, threshold 14d)
  ...

Bit-reproducible for a pinned --random-seed and --now.

Repo layout

jscc/           library code
  config.py     load + validate stages.yaml, profile.yaml
  mode.py       synthetic/real mode resolution + DB path convention
  storage.py    SQLite persistence with stamped mode marker
  models.py     pydantic domain models (Application, Contact, Interaction, ...)
  seed.py       deterministic synthetic fixture (evaluation infrastructure)
  sanitizer.py  the LLM-egress choke point; redacts, then HMAC-wraps
  personal_data.py  one definition of "personal" — shared by the scanner + sanitizer
  instrumentation.py  @instrumented — cost/latency/token capture on every LLM call
  extraction.py the extract_jd interface (D9 step 1) + JD extraction prompt v1
  llm_client.py Anthropic client + StubExtractionClient fallback (no key configured yet)
  evals.py      hand-rolled eval harness (jd_extraction suite so far)
  fetcher.py    requests + readability JD fetcher; optional Playwright fallback for JS-heavy pages
  report.py     staleness detector + funnel counts
  cli.py        click entry point (ingest, dlq list, resolve-dlq, ...)
tests/          pytest suite (249 tests)
config/         stages.yaml, profile.example.yaml, pipeline.yaml (playwright_fallback flag)
evals/          eval suites (jd_extraction so far); evals/README.md
scripts/        pre-commit content scanner (imports its rules from jscc/personal_data.py); smoke_fetch.py (real-URL smoke test, not CI-gated)
decisions/      ADRs (see below)
docs/           design-principles.md; smoke-test-results.md (smoke_fetch.py output snapshot)
.github/        CI workflow
data/           synthetic.db (tracked); real.db (gitignored)

ADRs

Design decisions with rejected alternatives:

The ten locked design principles behind them are in docs/design-principles.md.

Development

uv sync
uv run pytest              # ~seconds
uv run pre-commit install  # enable the safety scanner
uv run playwright install chromium  # optional -- only needed to use the Playwright fetch fallback

The pre-commit scanner refuses commits that match name/email/phone patterns or entries in a local .safety/danger-list.local.txt (gitignored).

Status

Phase A hardening complete: three rounds of adversarial + reviewer-walkthrough gates, structural fixes for every critical + high finding, 5 ADRs. Phase B in flight: B1 (eval suite), B2a (extraction prompt + client plumbing), B3a (baseline fetcher + DLQ core), B3b (Playwright fallback + real-URL smoke test), and B4 (JD paste-only path) shipped. No ANTHROPIC_API_KEY is configured yet, so extraction runs against a stub client end-to-end — live prompt iteration to the ≥80% eval bar (B2b) is next once a key is available. 203 pytest cases.

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages