# Session 2026-06-07 (cont.) — Phase 6: scheduled scrape + auto-score

## What's live
- New table `scheduled_searches` with: label, source (or null for fan-out),
  keywords, location, remote, posted_within_days, per_source_limit, cron,
  score_after, enabled, last_run_at, last_run_summary
- `worker/scheduler.py` runs APScheduler, reads schedules from DB,
  re-syncs every 60s (so MCP edits propagate without restart)
- `worker/tasks.run_scheduled(id)` — fans out the scrape, scores every "new"
  job against every active profile, writes the summary back to the row
- `worker/tasks.score_all_new()` — utility, also exposed as the `score_all` MCP tool
- **`jobscraper-worker.service`** installed + enabled. Healthy since 2026-06-07T16:13Z
- 4 new MCP tools: `add_schedule`, `list_schedules`, `remove_schedule`,
  `run_schedule_now`, plus `score_all`

## Verified live
- Seeded schedule `daily-python-remote-6am` (cron `0 6 * * *`, fan-out)
- One forced run via `run_scheduled(id)`:
  - linkedin: 6 ingested
  - greenhouse: 10 ingested
  - lever: 12 ingested
  - usajobs: 0 (needs key)
  - **41 jobs scored** against the active profile
  - `last_run_at` written back to DB
- Worker restart → log: `registered schedule label=daily-python-remote-6am cron=0 6 * * *` → ready to fire at next 06:00 UTC

## Total MCP tool count: 25
| Group | Tools |
|---|---|
| Sources/jobs | list_sources, search_jobs, search_all, get_job, list_jobs, mark_job, set_notes, fetch_details |
| Profile/match | set_profile, get_profile, score_new_jobs, score_all, top_jobs, list_resumes, register_resume |
| Apply | plan_apply, dry_run_apply, submit_apply, list_applications, cancel_application |
| Schedule | add_schedule, list_schedules, remove_schedule, run_schedule_now |
| Ops | db_stats |

## DB state
```
jobs               : 41
companies          : 20
sources            :  6 (4 enabled)
profiles           :  1
resumes            :  1 (dummy)
applications       :  1 (cancelled test)
scheduled_searches :  1 (daily 06:00 UTC)
scrape_runs        : 20
```

## Services running
- `jobscraper-api.service` — REST API on 127.0.0.1:8081, active
- `jobscraper-worker.service` — APScheduler, active, daily schedule registered

## What you can now do from Claude Desktop

```
# Add another schedule (e.g. data roles, ATS only, every 4 hours)
add_schedule label="ats-data-4h" keywords="data engineer" cron="0 */4 * * *" \
             source=null per_source_limit=15

# Tighten or loosen a source's throttle without touching code
# (writes sources.config_json.throttle)
# — TODO: dedicated set_source_throttle MCP tool, currently via direct DB edit

# Morning routine
top_jobs min_score=0.3 limit=20
plan_apply job_id=<n>
dry_run_apply job_id=<n>
submit_apply application_id=<m> confirm_token="<tok>"
```

## Open / next
- `set_source_throttle(name, min_delay, max_delay, reqs_per_hour)` MCP tool —
  currently throttle overrides require manual `config_json` edit
- USAJobs API key (webmaster@usajobs.gov) — enable 4th source
- Adzuna keys + flip enabled=1 — adds Indeed-equivalent coverage without proxy
- More sources from `docs/ADD_SOURCE.md`
- Real resume PDF + profile values
- Apply-confirmation email watching (Gmail MCP integration)
