JEV GIT WORKFLOW GUIDE

Jev for Git workflows: commits, pull requests, and CI gates

Use Jev for bounded semantic decisions around Git commits, pull requests, and CI without giving a probabilistic model permission to push, merge, or bypass branch protection.

Updated 2026-09-2418–25 min
01

1. Decide what Jev owns—and what it never owns

Use Jev where exact Git data is insufficient: classify a change, select a review area, estimate a risk band, or decide whether a human review is required. File existence, tests, permissions, required reviewers, and protected-branch policy remain deterministic checks. This tutorial never lets the model push, merge, tag, release, or bypass an approval.

02

2. Create a dependency-free PR decision script

The example uses Node 20 built-ins and the official POST /v1/systemone endpoint. Locally it reads the staged diff; in CI, JEV_BASE points it at the pull request base branch. It limits the patch, records whether truncation happened, and never sends repository credentials.

scripts/jev-pr-review.mjs
import { appendFileSync } from 'node:fs';
import { execFileSync } from 'node:child_process';

const apiKey = process.env.TYPESAFE_API_KEY;
if (!apiKey) throw new Error('TYPESAFE_API_KEY is required');

const base = process.env.JEV_BASE?.trim();
const range = base ? [base + '...HEAD'] : ['--cached'];
const git = (...args) => execFileSync('git', args, {
  encoding: 'utf8', maxBuffer: 2_000_000,
});

const names = git('diff', '--name-status', ...range);
const rawDiff = git('diff', '--unified=1', '--no-ext-diff', ...range);
if (!rawDiff.trim()) {
  console.log('No changes to review.');
  process.exit(0);
}

const sensitivePath = /(^|\t)(\.env($|\.)|.*\.(pem|key|p12)$)/m;
if (sensitivePath.test(names)) {
  throw new Error('Refusing to send a diff containing a sensitive path');
}

const MAX_DIFF = 14_000;
const state = {
  comparison: base ? base + '...HEAD' : 'staged changes',
  changed_files: names.trim().split('\n').slice(0, 200),
  patch_excerpt: rawDiff.slice(0, MAX_DIFF),
  patch_truncated: rawDiff.length > MAX_DIFF,
};

const questions = {
  change_type: {
    type: 'choice',
    instructions: 'What is the primary purpose of this Git change?',
    criteria: {
      feature: 'Adds user-visible behavior',
      fix: 'Corrects broken or incorrect behavior',
      maintenance: 'Refactor, dependency, documentation, or tooling',
      unknown: 'Evidence is insufficient or does not fit another option',
    },
  },
  risk: {
    type: 'score',
    instructions: 'How risky is this change to merge?',
    criteria: [
      'Low: isolated and easy to reverse',
      'Moderate: touches shared behavior but has bounded impact',
      'High: affects data, auth, payments, deployment, or broad behavior',
      'Critical: credible irreversible or security-sensitive impact',
    ],
  },
  needs_human_review: {
    type: 'noul',
    instructions: 'Does this change require deliberate human review before merge?',
    criteria: {
      true: 'Ambiguous, high-impact, security-sensitive, or difficult to reverse',
      false: 'Low-impact, well-bounded, and straightforward to reverse',
    },
  },
};

const response = await fetch('https://api.typesafe.ai/v1/systemone', {
  method: 'POST',
  headers: {
    authorization: 'Bearer ' + apiKey,
    'content-type': 'application/json',
  },
  body: JSON.stringify({ model: 'jev-latest', state, questions }),
  signal: AbortSignal.timeout(15_000),
});

if (!response.ok) {
  throw new Error('Jev request failed: ' + response.status);
}

const result = await response.json();
const { change_type: type, risk, needs_human_review: review } = result.answers ?? {};
const allowedTypes = new Set(Object.keys(questions.change_type.criteria));

if (!type || !allowedTypes.has(type.choice)) throw new Error('Invalid Choice answer');
if (!risk || !Number.isFinite(risk.score) || risk.score < 0 || risk.score > 3) {
  throw new Error('Invalid Score answer');
}
if (!review || !Number.isFinite(review.noul) || review.noul < 0 || review.noul > 1) {
  throw new Error('Invalid Noul answer');
}

