Pi router Jevv0.8.1

Pi router Jev

Pi에서 작업에 맞는 모델과 추론 수준을 선택하는 확장입니다. 기본 분류기는 TypeSafe Jev이며, API 키가 없거나 사용자가 선택하면 로컬 Laya multilingual을 사용합니다. 실제 답변과 도구 실행은 기존 Pi 제공자와 인증으로 처리합니다.

pi install npm:pi-router-jev

설치 가이드GitHub에서 보기

mejiasd3v/pi-jev-router를 기반으로 만든 포크입니다. 이 포크의 npm 이름은 pi-router-jev이며, 원본의 pi-jev-router와 구분됩니다.

설치

Pi 0.85.1 이상과 Node.js 22.19 이상이 필요합니다.

pi install npm:pi-router-jev

Git으로도 설치할 수 있습니다. 두 경로 중 하나만 설치하세요.

pi install git:github.com/cskwork/pi-jev-router
  1. Pi의 /login으로 사용할 모델 제공자를 인증합니다.
  2. 기본 웹 개발 설정을 그대로 사용하거나 아래 설정을 전역 ~/.pi/agent/settings.json에 합칩니다.
  3. /reload/model auto/jev를 선택합니다. /jev로 설정, 선택 결과, 지금 선택 가능한 후보를 확인합니다. /jev doctor는 설정과 평가기를 점검하고, /jev explain은 마지막 선택이나 대체가 왜 일어났는지 보여 줍니다.
  4. 새 세션마다 라우터로 시작하려면 전역 설정에 "defaultProvider": "auto", "defaultModel": "jev"를 넣거나 /model에서 auto/jev를 고른 뒤 Ctrl+S로 저장합니다.

기존 Git 설치는 pi update git:github.com/cskwork/pi-jev-router로 갱신할 수 있습니다. 실행 중 Pi 자체를 업데이트했다면 프로세스를 완전히 종료하고 다시 시작하세요.

Jev API 키

기본 설정은 "classifier": "jev"입니다. 다음 순서로 인증을 선택합니다.

  1. 환경 변수 TYPESAFE_API_KEY
  2. AI SDK가 사용하는 별칭 TYPESAFE_AI_API_KEY
  3. 전역 설정의 jevRouter.typesafeApiKey
  4. Pi에 저장한 Vercel AI Gateway 인증 또는 AI_GATEWAY_API_KEY
  5. 클라우드 키가 하나도 없으면 로컬 Laya
export TYPESAFE_API_KEY='your-key'
pi

설정 파일을 선호하면 jevRouter 안에 "typesafeApiKey": "your-key"를 추가하고 /reload하세요. 키는 비공개 설정에만 저장하고 Git에 커밋하지 마세요. 환경 변수를 변경했다면 해당 터미널에서 Pi를 다시 시작해야 합니다.

직접 호출은 공식 AI SDK TypeSafe 제공자jev-latest를 사용합니다. TypeSafe API 키는 모델 생성 제공자, /jev 출력, 세션의 라우팅 기록에 전달하지 않습니다. 잘못된 키가 설정되어 있으면 오류를 알리고 생성용 기본 모델을 사용합니다. 인증 오류를 숨기며 다른 분류기로 재시도하지 않습니다.

Claude / OpenAI 선택

전체 웹 개발 설정을 전역 설정에 합치세요. 예시는 Claude를 기본 계열로 선택하고, Opus와 Astra는 high, 나머지 모델은 medium으로 추론 수준을 고정합니다.

{
  "jevRouter": {
    "classifier": "jev",
    "provider": "anthropic",
    "options": {
      "anthropic/claude-sonnet-5": {
        "description": "Exploration, documentation, small fixes, and established QA scenarios.",
        "thinking": "medium"
      },
      "anthropic/claude-opus-5": {
        "description": "Architecture, difficult debugging, security, and conflicting verification evidence.",
        "thinking": "medium"
      },
      "openai-codex/gpt-5.6-sol": {
        "description": "Multi-component implementation, debugging, code review, and verification.",
        "thinking": "medium"
      }
    },
    "fallback": "anthropic/claude-sonnet-5",
    "rateLimitFallback": "openai-codex/gpt-5.6-sol",
    "monitor": false,
    "skills": false
  }
}

"provider": "openai"로 한 줄만 바꾸면 openai-codex 모델 중에서 선택합니다. /reload 후 새 세션을 시작하세요. 진행 중인 세션의 고정 모델은 바꾸지 않습니다. provider를 생략하면 등록한 모든 제공자를 후보로 사용합니다.

전체 설정에 포함된 모델 분류기에 전달하는 작업 설명
Sonnet 5 탐색, 문서, 작은 수정, 정해진 테스트와 브라우저 QA
Fable 5.1 계획된 웹 기능, UI/API 연결, 회귀 테스트
Opus 5 설계, 어려운 디버깅, 보안, 반대 관점의 리뷰, 검증 결과 해석
Luna 5.6 범위가 좁은 탐색, 기계적인 수정, 작은 테스트
Terra 5.6 기존 패턴에 따른 웹 개발, 국소 버그 수정
Sol 5.6 여러 구성 요소의 구현, 디버깅, 리뷰, 검증
Astra 6 OpenAI 계열의 설계와 계획, 모호한 요구사항, 어려운 디버깅
GLM 5.3 zai 인증이 있을 때 명확한 요구사항의 일반 개발, 문서, 검증

