OpenHire — Real Job Postings, Ghost Jobs Scored
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| DEEPSEEK_API_KEY | No | Your DeepSeek API key for higher-quality extraction when using --deepseek. | |
| OPENHIRE_DATABASE_URL | No | Optional PostgreSQL database URL (e.g., postgresql+psycopg://user:pass@host/db). Defaults to local SQLite file at ~/.openhire/openhire.db. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| search_jobsA | Search the live job index by hard filters; returns ranked JobPosting[]. The server does ONLY a hard filter plus a fixed ranking of match-quality × freshness — precise re-ranking is left to you, the client, which holds the user's context. Every result includes the five protocol fields (verified_at, source, ghost_score, response_sla_days, apply_channel) plus datePosted, days_open, remote_scope, eligible_regions, role_group and ghost_reason.
How to say it:
Null is NOT "abandoned": Ashby, Lever and Beisen do not report a last-touched date, and
those rows carry To answer "what is hiring?", pass Skills are alias-aware on the request side: 感知 finds rows tagged perception, 占用网络
finds occ / occupancy / occupancy networks. If a requested tag matches NOTHING in the
index, the response switches to
Two things worth knowing before you spend your budget:
Args:
skills: skill tags, ANY-overlap match (union), e.g. ["rust", "k8s"].
required_skills: skills that must ALL be present (AND), e.g. ["rust"].
remote: if true, only fully-remote roles.
remote_scope: filter remote roles by reach: "worldwide" | "unknown" | "region_locked" |
"country_locked".
min_salary: salary floor. By default roles with NO stated pay are KEPT (they can't
be ruled out); set require_stated_salary=true to drop them.
currency: restrict to a stated-pay currency, e.g. "USD" (implies stated pay).
require_stated_salary: if true, drop roles that publish no salary.
role_family: coarse family filter, one of engineering | data | product | design |
marketing | sales | ops | other. Any other value is refused
(ERR_UNKNOWN_ROLE_FAMILY) rather than ignored: "recruiting" used to pass
through and return the whole index. There is NO hr / recruiting / people
family — those roles are filed under ops; use Salary fields are null wherever the employer's ATS publishes no range, which is most
postings outside US states with pay-transparency law; |
| get_company_infoA | Aggregate, anonymous trust signals for one employer. Returns ghost_score_avg, active_jobs, and index_built_at (when the index was last built). NEVER returns any individual candidate data: the server holds none.
Takes an id or any part of the name in either language, like search_jobs' Known-but-not-indexed employers (Momenta, 小马智行 Pony.ai, 智元 AgiBot, MiniMax, 智谱
Zhipu, 商汤 SenseTime, 逐际动力 LimX, 自变量 X Square, 千寻智能 Spirit AI, 加速进化
Booster) return a structured answer instead of ERR_COMPANY_NOT_FOUND: |
| watch_intentA | Register a standing intent so new matches can be pulled later. The caller supplies its OWN anonymous fingerprint (e.g. "#a3f9-k2p7-x8q1"; make it 12+
random characters, a four-character tag collides with strangers) — the client generates
and owns it; the server stores but can never recover it, so persist it client-side and
pass the identical one to check_watches. Only the fingerprint and non-PII filter keys
are stored — never a name, email, phone or résumé. Accepted filter keys mirror
search_jobs:
Returns { watch_id, status, fingerprint, existing_watches, fingerprint_notice }.
|
| refresh_indexA | Re-crawl ONE employer's public ATS now. Takes about a minute. Throttled to 6h. The index is refreshed weekly, so Rules worth knowing before you call it:
Args: company: one employer — an id ("unitree") or any part of the name in either language ("宇树", "XPeng"). Ambiguous input is refused, not guessed. Returns: |
| check_watchesA | Pull matches that are new since this fingerprint's last check. stdio has no server push, so clients pull: call this at the start of a session. Returns the new matches per watch and advances each watch's last-notified marker. The FIRST pull on a watch returns everything matching it, not an increment: nothing
has been reported for that watch before, so the whole standing set is new to the user.
Each result says which it is via Each result also carries |
| authorize_applicationA | Record an authorized, employer-direct application. REFUSES résumés. (Formerly This tool never accepts a résumé, file, cover letter, name, email or phone — a résumé never transits the server. It only takes a job_id, an anonymous fingerprint, and an explicit per-job authorization. On success it returns the apply_channel (the employer's own application URL) for the user to submit as themselves, plus resume_transmitted=false. Do NOT paste résumé content into any argument. REFUSES means refuses: any argument this tool does not declare (a Args: job_id: the job to apply to (from search_jobs / check_watches). fingerprint: the user's anonymous fingerprint. authorized: must be true — explicit per-job consent. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 6 tools
The watch pair (watch_intent / check_watches) is clearly split by register-vs-pull semantics, and refresh_index, get_company_info and authorize_application each occupy a distinct role. The only mild overlap is between search_jobs filtered by `company` and get_company_info, both of which answer employer-scoped questions, but the descriptions explicitly delineate postings vs. aggregate trust signals.
All six names are snake_case, verb-first constructions (watch_intent, check_watches, get_company_info, refresh_index, authorize_application, search_jobs). No camelCase drift, no vague single-word verbs, and the noun half consistently names the resource or action target.
Six tools for a search + standing-watch + employer-trust + apply-handoff domain is well-scoped, and each one maps to a distinct stage of the workflow rather than being a near-duplicate. Nothing appears padded, and no obvious capability is crammed into an overloaded mega-tool.
Core lifecycle is covered: search, register a watch, pull new matches, force a single-employer re-crawl, inspect employer trust signals, and record an authorized application. The notable gap is watch management — there is no way to list or delete standing watches, and no direct job-detail fetch, though search results carry full posting fields so agents can work around it.