Academic jobs
Reusable skills for AI coding agents (Claude Code, Codex, Forge) covering paper review, commit triage, GPU rentals, reference search, research logs, image-prompt composition, and more.
npx -y skills add Axect/skills --skill academic-jobsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Fetch valid (still-open, deadline-not-passed) job postings from Academic Jobs Online (academicjobsonline.org, AJO) and the InspireHEP jobs board (inspirehep.net/jobs). Use when the user wants current academic openings: postdoc / faculty / PhD positions in physics, cosmology, HEP, ML, astrophysics or any field, filtered to postings whose application deadline has not passed. Searches both boards by default and merges the results. Manage field presets (keywords + position types + which boards), fetch and store valid postings, see what is new since last check, and inspect a posting's details. Triggers on: Academic Jobs Online, AJO, InspireHEP jobs, Inspire HEP 공고, academic job postings, postdoc openings, faculty positions, job listings, valid 공고, 학술 잡, 교수 공고, 포닥 공고, 채용 공고, 잡 마켓.
SKILL.md
9.6 KB, as published. Nobody here has run it
Academic Jobs Skill
Conversational interface over the ajo CLI, which fetches valid postings from two
academic job boards and tracks them in a local SQLite store:
- AJO — Academic Jobs Online (
academicjobsonline.org), HTML scraping, all fields. - InspireHEP — the HEP/astro jobs board (
inspirehep.net/jobs), via its public JSON API.
By default ajo fetch searches both boards with the same keywords and merges the
results, deadline-sorted. Each posting carries a source (ajo or inspire); the two
boards use overlapping integer ids, so everything is keyed by (source, id).
Quick Reference
| Intent | Command | Reference |
|---|---|---|
| Show / edit field presets | ajo config [...] | references/presets.md |
| Fetch current open postings | ajo fetch [--preset N | --keyword K] [--source ajo|inspire|both] [--preferred TIERS] [--excluded LIST] [--detail-cap N] | references/fetch.md |
| Show stored postings | ajo list [--valid] [--new] [--source S] | references/schema.md |
| Inspect one posting (stored-first) | ajo show {id} [--source ajo|inspire] [--refresh] | references/fetch.md |
| Fetch missing detail bodies | ajo enrich [--source ajo|inspire] [--detail-cap N] [--include-expired] | references/fetch.md |
| Emit curation skeleton | ajo report [--source S] [--preferred TIERS] [--excluded LIST] [--out PATH] | references/curation.md |
| Mark postings as seen | ajo mark-seen --all | references/fetch.md |
| Drop expired postings | ajo prune | references/schema.md |
Running the CLI
The CLI lives in this skill directory. Always invoke it through uv:
uv run --project <skill-dir> ajo <command> [...]
where <skill-dir> is the directory containing this file. Add --json to any command
when you (Claude) need to post-process the output; the default is a human table.
First run auto-creates the data dir, the SQLite DB, and a default physics-ml preset.
Curation rule (read before writing a report)
Before writing any postings report, you must deep-read every posting via ajo show {id}. After
ajo fetch or ajo enrich, full description bodies are stored in the DB, so ajo show reads
locally (no extra network calls). Never judge a posting from its title or keyword match alone.
Every posting in a report must fill the mandatory 10-field schema:
- 직급/seniority
- 기관, 그룹, 국가
- 연구주제, PI
- 자격/eligibility
- 기간, 급여, 시작일
- 마감 체계 (hard/rolling/etc.)
- 지원 서류
- fit 근거 + 등급
- 신빙성/주의 플래그
- 출처 URL
Use ajo report to generate a skeleton with data-backed fields pre-filled and blank placeholders
for judgment fields. The full procedure is in references/curation.md. Reports are saved to
~/Dropbox/AJO/AJO_YYYY-MM-DD.md in Korean.
Core behaviour you must understand
Two sources, one merged view
ajo fetchruns the preset's keywords against every board in the preset'ssources(default["ajo", "inspire"]), merges, dedups within each board, and stores everything keyed by(source, id).- Override per run with
--source ajo(AJO only),--source inspire(InspireHEP only), or--source both. With an ad-hoc--keyword, both boards are searched unless--sourcesays otherwise. - The same preset filters apply to both boards:
position_typesis matched against the AJO "Position Type" and against the InspireHEPranks(e.g.postdocmatchesPOSTDOC);countriesis matched against the institution string (plus InspireHEPregions).
AJO validity (HTML)
Validity is judged from the detail page, not the list. The AJO list page only shows a
deadline for some postings, and a missing list deadline does NOT mean "no deadline". So
ajo fetch fetches each AJO candidate's detail page by default and judges validity from the
effective deadline = firm Appl Deadline if present, else the listed until date.
--fast skips AJO detail pages (faster but deadlines are approximate and many valid postings
will be missed). Prefer the default detail mode for correctness. --fast does not affect
InspireHEP.
InspireHEP validity (API)
The InspireHEP API is queried with status=open (server-side), so closed postings never
arrive. The structured deadline_date is used directly, no detail fetch needed.
In both cases:
- valid → effective deadline is in the future
- expired → effective deadline has passed (excluded)
- rolling → no deadline (excluded unless
--include-rolling)
Common Rules
Base directory
All state lives under ~/.local/share/academic-jobs/ (override with AJO_DATA_DIR):
jobs.db— SQLite store of postingsconfig.toml— field presets
Typical flow for "show me current openings"
ajo fetch --json [--preferred "KR,DE; JP,HK,GB,US"] [--excluded "IN,IL"] [--detail-cap 80](uses the default preset; fetches details up to--detail-cap; stores + flags new). Pass--preferred/--excludedto override the preset for this run without saving. If AJO has more candidates than--detail-cap, the run is truncated; runajo enrichin a follow-up pass to capture the remaining detail bodies politely.- Render the returned
jobsas a table sorted bypref_tierthen deadline. Surface postings with"new": truefirst or in a separate "New since last check" group. - After presenting, if the user has reviewed them, run
ajo mark-seen --allso the next fetch only flags genuinely new postings. - To inspect one posting:
ajo show {id} [--source ajo|inspire]. It reads the stored row (including the cached description body) first; it only hits the network when the row is missing, has no stored body, or--refreshis given. A live fetch is written back to the DB.
Output formatting
- Sort by deadline ascending; show source, deadline, position type, title, institution, and
the posting URL (AJO
https://academicjobsonline.org/ajo/jobs/{id}, InspireHEPhttps://inspirehep.net/jobs/{id}). - When the user wants to know "where is this from", surface the
sourcecolumn. When merging, it is fine to interleave both boards by deadline; flag the source on each row. - When emitting a structured data table back to the user, prefer TOON over JSON (per the user's global preference): declare fields once, stream rows.
- Each output row now carries
country(ISO 2-letter code),region,flags, andpref_tier(integer; 0 = top tier, higher = lower preference, null = not in any tier). Results are sorted first bypref_tierascending, then by deadline ascending within each tier. Surfacepref_tierandcountrywhen presenting results so the user can see the preference grouping at a glance. - Per-board stats live under
stats.per_sourcein the JSON.--fastruns and any AJO detail-fetch cap truncation are reported there. Each board entry also includes anexcludedcount (postings dropped byexcluded_countries). The AJO entry additionally reportsdetail_cap(the cap used for that run). Never present a truncated run as complete; mention how many candidates were judged per board and whether the detail cap was hit.
Presets
A preset bundles keywords (each runs a separate search per board, results deduped) plus
optional position_types, countries, sources, preferred_countries, and
excluded_countries fields. Edit with
ajo config --set-preset NAME --keywords a,b --types postdoc --sources ajo,inspire. See
references/presets.md.
countries(unchanged): hard INCLUDE substring filter matched against the institution string. Only postings whose institution matches are kept.preferred_countries: ordered list of tiers; each tier is a list of selectors. Tier 0 is most preferred. This is a soft filter: it only reorders results (never drops). TOML example:preferred_countries = [["KR", "DE"], ["JP", "HK", "GB", "US"]]. Set via CLI:ajo config --set-preset NAME --preferred "KR,DE; JP,HK,GB,US"(;separates tiers,,separates entries within a tier). Displayed inajo configas[KR, DE] > [JP, HK, GB, US].excluded_countries: flat list of selectors. Hard filter: matching postings are dropped at fetch time. TOML example:excluded_countries = ["IN", "IL", "Middle East"]. Set viaajo config --set-preset NAME --excluded "IN,IL,Middle East".- Selectors for both
preferred_countriesandexcluded_countriesaccept: an ISO 2-letter code ("KR"), a country name ("Korea"), or a region alias ("Europe","Asia","North America","Middle East","EU","APAC","MENA"). position_typesandsourceswork as before.
Etiquette
The CLI uses one polite session per board with a real User-Agent and small delays between requests, and caps AJO detail fetches per run (logged when hit). Do not parallelise or hammer either board.