작업 설명은 수정할 수 있으며 성능 순위를 보장하지 않습니다. Pi에 등록되고 인증된 정확한 모델 ID를 사용하세요. options는 기본 목록을 통째로 대체합니다. fallbackrateLimitFallbackoptions에 등록해야 하며 Pi에 인증된 모델이어야 합니다. /jev는 설정한 모든 경로를 eligible, 사유가 붙은 excluded(Pi 레지스트리에 없음, 인증 미설정, 계열 선택에서 제외, 최소 추론 수준을 만족하는 단계 없음), 또는 선택한 계열 밖의 rateLimitFallback을 뜻하는 fallback only로 구분해 보여 줍니다. 설정만 되어 있고 사용할 수 없는 모델이 선택 가능한 모델과 같게 보이는 일은 없습니다.

작업 설명은 문자열 대신 role, use_when, not_for, boundary로 이루어진 구조화된 기준으로도 쓸 수 있습니다. roleboundary는 비어 있지 않은 문자열, 두 목록은 비어 있지 않은 문자열 배열이어야 합니다. 구조화된 기준은 모니터링을 포함해 분류기에 그대로 전달됩니다. 분류기는 작업 적합성으로 모델을 먼저 고른 뒤 그 모델 안에서 충분한 최저 추론 수준을 고릅니다. 높은 추론 수준이 모델의 역할 범위를 넓히지는 않으며, 다른 모델의 낮은 수준 표시가 그 모델을 선호할 이유가 되지 않습니다.

분류가 실패하면 선택한 계열에 familyFallback이 설정되어 있을 때 그 모델을 사용합니다. 예를 들어 "familyFallback": {"openai": "openai-codex/gpt-5.6-luna"}처럼 씁니다. 설정이 없으면 fallback이 같은 계열일 때 그 모델을, 아니면 설정 파일의 순서상 첫 번째 사용 가능한 모델을 선택합니다. 전체 예시에서는 Claude의 기본 모델이 Sonnet, OpenAI의 기본 모델이 Sol입니다. /jev doctor는 실제로 적용되는 기본 모델을 보여 주고, 순서에만 의존할 때 경고합니다. 후보가 없으면 명시적으로 실패합니다.

로컬 Laya multilingual

클라우드 키가 없으면 로컬 분류를 시도합니다. 키가 있어도 "classifier": "local"을 설정하면 로컬만 사용합니다. 기본 주소는 http://127.0.0.1:8765/v1이며 localUrl로 변경할 수 있습니다. 루프백 HTTP 주소만 허용하고 리다이렉트는 거부합니다.

이 저장소를 내려받은 폴더에서 실행하세요.

python3 -m venv .venv-laya
.venv-laya/bin/pip install 'laya==0.3.5'
.venv-laya/bin/python scripts/laya-server.py

이 터미널을 켜 둔 상태에서 Pi를 사용합니다. 첫 실행은 Hugging Face에서 모델을 내려받습니다. 준비 완료 메시지가 나온 뒤 요청을 받습니다. npm 패키지에도 같은 서버 스크립트가 포함됩니다.

convaiinnovations/layamultilingual 체크포인트 하나를 CPU에 올려 한국어·영어 등 지원 언어를 처리합니다. 영어 전용 모델로 바꾸지 않습니다. 서버는 127.0.0.1:8765에만 바인딩하며 /health에서 준비 상태를 확인할 수 있습니다. Ctrl+C로 종료합니다. 플러그인이 Python이나 모델을 자동 설치하거나 상시 프로세스를 만들지는 않습니다.

Laya 공식 설명처럼 로컬 모델은 Jev보다 문맥이 짧고 작업에 따라 정확도가 달라집니다. 브리지는 상태가 모델의 토큰 예산을 넘으면 거절하며 질문과 선택지를 각각 20개로 제한합니다. 모델마다 허용된 추론 단계 수만큼 선택지가 늘어나므로 8개 모델을 모두 "thinking": "auto"로 두면 한도를 넘습니다. 라우터는 요청을 보내기 전에 이를 확인하고 local classifier accepts at most 20 choices but the configuration offers N model/effort profiles라는 정확한 사유와 함께 기본 모델을 사용하며, /jev doctor에서도 개수를 보여 줍니다. 서버는 연결을 스레드로 처리하고 소켓 시간 제한을 두며, 모델은 하나만 올리고 추론은 한 번에 하나만 실행합니다. 대기 요청은 최대 2개를 --queue-wait 초(기본 5초)까지 기다리게 하고, 그 이상이거나 만료되면 503으로 응답합니다. /healthready, busy, queued, limits를 따로 알려 줍니다. 질문과 선택지 설명은 Laya 내부에서도 길이가 제한됩니다. 길거나 복잡한 작업에는 Jev를 권장합니다. 로컬 서버가 꺼져 있거나 입력을 처리하지 못하면 경고 후 생성용 기본 모델을 사용합니다.

사용량 제한과 오류

