mcpField
F
freehire-search

freehire-search

github.com/madslorentzen生产力67.9k199 次安装3 天前更新
代码仓库

关于 freehire-search

freehire-search 是用于搜索 freehire.me 技术职位的命令行技能;该聚合平台会统一多个 ATS 平台的职位数据。它支持结构化地点和职位筛选,搜索结果包含完整描述。

主要功能

  1. 01搜索技术类职位
  2. 02按地区、国家、城市和工作模式筛选
  3. 03按资历、类别和技能筛选
  4. 04搜索结果包含完整描述
  5. 05通过 slug 查询职位

适用场景

  1. 01查找欧盟地区的远程 React 职位
  2. 02按地区搜索高级后端职位
  3. 03查看已保存或已关闭职位的详情

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/madslorentzen/ai-job-search --skill freehire-search

安装后在 Claude Code 中输入/freehire-search确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

url-reference.md
cli/
package.json
README.md
tsconfig.json
cli/src/
cli.ts
helpers.ts
cli/src/commands/
detail.ts
search.ts
cli/tests/
cli-flag-validation.test.ts
commands.test.ts
helpers.ts
parsing.test.ts
request-timeout.test.ts
required-search-values.test.ts
retry-backoff.test.ts

详细介绍

freehire 搜索 Skill

从 freehire.me 职位聚合器搜索实时职位列表 —— 这是一个开源的 IT 职位板,将来自多个国家约 50 个 ATS 平台的职位统一为同一种数据结构。无需身份验证,无需 API key,且零运行时依赖 —— 仅用 bun 即可运行。市场通过 facet 标志(--region、--country)按查询选择,因此同一个 skill 对任何市场的 fork 者都能开箱即用。

这是本仓库职位门户 skill 模式的一个与国别无关的完整示例,类似 linkedin-search。与那些抓取 HTML 的门户不同,它查询 freehire 的公开 JSON API,因此结果是结构化的(技能、资历、地区 facet),而非从标记中解析而来。

⚠️ 适用范围:以技术为主

freehire 的语料库已包含一些非技术职位(它会抓取整个公司的招聘页面),但其分面筛选 —— 技能、类别和资历词典 —— 目前是以技术为先调优的,因此本 skill 将触发范围限定在软件 / 数据 / 工程 / 技术类职位,这些职位的筛选效果最强。非技术类覆盖虽然存在,但仍在成熟中;目前尚不能依赖本 skill 来覆盖一般(非技术)职位。

ℹ️ 托管服务依赖(尽力而为,无 SLA)

本 skill 依赖第三方托管服务 freehire.me。读取操作是公开且无需身份验证的 —— 与 linkedin-search 一样无需注册。

freehire.me 是一个个人项目,但仍在积极维护;它以尽力而为的方式运行(无正式 SLA)。 如果 API 无法访问,CLI 会优雅失败 —— 以非零退出并给出清晰的错误信息 —— 因此服务中断只会降低此来源的可用性,而不会破坏整个工作流。

