Build a weekly AI jobs digest agent in 20 lines of Python, no API key
Most job-search automation breaks on the same two things: scraping, and knowing which postings are worth reading. Level's catalog removes both. It is queryable over a free, read-only REST API and a remote MCP server, and every posting carries an AI score, so the "is this really an AI job" filter is a query parameter instead of a manual task. This tutorial builds a small digest script, shows where an agent fits on top of it, and lists the traps to watch for. Numbers were pulled on 16 October 2026.
Step 1: one request, filtered by AI level
The REST endpoint is https://jobsbylevel.com/api/v1/jobs. The parameters that matter for a digest are query, ai_level_min, ai_level_max, remote, city, company, posted_within_hours (1 to 168), sort=recent and page. Results come back 20 per page.
import json, urllib.parse, urllib.request
BASE = "https://jobsbylevel.com/api/v1/jobs"
def fetch(**params):
url = BASE + "?" + urllib.parse.urlencode(params)
req = urllib.request.Request(url, headers={"User-Agent": "weekly-digest/0.1"})
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r)
data = fetch(query="machine learning", ai_level_min=3, remote=1,
posted_within_hours=168, sort="recent")
print(f"{data['total']} matching jobs in the last 7 days")
for job in data["items"][:5]:
print(f"L{job['ai_level']} ({job['ai_score']}) {job['title']} @ {job['company']}")
print(" ", job["url"].split("?")[0])
I ran exactly this on 16 October 2026. It reported 110 matching jobs for the previous seven days. The first five were a Block security engineering role (score 65), a Databricks generative AI solutions architect role (70), a Natera Principal AI Engineer role (90), a Fetch staff machine learning engineer role (90) and an NVIDIA foundation model internship (90).
The first result is the lesson. A "Security Engineer" appeared for a "machine learning" query, because a search with a text query matches the posting text, not only the title. That is why the AI level filter exists: combined with ai_level_min=3, it keeps only postings where AI is central to the work, but you still want to look at the titles before you trust a keyword.
Step 2: add the pieces an agent needs
A digest is a loop with three decisions, and each maps to a field you already have:
-
Is it new? Store the
idof each posting you have seen. Skip repeats. -
Is it AI-heavy enough? Use
ai_scoredirectly. A score of 80 or above is Level 4, so you can set your own cut-off instead of relying on the level label. -
Is it worth a human's time? Pass the title, company,
toolsand pay fields to a language model and ask for a one-line reason to apply or skip. Salary fields (salary_min,salary_max,salary_currency) are present when the employer published them and null otherwise, so handle both.
Each result also carries a canonical url on the Level site. Keep that link when you show results to anyone; it is the one condition the data comes with.
Step 3: or skip the script and use MCP
If you already work inside Claude, Cursor or another MCP client, you do not need the script. Add the server, which is Streamable HTTP, stateless, read-only and needs no authentication:
claude mcp add --transport http level-jobs https://jobsbylevel.com/mcp
The server exposes tools including search_jobs, latest_ai_jobs, get_job, market_stats, list_companies_by_ai_level and get_level_definitions. Ask your assistant for "remote Level 3 or 4 roles posted in the last 48 hours, grouped by company", and it will compose the calls itself.
A useful sanity check before you build anything is market_stats. On 16 October 2026 it reported 140,530 live postings, split 116,494 at Level 1, 5,446 at Level 2, 11,769 at Level 3 and 6,821 at Level 4, with a remote share of 17.7%. If your digest returns hundreds of results a week, you now know what fraction of the whole board that is.
Traps worth knowing
-
Totals are capped with a query. A text query makes
totalstop at 1,000 and flags it withtotal_capped. Without a query the total is exact. - Rate limits are polite, not generous. Both interfaces allow about 60 requests per minute per IP address. A weekly job is nowhere near that, but a naive loop over pages can be.
- Postings change. Level re-reads employer systems every six hours and rescores a posting whose text changes. Do not cache a score for weeks.
- The score is about the text. If a description is thin, the level is low because the text is thin. Do not read it as a verdict on the job.
Where to go from here
Add city for a local digest, company to watch an employer, or ai_level_max=2 if you are looking for roles that use AI tools rather than build them. The parameters compose, and none of them need a signup.
Everything above, including the endpoint list and the fair-use limits, is documented on Level's free MCP server and REST API page.
Top comments (0)