Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "jev-code",
"displayName": "Jev for coding agents",
"version": "0.4.1",
"version": "0.5.0",
"description": "Jev, TypeSafe's System One classifier, as tools (jev_classify, jev_check, jev_score, jev_rank, jev_ask) plus a skill that says when to use them.",
"author": {
"name": "Fran\u00e7ois Chastel",
Expand Down
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ TYPESAFE_API_KEY=
# OPENROUTER_API_KEY=
# Vercel AI Gateway: https://vercel.com/docs/ai-gateway/authentication-and-byok/api-keys
# AI_GATEWAY_API_KEY=
# OpenAI Decisions API (limited preview); opt in with JEV_CODE_PROVIDER=openai
# OpenAI Decisions API (public beta); opt in with JEV_CODE_PROVIDER=openai
# OPENAI_API_KEY=
# Ollama (local, no key); opt in with JEV_CODE_PROVIDER=ollama after `ollama pull nimble`
# OLLAMA_HOST=localhost:11434

# Optional overrides (defaults shown)
# JEV_CODE_PROVIDER=typesafe # typesafe | openrouter | vercel | openai | ollama; forces the host (required for the last two)
# TYPESAFE_BASE_URL=https://api.typesafe.ai
# TYPESAFE_BASE_URL=https://api.typesafe.ai # a proxy or a System One gateway of your own; /v1/systemone is appended
# TYPESAFE_DEFAULT_MODEL=jev-latest # typesafe-ai/jev on Vercel AI Gateway
# JEV_CODE_TIMEOUT_MS=30000
# JEV_CODE_MAX_RETRIES=2
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,13 @@ jobs:
else
npm run test:e2e
fi
- name: Run live tests against OpenAI's Decisions API when a key is configured
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
JEV_CODE_PROVIDER: openai
run: |
if [ -z "$OPENAI_API_KEY" ]; then
echo "No OPENAI_API_KEY secret set; skipping the OpenAI live tests."
else
npm run test:e2e
fi
2 changes: 1 addition & 1 deletion .mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"mcpServers": {
"jev": {
"command": "npx",
"args": ["-y", "@french-castle/jev-code@0.4.1", "mcp"]
"args": ["-y", "@french-castle/jev-code@0.5.0", "mcp"]
}
}
}
44 changes: 43 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,47 @@ All notable changes to this project are documented here. The format follows

## [Unreleased]

## [0.5.0] - 2026-10-07

OpenAI's Decisions API, now in public beta for every developer, and a System One gateway of your
own as a first-class setup path. One change to check before upgrading: `TYPESAFE_BASE_URL` is now
validated, so a value carrying credentials, a query string, or a trailing `/v1/systemone` is
refused before any request instead of being sent.

### Added

- A System One gateway of your own, documented as what it already was: the proxy case. The key
goes in `TYPESAFE_API_KEY`, the SDK's generic variable, and the address in `TYPESAFE_BASE_URL`,
with `TYPESAFE_DEFAULT_MODEL` when the gateway's model id differs; nothing new to configure in
any harness. `setup` offers "Other System One gateway" when asking which host a pasted key is
for, then asks for the URL and the model and stores the three variables together.
- OpenAI's Decisions API in its public beta, open to every developer since October 6, 2026.
The mapping now follows OpenAI's published reference instead of recorded preview traffic; the
request jev-code sent already matched it, so existing setups keep working unchanged. All five
tools and the live test suite were run against `gpt-6-luna` before this release.
- A question the model declines comes back as a refusal on the Decisions API. Tools report it as
`status: "refused"` with the cautious outcome (`review`, or `uncertain` in `jev_check`)
instead of `invalid_response`, since retrying will not change it, and `jev_ask` lists declined
ids under `refused`.
- CI runs the live tests against the Decisions API too when an `OPENAI_API_KEY` secret is set.

### Changed

- `TYPESAFE_BASE_URL` is checked before any request: an absolute `http(s)` URL with no
credentials, query, or fragment, stopping before `/v1/systemone`, which the client appends.
A bad value is a configuration problem in `doctor` and `setup`, never echoed in case it embeds
a secret, instead of a connection error at the first call.
- Score probabilities from the Decisions API are keyed by the level index the API returns,
falling back to the label.
- `doctor --live` no longer calls a `403` from the Decisions API a preview restriction; it
quotes OpenAI's message and points at the key's project access to `gpt-6-luna`.

