Skip to content

Search Jobs

Search lets you find jobs from multiple sources. Adzuna API is the primary source (free, structured JSON). Seek and LinkedIn scrapers are available as fallback.

Usage

# Default: Adzuna API, interactive country/city selection
uv run kairos jobs search "software engineer" -i

# Direct flags
uv run kairos jobs search "rust developer" --country AU --location Perth

# Multiple platforms
uv run kairos jobs search "backend" -c AU -l Sydney --platforms adzuna,seek,linkedin

# With filters
uv run kairos jobs search "python" -c US -l "San Francisco" \
  --salary-min 120000 \
  --job-type fulltime \
  --posted-within 7 \
  --max-results 30

Search Criteria

Field Flag Description Example
Keywords (positional) Role titles or skills "software engineer"
Country --country, -c Country code AU, US, UK, CA, NZ
Location --location, -l City from predefined list Perth, Sydney, "New York City"
Interactive --interactive, -i Pick country & city from numbered list
Platforms --platforms, -p Comma-separated sources adzuna, seek, linkedin
Salary Min --salary-min Minimum salary 70000
Job Type --job-type, -t Employment type fulltime, parttime, contract
Posted Within --posted-within, -d Days since posted 7, 14, 30
Max Results --max-results, -n Maximum jobs to return 50

Available Cities

Each country has 15 predefined cities (14 cities + Remote):

AU US UK CA NZ
Sydney New York City London Toronto Auckland
Melbourne Los Angeles Manchester Vancouver Wellington
Brisbane Chicago Birmingham Montreal Christchurch
Perth San Francisco Leeds Calgary Hamilton
Adelaide Seattle Edinburgh Ottawa Tauranga
... ... ... ... ...

Use --interactive (-i) to see the full list.

How It Works

sequenceDiagram
    participant U as User
    participant CLI as CLI
    participant API as kairos-api
    participant AZ as Adzuna API
    participant SK as Seek Scraper
    participant DB as PostgreSQL

    U->>CLI: kairos jobs search "developer"
    CLI->>API: POST /api/v1/jobs/search
    API->>AZ: GET api.adzuna.com/v1/api/jobs/au/search/1
    API->>SK: GET seek.com.au/developer-jobs
    AZ-->>API: JSON (structured)
    SK-->>API: HTML (parsed)
    API->>DB: UPSERT jobs (deduplicated, owner-scoped)
    API-->>CLI: Job list

Data Sources

Adzuna API (Primary)

  • Method: HTTP API calls to api.adzuna.com
  • Auth: Free API key from developer.adzuna.com
  • Data: Structured JSON — title, company, location, salary, description
  • Coverage: AU, US, UK, CA, NZ + 14 more countries
  • Limits: ~250 requests/day (free tier)
  • Reliability: High — official API, no scraping

Seek.com.au (Fallback Scraper)

  • Server-side rendered pages with embedded Apollo GraphQL JSON
  • Rate limit: 2-5 second delay between requests
  • ~22 results per page
  • No login required

LinkedIn (Fallback Scraper)

  • Public job listings via guest API (no login required)
  • Rate limit: 2-6 second delay between requests
  • 25 results per page

~~Indeed~~ (Deferred)

  • Requires headless browser (Cloudflare protection)
  • High ban risk — deferred in favor of Adzuna API

Deduplication

Jobs are deduplicated by (owner_id, platform, platform_job_id) using PostgreSQL UPSERT. Re-running a search updates the same user's existing jobs rather than creating duplicates; two users can independently track the same listing without colliding.

Web frontend

The same search is available from the web app: every CLI flag (--country, --location, --platforms, --salary-min, --job-type, --posted-within, --max-results) has a UI control. Press Enter to submit; per-platform errors render inline so a Seek scraping failure doesn't hide successful Adzuna results.

Work Rights

Jobs carry three work rights fields (populated during JD analysis):

Field Meaning
PR Required Employer requires permanent residency
Citizenship Required Employer requires citizenship
Visa Sponsorship Employer is willing to sponsor a visa

These fields are nullable — many JDs don't state requirements explicitly.