fallback분류 실패에, rateLimitFallback답변 생성 중 사용량 제한에 사용합니다.

  • HTTP 429나 Anthropic의 out of extra usage처럼 사용량 제한이 확인되면, 출력이 시작되기 전에만 대체 모델로 한 번 시도합니다. 오류는 먼저 실행 파일 누락, 인증, 사용량 제한, 문맥 초과, 알 수 없음으로 분류하며 인증과 실행 파일 문구가 우선합니다. 401 ... rate limit information unavailable 같은 문구는 인증 실패로 보고하고 다른 제공자로 재시도하지 않습니다.
  • 대체 모델이 성공하면 해당 모델을 세션에 고정하고 재시작 후에도 유지합니다. 실패하면 원래 고정을 유지하고 오류를 반환합니다.
  • 텍스트·추론·도구 호출이 이미 시작되었거나 요청이 취소된 경우에는 다시 실행하지 않습니다.
  • 인증 실패, 실행 파일 누락, 다른 서버 오류, 보조 요청은 자동 전환 대상이 아닙니다. 인증·이미지·추론 정책에 맞지 않는 후보도 제외합니다.
  • 원문 문맥은 잘라내지 않고 전달합니다. 재시도 전에 마지막 제공자 사용량(없으면 바이트 수)으로 대화 크기를 추정하고 출력 예산을 더해, 대체 모델의 문맥 창에 들어가지 않으면 경고와 함께 시도를 건너뜁니다. /jev explain에서 추정치와 측정 여부를 확인할 수 있습니다. Pi나 제공자 자체의 재시도는 별도로 적용됩니다.
표시 의미와 조치
Jev [runtime] Pi 제공자의 실행 파일을 불러오지 못했습니다. Pi를 완전히 종료하고 재시작하세요. 계속되면 Pi 설치를 복구하세요. 인증이나 사용량 제한 오류가 아닙니다.
Jev [auth] 생성 모델의 인증이나 접근 권한 문제입니다. 안내된 제공자로 /login하세요.
Jev [usage-limit] 요청량 또는 사용량 한도입니다. 기다리거나 /model로 다른 모델을 선택하세요.
Jev [context] 제공자가 대화가 너무 길다고 거절했습니다. /compact를 쓰거나 짧은 세션으로 포크하세요. 모델 재시도는 하지 않습니다.
/jev doctor가 문제를 표시 표시된 조치를 따르세요. 제공자 /login, familyFallback 설정, 로컬 분류기의 자동 추론 선택지 축소, Laya 서버 시작 등입니다. 자격 증명은 설정 여부만 보고하며 실제 검증은 하지 않습니다.
Vercel AI Gateway refused the Jev request (HTTP 403) 키는 유효하지만 Vercel 팀에 결제 수단이 없거나 키에 AI Gateway 권한이 없습니다. vercel.com/ai에서 카드를 등록하면 무료 크레딧이 열립니다. 그동안은 생성용 기본 모델을 사용합니다.
TypeSafe rejected credentials (401) TypeSafe 키를 갱신하세요. 설정 파일을 변경했다면 /reload, 환경 변수를 변경했다면 Pi를 재시작하세요.
로컬 연결 실패·시간 초과·HTTP 413 Laya 서버의 준비 상태를 확인하거나 긴 작업에 Jev를 사용하세요.
Claude 경로에서 출력 없이 CPU 100%로 멈춤 라우터 문제가 아닙니다. pi-background-tasks 2.6.2의 attribution 기능이 Anthropic 제공자를 대체하며 Pi 0.86+의 시스템 메시지에서 무한 루프에 빠집니다. Pi 실행 전 PI_BG_FEATURES=process,delegate,fusion,attested를 내보내세요. 구체적인 Anthropic 모델을 직접 골라도 같은 증상이면 이 원인입니다.

SDLC Kit와 세션

SDLC Kit가 단계, 승인, QA·검증 근거를 관리합니다. 라우터는 테스트 성공이나 승인 여부를 판단하지 않으며 서브에이전트를 실행하지 않습니다. 기존 SDLC 스킬을 그대로 사용하세요. 구체적인 모델을 지정한 서브에이전트의 설정도 유지됩니다.

모델과 초기 추론 수준은 세션에 한 번 고정합니다. 도구 호출, 압축, /reload, /resume에서 유지하며 /new, /fork, /clone에서는 새로 선택합니다. 다른 단계로 넘어갈 때 새 세션이나 명시적 모델 선택을 사용할 수 있습니다. 구체적인 모델을 선택하면 라우팅을 우회합니다.

monitor: true는 새 사용자 요청을 검토해 다른 모델의 포크를 제안합니다. 제안만으로 자동 전환하지 않습니다. 전체 예시는 추가 평가 비용을 줄이기 위해 monitorskills를 끕니다.

고급 설정

설정 동작
thinking: "medium" 모델이 지원하는 범위 안에서 고정합니다.
thinking: "auto" 분류기가 모델과 필요한 추론 수준을 함께 선택합니다.
thinking: {"low": "설명", "high": "설명"} 허용 수준과 의미를 직접 정합니다.
thinking 생략 처음 고정할 때 Pi의 추론 수준을 상속합니다.
minThinking 전역 또는 모델별 최소 수준입니다. 지원하지 않는 후보는 제외합니다.
familyFallback {"anthropic": ..., "openai": ...} 형태로 계열별 분류 실패 기본 모델을 명시합니다. 설정 순서에 의존하지 않게 합니다.
timeoutMs 평가 시간 제한입니다. 기본 5,000ms, 1~60,000ms 범위입니다.
skills: true 발견된 스킬 중 관련성이 높은 최대 3개를 자동 로드합니다. 기본은 꺼짐입니다.
Astra의 adaptiveThinking: true openai-codex/gpt-6-astra에서 자동 추론 선택과 함께 쓸 수 있습니다. 다른 모델은 허용하지 않습니다.