// Example thresholds only. Calibrate them against your repository history.
const outcome = review.noul >= 0.65 || risk.score >= 2
  ? 'HUMAN REVIEW RECOMMENDED'
  : 'REPORT ONLY';

const report = [
  '## Jev PR decision report',
  '- Outcome: **' + outcome + '**',
  '- Change type: **' + type.choice + '**',
  '- Type confidence: **' + type.confidence.toFixed(2) + '**',
  '- Risk score: **' + risk.score.toFixed(2) + ' / 3**',
  '- P(human review): **' + review.noul.toFixed(2) + '**',
  '- Diff truncated: **' + state.patch_truncated + '**',
].join('\n');

console.log(report);
if (process.env.GITHUB_STEP_SUMMARY) {
  appendFileSync(process.env.GITHUB_STEP_SUMMARY, report + '\n');
}

Why direct HTTP: it follows the request shape in the official quickstart and avoids pinning this tutorial to a community wrapper. Node 20 includes fetch and AbortSignal.timeout.

03

3. Ask several bounded questions in one request

The script sends one state and three independent questions: Choice for change type, Score for ordered risk, and Noul for whether human review is required. TypeSafe documents that questions against the same state are evaluated independently, so application policy must combine the answers after the response arrives.

Choicechange_type

Can only return feature, fix, maintenance, or unknown.

Scorerisk

Returns a position on the four-level risk scale, including between levels.

Noulneeds_human_review

Returns P(true) for the proposition and has no separate confidence field.

04

4. Validate the response before applying policy

A typed response still needs runtime validation. Check that Choice returned an allowed key, Score is finite and inside the declared range, and Noul is between zero and one. Then map the validated values to a visible policy; do not hide authority inside prompt wording.

ConditionReport-only phaseCalibrated gate
API timeout or invalid responseRecord provider_failure; CI continuesEscalate by team policy; never auto-approve
High risk or review probabilityHighlight in the job summaryRequire the existing human-approval rule
Low riskStill run tests and normal reviewDoes not imply permission to auto-merge
05

5. Run locally in report-only mode

Start with staged changes so a developer can inspect the exact evidence before committing. Report the result without blocking. This reveals oversized diffs, ambiguous labels, sensitive paths, and question-design problems before the workflow affects anyone else.

# Review exactly what is staged for the next commit.
export TYPESAFE_API_KEY='your-server-side-key'
node scripts/jev-pr-review.mjs

# Inspect the same range a pull request would use.
git fetch origin main
JEV_BASE=origin/main node scripts/jev-pr-review.mjs
06

6. Add a GitHub Actions reporter

The workflow checks out full history, fetches the pull request base, runs the same script, and appends the result to the job summary. Keep permissions read-only and store TYPESAFE_API_KEY as an Actions secret. Reporting first also gives you data for later calibration.

.github/workflows/jev-pr-report.yml
name: Jev PR report

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Fetch base branch
        run: git fetch origin "${{ github.base_ref }}"

      - name: Build Jev report
        env:
          TYPESAFE_API_KEY: "${{ secrets.TYPESAFE_API_KEY }}"
          JEV_BASE: "origin/${{ github.base_ref }}"
        run: node scripts/jev-pr-review.mjs
07

7. Calibrate before enabling a gate

Replay labeled historical pull requests and measure false approvals, unnecessary reviews, coverage, latency, and provider failures. Choose thresholds from observed error cost, not intuition. If you later make the job blocking, fail closed only for the specific high-risk condition your team has validated.

  • Prepare a human-labeled historical PR set with low-, medium-, and high-risk examples.
  • Log question version, model version, full distributions, thresholds, final human outcome, and overrides.
  • Measure false approvals and unnecessary blocks separately; their costs are rarely equal.
  • Move from report-only to required human review; do not begin with auto-merge.
  • Define fallbacks for provider failure, oversized diffs, sensitive paths, and truncated state.