### Fixed

- `npm run test:e2e` found no tests to run, because the test config excluded the live suite for
every run, so the CI live job could never have exercised a host. The suite is now excluded
only when `JEV_CODE_E2E` is unset.

## [0.4.1] - 2026-10-03

### Fixed
Expand Down Expand Up @@ -136,7 +177,8 @@ each harness, and skill discovery. The first version published to npm.
- CLI access to every tool (`jev-code classify --input payload.json`).
- Claude Code plugin manifest and marketplace so the repository installs as a plugin.

[Unreleased]: https://github.com/FrancoisChastel/jev-code/compare/v0.4.1...HEAD
[Unreleased]: https://github.com/FrancoisChastel/jev-code/compare/v0.5.0...HEAD
[0.5.0]: https://github.com/FrancoisChastel/jev-code/compare/v0.4.1...v0.5.0
[0.4.1]: https://github.com/FrancoisChastel/jev-code/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/FrancoisChastel/jev-code/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/FrancoisChastel/jev-code/compare/v0.2.1...v0.3.0
Expand Down
72 changes: 51 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ npx -y @french-castle/jev-code@latest setup

That detects the harnesses on your machine and, for each one, copies the skill and registers the
tool. When no API key is in your shell, it asks for one right there (hidden input) and which host
it belongs to: TypeSafe, OpenRouter, Vercel AI Gateway, or OpenAI. There is nothing else to
configure.
it belongs to: TypeSafe, OpenRouter, Vercel AI Gateway, OpenAI, or a System One gateway of your
own, in which case it also asks for the gateway's URL. There is nothing else to configure.

Add harness names to be explicit (`setup claude codex pi opencode`), `--project` to install into
the current repository instead of your user profile, or `--dry-run` to see the plan first.
Expand Down Expand Up @@ -139,7 +139,7 @@ override per call. Policy stays in your hands; Jev supplies the probabilities.
<summary><strong>Claude Code</strong></summary>

`jev-code setup claude` copies the skill to `~/.claude/skills/jev/` and runs
`claude mcp add --scope user jev -- npx -y @french-castle/jev-code@0.4.1 mcp`. The tools appear as
`claude mcp add --scope user jev -- npx -y @french-castle/jev-code@0.5.0 mcp`. The tools appear as
`mcp__jev__jev_classify` and friends; the skill is `/jev`.

Prefer a plugin that updates itself? This repository is also a Claude Code plugin marketplace:
Expand All @@ -158,7 +158,7 @@ project-scope notes: [docs/harnesses/claude-code.md](docs/harnesses/claude-code.
<summary><strong>Codex</strong></summary>

`jev-code setup codex` copies the skill to `~/.agents/skills/jev/` (Codex's user-level skills
directory, shared with Pi and OpenCode) and runs `codex mcp add jev -- npx -y @french-castle/jev-code@0.4.1 mcp`.
directory, shared with Pi and OpenCode) and runs `codex mcp add jev -- npx -y @french-castle/jev-code@0.5.0 mcp`.
Without the `codex` binary it appends a `[mcp_servers.jev]` table to `~/.codex/config.toml`
instead. Invoke the skill with `$jev`. Details: [docs/harnesses/codex.md](docs/harnesses/codex.md).

