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.
3.6 KiB
3.6 KiB
gimme-job Learn Mode — System Instructions
You are working inside the gimme-job codebase.
Your Goal
Create or update a job site adapter so that gimme-job run --site {site_id} works without any AI assistance at runtime.
Core Rules
- Runtime must not require AI. The adapter must work with pure Python + Playwright.
- Use Chrome persistent profile
JobAgent— neverbrowser.new_context()directly. - No storage_state — Chrome profile reuse is the only session persistence mechanism.
- Prefer robust selectors:
aria-label,data-*attributes, semantic HTML. Avoid brittlenth-child. - Always define fallback selectors (list multiple per field in the manifest).
- Handle zero-result states explicitly —
ZERO_RESULTS_EXPECTEDis a normal exit. - No detail page visits by default — extract from card list only.
- If a date filter exists in the UI, use it.
Files to Generate
For site_id {site_id}:
sites/{site_id}.yaml— Site manifest YAMLgimme_job/adapters/{site_id}.py— Adapter Python filetests/adapters/test_{site_id}.py— Smoke testworkspace/manifests/{site_id}.learning-report.md— Learning report
Adapter Interface
The adapter must implement BaseJobSiteAdapter from gimme_job/adapters/base.py:
class BaseJobSiteAdapter(Protocol):
site_id: str
def prepare(self, page: Page, config: SiteManifest) -> None: ...
def apply_search(self, page: Page, query: SearchQuery) -> None: ...
def apply_filters(self, page: Page, query: SearchQuery) -> None: ...
def collect_cards(self, page: Page, config: SiteManifest) -> list[RawJobCard]: ...
def paginate(self, page: Page, page_index: int, config: SiteManifest) -> bool: ...
def normalize(self, raw: RawJobCard) -> JobPostingCandidate: ...
Use @register("{site_id}") from gimme_job/adapters/registry.py to register the adapter.
Manifest Schema
Key YAML fields (see gimme_job/models/manifest.py for full Pydantic schema):
site_id: {site_id}
enabled: true
repair_needed: false
identity:
label: "Site Name"
base_url: "https://..."
start_url_template: "https://...?q={keywords_urlencoded}"
browser:
profile_mode: persistent_chrome_profile
profile_name: JobAgent
headed_on_learn: true
headless_on_run: true
search:
keyword_mode: url_param # url_param | input_field | none
date_mode: none # none | url_param | click_filter
date_filter_text: null
result_list_wait_selector: null
pagination:
mode: none # none | next_button | url_increment
next_button_selectors: []
max_pages: 3
extract:
container_selectors:
- "CSS selector for each job card container"
fields:
title:
text: ["h2 a", "h3"]
company:
text: [".company-name"]
location:
text: [".location"]
posted_text:
text: ["time", ".date"]
url:
attr:
selector: "a[href*='/jobs/']"
name: href
post_filters:
include_posted_text:
- "today"
- "1 day ago"
Smoke Test Requirements
The smoke test in tests/adapters/test_{site_id}.py must:
- Open the job search page
- Either detect result cards OR confirm zero-result state
- Extract at least 2 fields from a card (title + one other) OR confirm zero results
- Pass with
pytest tests/adapters/test_{site_id}.py
Acceptance Criteria
Learning is successful when ALL of these are true:
sites/{site_id}.yamlexists and is validgimme_job/adapters/{site_id}.pyexists with no syntax errorstests/adapters/test_{site_id}.pyexistsgimme-job test {site_id}passes (smoke test)- At least 1 field extraction logic is verified