수준은 off, minimal, low, medium, high, xhigh, max입니다. Astra의 명시적 모델 최소값만 전역 최소값보다 낮출 수 있습니다. 자동 스킬은 확률 0.8 이상인 후보를 고르며, 명시적 호출 전용 스킬은 제외합니다. 도구 연속 실행에서는 같은 선택을 다시 평가하지 않습니다. 고급 기능의 캐시·압축·분기 처리 조건은 영문 상세 문서를 참고하세요.

입력·개인정보·비용

모델 선택에는 최근 사용자·어시스턴트 텍스트 최대 8개를 사용합니다. 시스템 프롬프트, 추론 내용, 이미지, 도구 결과는 기본 모델 선택 평가에 보내지 않습니다. 다만 일반 대화에 포함된 민감한 텍스트는 자동으로 가리지 않습니다.

Astra의 선택적 적응형 추론은 도구 결과 발췌를 포함할 수 있습니다. 자동 스킬 선택은 스킬 이름과 설명을 평가기에 보내고 본문은 로컬에서 읽습니다. 명시적 로컬 모드에서는 평가 내용을 클라우드로 보내지 않지만, 이후 답변 생성에는 선택한 Pi 제공자를 사용합니다.

평가 요청은 직렬화한 UTF-8 기준 28,000바이트로 제한합니다. 최신 작업이 길면 최대 8개 겹치는 조각으로 나누고 한 번 결합합니다. 192,000바이트를 넘거나 평가가 완성되지 않으면 기본 모델을 사용합니다. 최초 라우팅과 모니터링의 시간 초과 재시도는 최대 3회이며 전체 시간도 3 × timeoutMs로 제한합니다. 적응형 추론과 스킬 선택은 각각 별도 평가이며 재시도하지 않습니다.

Jev 평가는 별도 과금됩니다. /jev의 Gateway 비용은 추정치이며 Pi 생성 비용 합계에 포함되지 않습니다. 직접 TypeSafe와 로컬 평가에는 토큰 수만 표시합니다. Laya에는 API 요금이 없지만 로컬 연산과 모델 저장 공간이 필요합니다. 모델 고정은 캐시 재사용에 도움이 되지만 캐시 적중이나 비용 절감을 보장하지 않습니다.

개발·게시

nub install --frozen-lockfile --ignore-scripts
nub run typecheck
nub run test
nub run docs

nub run typecheck는 설치된 Pi의 호환 타입을 테스트와 같은 방식으로 찾아 index.tstsc를 실행하므로 패키지 관리자 배치 방식과 무관하게 동작합니다. 테스트는 네트워크 응답을 모의 처리하며 API 키가 필요하지 않습니다. nub run test는 npm tarball에 확장이 불러오는 파일이 모두 들어 있는지 확인하는 scripts/package_test.mjs도 실행합니다. CI는 Pi 0.85.1(잠금 파일)과 0.87.0에서 테스트합니다. 로컬 서버 검증은 python3 -m unittest discover -s scripts -p '*_test.py'로 실행합니다.

공개 npm 이름은 pi-router-jev입니다. pi-package 키워드와 pi.extensions가 있으므로 Pi 공식 패키지 목록의 수집 대상입니다. 게시 후 npm 버전과 실제 목록을 확인하세요. 검색 반영에는 시간이 걸릴 수 있습니다.

npm test
npm pack --dry-run
npm login
npm publish --access public

GitHub의 자동 npm 게시는 패키지 설정에 cskwork/pi-jev-routerpublish.yml을 trusted publisher로 연결한 뒤 사용할 수 있습니다. Git 푸시만으로 npm에 게시되지는 않습니다.

문서 사이트는 docs/에서 GitHub Pages로 제공합니다. 브라우저가 선호하는 한국어 또는 영어를 선택하며 둘 다 없으면 한국어를 표시합니다. 페이지의 언어 링크로 변경할 수 있습니다. GitHub README 자체는 브라우저 언어에 따라 자동 전환되지 않으므로 이 파일을 기본으로 두고 영어판을 연결합니다.

MIT 라이선스. 원본 작성자는 MejiasDev이며 이 포크에서 제공자 선택, TypeSafe 직접 호출, 로컬 Laya, 사용량 제한 복구를 추가했습니다.

Pi router Jev

Let TypeSafe's Jev choose a model and reasoning effort for Pi. The model stays fixed for the session unless you enable the usage-limit fallback below. Effort stays fixed too, unless you enable adaptive effort for Codex Astra. Generation uses your existing Pi providers and credentials, including Claude Opus, Fable, and Sonnet, plus Codex Luna, Terra, and Sol.

pi install npm:pi-router-jev

Get startedView on GitHub

Get started

Requires Pi 0.85.1+ and Node.js 22.19+. Use a TypeSafe key, a Vercel AI Gateway key, or the optional local Laya service.