Expand Down Expand Up @@ -194,7 +194,7 @@ works for the 70+ agents it supports:
npx skills add FrancoisChastel/jev-code --skill jev
```

Pair it with the MCP server (`npx -y @french-castle/jev-code@0.4.1 mcp`) in your agent's MCP config,
Pair it with the MCP server (`npx -y @french-castle/jev-code@0.5.0 mcp`) in your agent's MCP config,
or let the agent fall back to the CLI.

</details>
Expand All @@ -215,7 +215,7 @@ Output is JSON on stdout. Exit code 2 means a usage or configuration problem, 1

## Upgrading

Harness configs launch a pinned command, `npx -y @french-castle/jev-code@0.4.1 mcp`, so an agent
Harness configs launch a pinned command, `npx -y @french-castle/jev-code@0.5.0 mcp`, so an agent
starts fast and works offline once that version is cached, and nothing changes under you until
you decide. To upgrade, run setup again with `@latest`: it re-registers the tool with the new pin,
replacing the old entry (also through `claude mcp` and `codex mcp`), and refreshes the copied
Expand All @@ -232,16 +232,17 @@ on their own. Run the command above once to move them to a pinned command.
## Configuration

One host is required. The first three below serve Jev behind the same System One API, so the
tools behave identically and only the account you pay through changes. The last two are other
models that answer the same kinds of questions: OpenAI's Decisions API, and Ollama's local
decision models, which need no key at all.
tools behave identically and only the account you pay through changes; so does a gateway of your
own that speaks that API ([below](#your-own-gateway)). The last two are other models that answer
the same kinds of questions: OpenAI's Decisions API, and Ollama's local decision models, which
need no key at all.

| Host | Key variable | Default model | Get a key |
| --- | --- | --- | --- |
| TypeSafe (direct) | `TYPESAFE_API_KEY` | `jev-latest` | [console.typesafe.ai/keys](https://console.typesafe.ai/keys) |
| OpenRouter | `OPENROUTER_API_KEY` | `jev-latest` | [openrouter.ai/settings/keys](https://openrouter.ai/settings/keys) |
| Vercel AI Gateway | `AI_GATEWAY_API_KEY` | `typesafe-ai/jev` | [AI Gateway API keys](https://vercel.com/docs/ai-gateway/authentication-and-byok/api-keys) |
| OpenAI Decisions API (preview, opt-in) | `OPENAI_API_KEY` + `JEV_CODE_PROVIDER=openai` | `gpt-6-luna` | [platform.openai.com/api-keys](https://platform.openai.com/api-keys) |
| OpenAI Decisions API (public beta, opt-in) | `OPENAI_API_KEY` + `JEV_CODE_PROVIDER=openai` | `gpt-6-luna` | [platform.openai.com/api-keys](https://platform.openai.com/api-keys) |
| Ollama (local, opt-in) | no key; `JEV_CODE_PROVIDER=ollama`, `OLLAMA_HOST` optional | `nimble` | [docs.ollama.com/capabilities/decision](https://docs.ollama.com/capabilities/decision) |

How the host is chosen:
Expand All @@ -265,27 +266,35 @@ How the host is chosen:
| --- | --- | --- |
| `JEV_CODE_PROVIDER` | auto | Force `typesafe`, `openrouter`, `vercel`, `openai`, or `ollama` (required for the last two). |
| `OLLAMA_HOST` | `localhost:11434` | Ollama's server, as a URL, `host:port`, or bare host. |
| `TYPESAFE_BASE_URL` | per host | Point at a proxy or a compatible endpoint. TypeSafe keys only, unless `JEV_CODE_PROVIDER` is set. |
| `TYPESAFE_BASE_URL` | per host | A proxy, or a System One gateway of your own; the client appends `/v1/systemone`. TypeSafe keys only, unless `JEV_CODE_PROVIDER` is set. |
| `TYPESAFE_DEFAULT_MODEL` | per host | Pin a Jev version: `jev-1.13` on TypeSafe or OpenRouter; Vercel uses `typesafe-ai/jev`. |
| `JEV_CODE_TIMEOUT_MS` | `30000` | Per-attempt timeout. |
| `JEV_CODE_MAX_RETRIES` | `2` | Retries on 429, 5xx, timeouts, and connection errors. |

The `TYPESAFE_*` names match the official TypeSafe SDKs, so one export serves everything.

### OpenAI Decisions API (preview)
### OpenAI Decisions API (public beta)

OpenAI announced a Decisions API at DevDay 2026 that answers the same three question shapes
(yes/no, pick one, score on levels) with probabilities, served by GPT-6 Luna. It is in limited
preview with no public reference yet; accounts outside the preview get `403 Decision API is not
enabled for this user`, which `doctor --live` reports in plain words. jev-code maps every tool
onto it, so the payloads and results are unchanged, with these differences:
OpenAI's Decisions API answers the same three question shapes (yes/no, pick one, score on
levels) with probabilities, served by GPT-6 Luna. It opened to every developer in public beta on
October 6, 2026, with general availability expected in the following weeks; see OpenAI's
[guide](https://developers.openai.com/api/docs/guides/decisions). jev-code maps every tool onto
it, so the payloads and results are unchanged, with these differences:

- The request shape differs from System One. jev-code translates it; the mapping follows traffic
recorded by preview users and OpenAI's own client in the Codex repository, not a published
spec, and was not verified against a live preview account.
- The request shape differs from System One. jev-code translates it, following OpenAI's
[API reference](https://developers.openai.com/api/reference/resources/decisions/methods/create).
- Yes/no questions have no separate criteria field, so `yes` and `no` descriptions are folded
into the instructions. Score legends are rebuilt from your levels.
- Pricing and limits are OpenAI's and not published. Tool outputs still carry `usage`.
- The model can decline a question while answering the others. That item comes back with
`status: "refused"` and a `review` decision (an `uncertain` verdict in `jev_check`), and
`jev_ask` lists its id under `refused`. Retrying the same input will not change it.
- The API also takes images; the tools stay text-only, as they do on every host.
- Pricing is OpenAI's: at launch, $0.10 per million input tokens and nothing for output. Tool
outputs carry `usage`.

It stays opt-in. `OPENAI_API_KEY` is set in many shells for other reasons, so sending agent
evidence to OpenAI takes `JEV_CODE_PROVIDER=openai` (or pasting the key when `setup` asks). A
`403` from the API is reported in plain words by `doctor --live`.

### Ollama (local)

Expand All @@ -303,6 +312,27 @@ picks one). `OLLAMA_HOST` points at a server other than `localhost:11434`, in Ol
notation. Image inputs, which `clef` supports, are not exposed by the tools. `doctor --live` says
when the server is down or the model is not pulled.

### Your own gateway

Any server that speaks the System One API (`POST /v1/systemone`, same request and response
shapes) works without a row in the table: it is the proxy case the TypeSafe SDK already knows.
The gateway's key goes in `TYPESAFE_API_KEY`, the SDK's generic variable, and its address in
`TYPESAFE_BASE_URL`; `TYPESAFE_DEFAULT_MODEL` names the model when the gateway does not serve
`jev-latest`:

```bash
export TYPESAFE_API_KEY=... # the gateway's key
export TYPESAFE_BASE_URL=https://gateway.example/api # the client appends /v1/systemone
export TYPESAFE_DEFAULT_MODEL=vendor/jev # when the gateway's model id differs
```

`setup` offers the same thing when it asks which host a pasted key is for: choose "Other System
One gateway", give the URL and the model, and the three variables go where the key would have
gone. The URL is checked before anything is sent: an absolute `http(s)` URL with no credentials,
query, or fragment, stopping before `/v1/systemone`. A host-specific key (`OPENROUTER_API_KEY`
and the like) never follows `TYPESAFE_BASE_URL` to a gateway unless `JEV_CODE_PROVIDER` names
its host; `doctor` shows where requests go.

## Security notes

- Only the payload you pass to a tool leaves your machine, and only to the host your key
Expand Down
6 changes: 4 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ One `POST .../v1/systemone` per tool call, to the host your key belongs to:
- `https://api.openai.com` (OpenAI Decisions API), only when `JEV_CODE_PROVIDER=openai`
- `http://localhost:11434`, or `OLLAMA_HOST` (Ollama), only when `JEV_CODE_PROVIDER=ollama`; no key
is sent unless `OLLAMA_API_KEY` is set
- or `TYPESAFE_BASE_URL` when set, under the proxy rule below. A base URL on one of the known
hosts above while `JEV_CODE_PROVIDER` names another is refused, for Ollama too.
- or `TYPESAFE_BASE_URL` when set, under the proxy rule below: a proxy, or a System One gateway
of your own. The value is checked before any request (absolute `http(s)`, no embedded
credentials, query, or fragment). A base URL on one of the known hosts above while
`JEV_CODE_PROVIDER` names another is refused, for Ollama too.

