Skip to main content
ClaudeWave
Skill40.3k estrellas del repoactualizado 3d ago

freehire-search

>

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/MadsLorentzen/ai-job-search /tmp/freehire-search && cp -r /tmp/freehire-search/.agents/skills/freehire-search ~/.claude/skills/freehire-search
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# freehire Search Skill

Search live job listings from the **[freehire.me](https://freehire.me)** job
aggregator — an open-source IT job board that normalizes postings from ~50 ATS
platforms across many countries into one schema. No authentication, no API key,
and **zero runtime dependencies** — it runs with just `bun`. The market is chosen
per query via facet flags (`--region`, `--country`), so the same skill works for a
forker in any market out of the box.

> This is a country-agnostic worked example of the repo's job-portal-skill pattern,
> like `linkedin-search`. Unlike the HTML-scraping portals, it queries freehire's
> public JSON API, so results are structured (skills, seniority, region facets)
> rather than parsed from markup.

## ⚠️ Scope: tech-focused

freehire's corpus already includes some non-tech postings (it crawls whole company
career pages), **but its faceted filtering — skills, categories, and seniority
dictionaries — is tuned tech-first today**, so this skill scopes its triggers to
software / data / engineering / tech roles, where the filtering is strong. Non-tech
coverage exists but is still maturing; don't rely on this skill for general
(non-technical) job coverage yet.

## ℹ️ Hosted-service dependency (best-effort, no SLA)

This skill depends on a third-party hosted service, freehire.me. Reads are
**public and unauthenticated** — the same zero-signup bar as `linkedin-search`.

**freehire.me is a personal project but actively maintained; it runs on a
best-effort basis (no formal SLA).** If the API is unreachable, the CLI fails
gracefully — a non-zero exit with a clear error message — so an outage degrades
this source rather than breaking the surrounding workflow.

**Self-hosting / swappable base URL.** The freehire backend is a separate
MIT-licensed repo — [`strelov1/freehire`](https://github.com/strelov1/freehire)
(Go + PostgreSQL + Meilisearch) — that stands up with one command via Docker
Compose (`make up` → API on `:8080`, same `/api/v1/...` paths). The skill honors a
base-URL env var, `FREEHIRE_API_URL` (default `https://freehire.me`), so pointing
it at a local instance is a one-line change:

```bash
FREEHIRE_API_URL=http://localhost:8080 bun run .agents/skills/freehire-search/cli/src/cli.ts search -q "go"
```

Caveat: standing up the *API* is light, but keeping a *full, continuously-fresh*
mirror (millions of postings across ~50 platforms) is resource-heavy — a
self-hoster would either crawl a scoped subset of sources or point the env var back
at the hosted API.

## When to use this skill

- Search for tech job openings by keyword, in a given region/country or remotely —
  each result comes back with its **full description**, no per-hit follow-up needed
- Filter by seniority, category, skills, or recency (posted within N days)
- Look one freehire posting up by its slug (including a closed one)

## Commands

### Search job listings

```bash
bun run .agents/skills/freehire-search/cli/src/cli.ts search [-q "<keywords>"] [facet flags]
```

Key flags:
- `--query <text>` / `-q <text>` — keyword search (title, skill, role). Full-text; optional.
- `--jobage <days>` — posted within N days (maps to `posted_within_days`).
- `--page <n>` — 1-indexed page. Default 1.
- `--limit <n>` / `-n <n>` — results per page (API limit). Default 25.
- `--format json|table|plain` — default `json`.
- `--description-format markdown|text|html` — how each result's full description is
  rendered. Default `markdown`, which keeps the posting's headings and requirement
  lists intact. `json` output only.

**Search results already carry the full description.** This skill queries freehire's
agent search endpoint, which replaces the index's truncated preview with each
posting's complete text, so a search of 20 roles is 1 request rather than 1 + 20.
Do **not** loop `detail` over search hits to read their descriptions — reach for
`detail` only to look one posting up by slug (e.g. from the tracker, or a posting
already closed and therefore absent from search). Full descriptions are verbose:
keep `--limit` modest, and pre-filter on title/company before reading bodies -
or pass `--no-description` for a cheap discovery pass that keeps every other
field and drops the bodies entirely (fetch a shortlisted job's body with
`detail`, or re-run the search without the flag).

Facet filters (values come from freehire's controlled vocabularies; comma-separate for OR within a facet):
- `--region <codes>` — macro-region, e.g. `global`, `eu`, `us`, `apac`, `latam`, `cis`. `--region eu,us`. Use `none` to match jobs whose region could **not** be resolved (see "Partial data" below).
- `--country <codes>` — ISO-3166 alpha-2, e.g. `--country DE,GB`
- `--city <names>` — city name(s), e.g. `--city Berlin`
- `--seniority <levels>` — `junior`, `middle`, `senior`, `staff`, `principal`, `lead`, …
- `--category <cats>` — `backend`, `frontend`, `fullstack`, `devops`, `ml_ai`, `qa`, …
- `--skill <names>` — canonical skill(s), e.g. `--skill go,kubernetes`
- `--company <slug>` — company slug (from a result's `company_slug`)
- `--remote <mode>` — `remote` | `hybrid` | `onsite` (`work_mode` facet)
- `--facet <key=value>` — any other facet param (repeatable), e.g. `--facet salary_min=100000`

> **Location is a facet, not free text.** Unlike `linkedin-search`'s `--location`,
> freehire filters geography through the structured `--region`/`--country`/`--city`
> facets. Discover the live values for a market at
> [`/api/v1/jobs/facets`](https://freehire.me/api/v1/jobs/facets) (append `?q=<role>`
> to scope it) — never invent facet values.

### Fetch full job detail

```bash
bun run .agents/skills/freehire-search/cli/src/cli.ts detail <slug|url> [--format json|plain]
```

`slug` is the `id` from a `search` result (e.g. `golang-zensar-2bxu6dxm`). You may
also pass a full `https://freehire.me/jobs/<slug>` URL. Returns the full (HTML-stripped)
description, skills, region/country, and — when the posting is enriched — seniority,
category, employm