Typed decisions on scanned mail
Jev is a System One model: it takes a text state and typed questions and returns a choice, a score or a 0–1 truth value, with probabilities your code can branch on. Scanned mail already arrives as saved page text, so the only thing to build is the questions and the branches.
Jev does not generate text, draft a letter or send mail. It reads text only, so the worker passes OCR pages, never images. Physical handling and mailed replies stay behind the owner's approval.
inbound.keywords_matched names the rule, the matched terms, where and page_numbers.choice from a fixed list with per-option probabilities.score, so a coefficient in code changes priorities, not a prompt.noul for "expects a written reply" and for "asks for money or credentials", the second used purely as a guardrail.The receiver verifies the Standard Webhooks signature, stores the immutable event ID, and answers 2xx only after the event is durably queued.
The worker fetches pages_url with an inbound.read key and keeps pages whose OCR is ready or needs review. Nothing readable means wait, not guess.
Page text becomes the Jev state, with uncertain spans counted. It is data for the questions, never an instruction to the worker.
Branch in order: money or credential requests to a person; bulk mail filed; low confidence or an unknown route to review; only then a proposal.
A forward is proposed with expected_version and an idempotency key and waits for the owner. A reply is priced with dry_run=true before anything exists.
inbound.pages_ready, plus inbound.keywords_matched when rules gate the run. inbound.received is too early: the envelope is photographed, the contents are not scanned.sample: true and the test environment as rehearsal: record the decision, propose nothing.metadata; they come back on the mail record and every status callback, so the reason for a letter travels with it.item.id, item.reference, item.kinditem.sender as the scan read it, marked unverifiedneeds_review pages and uncertain_spansenvironment and sample// One request: the page text as state, every question evaluated in parallel.
{
"state": "<readable pages from pages_url, joined with page markers>",
"questions": [
{ "id": "route", "type": "choice",
"question": "Which team should handle this letter?",
"options": ["accounts_payable", "legal", "permits", "personal", "unknown"] },
{ "id": "urgency", "type": "score",
"question": "How time-sensitive is the requested action?",
"rubric": { "1": "no action requested", "5": "a stated deadline within 14 days" } },
{ "id": "wants_written_reply", "type": "noul",
"statement": "The document asks the recipient to respond in writing by mail." },
{ "id": "asks_for_money", "type": "noul",
"statement": "The document asks the reader to pay, wire funds or share account credentials." }
]
}
// Answers: route.choice + probabilities + confidence, urgency.score, *.noul (0–1)asks_for_money.noul > 0.6: escalate to a person, always, whatever else was answered.urgency.score ≤ 2: file it. No physical action, no cost.route.confidence < 0.8, any page needing review, or route.choice = unknown: review queue with the probabilities attached.urgency.score ≥ 4: propose forwarding the original; the owner approves.wants_written_reply.noul > 0.7: draft with your LLM, dry-run the cost, then submit with requires_approval=true and a cost cap.