The payload is what the agent passed to a tool: items, questions, optional context. Through
OpenRouter or Vercel AI Gateway it transits that gateway on its way to TypeSafe. jev-code never
Expand Down
12 changes: 7 additions & 5 deletions docs/harnesses/claude-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ What it does:
| Piece | User scope | Project scope |
| --- | --- | --- |
| Skill | `~/.claude/skills/jev/` | `.claude/skills/jev/` |
| Tool | `claude mcp add --scope user jev -- npx -y @french-castle/jev-code@0.4.1 mcp` | `claude mcp add --scope project ...`, which writes `.mcp.json` |
| Tool | `claude mcp add --scope user jev -- npx -y @french-castle/jev-code@0.5.0 mcp` | `claude mcp add --scope project ...`, which writes `.mcp.json` |

If the `claude` binary is not on PATH, project scope writes `.mcp.json` directly and user scope
prints the command to run. The command pins the version setup installed; re-running setup
Expand All @@ -36,7 +36,7 @@ The skill is then invoked as `/jev-code:jev`, and the tools appear as
Register the server yourself:

```bash
claude mcp add --scope user jev -e TYPESAFE_API_KEY=<your key> -- npx -y @french-castle/jev-code@0.4.1 mcp
claude mcp add --scope user jev -e TYPESAFE_API_KEY=<your key> -- npx -y @french-castle/jev-code@0.5.0 mcp
```

