You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

66 lines
3.2 KiB
Markdown

# gimme-job Project Rules for Claude Code
## Core Principles
1. **gimme-job is an "AI-assisted learning, non-AI runtime" project.**
- During runtime scraping, only adapter code and manifest YAML files are used — no AI calls.
- Claude Code is invoked ONLY when learning a new site or repairing a broken adapter.
2. **Runtime must never require AI.**
- All adapters must work with pure Python + Playwright, reading from site manifests.
- Do not add AI/LLM calls inside adapter `prepare()`, `apply_search()`, `apply_filters()`, `collect_cards()`, `paginate()`, or `normalize()`.
3. **Use Chrome persistent profile `JobAgent` for browser automation.**
- Always use `playwright.chromium.launch_persistent_context()` with `user_data_dir` pointing to `workspace/chrome-profiles/JobAgent/`.
- Never use `browser.new_context()` or `playwright.chromium.launch()` directly.
4. **Do not introduce `storage_state` as a new strategy.**
- Chrome profile reuse is the only session persistence mechanism.
5. **Summarization uses Ollama `qwen3.5:9b` only.**
- No other LLM should be called during the run pipeline.
6. **Final notification target is KakaoTalk self-memo.**
- Fall back to local Markdown file only when KakaoTalk fails.
7. **When a site fails, set `repair_needed=True` — never silently ignore failures.**
- After 2 consecutive failures, mark the site as `repair_needed`.
- `repair_needed` sites are skipped during `run`, noted in the summary.
8. **Selector robustness rules:**
- Prefer `aria-label`, `data-*` attributes, and semantic HTML over CSS class names.
- Avoid brittle `nth-child` selectors unless no better option exists.
- Always define fallback selectors (list multiple selectors per field).
- Handle zero-result states explicitly — `ZERO_RESULTS_EXPECTED` is a normal exit.
## When Generating or Patching Adapters
Each site adapter must implement the `BaseJobSiteAdapter` protocol from `gimme_job/adapters/base.py`:
- `prepare(page, config)` — navigate to start URL, wait for page readiness
- `apply_search(page, query)` — inject keywords/location
- `apply_filters(page, query)` — apply date/type filters via UI
- `collect_cards(page, config)` — extract all visible job cards as `RawJobCard`
- `paginate(page, page_index, config)` — advance to next page, return `False` when done
- `normalize(raw)` — clean/normalize a `RawJobCard` into `JobPostingCandidate`
Each site also requires:
1. `sites/{site_id}.yaml` — manifest YAML
2. `gimme_job/adapters/{site_id}.py` — adapter Python file
3. `tests/adapters/test_{site_id}.py` — smoke test
4. `workspace/manifests/{site_id}.learning-report.md` — learning report
The smoke test must verify:
- The search page opens successfully
- Either result cards are detected OR a zero-result state is explicitly handled
- At least 2 fields can be extracted from a card (or zero-result confirmed)
## File Locations
- Site manifests: `sites/{site_id}.yaml`
- Adapters: `gimme_job/adapters/{site_id}.py`
- Adapter tests: `tests/adapters/test_{site_id}.py`
- Prompts: `gimme_job/prompts/`
- Templates: `gimme_job/templates/`
- Workspace artifacts: `workspace/` (captures, traces, screenshots, dom, manifests, generated)
- Database: configured via `GIMME_JOB_DB_PATH` env var (default: `gimme_job.db`)