可自托管 / 可替换的 base URL。 freehire 后端是一个独立的 MIT 许可仓库 —— strelov1/freehire(Go + PostgreSQL + Meilisearch)—— 通过 Docker Compose 一条命令即可启动(make up → API 位于 :8080,相同的 /api/v1/... 路径)。本 skill 支持一个 base-URL 环境变量 FREEHIRE_API_URL(默认 https://freehire.me),因此将其指向本地实例只需改一行:

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

注意事项:启动 API 很轻量,但维护一个完整、持续更新的镜像(约 50 个平台上的数百万条职位)则资源消耗很大 —— 自托管者要么抓取限定范围的来源子集,要么将环境变量指回托管 API。

何时使用本 skill

  • 按关键词搜索某个地区/国家或远程的技术职位 —— 每条结果都会返回其完整描述,无需逐条跟进
  • 按资历、类别、技能或时效(发布于 N 天内)进行筛选
  • 通过 slug 查找某条 freehire 职位(包括已关闭的职位)

命令

搜索职位列表
bun run .agents/skills/freehire-search/cli/src/cli.ts search [-q "<keywords>"] [facet flags]

关键标志:

  • --query <text> / -q <text> — 关键词搜索(标题、技能、角色)。全文搜索;可选。
  • --jobage <days> — 在 N 天内发布(映射到 posted_within_days)。
  • --page <n> — 从 1 开始的页码。默认 1。
  • --limit <n> / -n <n> — 每页结果数(API 限制)。默认 25。
  • --format json|table|plain — 默认 json。
  • --description-format markdown|text|html — 每条结果的完整描述如何 呈现。默认 markdown,这会保留职位发布的标题和要求 列表的完整性。仅适用于 json 输出。

搜索结果已经带有完整描述。 此技能查询 freehire 的 agent 搜索端点,该端点会用每个 职位发布的完整文本替换索引中的截断预览,因此搜索 20 个角色只需 1 次请求,而不是 1 + 20 次。 不要对搜索结果循环调用 detail 来读取它们的描述 — 只有在 按 slug 查找单个职位时才使用 detail(例如,从跟踪器中,或某个已关闭因此不在搜索结果中的职位)。 完整描述很冗长: 保持 --limit 适中,并在阅读正文之前按标题/公司预过滤 - 或者传入 --no-description 进行一次低成本发现遍历,保留所有其他 字段并完全去掉正文(用 detail 获取入围职位的正文,或者在不带该标志的情况下重新运行搜索)。

分面过滤器(值来自 freehire 的受控词表;同一分面内用逗号分隔表示 OR):

  • --region <codes> — 宏观区域,例如 global、eu、us、apac、latam、cis。--region eu,us。使用 none 匹配区域无法解析的职位(见下文“部分数据”)。
  • --country <codes> — ISO-3166 alpha-2,例如 --country DE,GB
  • --city <names> — 城市名称,例如 --city Berlin
  • --seniority <levels> — junior、middle、senior、staff、principal、lead、……
  • --category <cats> — backend、frontend、fullstack、devops、ml_ai、qa、……
  • --skill <names> — 规范技能,例如 --skill go,kubernetes
  • --company <slug> — 公司 slug(来自结果的 company_slug)
  • --remote <mode> — remote | hybrid | onsite(work_mode 分面)
  • --facet <key=value> — 任何其他分面参数(可重复),例如 --facet salary_min=100000

位置是一个分面,不是自由文本。 不同于 linkedin-search 的 --location, freehire 通过结构化的 --region/--country/--city 分面来过滤地理信息。可在 /api/v1/jobs/facets 查看某个市场的实时值 (追加 ?q=<role> 来限定范围)— 绝不要凭空编造分面值。

获取完整职位详情
bun run .agents/skills/freehire-search/cli/src/cli.ts detail <slug|url> [--format json|plain]

slug 是来自 search 结果的 id(例如 golang-zensar-2bxu6dxm)。你也可以 传入完整的 https://freehire.me/jobs/<slug> URL。返回完整(已去除 HTML) 的描述、技能、区域/国家,以及 — 当职位发布已丰富时 — 资历、 类别、雇佣类型和薪资。当 freehire 记录了薪资周期时,salary 会保留该周期 (INR 300000–300000/year、INR 12000/month);只能在同一周期内比较薪酬。

当你已经有一个职位的 slug 时使用它 — 例如已跟踪的申请、共享 链接,或搜索不再列出的已关闭职位。重新获取 search 刚刚返回的命中项只会重新读取你已经拥有的描述。

使用示例

# Senior backend roles, table view
bun run .agents/skills/freehire-search/cli/src/cli.ts search -q "backend engineer" --seniority senior --limit 10 --format table

# Remote React roles in the EU
bun run .agents/skills/freehire-search/cli/src/cli.ts search -q "react" --remote remote --region eu --format table

# DevOps roles in Germany posted in the last 14 days
bun run .agents/skills/freehire-search/cli/src/cli.ts search --category devops --country DE --jobage 14 --format table

# ML/AI roles anywhere, fully remote
bun run .agents/skills/freehire-search/cli/src/cli.ts search -q "machine learning" --category ml_ai --remote remote --format table

# Descriptions as plain text instead of Markdown
bun run .agents/skills/freehire-search/cli/src/cli.ts search -q "platform engineer" --limit 5 --description-format text

# Full details for a specific job
bun run .agents/skills/freehire-search/cli/src/cli.ts detail golang-zensar-2bxu6dxm --format plain

输出格式

格式适用场景
json默认格式——适用于程序处理;唯一包含每条结果描述的格式
table快速浏览,便于人类阅读
plain查看单个职位的完整详情(detail 命令)

搜索结果的 JSON 结构为 { "meta": { "count", "page", "total" }, "results": [...] };每条结果至少包含 id(freehire slug)、title、company、location、date、url 和 description(缺失值为 null)。table 和 plain 格式不包含描述——描述会让列表难以浏览。所有错误都会以 { "error": "...", "code": "..." } 的形式写入 stderr,进程以代码 1 退出。

部分数据

筛选项按职位生成,数据可能不完整,尤其是地理信息。 职位可能已解析出 work_mode(例如 remote),但因来源中的地点文本含糊而无法确定地区或国家/地区(freehire 的字典不会进行猜测)。因此:

  • 缺少地区/国家/地区表示“未解析”,而不是“不适用”——使用 --region eu 筛选时,未解析出地区的职位会被静默排除,即使它们实际上位于欧盟也是如此。若要找回这些职位,请扩大筛选范围或移除该筛选项。
  • 有一个专门用于未解析类别的筛选值:--region none 可匹配没有已解析地区的职位——适合筛选出从未明确标注地理位置的远程职位。它可以与实际地区使用 OR 逻辑组合,例如 --region eu,none。
  • 出于相同原因,result.regions / countries / cities 可能是空数组;应将空数组视为未知,而不是“以上均不符合”。

说明

  • 数据来自 freehire.me 的公共 API——无需凭据。只有按用户追踪(申请/保存)需要密钥,而此技能有意不使用该功能:它仅支持搜索和查看详情。
  • 搜索结果中的 id 是 freehire 的 public_slug——将其原样传给 detail。
  • date 是职位发布的日期,格式为 YYYY-MM-DD(取自 API 的 posted_at 时间戳中的日期部分,这是所有招聘门户 CLI 都会输出的格式);未注明日期的职位可能为 null。
  • 筛选值属于受控词表。筛选前,可使用 /api/v1/jobs/facets 查看查询对应的实时值(及其数量)。
  • API 会在遇到 429/5xx 错误时采用指数退避重试;若 API 无法访问,进程会以非零状态退出并显示明确消息(尽力提供服务,参见上文的依赖说明)。
  • search 会调用 /api/v1/agent/jobs/search(与其他接口一样公开);--no-description 会调用较轻量的 /api/v1/jobs/search,该接口不提供完整正文。比该接口更旧的可自托管实例会返回 404,CLI 会报告错误并注明接口名称——绝不会将其当作空结果集。

评论

支持 Markdown