or add it to a project's `.mcp.json`:
Expand All @@ -46,7 +46,7 @@ or add it to a project's `.mcp.json`:
"mcpServers": {
"jev": {
"command": "npx",
"args": ["-y", "@french-castle/jev-code@0.4.1", "mcp"],
"args": ["-y", "@french-castle/jev-code@0.5.0", "mcp"],
"env": { "TYPESAFE_API_KEY": "<your key>" }
}
}
Expand All @@ -55,8 +55,10 @@ or add it to a project's `.mcp.json`:

Any provider key works in place of `TYPESAFE_API_KEY`: `OPENROUTER_API_KEY` routes through
OpenRouter and `AI_GATEWAY_API_KEY` through Vercel AI Gateway (the variable decides the host).
OpenAI's Decisions API (preview) needs both `OPENAI_API_KEY` and `JEV_CODE_PROVIDER=openai` in the
environment; a local Ollama needs only `JEV_CODE_PROVIDER=ollama`.
OpenAI's Decisions API needs both `OPENAI_API_KEY` and `JEV_CODE_PROVIDER=openai` in the
environment; a local Ollama needs only `JEV_CODE_PROVIDER=ollama`. A System One gateway of your
own takes `TYPESAFE_API_KEY` plus `TYPESAFE_BASE_URL`, as the
[README](../../README.md#your-own-gateway) explains.

Install the skill with `npx skills add FrancoisChastel/jev-code --skill jev -a claude-code`, or
copy `skills/jev/` into `~/.claude/skills/`.
Expand Down
10 changes: 6 additions & 4 deletions docs/harnesses/codex.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ What it does:
| Piece | Location |
| --- | --- |
| Skill | `~/.agents/skills/jev/` (Codex's user-level skills directory; Pi and OpenCode read it too). With `--project`: `.agents/skills/jev/`. |
| Tool | `codex mcp add jev -- npx -y @french-castle/jev-code@0.4.1 mcp`, or a `[mcp_servers.jev]` table appended to `~/.codex/config.toml` when the `codex` binary is not on PATH. |
| Tool | `codex mcp add jev -- npx -y @french-castle/jev-code@0.5.0 mcp`, or a `[mcp_servers.jev]` table appended to `~/.codex/config.toml` when the `codex` binary is not on PATH. |

Codex keeps MCP servers in its user configuration, so `--project` still registers the tool at user
level and only the skill moves into the repository.
Expand All @@ -27,16 +27,18 @@ Add to `~/.codex/config.toml`:
```toml
[mcp_servers.jev]
command = "npx"
args = ["-y", "@french-castle/jev-code@0.4.1", "mcp"]
args = ["-y", "@french-castle/jev-code@0.5.0", "mcp"]

[mcp_servers.jev.env]
TYPESAFE_API_KEY = "<your key>"
```

Any provider key works in place of `TYPESAFE_API_KEY`: `OPENROUTER_API_KEY` routes through
OpenRouter and `AI_GATEWAY_API_KEY` through Vercel AI Gateway (the variable decides the host).
OpenAI's Decisions API (preview) needs both `OPENAI_API_KEY` and `JEV_CODE_PROVIDER=openai` in the
environment; a local Ollama needs only `JEV_CODE_PROVIDER=ollama`.
OpenAI's Decisions API needs both `OPENAI_API_KEY` and `JEV_CODE_PROVIDER=openai` in the
environment; a local Ollama needs only `JEV_CODE_PROVIDER=ollama`. A System One gateway of your
own takes `TYPESAFE_API_KEY` plus `TYPESAFE_BASE_URL`, as the
[README](../../README.md#your-own-gateway) explains.

Install the skill with `npx skills add FrancoisChastel/jev-code --skill jev -a codex`, or copy
`skills/jev/` into `~/.agents/skills/`.
Expand Down
Loading
Loading