Jevis
Jevis is a set of hooks that gives a coding agent a second pair of eyes. It reads each message you send, each command or edit the agent is about to make, and each "done" it is about to report. It asks a fast decision model yes/no questions about what is happening. When one of its lessons applies, it steps in: it adds a note to the agent's context, refuses a command, or sends the turn back with a reason. After a turn of visual work, it renders the result and has a separate model review it the way a demanding designer would.
It was built for Codex, where it helped most. It also improved Claude Code in the same tests. It should help any agent harness that supports hooks, because what it adds (lessons at the right moment, a refusal before a mistake, a review before "done") doesn't depend on the model underneath.
The decision model is TypeSafe's hosted Jev, GPT-6 Luna through OpenAI's Decisions API, or any Jev-compatible server such as a self-hosted Laya (with caveats, below).
Some lesson questions now have exact code rules: destructive git commands, em dashes in interface prose, literal gradient text, and emoji feature markers. Those skip the pattern question when code can prove the answer. User-permission exceptions, unfamiliar syntax, and design judgments still go to the active decision model; see decide in the wiki format.
One prompt, the final page of each conversation, with the same simulated user. The photo is AI-generated by Codex. There's also a 73-second explainer video.
- What it does
- Results
- Limitations
- Which coding model to use
- Install
- Choosing the decision model
- Configuration
- Other agent harnesses
- How it works
- The wiki, and making it yours
- Evaluating it yourself
- Privacy
- Contributing
What it does
Jevis works at four moments in a session.
| Moment | Hook | What Jevis can do |
|---|---|---|
| You send a message | UserPromptSubmit | Add a short lesson to the agent's context: "a narrow ask gets a narrow change", "brief before the first edit", "the two default landing pages". |
| The agent is about to run a command or edit a file | PreToolUse | Refuse it with a reason ("this adds gradient-filled headline text"), or add a note. |
| A tool finishes | PostToolUse | Record bounded, redacted completion facts and exit codes locally, without a model call or block. Claude failures use PostToolUseFailure. |
| The agent is about to end its turn | Stop | Send it back: "you said it's deployed, but nothing after the deploy checked the live function". |
| The agent reports visual work done | Stop | Render the page (1440 and 390 px) or sample the film, and have Claude or Codex review it as a director who didn't make it. It can send the work back at most twice. |
Nearly everything Jevis knows lives in the wiki/: 98 lessons, one per file, each with the yes/no question that decides when it applies. For example:
- Refuse edits that add the telltales of generated design: gradient text, emoji icons, glass cards, glow blobs, fake testimonials, and 25 more.
- Stop "done, tests pass" on a deploy nobody checked live.
- Point out that a vague request left the actual decision open.
- Keep a narrow request narrow.
- Hold a film to a story a stranger can follow.
- Refuse
git reset --hardor a visible browser window nobody asked for.
Jevis always fails open. With no key, a timeout, an error, or the decision model down, the agent carries on as if Jevis weren't there.
Results
All numbers come from simulated sessions on Sep 27–28 2026 (eval/sim.mjs). Each task ran twice, once bare and once with Jevis, in both Codex (GPT-6 Sol) and Claude Code (Claude Opus 5.5). A simulated user wrote follow-ups, a blind judge compared each pair, and hidden checks the agent never saw tested the result. There were 9 tasks: 3 web pages and 6 engineering tasks (fix a rounding bug, add a flag, convert callbacks to async/await, extend a CLI, clean up a repo, answer "why are the tests slow?").
Where Jevis acted, it mostly won. In the confirmation round (36 pairs on frozen code), Jevis won 20 of the 27 pairs where it did something, lost 6 and tied 1.
| Slice | With Jevis vs bare |
|---|---|
| All pairs where Jevis acted | 20 wins, 6 losses, 1 tie |
| Codex | 12–4 |
| Claude Code | 8–2 |
| Design (pages) | 10–2 |
| Engineering | 10–4 |
| Hidden checks newly failed because of Jevis | 0 |
In the 9 pairs where Jevis did nothing, the "bare" agent led 5–1. That's the judge's noise floor: the same agent run twice. Jev failed or timed out on 26 of 831 calls (3%), and each time Jevis stood aside.
Where the extra time goes. Conversations with Jevis took a median 1.56× as long as bare ones. Almost none of that is Jevis itself. Each hook call to Jev takes about half a second (median 459 ms in live use). The longest session was a 71-minute Codex design task, and there Jevis's hooks took 28 s in total and its reviews 85 s, under 3% of the session. The rest is the agent doing more before it comes back to you:
- it plans against the lessons;
- it checks its work in a browser or with tests;
- it fixes what the review sends back, instead of reporting "done" early.
The split shows it. Design conversations, where the review sends pages back, took 2.2× (Claude Code) to 2.6× (Codex). Engineering took 1.3×. The extra time didn't turn into extra back-and-forth: the simulated user wrote 30 follow-ups with Jevis and 31 without.
It narrows the gap between models, but doesn't close it. Bare Codex lost to bare Claude Code 1–5 on the same tasks. Codex with Jevis beat bare Claude Code 4–2, but Claude still won both dashboards clearly.
It amplifies what each model is already good at. Claude Code with Jevis put frame-by-frame animation on 6 of 8 pages, against 1 of 8 bare. Codex's copy was punchier than Claude's, so the wiki gives each model the other's strength as a lesson.
Films. One "surprise me, make a video like this" brief, one run per arm, so treat these as anecdotes:
- Claude Code with Jevis beat bare Claude Code (slight margin).
- Bare Codex beat Codex with Jevis (slight margin). The loss traced to a Jevis bug: its review told the agent to skip the final re-render, so the user watched a stale cut. That bug is fixed.
- A later run with directing lessons got Codex to narrate on screen and keep one coherent world. The maintainer still judged Claude's films clearly better directed.
Wiring. Tested live with Claude Code 2.1.283 and Codex CLI 0.156.1: the prompt note, the tool note, the tool refusal and the stop block each reached the model.
More detail, and how to rerun everything, is in Evaluating it yourself.
Limitations
Read these before you install.
- It takes longer, mostly on design. A median 1.56× the bare agent's time: 2.2 to 2.6× on design and 1.3× on engineering. That time is the agent checking and revising, not Jevis processing (see Where the extra time goes). If you want speed over polish, install with
--critic off: that removes the design review and most of the extra time (see The design review). - It can't give a model taste it doesn't have. Lessons change what an agent does: it plans, checks, narrates, stays in scope. They don't change its instincts. On creative direction, Codex with every lesson we could write was still clearly behind Claude.
- The shipped wiki is one person's standards. The lessons were mined from about 660 Codex and 130 Claude Code sessions of one heavy user: their corrections, rejected designs, and false "done"s. Many will fit you, but some are taste. Turn off what isn't yours and add your own in
~/.jevis/wiki/(see Making it yours). - The evaluation is small, and there are no public benchmark numbers. 36 pairs in the confirmation round, one seed of most tasks, one film brief, and a model as the judge. The judge showed a 5–1 lean on pairs where Jevis did nothing, so single-pair results are noise. The aggregate, and the zero hidden-check regressions, are the signal. We haven't run Jevis against popular coding benchmarks such as SWE-bench or Terminal-Bench: that takes time and model usage we haven't had yet. The best test is your own work, so try it in shadow mode first (see Install).
- Only two model families have their own lessons. Some lessons fix a habit of Claude models or of GPT models, and target that family. Any other model, such as Gemini, Grok, or an open model, gets both families' lessons: that fits the shared failures, but nobody has measured it.
- Laya doesn't work out of the box yet. It serves the same API, but the shipped checkpoints don't separate Jevis's questions. Details in Laya, self-hosted.
- Two harnesses, used daily on macOS. Codex and Claude Code. Others need an adapter (see Other agent harnesses). On Linux and Windows, CI runs the full test suite, installs Jevis into a fresh home, and runs every installed hook through the shells the harnesses use there:
shandbashon Linux; Git Bash, Windows PowerShell, PowerShell 7, and cmd on Windows. Nobody has run a live Claude Code or Codex session on either yet. Two things work less well on Windows: the design review can't find a running dev server, so it reviews changed HTML files only, and the check that lets read-only commands skip the decision model reads bash, so Codex's PowerShell commands always wait for an answer. - The design review is optional. It needs Google Chrome and the
claudeorcodexCLI, and it runs on your own plan with that CLI. Without them, the review is skipped and everything else still works (see The design review).
Which coding model to use
Jevis works with any model. These four are the ones we recommend today (28 September 2026), best first:
| Model | Harness | Our take |
|---|---|---|
| Claude Opus 5.5 | Claude Code | The best model available, and cheaper than Fable 5.1. |
| GPT-6 Astra | Codex | Better than GPT-6 Sol, including at design, though still below Opus or Fable there. It costs more and is slower than Sol. |
| Claude Fable 5.1 | Claude Code | Strong, but Opus 5.5 is currently better and costs less. |
| GPT-6 Sol | Codex | Faster and cheaper than Astra, and less capable. |
That ranking is the maintainer's judgment from daily use, not a benchmark. The same goes for this: across all of the maintainer's testing, Jevis made a large difference to GPT-6 Sol and GPT-6 Luna, and made Opus 5.5, already strong, better still. The measured results are in Results.
Gemini: not recommended
We don't recommend Gemini models, including the latest, Gemini 3.8 Flash. They tend to get stuck rereading the same files, and they go off the rails too often instead of finishing the task at hand. Jevis's shipped lessons weren't written for these habits. If you still want to use Gemini, first have an agent teach Jevis to catch them, with the skill for changing Jevis:
Read ~/code/jevis/skills/jevis/SKILL.md. My coding model is Gemini 3.8 Flash. It gets stuck rereading
files it has already read, and drifts off the task instead of finishing it. Extend Jevis to catch both:
step in when it rereads a file that hasn't changed since it last read it, and send the turn back when its
final message doesn't deliver what I asked for. Check first that the hooks see read tools in my harness,
add any fact the rules need in code, and prove each rule with dry runs before you call it done.
The tier list
The maintainer's tier list, current as of 28 September 2026:
| Tier | Models |
|---|---|
| SSS | Claude Opus 5.5 |
| SS | GPT-6 Astra |
| S | Claude Fable 5.1, GPT-6 Sol |
| A | Claude Opus 5, Claude Fable 5, GPT-5.6 Sol, Kimi K3, Grok 4.6, Qwen3.8 Max 0902, GLM-5.3, GPT-6 Luna, Muse Spark 1.3, DeepSeek V4.1 Flash, Hy-4 Preview, Grok 4.7 |
| B | GPT-5.6 Terra, Qwen3.8-Flash-Next, GLM-5.3 Flash, Claude Sonnet 5, K2 Horizon 375B A23B |
| C | GPT-5.6 Luna, Grok 4.5, Qwen3.8 27B, Muse Spark 1.2, MiMo V2.5 Pro, Hy-3, MiniMax-M3 |
| D | Thinking Machines Inkling, Nemotron 3 Ultra, Muse Glimmer |
| E | Claude Haiku 4.5, Mistral Medium 3.5, Nemotron 3.5 Lightning |
| Below E | Gemini 3.8 Flash, Gemini 3.7 Flash, Gemini 3.6 Flash, Gemini 3.5 Flash |
Install
You need Node 22 or newer and a TypeSafe or OpenAI key (or your own Jev-compatible server). Everything else is optional: the design and film review also needs Google Chrome and the claude or codex CLI, and ffmpeg lets film reviews check the soundtrack.
git clone https://github.com/GLDRoger/jevis.git ~/code/jevis
cd ~/code/jevis
npm install
npm test # offline, with a scripted decision model
Give Jevis a decision-model key (see below), then install the hooks:
Alternatively, use the native Codex plugin below. Choose one hook installation method per harness so Jevis does not run twice.
node bin/install.mjs --dry-run # show exactly what changes in ~/.claude/settings.json and ~/.codex/hooks.json
node bin/install.mjs # install for both harnesses (your old configs are backed up in ~/.jevis/backups/)
node bin/jevis.mjs doctor # check the setup: hooks, settings, key, a live call, recent activity
On Windows, the installer writes forward-slash paths and an unquoted first word, for example node "C:/Users/me/My Projects/jevis/bin/jevis.mjs" hook prompt. It uses the full Node executable path when it can stay unquoted, otherwise its unquoted 8.3 short name if available. Only when neither works does it fall back to node on PATH; doctor warns that cmd can then run a repository's own node.exe. Install Node in a folder without spaces, or enable 8.3 names, to avoid that fallback. Paths with shell expansion characters are refused before the installer writes anything. The same command works in Git Bash, Windows PowerShell 5.1, PowerShell 7, and cmd. ~/.jevis is under your Windows user profile; doctor reports that POSIX permissions are not checked there.
The installer adds Jevis's entries next to your existing hooks and leaves every other hook alone. Running it twice gives the same config. The hooks take effect in new sessions, and Codex asks you to approve new hooks once.
Jevis fails open: without a key, with a moved checkout, or with a broken settings file, it steps aside and your agent works as if it weren't there. doctor is how you tell that apart from "no lesson applied". It checks each harness's hooks, your settings and where each came from, the key and a live call to the decision model, file permissions, the design review's tools, the lessons, and the last day of the log, and prints the fix for anything wrong.
Try it without an agent:
node bin/jevis.mjs ask "make me a landing page for my pottery studio"
node bin/jevis.mjs ask --event tool --request "clean up the repo" "git reset --hard HEAD~2"
node bin/jevis.mjs ask --event stop --request "fix the login bug and deploy it" "Deployed. All tests pass."
Other installer options:
node bin/install.mjs --shadow # Jevis logs what it would do and changes nothing; review with `jevis stats`
node bin/install.mjs --live # switch shadow mode off
node bin/install.mjs --harness codex # one harness only
node bin/install.mjs --jev-url URL # use a self-hosted server instead of TypeSafe
node bin/install.mjs --decider luna # use GPT-6 Luna (jev to go back)
node bin/install.mjs --critic off # no design review; every other check still runs (or --critic codex)
node bin/install.mjs --uninstall # remove Jevis's hooks
To try it out, start in shadow mode for a few days, read node bin/jevis.mjs stats, and then switch it on with --live.
The options are saved in ~/.jevis/config.json (see Configuration), not on the hook commands, so they last until you change them and a plain reinstall keeps them. To go back to a default, pass it: --live, --jev-url typesafe, or --critic claude.
Native Codex plugin
This repository is also a plugin source: root plugin.json packages the existing skills/jevis/ workflow and hooks/hooks.json calls the same CLI as the standalone installer. There is no MCP server, new service, automatic installer, or second hook engine.
The repo marketplace at .agents/plugins/marketplace.json exposes jevis@jevis-local. With Codex CLI 0.159.0:
cd ~/code/jevis
npm ci
codex plugin marketplace add "$PWD"
codex plugin add jevis@jevis-local
codex plugin list --marketplace jevis-local --json
For a smaller distributable source, node bin/package-plugin.mjs --out /absolute/path/to/new/jevis-plugin copies only the runtime, lessons, skill, manifests, repo marketplace, and public documentation. It refuses an existing destination. Run npm ci in the packaged source, then run the marketplace and plugin commands above from that directory; dependencies are not bundled or installed by a hook. Keep the resulting installed cache's node_modules available for the optional visual reviewer (playwright-core). A ZIP of the source is not a preinstalled runtime.
Start a new Codex session, open /hooks, and review and trust Jevis's six event definitions. Installing the plugin does not approve its hooks. In the desktop app, restart after adding the marketplace, choose Jevis Local in the Plugins Directory, and install Jevis. Desktop discovery and trust are separate from CLI installation. Ordinary Chat can load the skill but does not run these command hooks.
The plugin uses Node 22+ on PATH and the same ~/.jevis settings, personal wiki, private logs, and Jev credentials as the standalone install. The optional review still needs Chrome and the chosen reviewer CLI. Commands are quoted for macOS/Linux; the native plugin's Windows shell behavior has not been verified, so use the existing standalone installer on Windows.
Migration: first inspect node bin/install.mjs --harness codex --uninstall --dry-run. If you choose to switch, run it without --dry-run before enabling the plugin hooks. This removes only the standalone Codex Jevis entries and preserves other hooks and Claude Code. Do not run both sources: Codex runs matching hooks from every source, and duplicate Jevis hooks share counters and logs.
Check it: use codex plugin list for installation, /hooks for enablement and trust, and node /absolute/path/to/installed/jevis/bin/jevis.mjs stats for actual activity. The current doctor checks standalone harness hook files, not plugin installation or trust; its "not installed" warning alone is not evidence that the plugin failed. Configure a TypeSafe or OpenAI key, or your own Jev endpoint as described below, then try shadow mode before live use. Without that backend, Jevis fails open; installation alone does not prove a lesson fired.
Packaging and trust follow the OpenAI plugin format and Codex hook runtime. Nothing is published to the public plugin directory by these local commands.
The design review
After a turn of visual work (a page, a component, a film), Jevis renders the result, or samples a film's frames, in headless Chrome and hands the screenshots to a second model, which reviews it as a designer who didn't make it and can send the work back. That second model is separate from the decision model: it runs through a coding agent's CLI, on your own plan.
| Install with | Who reviews | Needs |
|---|---|---|
| nothing (default) | Claude, through the claude CLI | Google Chrome, claude signed in |
--critic codex | Codex, through the codex CLI | Google Chrome, codex signed in |
--critic off | nobody | nothing |
Only the review needs these. The notes, refusals and "done" checks run on the active decision model either way. The installer ends with one line saying whether the review can run on this machine. If Chrome or the CLI is missing, the review is skipped, not failed. JEVIS_CRITIC_MODEL picks the reviewer's model.
Choosing the decision model
Jevis asks every question as a yes/no with a probability, in parallel calls per event. It supports two hosted decision models as equals, and any server that speaks TypeSafe's POST /v1/systemone protocol:
- TypeSafe Jev (
jev-1.14.0, the default) - GPT-6 Luna, through OpenAI's
POST /v1/decisions. Select it with--decider luna.
Every hook, setting, installer option, doctor check, outage note, call record, and jevis stats view works the same with either. What differs is how well today's lessons are tuned to each. Every lesson's min and unless_max threshold was set against Jev's probabilities, and Luna's are spread differently. Measured on Oct 15 2026 with the shipped lessons:
| Jev 1.14 | GPT-6 Luna | |
|---|---|---|
Design battery (eval/slop.mjs) | 66 to 69 of 70 | 59 of 70 |
Tool battery (eval/tools.mjs) | 30 of 34 | 24 of 34 |
Real turn endings it would send back (eval/stops.mjs, 406 turns) | 2.0% | 12.1% |
| Median / slowest call, 66 questions, 10 runs | 357 ms / 390 ms | 383 ms / 1,574 ms |
| Input price per million tokens (output free) | $0.042 | $0.10 |
| Questions per request | any that fit 64k tokens | 200 |
Most of Luna's misses are on the unless question ("did the user ask for exactly this?"): it answers yes to commands like git reset --hard that nobody asked for, so the refusal stands down. On turn endings it leans the other way and sends back about one in eight. To run Jevis on Luna, start in shadow mode (--decider luna --shadow) and read jevis stats --near, which judges thresholds against Luna's own recorded answers, never Jev's. Jev remains the recommendation until the thresholds have been tuned for Luna.
TypeSafe Jev (recommended)
Jevis pins TypeSafe to jev-1.14.0; JEVIS_JEV_MODEL overrides it. Jev is what every result above used. Answers typically come back in under half a second, even for hundreds of questions. At the time of writing, TypeSafe listed $42 per billion input tokens ($0.042 per million), with output free. In the maintainer's heavy agentic use, that has come to between $0.20 and $2 a day.
-
Get a key from the TypeSafe console. The docs are at docs.typesafe.ai.
-
Save it where only you can read it:
mkdir -p ~/.jevis/secrets && chmod 700 ~/.jevis ~/.jevis/secrets printf '%s' 'YOUR_KEY' > ~/.jevis/secrets/typesafe_api_key && chmod 600 ~/.jevis/secrets/typesafe_api_keyOr set
TYPESAFE_API_KEYin the environment your agent runs in. The key file is outside the repo and never committed.
Jev's latency has a long tail: occasionally a call takes several seconds. Jevis therefore sends the same request again at 350 ms and 750 ms and uses the first answer back. At these prices, the duplicates cost next to nothing.
GPT-6 Luna (OpenAI Decisions API)
Luna is OpenAI's decision model, served at https://api.openai.com/v1/decisions as gpt-6-luna (the Decisions guide; the API is in public beta). At the time of writing, input costs $0.10 per million tokens, with output free. A Jevis call bills about twice as many tokens on Luna as on Jev, so a call costs roughly five times as much: about $0.0016 for a typical 66-question tool check.
-
Get a key from the OpenAI platform and save it where only you can read it:
mkdir -p ~/.jevis/secrets && chmod 700 ~/.jevis ~/.jevis/secrets printf '%s' 'YOUR_KEY' > ~/.jevis/secrets/openai_api_key && chmod 600 ~/.jevis/secrets/openai_api_keyOr set
JEVIS_LUNA_KEYorOPENAI_API_KEYin the environment your agent runs in. Jevis checks those in that order, then the file. Luna always needs a key. -
Select it:
node bin/install.mjs --decider luna # --decider jev goes back node bin/jevis.mjs doctor # makes one live Luna call
Both keys can sit in ~/.jevis/secrets/ at once, so switching is one installer flag. JEVIS_LUNA_MODEL picks another Decisions model when OpenAI adds one. JEVIS_JEV_URL and JEVIS_JEV_MODEL apply only to Jev.
How Jevis talks to it:
- Each lesson's question becomes a Decisions
predicate, and itsyes/nowording is folded into the instructions, because the API has no criteria field. - The masked state is sent as JSON text.
- Sets over 200 questions are split into parallel calls.
- Luna's latency has a tail too, so it gets the same 350 ms and 750 ms duplicate requests as Jev.
- A question Luna refuses has no score, and that lesson stands aside, as with any failure.
Every call is recorded with decider and deciderModel. jevis stats --near reads only the active decider's records. jevis export writes only Jev's, because it builds training labels for Laya, a Jev-compatible model.
Laya, self-hosted
Laya is an open-source (Apache-2.0) decision model from ConvAI Innovations. Its server exposes the same /v1/systemone endpoint, so Jevis can use it with no code changes:
python -m pip install "laya[serve]"
LAYA_HOST=127.0.0.1 LAYA_PORT=8000 LAYA_PRELOAD=1 laya-serve
node bin/install.mjs --jev-url http://127.0.0.1:8000/v1/systemone
No key is needed unless you start Laya with LAYA_API_KEY. Then set JEVIS_JEV_KEY to the same value. Jevis sends Laya at most 64 questions per request (the server's limit) and doesn't send duplicate requests to a local server.
What we measured, and why it isn't the default. Laya 0.3.21's English checkpoint, run on an Apple Silicon Mac without a GPU, against Jevis's 70-case design battery:
- It caught 0 of 35 telltales Jev catches.
- It passed all 35 look-alikes, only because it never refused anything.
- Its probabilities sat between 0.46 and 0.72 whatever the input.
- A call took a median 4.2 s, well over Jevis's 1.5 s budget for a tool call.
As shipped, then, Laya-backed Jevis mostly does nothing. Two things would change that:
- Speed: a GPU (Laya reports about 7 ms per question batched on a T4), or a higher
JEVIS_TIMEOUT_MS. - Accuracy: fine-tuning. Laya's docs report that fine-tuning is where its accuracy jumps. Jevis records every Jev call it makes (the masked state, each question, and the answer probability) in
~/.jevis/jev/calls.jsonl, so a few weeks on TypeSafe produce a labeled dataset.node bin/jevis.mjs exportwrites it in the row format of Laya's fine-tuning notebook: gzipped JSON lines of state, questions, and Jev's answers as the gold labels, split into train and test by session. It prints the two lines to change in the notebook. The rows hold your prompts, commands, and file names with only secrets masked, so upload them as a private dataset. We haven't trained on it yet. If you do, rerunnode eval/slop.mjsand the other batteries against your server before trusting it.
Configuration
Every setting below can live in ~/.jevis/config.json, keyed by its variable name. The installer's options write there, and you can edit it by hand:
{ "JEVIS_MODE": "shadow", "JEVIS_CRITIC": "codex", "JEVIS_ENABLE": ["safety"] }
The environment wins over the file, so JEVIS_DISABLE=1 in one terminal still turns Jevis off for that session. The file can't hold JEVIS_HOME (the file lives there) or the API key (it belongs in ~/.jevis/secrets/, where no settings listing prints it). A file with a mistake is ignored rather than breaking your hooks; node bin/jevis.mjs doctor names the mistake and shows each setting in effect with where it came from.
| Variable | Default | What it does |
|---|---|---|
JEVIS_DECIDER | jev | Decision provider: jev or luna. The installer's --decider sets it. |
JEVIS_LUNA_MODEL | gpt-6-luna | The model sent to OpenAI Decisions |
JEVIS_LUNA_KEY / OPENAI_API_KEY | ~/.jevis/secrets/openai_api_key | Luna bearer key, checked in the listed order before the file. Required for Luna; keep keys out of config.json. |
JEVIS_JEV_URL | TypeSafe's endpoint | For the Jev decider only: any /v1/systemone server, such as http://127.0.0.1:8000/v1/systemone for Laya |
JEVIS_JEV=off | on | Disable decision-model calls; hooks pass through. Unlike JEVIS_DISABLE, local evidence recording still runs. |
JEVIS_JEV_KEY / TYPESAFE_API_KEY | ~/.jevis/secrets/typesafe_api_key | The bearer key. Optional for a self-hosted server. |
JEVIS_JEV_MODEL | jev-1.14.0 on TypeSafe; unset elsewhere | The model field sent with each Jev call |
JEVIS_JEV_CHUNK | 200 on TypeSafe or Luna; 64 on self-hosted Jev | Questions per request; larger sets are split into parallel calls |
JEVIS_TIMEOUT_MS | 3000 prompt, 1500 tool, 3000 stop | How long a hook waits for the decision model before standing aside |
JEVIS_MODE=shadow | off | Log what would have happened and change nothing |
JEVIS_DISABLE=1 | off | Turn Jevis off (for one session, if set there) |
JEVIS_SCOPE | everywhere | Folders separated by : on macOS/Linux or ; on Windows; Jevis only acts inside them |
JEVIS_ENABLE | none | Turn on optional entries: safety, all, or entry ids. Off by default: force pushes, machine-wide Docker deletes, browser security flags, wide deletes. The harnesses already guard these. |
JEVIS_CRITIC | claude | Who reviews visual work: claude, codex, or off. The installer's --critic sets it. |
JEVIS_CRITIC_MODEL | the CLI's default | The model the critic uses |
JEVIS_DESIGN_LAW | ~/.jevis/design-law.md, else ~/.claude/slop.md or ~/.codex/slop.md, if present | A Markdown file of your own design rules. When it exists, the agent is told to read it on visual work, and the critic judges against it. |
JEVIS_WIKI | ./wiki, then ~/.jevis/wiki, then a trusted project's .jevis/wiki | Lesson folders separated by : on macOS/Linux or ; on Windows, later ones winning. Windows paths must name a drive (C:/wiki) or UNC share (\\server\share). Replaces all the defaults. |
JEVIS_HOME | ~/.jevis | Where sessions, logs, backups, and the key live |
JEVIS_RECORD=off | on | Keep no record of decision-model calls (~/.jevis/jev/calls.jsonl, the training data for a local model) |
Other agent harnesses
Jevis speaks the hook protocol that Claude Code and Codex share. The harness runs a command with JSON on stdin (session_id, cwd, transcript_path, plus prompt or tool_name and tool_input; post hooks also send tool_response). Jevis answers on stdout with hookSpecificOutput.additionalContext, a permissionDecision: "deny", or decision: "block". Any harness that uses this protocol should work as it is. Use the same node bin/jevis.mjs hook <prompt|tool|post|stop|session> commands the installer writes, shown below.
A harness with a different protocol needs a small adapter in three places:
src/context.mjs→harnessOf: recognise the harness and read the model name.src/context.mjs→ the transcript reader (sessionItems): turn its session log into the commands, edits, and messages the stop checks read.src/hooks.mjs: map its output format.
The lessons themselves are harness-neutral.
The entries the installer writes, if you'd rather edit your config by hand:
{
"hooks": {
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "node ~/code/jevis/bin/jevis.mjs hook prompt", "timeout": 10 }] }],
"PreToolUse": [{ "matcher": "^(Bash|Edit|Write|MultiEdit|NotebookEdit|mcp__.*)$", "hooks": [{ "type": "command", "command": "node ~/code/jevis/bin/jevis.mjs hook tool", "timeout": 10 }] }],
"PostToolUse": [{ "matcher": "^(Bash|Edit|Write|MultiEdit|NotebookEdit|mcp__.*)$", "hooks": [{ "type": "command", "command": "node ~/code/jevis/bin/jevis.mjs hook post", "timeout": 10 }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "node ~/code/jevis/bin/jevis.mjs hook stop", "timeout": 420 }] }],
"SessionStart": [{ "hooks": [{ "type": "command", "command": "node ~/code/jevis/bin/jevis.mjs hook session", "timeout": 10 }] }],
"PostCompact": [{ "hooks": [{ "type": "command", "command": "node ~/code/jevis/bin/jevis.mjs hook session", "timeout": 10 }] }]
}
}
- Claude Code: the
hookskey of~/.claude/settings.json; also register thehook postcommand underPostToolUseFailurewith the same tool matcher. - Codex:
~/.codex/hooks.json, or the bundled plugin. Codex supports the same matchers and aliasesapply_patchtoEdit/Write.
Both harnesses register PostCompact to reset shown lessons after compaction. SessionStart with source compact also resets them; neither path resets the once-per-session outage warning. See the Claude hook reference and Codex hook reference.
After three consecutive decision-model failures within ten minutes, the next session start or prompt adds one short outage note (never in shadow mode). A successful call clears the streak; jevis doctor reports failure classes and streak windows from the recent log. Log and session/state writes are best-effort.
jevis gate-replay [--file ~/.jevis/log.jsonl] [--json] audits Bash gates offline: judged/skipped counts, lost historical fires, and summed hook wait saved. Clipped inputs remain unknown, and historical optional lesson fires are audited even when disabled today. This estimates cumulative wait, not elapsed session wall time.
The Stop timeout is 420 s because a review renders the page and waits for the critic, which takes about 30 to 90 s per round.
Gemini CLI and Antigravity CLI
These harnesses use bin/google-hook.mjs rather than the shared hook protocol above. Configure them manually; the installer does not register these adapters. Replace <repo> in every command with the absolute path to your Jevis checkout. Keep the quotes around the script path, especially if it contains spaces. Merge these entries into your existing configuration rather than replacing other settings or hooks.
Gemini CLI: add these events under hooks in ~/.gemini/settings.json:
{
"hooks": {
"SessionStart": [{ "hooks": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" gemini-cli SessionStart", "timeout": 10000 }] }],
"BeforeAgent": [{ "hooks": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" gemini-cli BeforeAgent", "timeout": 10000 }] }],
"BeforeTool": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" gemini-cli BeforeTool", "timeout": 10000 }] }],
"AfterTool": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" gemini-cli AfterTool", "timeout": 10000 }] }],
"AfterAgent": [{ "hooks": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" gemini-cli AfterAgent", "timeout": 420000 }] }]
}
}
Antigravity CLI: add this named hook to ~/.gemini/config/hooks.json (global) or .agents/hooks.json (workspace). Unlike Gemini CLI, this file has no top-level hooks wrapper, and lifecycle events contain handlers directly:
{
"jevis": {
"SessionStart": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" antigravity SessionStart", "timeout": 10 }],
"PreInvocation": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" antigravity PreInvocation", "timeout": 10 }],
"PreToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" antigravity PreToolUse", "timeout": 10 }] }],
"PostToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" antigravity PostToolUse", "timeout": 10 }] }],
"Stop": [{ "type": "command", "command": "node \"<repo>/bin/google-hook.mjs\" antigravity Stop", "timeout": 420 }]
}
}
Gemini CLI timeouts are in milliseconds; Antigravity timeouts are in seconds. Tool matchers cover all tools, including file reads. Jevis denies remain denies; otherwise Antigravity receives allow, leaving its next hook or native permission policy in control. Stop checks run on model_stop (and the legacy NO_TOOL_CALL), not errors or execution limits.
See the Gemini CLI hooks documentation and Antigravity hooks documentation for configuration details. Inspect loaded hooks with /hooks panel in Gemini CLI or /hooks in Antigravity CLI. These adapters have automated protocol tests; live authenticated sessions in either harness have not been verified here.
How it works
Each event produces two sets of yes/no questions, sent to the decision model in one call:
- Axes: a fixed profile scored on every event of a kind. For a message, that means: does it want a change? Is it open-ended, visual, code, a new build, risky? Is it a correction, a delegation, or mostly writing?
- Entries: every wiki lesson that could apply to the event contributes its own question.
A lesson fires when three things hold:
- its answer clears its threshold;
- its
unlessquestion, usually "did the user ask for exactly this?", stays low; - its conditions on the axes and on plain facts from the session hold. Facts include whether anything was edited and which commands ran after the last edit.
Then:
contextlessons are added once per session, and again after the context is compacted.denylessons refuse a tool call with the lesson as the reason. Every pattern an edit adds goes back in one reason, so the agent fixes them all in one retry.blocklessons send the turn back, at most twice per turn.
Two rules keep the cost down. Jevis never blocks the same way twice in a turn, and a review round tells the agent what to check so it doesn't redo a full sweep.
Code settles what it can before the decision model is asked. An entry whose facts already fail is left out of the call. A shell command that provably only reads (ls, rg, sed -n 1,80p, git log, gh pr view, with no redirect, substitution, or credential in sight) skips the call entirely, because every lesson about commands gates on marks.plain_read: false. In the maintainer's log, 42% of commands were plain reads. Each had waited about half a second for an answer, and none of those answers ever fired.
The design and film review runs when a turn of visual work passes the stop checks and says the work is done. A progress report ("the workers are still rendering") isn't reviewed, so an agent orchestrating background work isn't sent back over frames its workers haven't finished. For a page, Jevis renders what the agent served (or a dev server running from the project, or the changed HTML file) in headless, muted Chrome at 1440 and 390 px, plus dark mode when the page has one. For a film, it samples frames across the whole runtime, adds a spectrogram and measured loudness of the rendered video, and warns when the video is older than its source. The critic answers "ship" or up to five "Now: A. Instead: X." fixes. The first reviewed turn gets two rounds, and later turns get one.
The wiki, and making it yours
wiki/<area>/<name>.md holds one lesson per file. For example:
---
event: tool
tools: [Write, Edit, MultiEdit, apply_patch, Bash]
ask: Does `input` write user-interface code that fills text with a gradient (background-clip: text or -webkit-background-clip: text with a gradient, Tailwind bg-clip-text with text-transparent)?
yes: A heading, word, or number is painted with a gradient through background-clip text
no: Solid-colored text, or a gradient used on a non-text background. The pattern is only named in prose, comments, documentation, a lint rule, a test, or a list of things to avoid; ...
unless: Does `request` explicitly ask for gradient-filled text?
min: 0.85
action: deny
title: Gradient-filled text
source: 'Where the lesson came from.'
---
What goes wrong, and what to do instead. The agent sees this text when the lesson fires.
WIKI.md is the authoring guide. It covers the format, the state each event sees, the axes, conditions, and how to write a question the decision model answers well. node bin/jevis.mjs lint checks every entry against it.
The source: fields record where each lesson came from, anonymised: counts, dates, and the user's own words from the maintainer's sessions.
Making it yours
Your lessons live in ~/.jevis/wiki/, in the same format. Jevis loads the shipped wiki first and yours second, so git pull never touches your changes:
- a new id adds a lesson;
- the same id as a shipped entry replaces it (copy the file across and edit it);
- a file whose frontmatter is only
off: trueturns the shipped entry with that id off.
Changes take effect on the next hook call. node bin/jevis.mjs lint lists what yours replaced or turned off.
Lessons for one project
A repository can carry lessons for everyone who works in it, in .jevis/wiki/ at its root, in the same format. They apply only inside that repository, load after yours, and load only once you trust them:
node bin/jevis.mjs trust ~/code/app # lists what the lessons add, replace, or turn off, then trusts them as they are
node bin/jevis.mjs trust --remove ~/code/app # stop loading them
A cloned repository could otherwise slip text into your agent's context or switch off a refusal, so trust is pinned to the files' contents: after a pull or an edit changes any of them (even only their line endings), they stop loading until you trust them again. Until you trust a folder, Jevis doesn't read it at all, and it never follows a symlink out of one. A project's lessons can turn off or replace any shipped lesson except the safety ones (force pushes, machine-wide deletes, borrowed credentials); that stays your call, in ~/.jevis/wiki/. Run lint inside the repository to check its lessons before you trust them. doctor tells you when the folder you're in has lessons you haven't trusted.
For a style guide of your own, too long and too nuanced for yes/no questions, write it as Markdown in ~/.jevis/design-law.md. Agents are then told to read it before visual work, and the design review judges against it.
Or let your agent do it. skills/jevis/SKILL.md teaches any coding agent how to change Jevis. It covers which kind of entry, file, or setting produces which behavior, how to write a question the decision model answers well, and how to prove the change with dry runs before calling it done. Point your agent at it with the change you want:
Read ~/code/jevis/skills/jevis/SKILL.md, then make Jevis refuse edits that put lorem ipsum into a page.
To have it on hand in every session, link it into your agents' skill folders:
mkdir -p ~/.claude/skills ~/.codex/skills
ln -s ~/code/jevis/skills/jevis ~/.claude/skills/jevis
ln -s ~/code/jevis/skills/jevis ~/.codex/skills/jevis
The best lessons come from your own sessions:
node bin/jevis.mjs minelists the turns where you corrected the agent, each with what you asked, what it answered, what you said next, and what Jevis did that turn. A habit that repeats across sessions is a lesson, and the skill above turns one into an entry.node bin/jevis.mjs stats --nearscores each lesson against every recorded answer to its current question. It shows how often the lesson would fire under today's rules, how often it came within 0.1 of its threshold, and how oftenunlessor a condition stood it down. Setminfrom that rather than a guess.node bin/jevis.mjs replay <session file>dry-runs a recorded Codex or Claude Code session through the current wiki, which shows what would have fired.
Evaluating it yourself
npm test # offline, scripted decision model
node bin/jevis.mjs lint # every wiki entry against the guide
node eval/tools.mjs # tool-call battery: refusals and look-alikes (live)
node eval/slop.mjs [name] # design battery: 35 telltales refused, 35 look-alikes allowed (live)
node eval/sim.mjs [scenario ...] # simulated conversations with and without Jevis (uses real Codex and Claude usage)
node eval/sim-report.mjs <summary.json ...> # the gates: no harm, net good, no losing slice, time, errors
node eval/sim-cross.mjs <sim root> # Codex with Jevis against bare Claude Code
node eval/gallery.mjs && node eval/films.mjs # browse the pages and films side by side, with a blind mode
node bin/jevis.mjs stats # what fired in your real sessions, and the decision model's latency
node bin/jevis.mjs stats --near # each lesson against the recorded answers: fires, near misses, stand-downs
node bin/jevis.mjs doctor # the installation, end to end
eval/sim.mjs runs every agent with a rule against opening windows or playing sound, and enforces it: a Codex rules file and Claude Code deny rules. Its gates are in eval/sim-report.mjs:
- no newly failed hidden checks;
- more wins than losses where Jevis acted;
- no slice net negative;
- no more follow-ups than bare;
- at most 1.5× the time;
- under 5% decision-model errors.
The last confirmation round passed every gate except time.
docs/flow.html walks through each moment, showing what Jevis reads, asks, and returns. docs/index.html is a scrolling manual with a simulator that replays example events through Jev's live answers (node eval/scenarios.mjs && node docs/build.mjs recaptures it).
Privacy
-
Masking. Before anything reaches the decision model or the critic, and before anything is written to disk,
src/redact.mjsmasks secrets:- private keys (SSH, PEM, PGP);
- card numbers that pass the Luhn check, and their security codes;
- passwords and keys in assignments (a quoted phrase whole), JSON, flags,
config setcommands, URLs, headers, connection strings, and signed URLs; - provider tokens.
Variable names stay (
DB_PASSWORD=[redacted]), so the model can still read the command. -
What leaves your machine. The masked state (your message, the command or the lines an edit adds, the agent's final message, and file names) goes to the decision model you chose: TypeSafe for Jev, OpenAI for Luna, or your own server. Screenshots, frames, and the request go to the critic (the Claude or Codex CLI you already use).
-
What stays on your machine. Sessions, logs, config backups, and the call record live in
~/.jevis, which Jevis keeps readable only by you (0700). The call record is the largest: in the maintainer's heavy use it grew about 60 MB a day before plain reads stopped calling Jev and answers were stored as bare probabilities, changes that cut each day's record by roughly half. SetJEVIS_RECORD=offif you won't train a local model.jevis exportwrites its training set to~/.jevis/export/unless you pick another folder, private like the rest.
Contributing
Lessons with evidence, new design telltales, benchmark runs, and harness adapters are all welcome. CONTRIBUTING.md covers setup, what a lesson needs to be merged, and how to keep private session details out of the repo.
History and license
Jevis grew out of an earlier private hook system its maintainer used, which some source: fields cite. Jevis replaced that system's word-pattern classifiers with the decision model's answers and plain session facts, and kept its critic.
MIT. See LICENSE.