What it does
Describe what you care about in a small YAML file: a name and a description, plus optional exclusions, categories, fields, flags and scores. Each topic comes back as match, review or no. Field values like a company name are picked from candidates you pass in, never generated.
It's stateless: no storage and no network except the model call, and every result serialises to plain JSON with its cost. There's an async batch filter with a budget that refuses rather than overspends, tracked-item matching with status rules, and a CLI to try topics, explain results, lint definitions and evaluate them on labelled data with per-topic threshold sweeps.
By default it asks every question about a piece of content in one request: does it match, which category, which company. When most content matches nothing, that pays for details nobody needs, so there's also a staged mode that first asks only whether each topic could match, then asks the details for the ones that might. It takes two round trips instead of one, and on a test mix of emails it cut token costs by 31% with the same results.
I pulled it out of two other projects, semantic-pubsub and jev-gmail-filter, which had each rebuilt the same layer.
- +Fake, recording and fallback judges for testing
- +Published on PyPI (pre-alpha)
>>> jf.choose("I was charged twice", ["billing", "bug", "feature request"])
Choice(value='billing', confidence=0.96, ...)