pi install npm:pi-router-jev

Git installation: pi install git:github.com/cskwork/pi-jev-router. Keep one installation. This fork of mejiasd3v/pi-jev-router is published as pi-router-jev; the npm package pi-jev-router remains the upstream project.

  1. Use /login for your generation provider. For Jev, set a TypeSafe key as described below, or use /login vercel-ai-gateway / AI_GATEWAY_API_KEY.
  2. Run /reload, then /model auto/jev. To start every new session on the router, set "defaultProvider": "auto" and "defaultModel": "jev" in global settings, or press Ctrl+S on auto/jev in /model.
  3. Start with your actual task. /jev shows the pin, selected effort, fork suggestions, and which configured routes are eligible right now. /jev doctor checks the configuration and evaluator; /jev explain shows why the last decision or fallback happened.

Classifier and API keys

Jev is the default classifier. The selection order is TYPESAFE_API_KEY, TYPESAFE_AI_API_KEY (the AI SDK alias), jevRouter.typesafeApiKey, then the Pi Gateway credential. When no cloud key is configured, the router tries local Laya. An invalid configured key does not silently switch evaluators; the error is reported and the generation fallback is used.

export TYPESAFE_API_KEY='your-key'
pi

Alternatively, add "typesafeApiKey": "your-key" under global jevRouter, then /reload. Use a private settings file; never commit keys. Keys are not included in /jev, session routing records, or generation-provider requests. An environment key takes precedence over the setting. Changing a shell environment variable requires restarting Pi from that shell.

Direct calls use the official AI SDK TypeSafe provider, jev-latest, and TypeSafe's API. Model routing, opt-in skill selection, and adaptive effort use the same evaluator. /jev shows which evaluator is selected. Direct and local calls show token usage without applying Gateway cost estimates.

Local multilingual Laya

Set "classifier": "local" to explicitly use local inference even when keys exist. Keep "classifier": "jev" for Jev-first behavior. The local URL defaults to http://127.0.0.1:8765/v1; localUrl accepts loopback HTTP addresses only. Cloud credentials are never forwarded to this service, and redirects are refused.

From a Git checkout of this repository:

python3 -m venv .venv-laya
.venv-laya/bin/pip install 'laya==0.3.5'
.venv-laya/bin/python scripts/laya-server.py

Leave that terminal open. First startup downloads the checkpoint from Hugging Face. The service binds to 127.0.0.1:8765 and loads convaiinnovations/laya's multilingual subfolder on CPU before accepting requests. The same model handles Korean, English, and other supported languages. /health reports readiness. Stop with Ctrl+C. The extension does not install Python, download weights, or launch a daemon automatically. The npm tarball also includes the server script.

Laya has a much shorter context than Jev. The bridge rejects state that exceeds the checkpoint's token budget and limits questions/choices to 20. Laya internally bounds question and option descriptions; it is not equivalent to Jev for long or ambiguous tasks. Every configured model expands into one choice per allowed thinking level, so eight models with "thinking": "auto" exceed the limit; the router checks this before sending anything and falls back with an exact reason (local classifier accepts at most 20 choices but the configuration offers N model/effort profiles), and /jev doctor reports the count. The bridge serves connections on threads with a socket timeout, keeps one loaded model and one active inference, queues at most two waiting requests for --queue-wait seconds (default 5), and answers 503 when busy or expired; /health reports ready, busy, queued, and limits separately. A rejected request or stopped server uses the configured generation fallback with a warning. No cloud request is made in explicit local mode. Routing decisions are heuristics, not QA results or permission to act.

Configure

Merge jevRouter into global ~/.pi/agent/settings.json, then /reload:

{
  "jevRouter": {
    "options": {
      "openai-codex/gpt-5.6-luna": {
        "description": "Small fixes, tests, and routine implementation.",
        "thinking": "auto"
      },
      "openai-codex/gpt-6-astra": {
        "description": "Architecture, difficult debugging, and complex reasoning.",
        "thinking": "auto"
      }
    },
    "fallback": "openai-codex/gpt-6-astra",
    "timeoutMs": 5000,
    "monitor": true,
    "skills": false
  }
}

