Method, not magic

Building reliably
on a local model.

Daymark treats a language model as an untrusted proposal engine. The model suggests; deterministic code decides. Here is how that discipline is enforced — and how the tradeoffs were actually measured.

Run the demo Back to overview

Three ideas

The same discipline runs through the task planner and the job-scoring engine.

1 · Structured output over a closed schema

The model proposes; deterministic code disposes

Every model call asks for a fixed JSON shape drawn from a small, closed vocabulary — a bounded set of actions, categories, priorities, and numeric ranges. Nothing free-form reaches application state.

Each response is strictly validated before it can cause any effect: unknown fields, out-of-range values, bad enums, and dangling task or day references are all rejected. In the task planner the contract is enforced twice — a strict Pydantic schema on the server (extra = "forbid") and a mirror validator in the browser that also refuses no-ops and contradictory actions, then shows a preview before anything is applied. See the runnable constrained-scoring demo.

2 · Cheap-first inference funnels

Spend model calls only where they earn their cost

Expensive inference runs only on plausible candidates. In the job engine, fast regex pre-filters discard obvious non-matches for free, and a cheap heuristic ranks the survivors so the scoring budget is spent on the most promising postings first. The model's job is to decide what a human should look at — not to read everything.

3 · Local, private, reproducible

Inference on your own hardware

Inference runs on-device via Ollama; no data leaves the machine by default. The single biggest driver of output quality is the user-controlled profile/rubric — and it will inflate results if it overstates experience. That failure mode is stated plainly in the rubric rather than hidden, because an inflated score quietly wastes the scarcest resource: application time.

The funnel

Fetch from the source, filter cheaply, score under a contract, validate, rank.

FetchPublic, unauthenticated ATS APIs — Greenhouse, Lever, Ashby — the source boards, not scraped mirrors.
Cheap regex pre-filterHard disqualifiers only (senior/staff titles, out-of-region). A heuristic ranks the rest; nothing promising is dropped.
Constrained-JSON scoringThe local model returns one JSON shape — score, verdict, reasons, tailoring — against a weighted rubric.
Strict validationScores clamped, verdict enum checked, unknown fields rejected — before anything reaches the shortlist.
Ranked shortlistWhat survives is worth a human's limited attention. One pass sees ~10,000 postings and keeps a few hundred.

An honest evaluation note

Choosing a local model is a latency–quality tradeoff, so it should be measured rather than assumed. The measurement here was an informal spot-check, and it is labelled as one — not a benchmark.

ConfigurationLatency / postingAgreement on 4 test postings
Local model, reasoning off~4.7 s3 of 4 matched the reasoning-on verdict
Local model, reasoning on~16.9 sreference

Because the model's role is only to decide what to look at — a human still reads every shortlisted posting before applying — the ~3.5× latency win was the right trade for a one-verdict-in-four disagreement on a tiny sample. The point is not the numbers, which are too small to generalize. The point is the method: measure the tradeoff on your own hardware and your own task before committing to a model, and keep the human in the loop where the sample is too small to trust.

Takeaway. Constrain the output, validate before you act, filter before you infer, and measure the model choice instead of assuming it. None of that is specific to Daymark — it is how any system should build on top of a language model it does not fully control.