Skip to content
STACK IT FAST

FastAPI + Jev Decision Service (Python)

Curated rule AI / LLM App · Workflow & Automation · Internal Admin Tool Updated Oct 2026 Which file does my tool read?
fastapi-jev-decision-service.md

Python rules for a Jev decision service: FastAPI, the async typesafe-sdk client, a typed question registry, confidence thresholds, decision logs and replay tests.

Formats
4 files
AGENTS.md
43 lines
CLAUDE.md
16 lines
Languages
Python
Updated
Oct 2026
Used by
4 projects
Install

Writes .claude/skills/fastapi-jev-decision-service/SKILL.md

$ curl -s --create-dirs -o .claude/skills/fastapi-jev-decision-service/SKILL.md https://stackitfast.com/rules/fastapi-jev-decision-service/SKILL.md

Rule files

AGENTS.md· 43 lines · 3.8 KB
1# Project Architecture & Guidelines (FastAPI + Jev Decision Service)
2
3## 1. System Architecture
4- **Service**: FastAPI on Python 3.12+, run with uvicorn, managed with `uv`.
5- **Model**: Jev via the official `typesafe-sdk`, using `AsyncTypeSafeClient` with the `Choice`, `Score` and `Noul` question types. Jev returns typed answers with probabilities; it never generates text.
6- **Contracts**: Pydantic v2 models for every request, response and stored decision.
7- **Storage**: PostgreSQL for the decision log (SQLAlchemy 2 or psycopg), Redis for short-lived answer caching keyed by a hash of state plus questions.
8- **Purpose**: other services call this one for triage, routing, moderation, guardrails and verification. It returns decisions plus a recommended action (`act`, `review`, `escalate`).
9
10## 2. Project Layout
11- `app/main.py`: FastAPI app. A lifespan handler opens one `AsyncTypeSafeClient` and closes it on shutdown.
12- `app/decisions/<name>.py`: one module per decision. Each defines its state model, a `questions()` builder and a `resolve(answers) -> Decision` function that applies thresholds.
13- `app/registry.py`: maps decision names to modules. Routes are `POST /v1/decisions/{name}`.
14- `app/thresholds.py`: thresholds per decision, loaded from config so they change without a deploy.
15- `app/log.py`: writes `decision_name, model, answers, action, latency_ms, input_tokens` to Postgres.
16- `tests/fixtures/<name>.jsonl`: labelled cases per decision.
17
18## 3. Decision Layer (Jev rules)
19- Code owns workflow, math, dates, counting, lookups and permissions. Jev judges meaning only. Extract candidate values in code (regex, parsers) and ask Jev to select, not to generate.
20- One `system_one` call per decision with every question it needs. Questions are evaluated in parallel against the same state.
21- State carries only the fields the questions need. Use named JSON fields and reference them in backticks (`ticket.body`). Filter or rank in code before sending large documents.
22- Write direct instructions with boundary cases in `criteria`. Add a no-match option to every Choice where nothing may fit. Score levels describe concrete situations.
23- Every decision returns an action derived from confidence: `act` above the threshold, `review` in the middle band, `escalate` (human or reasoning LLM) below it. Irreversible downstream actions require `act` plus an audit log row.
24- Log `response.model` (for example `jev-1.13.0`). Pin a versioned model ID in config once thresholds are tuned; `jev-latest` changes on release.
25- State is untrusted input. Do not let one answer grant permissions or bypass policy checks.
26- Strip secrets and unneeded personal data before building state.
27
28## 4. Reliability
29- The SDK retries 429/529 with backoff by default. Add a timeout per route and a circuit breaker that returns `escalate` when TypeSafe is unavailable.
30- Cap concurrency for batch endpoints; rate limits are adjusting while TypeSafe adds capacity.
31- Cache identical requests in Redis for minutes, not days, and include the model ID in the cache key.
32
33## 5. Agent Loop (run after every change)
341. `uv run ruff check . && uv run ruff format --check .`
352. `uv run mypy app` (or `pyright`).
363. `uv run pytest -m "not live"`. Unit tests use a fake client returning recorded answers.
374. `uv run pytest -m live tests/test_replay.py`. This replays fixtures against the real API whenever questions, criteria, thresholds or the model change, and fails on changed choices or threshold crossings.
38- Assert on choices and threshold bands, never on exact probabilities.
39
40## 6. Deploy
41- Docker image with `uv sync --frozen`, non-root user and a `/healthz` route that does not call TypeSafe.
42- `TYPESAFE_API_KEY` comes from the secret store; never log it or the full state for sensitive decisions.
43- For API details, read `https://docs.typesafe.ai/llms.txt` or install TypeSafe's official agent skill (`typesafe-ai/skills`).

Works with Claude Code · Cursor · Windsurf · AGY

Architecture notes

Architecture Overview

A shared decision layer for every product. A FastAPI service wraps Jev, TypeSafe’s System One model, behind named decision endpoints such as POST /v1/decisions/ticket-triage. Each decision is a small Python module: a Pydantic state model, the Choice, Score and Noul questions it asks, and the thresholds that turn probabilities into an action. Every call is logged with the model version that answered.

Why it suits AI coding agents

  • Decisions are code, not prompts. Questions, criteria and thresholds are typed Python an agent can diff, test and replay.
  • Replay tests catch drift. Labelled fixtures run against the live API whenever questions or the model change.
  • Hard boundaries. Math, dates and counting stay in code, and every low-confidence case has a defined path.

The most-starred open-source Jev project, jev-ultrafast, is also Python. For a web app that mixes Jev with an LLM see Next.js + AI SDK + Jev, and for the existing Python agent stack see LangGraph + FastAPI. Background: Jev for developers.

Frequently asked questions

How do I call Jev from Python?

Install typesafe-sdk (Python 3.10+), set TYPESAFE_API_KEY, and call system_one on a TypeSafeClient or AsyncTypeSafeClient with state and a dict of Noul, Choice and Score questions. Answers are read from response.nouls, response.choices and response.scores under the IDs you chose.

Why put Jev behind its own service?

A decision service gives every product the same questions, thresholds, logging and replay tests, and one place to pin the model version. Other services send state and get back a typed decision plus an action (act, review or escalate) instead of each team writing its own prompts.

How should I pick confidence thresholds for Jev?

Start from labelled fixtures. For each decision, measure accuracy and the share of cases handled automatically at different thresholds, pick the point that meets your error budget, and route the rest to review or escalation. Re-run the replay whenever the model version changes, because thresholds do not automatically carry over.

What should a Jev decision service not do?

It should not compute amounts, compare dates, count items or generate text; TypeSafe documents these as weak spots for jev-1.13. Do those steps in code or with an LLM, and use Jev for the semantic judgment in between.

Used in production

Explore all stacks