Skip to main content

jevbrief

Clean, traceable state briefings for TypeSafe's Jev, from any source.

Other tools show what Jev decided. jevbrief shows what Jev was told, what it wasn't told, and why.

PyPI Python License: MIT Adapters

Quick start  ·  Adapters  ·  Python  ·  Viewer  ·  How it works  ·  Benchmarks  ·  Contributing


Animation: facts from a source flow into the rules, noise is dropped with a reason code, the rest goes to Jev, and Jev picks one


Why jevbrief

Jev turns state into typed decisions. It does its best work on small, relevant state, and it is weak at raw numbers, dates, and long lists of irrelevant detail. Real sources are the opposite: a web page has hundreds of elements, a failed build prints thousands of log lines, and an incident produces thousands more.

jevbrief sits between your source and Jev. It keeps what matters, drops the rest with a reason for every drop, asks Jev one clear question, and records the whole decision so you can replay it.

Before and after: 1,395 raw log lines at 29,678 tokens become 5 log groups at 1,070 tokens, and Jev picks the config reload failure

Adapters Read a source into facts, with numbers and dates already turned into plain words.
Rules with reasons Fixed rules drop the noise. Every dropped fact gets a reason code, so a wrong answer is debuggable.
A token budget 48% to 97% fewer input tokens on our benchmarks, with the same or better accuracy on the main question.
One clear question Question packs ask Jev a narrow judgment and return a typed answer, a confidence, and every option's probability.
A trace and a replay One JSON line per decision, and jevbrief view replays it step by step in one offline HTML file.

Quick start

pip install jevbrief                  # json, otel, and ci; add [web] or [nes], or [all] for everything

Get an API key at console.typesafe.ai, and set TYPESAFE_API_KEY in your environment or in a .env file where you run the CLI.

Every adapter uses the same two commands. inspect shows what would be kept and dropped, with no API key and no cost. ask calls Jev, writes a trace, and --view opens the replay.

gh run view <run id> --log-failed > run.log
jevbrief inspect run.log --adapter ci --goal "CI is red on main"
jevbrief ask     run.log --adapter ci --goal "CI is red on main" --view
27 log lines -> 7 failures -> 3 sent to Jev
likely cause: Run pytest -q: E KeyError: 'currency_code'   (confidence 0.84)
looks flaky: no (0.07)

Run jevbrief adapters to list what is installed. Each adapter's page below has its own quick start.

Adapters

Adapter overview: web pages, JSON data, OpenTelemetry logs, CI logs, and NES games are supported; Slack and Discord are planned; new sources are open for contribution

Adapter Reads Jev answers Install
ci GitHub Actions logs and JUnit XML Which error broke the build, and whether it looks flaky jevbrief
otel OpenTelemetry logs (OTLP JSON) Which log group explains an incident jevbrief
json JSON and JSON Lines, with a config file Which item fits, or which action to take jevbrief
web Web pages, through Playwright Which element to click next jevbrief[web]
nes An NES game's memory (Nova the Squirrel) Which move to make next jevbrief[nes]
chat Slack and Discord exports Which message answers a question Planned for v0.4
Yours Suggest it or build it

Watch Jev play a game

Jev plays level 1-1 of Nova the Squirrel: each frame shows the facts sent to Jev and the move it picked

Every frame is a real Jev decision. The nes adapter reads the game's memory, turns it into a few facts in words (Wall ahead, low (one block), touching), and asks Jev for one move. Play it yourself with python examples/nes_live.py --rom nova.nes --headed. The nes page covers getting the free game, the options, and adding another game.

Use it in Python

Every adapter works the same way: create a Briefing, extract, decide.

from jevbrief import Briefing
from jevbrief.adapters.ci import CiAdapter

brief = Briefing(CiAdapter(), goal="CI is red on main", trace="traces/ci.jsonl")
brief.extract(["logs.zip", "reports/junit.xml"])
decision = brief.decide()
if decision.fact:
    print("likely cause:", decision.fact.label, decision.fact.attrs)

Every decision comes back in the same shape:

decision.outcome Meaning Your code should
applied Jev answered at or above min_confidence (default 0.5) Act on decision.choice, and on decision.fact when the options are facts
reused The facts did not change, so the last answer was reused with no API call Act, but stop if nothing changes
low_confidence Below min_confidence, or Jev chose "none" Take no action
error The API call failed Take no action

Extra questions in the same call, such as ci's flaky, are in decision.answers.

Web shortcut for Playwright agents
from jevbrief import Brief

brief = Brief(goal="add this item to the cart", trace="traces/agent.jsonl")
await brief.from_page(page)                 # or brief.from_page_sync(page)
decision = brief.next_click()
if decision.fact:
    await page.locator(decision.fact.selector).click()

More in examples/: one script per adapter.

See every decision

jevbrief ask ... --view opens the viewer after a run, and jevbrief view opens the newest trace. Each decision starts with an animated replay: every fact read, the dropped ones struck out with their reason, the ones sent to Jev, Jev's answer, and a plain-English summary of what it means.

The viewer replaying a JSON decision: facts read, dropped with reasons, sent to Jev, and Jev's answer

Each adapter picks the view that fits its source:

View Used by Shows
Table json, ci Every fact with its score and reason
Timeline otel One bar per log group, with the incident start marked
Snapshot web The page with Jev's pick outlined
Live nes Decisions as they are written, next to the running game (jevbrief view --live)