Only listed, authenticated models are eligible; fallback and rateLimitFallback must be listed and authenticated too. /jev lists every configured route as eligible, excluded with the reason (not in Pi's registry, authentication not configured, provider preference, or no thinking level meeting the floor), or fallback only for a rateLimitFallback outside the selected family. A configured-but-unavailable model is never shown the same way as a selectable one. Routes replace the default list; they aren't merged. PI_CODING_AGENT_DIR is respected; project settings cannot override routing.

Without configuration, the web-development preset below is used: Jev-first classification, Claude models with Opus at high effort and the rest at medium, Sonnet fallback, Sol usage-limit fallback, a five-second timeout, and monitoring/skill selection off. The custom example above replaces that preset with Codex routes and automatic effort.

Descriptions accept either a nonempty string or a structured rubric with role, use_when, not_for, and boundary. The role and boundary must be nonempty strings; both lists must contain nonempty strings. Structured rubrics are passed intact as each Choice option's task, including during monitoring. Jev chooses the model by task fit first, then the lowest sufficient effort within that model. High effort never expands a model's scope, and a lower effort label on another model is not a reason to prefer it.

Web development with Claude, Codex, and SDLC Kit

Merge examples/web-development.json into your global settings. It uses existing Pi providers, with high thinking for Opus and Astra and medium for the other routes:

Model Task description offered to Jev
anthropic/claude-sonnet-5 Exploration, documentation, small fixes, established tests and browser QA scenarios.
anthropic/claude-fable-5-1 Web features, UI/API integration, regression tests, and planned multi-file changes.
anthropic/claude-opus-5 Architecture, difficult debugging, security, adversarial review, and conflicting verification evidence.
openai-codex/gpt-5.6-luna Narrow exploration, mechanical edits, and small tests.
openai-codex/gpt-5.6-terra Planned web features, localized fixes, and regression coverage.
openai-codex/gpt-5.6-sol Multi-component implementation, debugging, review, and interpreting QA evidence.
openai-codex/gpt-6-astra Architecture and planning: system design, implementation plans, ambiguous requirements, and difficult debugging on the OpenAI side.
zai/glm-5.3 General development, documentation, and verification with clear requirements when zai is authenticated.

These are editable task descriptions, not model benchmarks or guaranteed classifications. Use exact model IDs available in your Pi /model picker. Only authenticated models are offered. Choose another allowed fallback if you do not use Z.ai.

The preset defaults to "provider": "anthropic". Change just this field to "provider": "openai" to select from the configured openai-codex models. Run /reload, then start a new session. Existing pins remain unchanged. Omit provider to let Jev choose across all configured providers, as in upstream. /jev shows the selected family.

If neither Jev nor the local classifier can evaluate the task, the router uses familyFallback for the selected family when set, for example "familyFallback": {"openai": "openai-codex/gpt-5.6-luna"}; otherwise fallback if it belongs to the selected family; otherwise the first eligible model in that family's configured option order. In this preset that means Sonnet for Claude and Sol for OpenAI. /jev doctor reports the effective fallback and warns when it is only implied by option order. Models without authentication or compatible input/thinking are excluded. If the selected family has no eligible model, the request fails explicitly. The separate rateLimitFallback may cross provider families.

Select /model auto/jev to use the router. The preset disables monitoring and automatic skill loading to avoid extra evaluations. New sessions choose a model for their first task; later tasks remain on that pin. Start a new session or explicitly choose a model when changing stages.

SDLC Kit continues to own its stages, approvals, and verification evidence. The router does not run tests, declare QA successful, dispatch subagents, or approve gates. Invoke your SDLC skills normally. Subagents that select a concrete model keep their own settings; this preset does not override them.

Usage-limit fallback (opt-in)

Set "rateLimitFallback": "zai/glm-5.3" inside jevRouter, with that model also listed in options. This is separate from fallback, which handles Jev classification failures. Without this setting, backend errors behave as before.

For a main request, a provider-reported rate or usage-limit error before any text, reasoning, or tool output triggers one attempt on the configured model. This includes HTTP 429 and Anthropic's out of extra usage error. Backend failures are first classified as runtime, authentication, usage-limit, context-overflow, or unknown; authentication and runtime wording takes precedence, so an error such as 401 ... rate limit information unavailable is reported as an authentication failure and never retried on another provider. The router uses the fallback's own authentication and supported thinking policy, and reports the switch. A successful response pins the fallback for the rest of the session, including reload/resume. A failed attempt keeps the original pin and returns the failure.

There is no fallback after partial output, on cancellation, for auxiliary requests, or for unrelated errors such as authentication failures. Unavailable models, incompatible image inputs, and unsupported thinking policies are not retried. The complete original context is forwarded without truncation. Before retrying, the router estimates the conversation size from the last provider-reported usage (or bytes when none exists), reserves the output budget, and skips the attempt with a warning when the replacement's context window cannot hold it; /jev explain shows the estimate and whether it was measured or estimated. Provider or Pi retries remain separate from this single router fallback. Use a different provider when models share the same exhausted quota. A switch can lose prompt-cache savings.

Thinking

thinking Behavior
"auto" Jev chooses the lowest effort it judges sufficient.
"high" Force a level, clamped to the model's capabilities.
{"low": "Small changes", "high": "Hard problems"} Customize the allowed choices and their descriptions.
Omitted Inherit Pi's thinking level when the pin is created.

Levels: off, minimal, low, medium, high, xhigh, max. Automatic choices are filtered to supported levels. Model and effort are chosen in one evaluation: task fit determines the model first, then Jev selects the lowest sufficient allowed effort within that model. Effort labels are model-relative; another model's lower label does not make it a better fit. A configured floor can intentionally exceed what a routine task needs.

Set jevRouter.minThinking for a global floor, and minThinking inside a model's option for a stricter per-model floor. For example, global "medium" plus Luna "high" lets Jev choose medium or higher for Astra and high or higher for Luna when both use "thinking": "auto". An omitted model minimum inherits the global floor. Only openai-codex/gpt-6-astra can override it: an explicit Astra "minThinking": "low" permits low effort even with global "medium", for both initial routing and adaptive effort. Other models can only raise the global floor. Both fields are optional and default to no additional restriction.

Automatic and custom choices below the floor are excluded. Fixed or inherited effort below the floor is raised to the lowest supported level meeting it. Routes with no eligible level are excluded, including non-reasoning models when the floor is above off; fallback errors if it has no eligible choice. /jev shows configured minimums. Reload after editing; existing session pins keep their original effort.

Adaptive Astra effort (opt-in)

Set "adaptiveThinking": true inside the openai-codex/gpt-6-astra option, alongside "thinking": "auto" or custom thinking choices. Other models and fixed/inherited effort policies do not accept this flag.

"openai-codex/gpt-6-astra": {
  "description": "Architecture and difficult debugging.",
  "thinking": "auto",
  "adaptiveThinking": true
}

After the initial route, Jev assesses the next step before each main model request, including tool continuations. It can raise effort for unresolved failures or difficult decisions and lower it for routine work. It chooses only supported levels allowed by your choices and minimums. This is a heuristic, not a guarantee that Jev detects every stall. Changes take effect between responses, never inside a running response.

  • Keep the model and request prefix. The original request-level effort stays fixed. Changes use Astra's append-only configuration_update items, replayed at their original input positions. This follows OpenAI's cache-preserving mechanism; normal cache requirements still apply. Do not use provider-side automatic compaction, automatic truncation, or another hook that inserts configuration updates.
  • Persist and recover. Decisions follow the active branch across reload/resume. If local Pi compaction or edited history invalidates an update's original prefix, the current effort is re-established on the rebuilt input. Forks choose afresh. Auxiliary requests reuse effort without evaluating or saving changes.
  • Bound overhead. At most one additional evaluation per distinct request context, bounded by timeoutMs, with no retries and a 28,000-byte request budget. Failure retains current effort; cancellation stops the request. monitor: false disables model-switch suggestions, not adaptive effort.
  • See changes. Notifications, the status line, and /jev show current effort. /jev also shows the initial effort used at request level. Pi's thinking picker still does not control or track the router's effort.

Reload after changing the flag. Enabling it can adapt an existing Astra pin on its next request. Disabling it stops new decisions but preserves and replays prior updates; use a new session for a fresh pin.

Additional data and cost: effort checks send the latest user-text excerpt plus up to eight recent user, assistant, and tool-result excerpts to the selected evaluator. Each excerpt keeps up to 1,600 characters, split between its beginning and end. Tool names and error flags are included; tool-call arguments, reasoning blocks, images, and system messages are excluded. Tool-result text can contain secrets and is not redacted. These evaluations are billed separately and are not included in /jev routing-cost estimates.

Automatic skill loading (opt-in)

Set "skills": true inside your existing global jevRouter configuration, then /reload. It defaults to false and works with both auto/jev and concrete models, independently of monitor.

Before generation for each new user turn, including steering messages, Jev checks Pi's discovered skill names and descriptions against recent user/assistant text. It loads up to three matches with a returned probability of at least 0.8. These probabilities are heuristic relevance signals, not guarantees.

  • Uses Pi's catalog, including its trust and discovery settings. Skills marked disable-model-invocation are never auto-loaded.
  • Injects full skill instructions with their source path and reference directory. It does not execute scripts or eagerly load linked references.
  • Skips skills already included as <skill> blocks or successfully loaded through a complete read call in the current context. Path aliases are canonicalized. Arbitrary shell commands or unmarked pasted instructions cannot reliably be recognized as skill loads.
  • Saves selections and instructions on the active session branch. Tool continuations and /reload reuse them without another evaluation or file read. Skills removed by compaction or branch navigation can be selected again when needed.
  • Makes at most one additional evaluation per user turn, bounded by timeoutMs with no retries and the same 28,000-byte request budget. Older history is dropped first; oversized tasks/catalogs skip selection rather than using a partial task. Full injected instructions are limited to 50,000 bytes per turn; unreadable or oversized skills are skipped with a warning.

/jev shows whether this feature is enabled. Failures leave ordinary skill loading available. Turning it off stops selection and reinjection; it does not erase instructions the model already read or remove saved session records.

Long prompts

The latest task takes priority; older history is dropped before splitting it. Requests have a 28,000-byte serialized UTF-8 budget, including route descriptions. This is a conservative proxy for Jev's roughly 32K-token request budget, not an exact token count.

Tasks that don't fit are split into at most eight overlapping chunks, evaluated two at a time, then combined in one final evaluation. The final evaluation is instructed to weigh requirements, not vote counts. This is still a heuristic: relationships across sections may be missed.

Tasks over 192,000 UTF-8 bytes, excessive chunk plans, or incomplete evaluations use fallback (or retain the existing pin during monitoring). The coding model always receives the original input; its context limits still apply.

Session behavior

  • Pin once. The model and initial effort survive tool calls, compaction, /reload, and /resume. Effort remains fixed unless adaptive Astra effort is enabled. /new, /fork, and /clone choose afresh. Model and initial-effort configuration changes don't rewrite existing pins. A successful opt-in usage-limit fallback creates a replacement pin.
  • Suggest, never switch. Monitoring checks new user text and may suggest a fork with another model, once per alternative per session. Use /fork, then /model and /thinking in the fork to follow it. No automatic forks or task-driven model switches. The opt-in usage-limit fallback is the only automatic model switch.
  • Control overhead. Routing and model-monitor evaluation timeouts retry up to three attempts of timeoutMs each (1 to 60,000 ms). The entire operation shares a ceiling of 3 × timeoutMs, including chunks and combination: 15 seconds by default. Set "monitor": false to disable model-switch advisory checks; tool continuations don't trigger those checks. Adaptive effort has its own per-request check described above.
  • Fail explicitly. Initial routing failures use the fallback, with its fixed/inherited effort or highest supported automatic choice. If an existing pin becomes unavailable or cannot accept the input, the router errors instead of switching.

Context limits follow the pinned backend. The status and /jev show its current effort; Pi's thinking picker does not track automatic choices. Selecting a concrete model bypasses model routing, but not opt-in skill selection. Deferred/background generation is unsupported by auto/jev.

Privacy and cost

Routing and monitoring consider up to eight recent user/assistant text messages, limited to 192,000 UTF-8 bytes of source text. Evaluations send selected text, route/effort descriptions, and chunk assessments to the selected evaluator. Overlaps, excerpts, and retries can send the same text more than once. System prompts, reasoning blocks, tool-result blocks, images, and provider credentials are excluded from model-routing evaluations. Opt-in adaptive effort additionally sends tool-result excerpts as described above. Conversation text is not redacted and may contain secrets.

Opt-in skill selection additionally sends eligible skill names and descriptions to the selected evaluator. Skill file contents are read locally and stored in the session; automatically injected skill messages are excluded from subsequent Jev evaluations. Manually pasted or expanded skill instructions in user messages remain conversation text.

Cloud evaluations are billed separately. Local Laya incurs local compute and model storage costs, without API charges. Chunking uses at most nine evaluations before timeout retries, or 27 attempts total. /jev estimates sum returned usage; failed, cancelled, or timed-out calls may still be billed. Skill-selection evaluations are additional and are not included in /jev routing estimates. Evaluation costs are not in Pi's footer totals. Pinning favors cache reuse but guarantees neither cache hits nor savings.

Migrating from file-based configuration

Move the old routes.json contents under jevRouter and unset JEV_ROUTES_FILE; neither is read anymore. Sessions created before pinning was introduced select a pin on their next main request.

Development

nub install --frozen-lockfile --ignore-scripts
nub run typecheck
nub run test
nub run docs

nub run typecheck runs tsc on index.ts against the compatibility types of the installed Pi, resolved the same way the tests resolve them, so it works with any package-manager layout. Tests mock network responses; no API keys or paid requests are needed. nub run test also runs scripts/package_test.mjs, which checks that the npm tarball contains every file the extension imports. CI runs the suite against Pi 0.85.1 (the lockfile) and 0.87.0.

Publishing this fork

.github/workflows/publish.yml publishes stable GitHub releases to npm using trusted publishing. It checks that the release tag matches package.json, installs from the frozen lockfile, and runs tests before publishing. Prereleases are skipped. The publish step uses npm's native OIDC flow; installs and tests use Nub.

Publish only pi-router-jev. The upstream package name belongs to its maintainer. Pi's official package catalog discovers public npm packages carrying pi-package; catalog indexing may lag npm publication.

npm test
npm pack --dry-run
npm login
npm publish --access public

The release workflow uses npm trusted publishing. Configure a trusted publisher for cskwork/pi-jev-router, workflow publish.yml, in this package's npm settings before using GitHub releases to publish. A Git push alone does not publish npm. The documentation site is served from docs/ with GitHub Pages; its initial language follows the first Korean or English browser preference, with Korean as the fallback. The language links override detection.

Troubleshooting

Message Meaning and next action
Jev [runtime] / Cannot find module .../dist/bundle/chunks/... Pi cannot load a provider module, often after updating a running Pi process. Exit and restart Pi, then resume the session. If it persists, reinstall Pi. This is not an API-key or quota error.
Jev [auth] Generation credentials or model permissions failed. Use the named provider's /login. No model retry occurs for authentication errors.
Jev [usage-limit] Provider quota or rate limit. A configured eligible rateLimitFallback is tried once before any output; otherwise wait or choose a model.
Jev [context] The provider rejected the conversation as too long. Use /compact or fork a shorter session. No model retry occurs.
/jev doctor lists a problem Follow the listed fix: /login the provider, set familyFallback, reduce automatic thinking choices for the local classifier, or start the Laya bridge. Credentials are reported as configured, not verified.
Vercel AI Gateway refused the Jev request (HTTP 403) The key is valid, but the Vercel team has no payment method on file or the key lacks AI Gateway access. Adding a card at vercel.com/ai unlocks the free credits; until then the generation fallback is used.
TypeSafe rejected credentials (401) Replace the TypeSafe key, then reload or restart depending on where it is configured.
Claude routes hang at 100% CPU with no output Not the router. pi-background-tasks 2.6.2's attribution feature replaces the Anthropic provider and loops forever on the system messages Pi 0.86+ keeps in the transcript. Export PI_BG_FEATURES=process,delegate,fusion,attested before starting Pi. Selecting a concrete Anthropic model reproduces it without the router.
Local connection/timeout or HTTP 413 Start the Laya bridge, wait for readiness, or use Jev for a longer task. The generation fallback remains available.

fallback handles classifier failures; rateLimitFallback handles generation usage limits. Selecting a concrete model bypasses the router. Keep /model auto/jev selected to use its behavior.

MIT. Original router by MejiasDev; this fork adds provider selection, direct TypeSafe, local Laya, and usage-limit recovery.