Limier: ranking freelance missions by relevance, not keywords
Abstract
Limier aggregates freelance missions from five platforms (official APIs and feeds, no scraping), filters them in code before any model call, then ranks them by relevance by weighing the full content of each offer against the resume and criteria expressed in natural language. Every verdict is explained, and every change to the system is validated by a dedicated evaluation set. In production at limier.io, designed, built and operated by Myelink.
01The problem
Searching for freelance missions today means going platform by platform, filtering by job title. Yet titles say very little: two "Data Scientist" offers can cover opposite realities, and the ideal mission sometimes hides under an unexpected title. The result: hours of monitoring, and relevant opportunities slipping under the radar.
02The approach
Nothing is pre-indexed: every search queries the platforms live. Five official connectors (Free-Work, France Travail, Jean-Michel.io, Codeur.com, Jobicy) consume APIs and structured feeds, with no HTML scraping at all. Objective filters, offer freshness and freelance contracts, are applied in code before any model call: you do not pay an LLM to discard a stale offer.
The rest is the model's job: the full content of each offer is weighed against the resume and a natural-language criteria note (daily rate, location, remote policy, including conditional rules), and the resulting ranking is explained offer by offer.
03The architecture
A search runs through a streaming pipeline: resume text extraction, search planning (LLM-generated keywords), parallel querying of the five connectors, code filters, relevance judging in parallel batches, global reordering, and delivery of the cards to the browser over Server-Sent Events as each batch is judged.
04The ranking
Judging happens in two passes, at temperature 0 with structured outputs (JSON Schema). Offers are first judged in parallel batches of 12: a three-state verdict (kept, almost, off-profile) and a justification, written before the verdict - the field order of the schema forces the model to argue before deciding. Since scores from independent batches are not comparable, a second pass globally reorders the top 60 offers and returns an order only, not grades: LLMs rank far better than they calibrate absolute scores.
Conditional criteria ("600 daily rate if 2 days on site, 700 if 3") are handled by enumerating the interpretations compatible with what the offer actually states. Missing information gets the benefit of the doubt, never invention. And the factual card fields (title, rate, location, link) come from the sources, never from the model; offer text is treated as data, and any instructions found inside are ignored.
05Evaluation
The ranking is evaluated against a reference set of 56 annotated cases, including adversarial ones: prompt injections inside offer text, missing information, trap titles. No prompt or model change ships without being validated by these scores. This work took the ranking accuracy from 0,83 to 0,95.
06Data and privacy
The resume zero-retention policy is verifiable in the code: the document is read in memory, never written to disk, consumed when the results stream opens, then destroyed; a search never opened is purged after 15 minutes. Observability traces mask the resume text. It only passes through the inference provider for the duration of the analysis, which the privacy policy states explicitly. On the browsing side: no analytics, no cookie banner, a single session cookie.
07The stack
| Layer | Choice |
|---|---|
| Web | FastAPI, HTMX, Server-Sent Events, server-side rendering |
| Agent | LangChain / LangGraph, JSON Schema structured outputs |
| Inference | open-weights models through OpenRouter, temperature 0 |
| Data | PostgreSQL, Alembic migrations |
| Payments | Stripe, credit packs |
| Observability | Langfuse, traces with resume masking |
| Quality | 201 tests, Playwright browser tests, lint + test CI, 56-case evaluation set |
| Deployment | Docker on a self-hosted VPS (Coolify / Traefik), continuous deployment |
08Status
Limier is in production and evolves continuously. One billing principle sums up the product's mindset: a credit is only charged when the search yields at least one relevant mission.
@software{limier,
author = {Vinceslas, Medhy},
title = {Limier: missions freelance triees par pertinence},
url = {https://limier.io},
note = {En production, Myelink EURL}
}