# jevreel
**A zero-embedding approach to video intelligence, using Jev.**
[](https://github.com/DeepAleph/jevreel/actions/workflows/ci.yml)
[](https://github.com/DeepAleph/jevreel/blob/main/LICENSE)

jevreel lays a video out on labelled contact sheets, one frame per second and sixty frames to an
image, and has [Jev](https://docs.typesafe.ai), TypeSafe's fast decision model, judge every sheet in
parallel. The best windows are re-checked on full frames. Your agent (Claude Code, Codex, Cursor,
Claude Desktop, anything that speaks MCP) gets back moments, times and probabilities, then looks
closer itself. No vectors are computed or stored anywhere.
## See it work
Five unedited Claude Code sessions using the jevreel MCP server and skill on Blender's open movie
[*Tears of Steel*](https://mango.blender.org) (12:14, (CC) Blender Foundation,
[CC BY 3.0](https://creativecommons.org/licenses/by/3.0/)). Each clip is drawn from its
recording: the agent's tool calls, what Jev answered for every sheet and frame, the hits, the cost,
and the agent's own answer, quoted. Click a clip for the full-resolution video.
| | Asked | What happened | Jev |
| - | - | - | - |
| 1 | Is there a moment where someone drinks from a juice box? | 13 sheets screened, 6 windows verified on full frames, 2 kept: **2:28.5** (p 0.95) and 12:06.5 (0.86) | 19 requests, $0.0054 |
| 2 | When does Thom apologise to Celia, and what does he say? | Speech mode over the captions: 6:47 *"I'm sorry."* (0.85), and a blurted *"Sorry!"* at 5:02 the agent set aside | 10 requests, $0.0003 |
| 3 | Somebody reads a newspaper early on. What does the headline say? | First 5 minutes only: verified at **1:20.5** (0.94); the agent read *ROBOTICIST CREATES KILLER ROBOTS* off the frame | 8 requests, $0.0024 |
| 4 | `captain.jpg` is a character. List every scene he's in. | Search by photo: 8 moments, 6 verified at 0.86–0.97, 2 more confirmed by the agent with `zoom` | 19 requests, $0.0064 |
| 5 | Map the film: robots, guns, holograms, settings, and what kind of film. | The agent wrote its own 4-question lens, read the per-minute rows back for free, and asked one whole-film question | 14 requests, $0.0051 |
### 1. Find a three-second moment
### 2. Search the dialogue
### 3. Read what's on screen
### 4. Find a person from a photo
The reference photo is a crop of the frame at 9:18, so the 9:17 hit is its own source; the other
seven are what the search found.
### 5. Map a whole film
The session starts with two failed calls, left in: a shell command the recording didn't allow, then
a wrong folder. The error names the folder relative paths resolve from, and the next call works.
## Why a decision model instead of embeddings
Multimodal embedding models already search video well: EmbeddingGemma 2 (October 2026) puts text,
images, video frames and audio in one vector space and runs on a phone. jevreel takes a different
route to the same goal, with different trade-offs.
- **Your question, not a fixed notion of "similar".** An embedding index decides at index time what
counts as close. A decision model judges the question you ask now, and returns a probability your
code can threshold, sort and gate on.
- **Every second, cheaply.** Jev charges for input tokens only, and output is free. A contact sheet
is sent once and every question about it rides along in the same request, so jevreel screens the
whole video at one frame per second instead of a handful of keyframes.
- **Questions are nearly free, so ask many.** Lenses add your own typed questions to every minute
at almost no extra cost, then filter them as often as you like for nothing.
- **The expensive model only sees what passed.** Your agent gets the few moments that matter, as
full-resolution frames, rather than a pile of thumbnails.
- **Typed answers, not just rankings.** Yes/no with the second it happens, one of your options, or a
level on your scale, per minute or for the whole video.
Embeddings are the better fit for querying a large library over and over: once the vectors exist,
each search is a lookup that costs nothing, while every jevreel question pays Jev for the minutes it
screens (about $0.02–0.03 per hour of video). The two combine well: embeddings to shortlist
videos, jevreel to find, verify and describe the moment.
## How it works
```mermaid
flowchart LR
V[video file or URL] --> F["ffmpeg: 1 frame/s"]
F --> S["contact sheets
60 labelled tiles, 1 minute each"]
V --> T["captions, or local
speech-to-text"]
S --> J{{"screen: one Jev request
per sheet, in parallel"}}
T --> J
J --> R["verify: top-ranked windows
re-checked on full frames,
every 0.5 s around the pick"]
R --> H["hits: time, probability,
frame, nearby speech"]
H --> A["your agent: zoom, locate,
read, cite 12:04"]
```
1. **Index.** Sample the video at 1 fps and tile the frames onto 1568 px contact sheets, each tile
labelled `T01`, `T02`, and so on. Fetch captions, or transcribe locally. Ask every sheet a fixed
set of questions once (people, on-screen text, cuts, setting, activity, a representative frame)
plus any **lenses** you add, which gives a typed timeline.
2. **Screen.** One request per sheet: a yes/no (Noul) for "is it in this minute" plus a Choice over
tile IDs for "which second". Screen and speech are separate questions combined in code.
3. **Verify.** The top-ranked windows (by rank, not threshold) are re-checked with one yes/no per full
frame, every half second around the pick. Screening ranks a one-second event correctly even when
it can't confirm it; verification confirms it, or throws out a false lead.
4. **Look closer.** `zoom` re-renders full-resolution frames; `locate` puts a Box around a target in
one frame and crops it; `whole` answers one question about the entire video from a storyboard,
the timeline and the transcript.
Answers are cached: the same images and questions to the same model never cost twice.
This follows TypeSafe's own patterns. Their line-search cookbook pairs a Choice over labelled units
with a Noul for "is it there at all". Their images guide searches a large image by Choice over tiles
and looks closer only where needed. Their Box guide gates every box behind a Noul and checks its edges.
## Quickstart
You need Python 3.11+, [FFmpeg](https://ffmpeg.org/download.html) on your PATH, and a
[TypeSafe API key](https://console.typesafe.ai).
```bash
uv tool install "jevreel[all]"
export TYPESAFE_API_KEY=...
jevreel index talk.mp4 # prints the video id
jevreel ask talk "a slide with a bar chart" # id, id prefix, path or title all work
jevreel zoom talk 12:00 12:10 # full-resolution frames to look at
```
`[all]` adds URL support (yt-dlp) and local speech-to-text (faster-whisper). Without them, jevreel
indexes local files and uses `.srt` or `.vtt` captions saved next to the video.
## Lenses: your own questions on every minute
A lens is a set of typed questions asked of every sheet and kept as timeline columns. Questions can
be `noul` (yes/no, plus the second it happens), `choice` (one of your options) or `score` (levels,
lowest first).
```toml
# examples/lenses/driving.toml
name = "driving"
[[questions]]
name = "on_bridge"
type = "noul"
ask = "Is the car driving on a bridge?"
[[questions]]
name = "weather"
type = "choice"
ask = "What is the weather mostly like?"
options = ["clear", "cloudy", "rain", "snow", "fog"]
[[questions]]
name = "traffic"
type = "score"
ask = "How much other traffic is on the road?"
levels = ["None", "Light", "Moderate", "Heavy"]
```
```bash
jevreel index drive.mp4 --lens driving.toml # rides in the indexing requests: almost free
jevreel lens drive driving.toml # or run it later: one request per minute of video
jevreel query drive "on_bridge > 0.7" # filter as often as you like: no requests
jevreel query drive "weather == snow and traffic >= 2"
```
## Use it from your agent
The MCP server exposes ten tools. The skill teaches agents the workflow: ask, look before claiming
anything, cite times.
### As a plugin
The plugin bundles the MCP server and the skill. It starts the server with
`uvx --from "jevreel[url]==0.2.0"`, so you need [uv](https://docs.astral.sh/uv/) and FFmpeg on
your PATH. Local speech-to-text is left out to keep the first start quick; for it, add the server
by hand with `jevreel[all]` as shown further down.
**Claude Code** asks for your TypeSafe API key when you enable the plugin and keeps it in your
system's credential store:
```bash
claude plugin marketplace add DeepAleph/jevreel
claude plugin install jevreel@jevreel
```
**Codex** passes plugin servers only an allowlist of environment variables, so save the key once.
The same command installs the environment the plugin starts, so its first start is fast:
```bash
uvx --from "jevreel[url]==0.2.0" jevreel login
codex plugin marketplace add DeepAleph/jevreel
codex plugin add jevreel@jevreel
```
### By hand
**Claude Code**
```bash
claude mcp add jevreel -e TYPESAFE_API_KEY=your-key -- uvx --from "jevreel[all]" jevreel mcp
```
**Codex**
```bash
codex mcp add jevreel --env TYPESAFE_API_KEY=your-key -- uvx --from "jevreel[all]" jevreel mcp
```
**Claude Desktop, Cursor and other `mcpServers` clients**
```json
{
"mcpServers": {
"jevreel": {
"command": "uvx",
"args": ["--from", "jevreel[all]", "jevreel", "mcp"],
"env": { "TYPESAFE_API_KEY": "your-key" }
}
}
}
```
VS Code uses the same entry under `"servers"` with `"type": "stdio"`.
**The skill** (Claude Code, Codex and other agents that read Agent Skills):
```bash
npx skills add DeepAleph/jevreel
```
Agents without MCP can use the skill with the CLI alone; every command prints JSON.
## Tools
| MCP tool | CLI | What it does |
| - | - | - |
| `index_video` | `jevreel index` | Sheets, transcript, typed timeline and any lenses. Runs as an MCP background task; repeat calls return the index and only run new lenses. |
| `ask_video` | `jevreel ask` | Moments matching a description: screened, verified on full frames, with times, probabilities, nearby speech and the frames themselves. `mode`: visual, speech, both. |
| `find_in_video` | `jevreel find` | Every moment the subject of a reference photo appears. |
| `locate_in_frame` | `jevreel locate` | Box and crop a target in one full-resolution frame. |
| `zoom_video` | `jevreel zoom` | Evenly spaced full-resolution frames between two times. |
| `video_transcript` | `jevreel transcript` | What is said between two times. |
| `ask_whole_video` | `jevreel whole` | One typed answer (yes/no, choice, or score) about the entire video. |
| `run_lens` | `jevreel lens` | Ask your own typed questions of every minute of an indexed video. |
| `query_timeline` | `jevreel query` | Filter the timeline (default answers and lenses). No requests. |
| `list_videos` | `jevreel list` | Videos indexed on this machine. |
`jevreel measure