The viewer is a single HTML file with the trace and images embedded. It needs no server and no network, so it can be attached to a bug report.

Screenshots: timeline, snapshot, and a browser agent

Timeline view: the config error is a single mark at the incident start, followed by many symptom errors

Web view: a screenshot of the page with boxes on every element

An agent adds an item to the cart and checks out, then the viewer replays what Jev was told

How it works

Step What happens
1. Extract The adapter reads the source into facts. Each fact has a kind, a label, attrs sent to Jev, and meta kept private. Numbers, counts, and dates become words here.
2. Rules A RuleSet scores each fact and drops noise. Core rules are shared, adapters add their own, and you can remove, add, or reorder rules without forking.
3. Budget Kept facts are sorted by score and cut to a token budget (default 2,000) and an option cap (default 60).
4. Fingerprint If the kept facts have not changed, the previous answer is reused and Jev is not called.
5. Ask Jev A question pack builds one or more questions (Choice, Noul, or Score) in a single call. Options are either the facts or a fixed set of actions.
6. Trace One JSON line per decision, with a legend of every reason code used. Images are stored next to the trace.
Reason codes

Core codes are shared by every adapter. Adapter codes are namespaced as <adapter>.<code>, such as ci.after_failure or otel.healthcheck, and listed on each adapter's page.

Code Meaning
hidden Not observable right now
disabled Exists but cannot be acted on
unlabeled No usable label, so Jev could not tell what it is
duplicate Same kind and label as a higher-scored fact
low_score Scored below the keep threshold
budget Would have been kept, cut only to fit the token or option budget

Force-keep facts with pins=["<fact id>"]. Fact IDs are stable across decisions.

Benchmarks

Benchmark chart: median input tokens, raw state against jevbrief, for web, JSON, OpenTelemetry logs, CI logs, and an NES game

Adapter Data Tasks Raw accuracy jevbrief accuracy Raw tokens jevbrief tokens
ci Real 16 failed GitHub Actions runs 88% 100% 30,502 988 (−97%)
otel Synthetic 6 incidents 83% 100% 29,678 1,070 (−96%)
json Synthetic 9 queries 89% 100% 3,848 2,002 (−48%)
web Synthetic 10 pages 100% 100% 5,400 2,344 (−57%)
nes Real game 100 moves on level 1-1 block 8.6 block 56.4 2,829 713 (−75%)
  • Same setup for both arms: the same Jev (jev-1.13.0) and the same question, with three runs per task and median input tokens. The raw arm sends what a naive integration would send: every element, every record, or the most recent log lines.
  • ci's flaky question: here jevbrief scored lower, 67% against 93%. The raw arm answered "flaky" every time, and 13 of the 16 labels are flaky.
  • Synthetic sets: some rules were designed while building them, so treat those numbers as illustrations.

Each adapter name links to its full results and caveats. Reproduce them with jevbrief bench.

Contributing

To Do this
Suggest a source Open an adapter request. Upvote the ones you want; the most requested are built first.
Build an adapter Copy contrib/adapter_template, follow ADAPTERS.md, and pass check_adapter(MyAdapter(), "sample.json", goal="..."). Ship it here in a pull request, or as your own package with a jevbrief.adapters entry point.
Report a wrong decision Open a bug report and attach the trace.
Ask a question or share an idea Start a discussion.

An adapter is one class with extract, rules, packs, and optionally state. Adding one never changes the core, and removing one never breaks anything. Working with a coding agent? Copy skills/jevbrief/SKILL.md into its skills folder (for Claude Code, .claude/skills/jevbrief/SKILL.md).

git clone https://github.com/parthkomalwad/jevbrief && cd jevbrief
python -m venv .venv && . .venv/bin/activate    # Windows: .venv\Scripts\activate
pip install -e ".[dev]" && playwright install chromium
pytest -q

Privacy

  • API key: read from the environment or .env, and never printed, logged, or written to a trace.
  • What adapters send:
    • The web adapter never sends form values.
    • The json adapter sends only the configured fields and buckets.
    • The otel and ci adapters send message templates, with IDs, emails, and addresses replaced.
  • Traces: they contain labels, source names, and, for web pages, a screenshot. Treat them like logs, and use --no-screenshot for private pages.

License

MIT. Community project, not affiliated with TypeSafe AI.

Release files for jevbrief 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jevbrief 0.3.0
File Size Uploaded
jevbrief-0.3.0.tar.gz 78.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jevbrief 0.3.0
File Interpreter ABI Platform
jevbrief-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 147.4 kB

Release files / jevbrief-0.3.0.tar.gz

Download URL jevbrief-0.3.0.tar.gz
Size 78.2 kB
Tags Source
SHA-256 checksum
How to use checksums
62ade578d08fbd9e0657632c6a49900162e258ea4c67bdcb604d41895bec4436
BLAKE2b-256 checksum
How to use checksums
84c3661578d341b3a3cc64b13e8b9a1b14968339b4c0536ea8f1ad158fc6437e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / jevbrief-0.3.0-py3-none-any.whl

Download URL jevbrief-0.3.0-py3-none-any.whl
Size 69.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3efb8662d26ca9b39582d0d7c9f94b868bdea943c860bc279015b70fec6a05ae
BLAKE2b-256 checksum
How to use checksums
7dc7bbdb955db74c9cd2e3b812b883d3ea7203b04a827a0ee53f68b2c9bd3b4f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page