agenticjobs 0.5.0 is out. One filter now works whichever way you read the board: HTML, JSON, JSON Feed, RSS, Markdown, MCP.
/?workplace=remote&tags=javascript
/api/v1/jobs?workplace=remote&tags=javascript
/jobs.md?workplace=remote&tags=javascript
/feed?workplace=remote&tags=javascript
Getting there meant finding a bug I want to write down, because it is a worse failure than the obvious one.
Two of the RSS feeds took a query and threw it away. Not "did not support filtering", which would be fine and visible. They accepted the parameters, ignored them, and answered with the whole board:
const page = await searchJobs(pool, {
...parseQuery(new URLSearchParams()), // an EMPTY one
limit: 100,
});
Every other surface built its query from the actual request. These two built one from an empty parameter list, so whatever a reader put in the address was discarded before it reached the database.
The test that found it is the useful part. Ask every surface for something no listing is, and require all of them to return nothing:
workplace=onsite, on a board whose only job is remote
/api/v1/jobs 0 correct
/jobs.json 0 correct
/feed 0 correct
/jobs.rss 1 ignored the filter
/feed.rss 3 ignored the filter
A feed that returns nothing when you filter is either correct or obviously broken, and you can tell which in a second. A feed that returns everything looks like a working feed with a lot of results. Nobody subscribes to ?workplace=remote and then counts.
The interesting question was what a filtered everything-feed should contain. /feed.rss carries jobs, employers and candidates. If you filter it by employmentType=contract, what happens to the people?
The rule I settled on: tags are the only filter that means the same thing on both halves of the board. Workplace, employment type, seniority, agent policy, a salary floor and an employer are questions about a job, and a person cannot answer them. So a job-shaped filter drops the candidates, and employers drop out of any filtered feed, because a company is neither a job nor a skill. Answering a narrow question with the whole roster is the same failure as ignoring the filter, just quieter.
Also new: /jobs.md and /candidates.md. A model handed HTML has to pull a page apart to find the job. Handed Markdown it has the document. Each listing carries its own apply-schema URL, so an agent reading the Markdown does not have to guess how to apply:
- Apply: https://agenticjobs.work/api/v1/jobs/{slug}/apply-schema
The rest of 0.5.0, and the 0.4.x releases under it: a candidates directory, importing a job from a URL with agenticjobs new <url>, editing a listing without breaking its URL, and tags that link and filter on both halves of the board.
One more from the same afternoon, since it is the same shape as the feeds. SECRET was read by no code anywhere. Sessions, magic links, device codes and passkey challenges are all random tokens stored as hashes, so there was nothing to key. The README called it one of the two variables that matter, and the boot log warned that sessions would not survive a restart without it. Both untrue. That is the fourth setting in this codebase that pointed at nothing.
Written with AI assistance.
Top comments (0)