mcpField
F
freehire-search

freehire-search

github.com/ai-job-search-dev生产力67.2k199 次安装1 天前更新
代码仓库

关于 freehire-search

freehire-search 是通过 freehire.me 搜索科技、软件、数据和工程职位的 CLI 技能,面向求职者及检索职位的 Agent。它支持结构化筛选,并在搜索结果中提供完整职位描述。

主要功能

  1. 01搜索实时科技职位
  2. 02按地点、资历、技能和发布时间筛选
  3. 03在搜索结果中获取完整描述
  4. 04按 slug 查询职位
  5. 05输出 JSON、表格或纯文本

适用场景

  1. 01查找远程资深工程职位
  2. 02比较不同地区和国家的职位
  3. 03按 slug 查看已收藏或已关闭的职位

安装

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

$npx skills add https://github.com/ai-job-search-dev/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
detail-flags.test.ts
helpers.ts
parsing.test.ts
region-value-warning.test.ts
remote-mode.test.ts
request-timeout.test.ts
required-search-values.test.ts
retry-backoff.test.ts

详细介绍

freehire Search Skill

搜索 freehire.me 上的实时职位——这是一个开源 IT 招聘平台,会将多个国家和地区约 50 个 ATS 平台发布的职位信息标准化为统一格式。无需身份验证、API 密钥或任何运行时依赖——只需 bun 即可运行。可通过筛选标记(--region、--country)为每次查询选择市场,因此这项技能开箱即用,适用于任何市场。

这是本仓库 job-portal-skill 模式的一个不限定国家/地区的完整示例,类似于 linkedin-search。与抓取 HTML 的招聘门户不同,它查询 freehire 的公开 JSON API,因此返回的是结构化结果(技能、资历级别、地区筛选项),而非从标记语言中解析的内容。

⚠️ 范围:以科技类职位为主

freehire 的职位库已包含一些非科技类职位(它会抓取整家公司职业页面),但目前其分面筛选——技能、类别和资历级别字典——主要针对科技类职位优化,因此这项技能的触发范围限定为软件、数据、工程和科技类职位,这些领域的筛选效果较好。它也涵盖非科技类职位,但相关能力仍在完善中;目前请勿依赖这项技能来搜索一般(非技术类)职位。

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

这项技能依赖第三方托管服务 freehire.me。读取操作公开且无需身份验证——与 linkedin-search 一样,无需注册。

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

自托管/可更换基础 URL。 freehire 后端是一个独立的 MIT 许可仓库——strelov1/freehire(Go + PostgreSQL + Meilisearch)——可通过 Docker Compose 使用一条命令启动(make up → API 运行于 :8080,路径与 /api/v1/... 相同)。这项技能支持基础 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。

何时使用这项技能

  • 按关键词搜索指定地区/国家的科技类职位,或搜索远程职位——每条结果都会附带完整职位描述,无需再逐条查询
  • 按资历级别、类别、技能或新近程度筛选(发布于 N 天内)
  • 按 slug 查询一条 freehire 职位(包括已关闭的职位)

命令

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

主要标记:

  • --query <text> / -q <text> — 关键词搜索(职位名称、技能、角色)。全文搜索;可选。 支持 OR 和 title:(见下文“查询运算符”)。
  • --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 输出。

查询运算符。 -q 支持两个运算符;CLI 会原样传递文本,由 API 解析:

  • 在备选项之间使用 OR,可返回匹配任一备选项的职位,例如: -q "golang OR rust"。仅大写形式有效:小写的 or 会被视为普通搜索词。以空格分隔的普通词语不会合并搜索(-q "golang rust" 返回的职位少于单独使用 -q golang),因此应使用 OR 搜索同义词和备选技术栈,而不是针对每个关键词分别搜索。最多可有 5 个备选项;第 6 个会被拒绝并报错。双引号内的 OR 会被视为字面文本。
  • 在开头添加 title:,可将该备选项限制为职位标题,例如: -q "title:staff engineer" 会跳过只在职位描述中提到这些词的招聘信息。该限制针对每个备选项分别生效,因此每个备选项都要重复添加: -q "title:staff engineer OR title:principal engineer"。只有位于备选项开头时才生效;中间的 title: 会作为文本搜索。其内部可以使用引号: -q 'title:"staff engineer"' 会匹配该词组。

分类筛选标志、--jobage、--page 和 --limit 会应用于合并后的结果:所有备选项都使用相同的筛选条件,匹配多个备选项的职位只会出现一次。

搜索结果已包含完整职位描述。 此技能会查询 freehire 的 Agent 搜索端点,该端点会将索引中被截断的预览替换为每条招聘信息的完整文本,因此搜索 20 个职位只需 1 次请求,而不是 1 + 20 次。不要循环对搜索结果调用 detail 来读取职位描述——只有在需要按 slug 查询某条招聘信息时才使用 detail(例如,从跟踪器中查询,或查询一条已关闭、因此不会出现在搜索结果中的招聘信息)。完整职位描述篇幅较长:请适当降低 --limit,并在阅读正文前按职位标题/公司筛选;或者传入 --no-description,以较低开销进行初步搜索,保留其他所有字段但完全省略正文(可使用 detail 获取入围职位的正文,或不带该标志重新搜索)。

分类筛选(值来自 freehire 的受控词汇表;在同一分类筛选中用逗号分隔表示 OR):

  • --region <codes> - 大区:global、eu、uk、north_america、latam、apac、mena、africa、cis。--region eu,uk。eu 不包括 UK;如需覆盖整个欧洲,请添加 uk。单个国家请改用 --country - us 是国家代码,不是大区,--region us 不会匹配任何结果。--region、--country 和 --city 组成一个 OR 组,因此单独使用 --country 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 分类筛选)。单独使用 --remote 表示 remote。用逗号分隔表示 OR(remote,hybrid;on-site 会规范化为 onsite)。未知项目会以 BAD_ARG 退出,代码为 1。
  • --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。任何其他主机上的 URL(包括搜索结果 url 字段中的雇主申请链接)都会在发出任何请求前被拒绝,并返回 BAD_ID。返回完整的(已去除 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

# Go or Rust roles, one search (OR must be uppercase)
bun run .agents/skills/freehire-search/cli/src/cli.ts search -q "golang OR rust" --remote remote --format table

# Staff or principal titles only, not postings that mention them in passing
bun run .agents/skills/freehire-search/cli/src/cli.ts search -q "title:staff engineer OR title:principal engineer" --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 退出进程。

有一类诊断信息不属于错误:如果 --region(或 --facet regions=)的值不在文档列出的词汇范围内(us 是国家代码,不是地区),程序会在结果之后将 { "warning": "...", "code": "REGION_VALUE_UNKNOWN" } 输出到 stderr,进程仍以 0 退出,且 stdout 是有效的 JSON 文档。

部分数据

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

  • 缺少地区/国家表示“未解析”,不表示“不适用”——按 --region eu 筛选会悄悄排除地区尚未解析的职位,即使它们实际上位于 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